diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs index 0aa368a004..bac69badcf 100755 --- a/OpenRA.Game/Network/UnitOrders.cs +++ b/OpenRA.Game/Network/UnitOrders.cs @@ -51,14 +51,14 @@ namespace OpenRA.Network Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString); break; } - + case "Message": // Server message + Game.AddChatLine(Color.White, "Server", order.TargetString); + break; case "Disconnected": /* reports that the target player disconnected */ { var client = orderManager.LobbyInfo.ClientWithIndex(clientId); if (client != null) - { client.State = Session.ClientState.Disconnected; - } break; } diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs index a6fb8414c2..cb0d481268 100644 --- a/OpenRA.Game/Server/Server.cs +++ b/OpenRA.Game/Server/Server.cs @@ -306,7 +306,7 @@ namespace OpenRA.Server t.ClientJoined(this, newConn); SyncLobbyInfo(); - SendChat(newConn, "has joined the game."); + SendMessage("{0} has joined the server.".F(client.Name)); // Send initial ping SendOrderTo(newConn, "Ping", Environment.TickCount.ToString()); @@ -314,20 +314,18 @@ namespace OpenRA.Server if (File.Exists("{0}motd_{1}.txt".F(Platform.SupportDir, lobbyInfo.GlobalSettings.Mods[0]))) { var motd = System.IO.File.ReadAllText("{0}motd_{1}.txt".F(Platform.SupportDir, lobbyInfo.GlobalSettings.Mods[0])); - SendChatTo(newConn, motd); + SendOrderTo(newConn, "Message", motd); } if (lobbyInfo.GlobalSettings.Dedicated) { - if (client.IsAdmin) - SendChatTo(newConn, " You are admin now!"); - else - SendChatTo(newConn, " Current admin is {0}".F(clientAdmin.Name)); + var message = client.IsAdmin ? "You are the server admin." : "{0} is the server admin.".F(clientAdmin.Name); + SendOrderTo(newConn, "Message", message); } if (mods.Any(m => m.Contains("{DEV_VERSION}"))) - SendChat(newConn, "is running a non-versioned development build, "+ - "and may cause desync if it contains any incompatible changes."); + SendMessage("{0} is running an unversioned development build, ".F(client.Name) + + "and may desynchronize the game state if they have incompatible rules."); } catch (Exception) { DropClient(newConn); } } @@ -376,16 +374,19 @@ namespace OpenRA.Server catch (Exception) { DropClient(c); } } + public void DispatchOrdersToClients(Connection conn, int frame, byte[] data) + { + var from = conn != null ? conn.PlayerIndex : 0; + foreach (var c in conns.Except(conn).ToArray()) + DispatchOrdersToClient(c, from, frame, data); + } + public void DispatchOrders(Connection conn, int frame, byte[] data) { if (frame == 0 && conn != null) InterpretServerOrders(conn, data); else - { - var from = conn != null ? conn.PlayerIndex : 0; - foreach (var c in conns.Except(conn).ToArray()) - DispatchOrdersToClient(c, from, frame, data); - } + DispatchOrdersToClients(conn, frame, data); } void InterpretServerOrders(Connection conn, byte[] data) @@ -406,32 +407,18 @@ namespace OpenRA.Server catch (NotImplementedException) { } } - public void SendChatTo(Connection conn, string text) - { - SendOrderTo(conn, "Chat", text); - } - public void SendOrderTo(Connection conn, string order, string data) { - DispatchOrdersToClient(conn, 0, 0, - new ServerOrder(order, data).Serialize()); + DispatchOrdersToClient(conn, 0, 0, new ServerOrder(order, data).Serialize()); } - public void SendChat(Connection asConn, string text) + public void SendMessage(string text) { - DispatchOrders(asConn, 0, new ServerOrder("Chat", text).Serialize()); - } - - public void SendDisconnected(Connection asConn) - { - DispatchOrders(asConn, 0, new ServerOrder("Disconnected", "").Serialize()); + DispatchOrdersToClients(null, 0, new ServerOrder("Message", text).Serialize()); } void InterpretServerOrder(Connection conn, ServerOrder so) { - var fromClient = GetClient(conn); - var fromIndex = fromClient != null ? fromClient.Index : 0; - switch (so.Name) { case "Command": @@ -443,7 +430,7 @@ namespace OpenRA.Server if (!handled) { Log.Write("server", "Unknown server command: {0}", so.Data); - SendChatTo(conn, "Unknown server command: {0}".F(so.Data)); + SendOrderTo(conn, "Message", "Unknown server command: {0}".F(so.Data)); } break; @@ -451,16 +438,10 @@ namespace OpenRA.Server case "HandshakeResponse": ValidateClient(conn, so.Data); break; - case "Chat": case "TeamChat": - foreach (var c in conns.Except(conn).ToArray()) - DispatchOrdersToClient(c, fromIndex, 0, so.Serialize()); - break; - case "PauseGame": - foreach (var c in conns.Except(conn).ToArray()) - DispatchOrdersToClient(c, fromIndex, 0, so.Serialize()); + DispatchOrdersToClients(conn, 0, so.Serialize()); break; case "Pong": { @@ -471,6 +452,7 @@ namespace OpenRA.Server break; } + var fromClient = GetClient(conn); var history = fromClient.LatencyHistory.ToList(); history.Add(Environment.TickCount - pingSent); @@ -502,34 +484,37 @@ namespace OpenRA.Server else { conns.Remove(toDrop); - SendChat(toDrop, "Connection Dropped"); - + OpenRA.Network.Session.Client dropClient = lobbyInfo.Clients.Where(c1 => c1.Index == toDrop.PlayerIndex).Single(); - - if (State == ServerState.GameStarted) - SendDisconnected(toDrop); /* Report disconnection */ + + // Send disconnected order, even if still in the lobby + SendMessage("{0} has disconnected.".F(dropClient.Name)); + DispatchOrdersToClients(toDrop, 0, new ServerOrder("Disconnected", "").Serialize()); lobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex); - // reassign admin if necessary + // Client was the server admin + // TODO: Reassign admin for game in progress via an order if (lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers) { - // clean up the bots that were added by the last admin + // Remove any bots controlled by the admin lobbyInfo.Clients.RemoveAll(c => c.Bot != null && c.BotControllerClientIndex == toDrop.PlayerIndex); - if (lobbyInfo.Clients.Any(c1 => c1.Bot == null)) + OpenRA.Network.Session.Client nextAdmin = lobbyInfo.Clients.Where(c1 => c1.Bot == null) + .OrderBy(c => c.Index).FirstOrDefault(); + + if (nextAdmin != null) { - // client was not alone on the server but he was admin: set admin to the last connected client - OpenRA.Network.Session.Client lastClient = lobbyInfo.Clients.Where(c1 => c1.Bot == null).Last(); - lastClient.IsAdmin = true; - SendChat(toDrop, "Admin left! {0} is a new admin now!".F(lastClient.Name)); + nextAdmin.IsAdmin = true; + SendMessage("{0} is now the admin.".F(nextAdmin.Name)); } } - DispatchOrders( toDrop, toDrop.MostRecentFrame, new byte[] { 0xbf } ); + DispatchOrders(toDrop, toDrop.MostRecentFrame, new byte[] {0xbf}); if (conns.Count != 0 || lobbyInfo.GlobalSettings.Dedicated) SyncLobbyInfo(); + if (!lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin) Shutdown(); } diff --git a/OpenRA.Mods.RA/ConquestVictoryConditions.cs b/OpenRA.Mods.RA/ConquestVictoryConditions.cs index f37020a031..d183cb051b 100644 --- a/OpenRA.Mods.RA/ConquestVictoryConditions.cs +++ b/OpenRA.Mods.RA/ConquestVictoryConditions.cs @@ -10,6 +10,7 @@ using System.Linq; using OpenRA.FileFormats; +using OpenRA.Network; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -31,12 +32,29 @@ namespace OpenRA.Mods.RA Info = info; } + Session.Client HumanClient(Player p) + { + var client = p.World.LobbyInfo.ClientWithIndex(p.ClientIndex); + if (client != null && client.Bot != null) + return p.World.LobbyInfo.ClientWithIndex(client.BotControllerClientIndex); + return client; + } + public void Tick(Actor self) { - if (self.Owner.WinState != WinState.Undefined || self.Owner.NonCombatant) return; + if (self.Owner.NonCombatant) + return; + + // Surrender when the controlling player disconnects + var client = HumanClient(self.Owner); + if (client != null && client.State == Session.ClientState.Disconnected) + Lose(self); + + if (self.Owner.WinState != WinState.Undefined) + return; var hasAnything = self.World.ActorsWithTrait() - .Any( a => a.Actor.Owner == self.Owner ); + .Any(a => a.Actor.Owner == self.Owner); if (!hasAnything && !self.Owner.NonCombatant) Lose(self); @@ -44,9 +62,10 @@ namespace OpenRA.Mods.RA var others = self.World.Players.Where( p => !p.NonCombatant && p != self.Owner && p.Stances[self.Owner] != Stance.Ally ); - if (others.Count() == 0) return; + if (others.Count() == 0) + return; - if(others.All(p => p.WinState == WinState.Lost)) + if (others.All(p => p.WinState == WinState.Lost)) Win(self); } diff --git a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs index 277849175b..cea8278a39 100644 --- a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs +++ b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs @@ -30,7 +30,7 @@ namespace OpenRA.Mods.RA.Server if (requiresHost && !client.IsAdmin) { - server.SendChatTo(conn, "Only the host can do that"); + server.SendOrderTo(conn, "Message", "Only the host can do that"); return false; } @@ -41,12 +41,12 @@ namespace OpenRA.Mods.RA.Server { if (server.State == ServerState.GameStarted) { - server.SendChatTo(conn, "Cannot change state when game started. ({0})".F(cmd)); + server.SendOrderTo(conn, "Message", "Cannot change state when game started. ({0})".F(cmd)); return false; } else if (client.State == Session.ClientState.Ready && !(cmd == "ready" || cmd == "startgame")) { - server.SendChatTo(conn, "Cannot change state when marked as ready."); + server.SendOrderTo(conn, "Message", "Cannot change state when marked as ready."); return false; } @@ -94,7 +94,7 @@ namespace OpenRA.Mods.RA.Server if (server.lobbyInfo.Slots.Any(sl => sl.Value.Required && server.lobbyInfo.ClientInSlot(sl.Key) == null)) { - server.SendChatTo(conn, "Unable to start the game until required slots are full."); + server.SendOrderTo(conn, "Message", "Unable to start the game until required slots are full."); return true; } server.StartGame(); @@ -180,7 +180,7 @@ namespace OpenRA.Mods.RA.Server if (parts.Length < 3) { - server.SendChatTo(conn, "Malformed slot_bot command"); + server.SendOrderTo(conn, "Message", "Malformed slot_bot command"); return true; } @@ -200,7 +200,7 @@ namespace OpenRA.Mods.RA.Server // Invalid slot if (bot != null && bot.Bot == null) { - server.SendChatTo(conn, "Can't add bots to a slot with another client"); + server.SendOrderTo(conn, "Message", "Can't add bots to a slot with another client"); return true; } @@ -245,12 +245,13 @@ namespace OpenRA.Mods.RA.Server { if (!client.IsAdmin) { - server.SendChatTo( conn, "Only the host can change the map" ); + server.SendOrderTo(conn, "Message", "Only the host can change the map"); return true; } - if(!server.ModData.AvailableMaps.ContainsKey(s)) + + if (!server.ModData.AvailableMaps.ContainsKey(s)) { - server.SendChatTo( conn, "Map not found"); + server.SendOrderTo(conn, "Message", "Map not found"); return true; } server.lobbyInfo.GlobalSettings.Map = s; @@ -292,7 +293,7 @@ namespace OpenRA.Mods.RA.Server { if (!client.IsAdmin) { - server.SendChatTo( conn, "Only the host can set that option" ); + server.SendOrderTo(conn, "Message", "Only the host can set that option"); return true; } @@ -305,7 +306,7 @@ namespace OpenRA.Mods.RA.Server { if (!client.IsAdmin) { - server.SendChatTo( conn, "Only the host can set that option" ); + server.SendOrderTo(conn, "Message", "Only the host can set that option"); return true; } @@ -318,14 +319,14 @@ namespace OpenRA.Mods.RA.Server { if (!client.IsAdmin) { - server.SendChatTo(conn, "Only the host can set that option"); + server.SendOrderTo(conn, "Message", "Only the host can set that option"); return true; } int teams; if (!int.TryParse(s, out teams)) { - server.SendChatTo(conn, "Number of teams could not be parsed: {0}".F(s)); + server.SendOrderTo(conn, "Message", "Number of teams could not be parsed: {0}".F(s)); return true; } teams = teams.Clamp(2, 8); @@ -335,12 +336,12 @@ namespace OpenRA.Mods.RA.Server .Where(c => c != null && !server.lobbyInfo.Slots[c.Slot].LockTeam).ToArray(); if (players.Length < 2) { - server.SendChatTo(conn, "Not enough players to assign teams"); + server.SendOrderTo(conn, "Message", "Not enough players to assign teams"); return true; } if (teams > players.Length) { - server.SendChatTo(conn, "Too many teams for the number of players"); + server.SendOrderTo(conn, "Message", "Too many teams for the number of players"); return true; } @@ -367,7 +368,7 @@ namespace OpenRA.Mods.RA.Server { if (!client.IsAdmin) { - server.SendChatTo(conn, "Only the host can set that option"); + server.SendOrderTo(conn, "Message", "Only the host can set that option"); return true; } @@ -380,13 +381,13 @@ namespace OpenRA.Mods.RA.Server { if (!client.IsAdmin) { - server.SendChatTo(conn, "Only the host can set that option"); + server.SendOrderTo(conn, "Message", "Only the host can set that option"); return true; } if ((server.Map.Difficulties == null && s != null) || (server.Map.Difficulties != null && !server.Map.Difficulties.Contains(s))) { - server.SendChatTo(conn, "Unsupported difficulty selected: {0}".F(s)); - server.SendChatTo(conn, "Supported difficulties: {0}".F(server.Map.Difficulties.JoinWith(","))); + server.SendOrderTo(conn, "Message", "Unsupported difficulty selected: {0}".F(s)); + server.SendOrderTo(conn, "Message", "Supported difficulties: {0}".F(server.Map.Difficulties.JoinWith(","))); return true; } @@ -400,7 +401,7 @@ namespace OpenRA.Mods.RA.Server if (!client.IsAdmin) { - server.SendChatTo( conn, "Only the host can kick players" ); + server.SendOrderTo(conn, "Message", "Only the host can kick players"); return true; } @@ -410,7 +411,7 @@ namespace OpenRA.Mods.RA.Server var connToKick = server.conns.SingleOrDefault( c => server.GetClient(c) != null && server.GetClient(c).Index == clientID); if (connToKick == null) { - server.SendChatTo( conn, "Noone in that slot." ); + server.SendOrderTo(conn, "Message", "Noone in that slot."); return true; } @@ -497,7 +498,7 @@ namespace OpenRA.Mods.RA.Server if (server.lobbyInfo.Clients.Where( cc => cc != client ).Any( cc => (cc.SpawnPoint == spawnPoint) && (cc.SpawnPoint != 0) )) { - server.SendChatTo( conn, "You can't be at the same spawn point as another player" ); + server.SendOrderTo(conn, "Message", "You can't be at the same spawn point as another player"); return true; } diff --git a/OpenRA.Mods.RA/ServerTraits/MasterServerPinger.cs b/OpenRA.Mods.RA/ServerTraits/MasterServerPinger.cs index 86a1dcecaa..bac7c8b0e9 100644 --- a/OpenRA.Mods.RA/ServerTraits/MasterServerPinger.cs +++ b/OpenRA.Mods.RA/ServerTraits/MasterServerPinger.cs @@ -30,7 +30,7 @@ namespace OpenRA.Mods.RA.Server else lock (masterServerMessages) while (masterServerMessages.Count > 0) - server.SendChat(null, masterServerMessages.Dequeue()); + server.SendMessage(masterServerMessages.Dequeue()); }