From f365f9da2b5f7bfd762269cf0da301d9aea0cdb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Wed, 16 Apr 2014 17:29:26 +0200 Subject: [PATCH] split lobby SyncInfo order into smaller chunks closes #4594 --- OpenRA.Game/Network/Session.cs | 31 ++++++++-- OpenRA.Game/Network/UnitOrders.cs | 62 ++++++++++++++++++-- OpenRA.Game/Server/Server.cs | 50 +++++++++++++++- OpenRA.Mods.RA/Player/PlayerStatistics.cs | 5 +- OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs | 58 +++++++++--------- 5 files changed, 166 insertions(+), 40 deletions(-) diff --git a/OpenRA.Game/Network/Session.cs b/OpenRA.Game/Network/Session.cs index 8e5ad45553..58d4242b2f 100644 --- a/OpenRA.Game/Network/Session.cs +++ b/OpenRA.Game/Network/Session.cs @@ -110,6 +110,13 @@ namespace OpenRA.Network public int Latency = -1; public int LatencyJitter = -1; public int[] LatencyHistory = { }; + + public string Serialize() + { + var clientData = new List(); + clientData.Add(new MiniYamlNode("Client@{0}".F(this.Index), FieldSaver.Save(this))); + return clientData.WriteToString(); + } } public class Slot @@ -123,6 +130,13 @@ namespace OpenRA.Network public bool LockTeam; public bool LockSpawn; public bool Required; + + public string Serialize() + { + var slotData = new List(); + slotData.Add(new MiniYamlNode("Slot@{0}".F(this.PlayerReference), FieldSaver.Save(this))); + return slotData.WriteToString(); + } } public class Global @@ -144,21 +158,28 @@ namespace OpenRA.Network public string StartingUnitsClass = "none"; public bool AllowVersionMismatch; public string GameUid; + + public string Serialize() + { + var globalData = new List(); + globalData.Add(new MiniYamlNode("GlobalSettings", FieldSaver.Save(this))); + return globalData.WriteToString(); + } } public string Serialize() { - var clientData = new List(); + var sessionData = new System.Text.StringBuilder(); foreach (var client in Clients) - clientData.Add(new MiniYamlNode("Client@{0}".F(client.Index), FieldSaver.Save(client))); + sessionData.Append(client.Serialize()); foreach (var slot in Slots) - clientData.Add(new MiniYamlNode("Slot@{0}".F(slot.Key), FieldSaver.Save(slot.Value))); + sessionData.Append(slot.Value.Serialize()); - clientData.Add(new MiniYamlNode("GlobalSettings", FieldSaver.Save(GlobalSettings))); + sessionData.Append(GlobalSettings.Serialize()); - return clientData.WriteToString(); + return sessionData.ToString(); } } } diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs index 87b501bc90..f7f629e800 100644 --- a/OpenRA.Game/Network/UnitOrders.cs +++ b/OpenRA.Game/Network/UnitOrders.cs @@ -8,6 +8,7 @@ */ #endregion +using System.Collections.Generic; using System.Drawing; using System.Linq; using OpenRA.Traits; @@ -162,13 +163,57 @@ namespace OpenRA.Network case "SyncInfo": { orderManager.LobbyInfo = Session.Deserialize(order.TargetString); + SetOrderLag(orderManager); + Game.SyncLobbyInfo(); + break; + } - if (orderManager.FramesAhead != orderManager.LobbyInfo.GlobalSettings.OrderLatency - && !orderManager.GameStarted) + case "SyncLobbyClients": + { + var clients = new List(); + var nodes = MiniYaml.FromString(order.TargetString); + foreach (var node in nodes) { - orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency; - Log.Write("server", "Order lag is now {0} frames.", orderManager.LobbyInfo.GlobalSettings.OrderLatency); + var strings = node.Key.Split('@'); + if (strings[0] == "Client") + clients.Add(FieldLoader.Load(node.Value)); } + + orderManager.LobbyInfo.Clients = clients; + Game.SyncLobbyInfo(); + break; + } + + case "SyncLobbySlots": + { + var slots = new Dictionary(); + var nodes = MiniYaml.FromString(order.TargetString); + foreach (var node in nodes) + { + var strings = node.Key.Split('@'); + if (strings[0] == "Slot") + { + var slot = FieldLoader.Load(node.Value); + slots.Add(slot.PlayerReference, slot); + } + } + + orderManager.LobbyInfo.Slots = slots; + Game.SyncLobbyInfo(); + break; + } + + case "SyncLobbyGlobalSettings": + { + var nodes = MiniYaml.FromString(order.TargetString); + foreach (var node in nodes) + { + var strings = node.Key.Split('@'); + if (strings[0] == "GlobalSettings") + FieldLoader.Load(orderManager.LobbyInfo.GlobalSettings, node.Value); + } + + SetOrderLag(orderManager); Game.SyncLobbyInfo(); break; } @@ -227,5 +272,14 @@ namespace OpenRA.Network foreach (var nsc in w.ActorsWithTrait()) nsc.Trait.StanceChanged(nsc.Actor, p, target, oldStance, s); } + + static void SetOrderLag(OrderManager o) + { + if (o.FramesAhead != o.LobbyInfo.GlobalSettings.OrderLatency && !o.GameStarted) + { + o.FramesAhead = o.LobbyInfo.GlobalSettings.OrderLatency; + Log.Write("server", "Order lag is now {0} frames.", o.LobbyInfo.GlobalSettings.OrderLatency); + } + } } } diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs index a07fc1361c..614221da22 100644 --- a/OpenRA.Game/Server/Server.cs +++ b/OpenRA.Game/Server/Server.cs @@ -361,7 +361,7 @@ namespace OpenRA.Server else LobbyInfo.GlobalSettings.OrderLatency = 3; - SyncLobbyInfo(); + SyncLobbyGlobalSettings(); } public void UpdateInFlightFrames(Connection conn) @@ -485,7 +485,7 @@ namespace OpenRA.Server fromClient.LatencyHistory = history.ToArray(); if (State == ServerState.WaitingPlayers) - SyncLobbyInfo(); + SyncLobbyClients(); // TODO: SyncClientLatency break; } @@ -545,7 +545,7 @@ namespace OpenRA.Server } if (Conns.Any() || LobbyInfo.GlobalSettings.Dedicated) - SyncLobbyInfo(); + SyncLobbyClients(); if (!LobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin) Shutdown(); @@ -570,6 +570,50 @@ namespace OpenRA.Server t.LobbyInfoSynced(this); } + public void SyncLobbyClients() + { + if (State != ServerState.WaitingPlayers) + return; + + var clientData = new System.Text.StringBuilder(); + foreach (var client in LobbyInfo.Clients) + clientData.Append(client.Serialize()); + + DispatchOrders(null, 0, + new ServerOrder("SyncLobbyClients", clientData.ToString()).Serialize()); + + foreach (var t in serverTraits.WithInterface()) + t.LobbyInfoSynced(this); + } + + public void SyncLobbySlots() + { + if (State != ServerState.WaitingPlayers) + return; + + var slotData = new System.Text.StringBuilder(); + foreach (var slot in LobbyInfo.Slots) + slotData.Append(slot.Value.Serialize()); + + DispatchOrders(null, 0, + new ServerOrder("SyncLobbySlots", slotData.ToString()).Serialize()); + + foreach (var t in serverTraits.WithInterface()) + t.LobbyInfoSynced(this); + } + + public void SyncLobbyGlobalSettings() + { + if (State != ServerState.WaitingPlayers) + return; + + DispatchOrders(null, 0, + new ServerOrder("SyncLobbyGlobalSettings", LobbyInfo.GlobalSettings.Serialize()).Serialize()); + + foreach (var t in serverTraits.WithInterface()) + t.LobbyInfoSynced(this); + } + public void StartGame() { listener.Stop(); diff --git a/OpenRA.Mods.RA/Player/PlayerStatistics.cs b/OpenRA.Mods.RA/Player/PlayerStatistics.cs index 23550375cd..71175c7bc7 100644 --- a/OpenRA.Mods.RA/Player/PlayerStatistics.cs +++ b/OpenRA.Mods.RA/Player/PlayerStatistics.cs @@ -91,7 +91,10 @@ namespace OpenRA.Mods.RA case "Disconnected": case "ServerError": case "AuthenticationError": - case "SyncInfo": + case "SyncLobbyInfo": + case "SyncClientInfo": + case "SyncLobbySlots": + case "SyncLobbyGlobalSettings": return; } if (order.OrderString.StartsWith("Dev")) diff --git a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs index bd1721f8e6..5b1866dec9 100644 --- a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs +++ b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs @@ -91,7 +91,7 @@ namespace OpenRA.Mods.RA.Server Log.Write("server", "Player @{0} is {1}", conn.socket.RemoteEndPoint, client.State); - server.SyncLobbyInfo(); + server.SyncLobbyClients(); CheckAutoStart(server, conn, client); @@ -106,7 +106,7 @@ namespace OpenRA.Mods.RA.Server return true; } - if (server.LobbyInfo.Slots.Any(sl => sl.Value.Required && + if (server.LobbyInfo.Slots.Any(sl => sl.Value.Required && server.LobbyInfo.ClientInSlot(sl.Key) == null)) { server.SendOrderTo(conn, "Message", "Unable to start the game until required slots are full."); @@ -130,8 +130,7 @@ namespace OpenRA.Mods.RA.Server client.Slot = s; S.SyncClientToPlayerReference(client, server.Map.Players[s]); - - server.SyncLobbyInfo(); + server.SyncLobbyClients(); CheckAutoStart(server, conn, client); return true; @@ -141,7 +140,7 @@ namespace OpenRA.Mods.RA.Server { if (bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllowSpectators)) { - server.SyncLobbyInfo(); + server.SyncLobbyGlobalSettings(); return true; } else @@ -158,7 +157,7 @@ namespace OpenRA.Mods.RA.Server client.Slot = null; client.SpawnPoint = 0; client.Color = HSLColor.FromRGB(255, 255, 255); - server.SyncLobbyInfo(); + server.SyncLobbyClients(); return true; } else @@ -167,7 +166,7 @@ namespace OpenRA.Mods.RA.Server { "slot_close", s => { - if (!ValidateSlotCommand( server, conn, client, s, true )) + if (!ValidateSlotCommand(server, conn, client, s, true)) return false; // kick any player that's in the slot @@ -178,7 +177,7 @@ namespace OpenRA.Mods.RA.Server server.LobbyInfo.Clients.Remove(occupant); else { - var occupantConn = server.Conns.FirstOrDefault( c => c.PlayerIndex == occupant.Index ); + var occupantConn = server.Conns.FirstOrDefault(c => c.PlayerIndex == occupant.Index); if (occupantConn != null) { server.SendOrderTo(occupantConn, "ServerError", "Your slot was closed by the host"); @@ -188,7 +187,7 @@ namespace OpenRA.Mods.RA.Server } server.LobbyInfo.Slots[s].Closed = true; - server.SyncLobbyInfo(); + server.SyncLobbySlots(); return true; }}, { "slot_open", @@ -199,13 +198,14 @@ namespace OpenRA.Mods.RA.Server var slot = server.LobbyInfo.Slots[s]; slot.Closed = false; + server.SyncLobbySlots(); // Slot may have a bot in it var occupant = server.LobbyInfo.ClientInSlot(s); if (occupant != null && occupant.Bot != null) server.LobbyInfo.Clients.Remove(occupant); + server.SyncLobbyClients(); - server.SyncLobbyInfo(); return true; }}, { "slot_bot", @@ -272,7 +272,8 @@ namespace OpenRA.Mods.RA.Server } S.SyncClientToPlayerReference(bot, server.Map.Players[parts[0]]); - server.SyncLobbyInfo(); + server.SyncLobbyClients(); + server.SyncLobbySlots(); return true; }}, { "map", @@ -290,6 +291,7 @@ namespace OpenRA.Mods.RA.Server return true; } server.LobbyInfo.GlobalSettings.Map = s; + var oldSlots = server.LobbyInfo.Slots.Keys.ToArray(); LoadMap(server); SetDefaultDifficulty(server); @@ -342,7 +344,7 @@ namespace OpenRA.Mods.RA.Server } bool.TryParse(s, out server.LobbyInfo.GlobalSettings.FragileAlliances); - server.SyncLobbyInfo(); + server.SyncLobbyGlobalSettings(); return true; }}, { "allowcheats", @@ -361,7 +363,7 @@ namespace OpenRA.Mods.RA.Server } bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllowCheats); - server.SyncLobbyInfo(); + server.SyncLobbyGlobalSettings(); return true; }}, { "shroud", @@ -380,7 +382,7 @@ namespace OpenRA.Mods.RA.Server } bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Shroud); - server.SyncLobbyInfo(); + server.SyncLobbyGlobalSettings(); return true; }}, { "fog", @@ -400,7 +402,7 @@ namespace OpenRA.Mods.RA.Server bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Fog); - server.SyncLobbyInfo(); + server.SyncLobbyGlobalSettings(); return true; }}, { "assignteams", @@ -441,7 +443,7 @@ namespace OpenRA.Mods.RA.Server player.Team = assigned++ * teamCount / playerCount + 1; } - server.SyncLobbyInfo(); + server.SyncLobbyClients(); return true; }}, { "crates", @@ -460,7 +462,7 @@ namespace OpenRA.Mods.RA.Server } bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Crates); - server.SyncLobbyInfo(); + server.SyncLobbyGlobalSettings(); return true; }}, { "allybuildradius", @@ -479,7 +481,7 @@ namespace OpenRA.Mods.RA.Server } bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllyBuildRadius); - server.SyncLobbyInfo(); + server.SyncLobbyGlobalSettings(); return true; }}, { "difficulty", @@ -499,7 +501,7 @@ namespace OpenRA.Mods.RA.Server } server.LobbyInfo.GlobalSettings.Difficulty = s; - server.SyncLobbyInfo(); + server.SyncLobbyGlobalSettings(); return true; }}, { "startingunits", @@ -518,7 +520,7 @@ namespace OpenRA.Mods.RA.Server } server.LobbyInfo.GlobalSettings.StartingUnitsClass = s; - server.SyncLobbyInfo(); + server.SyncLobbyGlobalSettings(); return true; }}, { "startingcash", @@ -537,7 +539,8 @@ namespace OpenRA.Mods.RA.Server } server.LobbyInfo.GlobalSettings.StartingCash = Exts.ParseIntegerInvariant(s); - server.SyncLobbyInfo(); + server.SyncLobbyGlobalSettings(); + return true; }}, { "kick", @@ -581,7 +584,8 @@ namespace OpenRA.Mods.RA.Server server.TempBans.Add(kickConnIP); } - server.SyncLobbyInfo(); + server.SyncLobbyClients(); + server.SyncLobbySlots(); return true; }}, { "name", @@ -589,7 +593,7 @@ namespace OpenRA.Mods.RA.Server { Log.Write("server", "Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s); client.Name = s; - server.SyncLobbyInfo(); + server.SyncLobbyClients(); return true; }}, { "race", @@ -607,7 +611,7 @@ namespace OpenRA.Mods.RA.Server return true; targetClient.Country = parts[1]; - server.SyncLobbyInfo(); + server.SyncLobbyClients(); return true; }}, { "team", @@ -632,7 +636,7 @@ namespace OpenRA.Mods.RA.Server } targetClient.Team = team; - server.SyncLobbyInfo(); + server.SyncLobbyClients(); return true; }}, { "spawn", @@ -668,7 +672,7 @@ namespace OpenRA.Mods.RA.Server } targetClient.SpawnPoint = spawnPoint; - server.SyncLobbyInfo(); + server.SyncLobbyClients(); return true; }}, { "color", @@ -687,7 +691,7 @@ namespace OpenRA.Mods.RA.Server var ci = parts[1].Split(',').Select(cc => Exts.ParseIntegerInvariant(cc)).ToArray(); targetClient.Color = targetClient.PreferredColor = new HSLColor((byte)ci[0], (byte)ci[1], (byte)ci[2]); - server.SyncLobbyInfo(); + server.SyncLobbyClients(); return true; }} };