diff --git a/OpenRA.Game/Network/Session.cs b/OpenRA.Game/Network/Session.cs index b82ef6548d..ffa6be46dc 100644 --- a/OpenRA.Game/Network/Session.cs +++ b/OpenRA.Game/Network/Session.cs @@ -57,6 +57,7 @@ namespace OpenRA.Network public int Team; public string Slot; // slot ID, or null for observer public string Bot; // Bot type, null for real clients + public int BotControllerClientIndex; // who added the bot to the slot public bool IsAdmin; public bool IsReady { get { return State == ClientState.Ready; } } public bool IsObserver { get { return Slot == null; } } diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs index 33086d414a..43c8477d43 100644 --- a/OpenRA.Game/Server/Server.cs +++ b/OpenRA.Game/Server/Server.cs @@ -528,9 +528,11 @@ namespace OpenRA.Server SendDisconnected(toDrop); /* Report disconnection */ lobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex); + // remove the bots he added + lobbyInfo.Clients.RemoveAll(c => c.BotControllerClientIndex == toDrop.PlayerIndex); // reassign admin if necessary - if ( lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers) + if (lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers) { if (lobbyInfo.Clients.Where(c1 => c1.Bot == null).Count() > 0) { @@ -545,7 +547,7 @@ namespace OpenRA.Server if (conns.Count != 0 || lobbyInfo.GlobalSettings.Dedicated) SyncLobbyInfo(); - if ( !lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin ) + if (!lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin) Shutdown(); } diff --git a/OpenRA.Game/Traits/ValidateOrder.cs b/OpenRA.Game/Traits/ValidateOrder.cs index b284c98716..fe50800bde 100644 --- a/OpenRA.Game/Traits/ValidateOrder.cs +++ b/OpenRA.Game/Traits/ValidateOrder.cs @@ -31,8 +31,7 @@ namespace OpenRA.Traits return false; } - // Hack: Assumes bots always run on clientId 0. - var isBotOrder = subjectClient.Bot != null && clientId == 0; + var isBotOrder = subjectClient.Bot != null && clientId == subjectClient.BotControllerClientIndex; // Drop exploiting orders if (subjectClientId != clientId && !isBotOrder) diff --git a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs index fa94b7977d..de24739eba 100644 --- a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs +++ b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs @@ -104,7 +104,11 @@ namespace OpenRA.Mods.RA.Server s => { int lag; - if (!int.TryParse(s, out lag)) { Log.Write("server", "Invalid order lag: {0}", s); return false; } + if (!int.TryParse(s, out lag)) + { + Log.Write("server", "Invalid order lag: {0}", s); + return false; + } Log.Write("server", "Order lag is now {0} frames.", lag); @@ -190,23 +194,29 @@ namespace OpenRA.Mods.RA.Server { var parts = s.Split(' '); - if (parts.Length < 2) + if (parts.Length < 3) { - server.SendChatTo( conn, "Malformed slot_bot command" ); + server.SendChatTo(conn, "Malformed slot_bot command"); return true; } - if (!ValidateSlotCommand( server, conn, client, parts[0], true )) + if (!ValidateSlotCommand(server, conn, client, parts[0], true)) return false; var slot = server.lobbyInfo.Slots[parts[0]]; var bot = server.lobbyInfo.ClientInSlot(parts[0]); - var botType = parts.Skip(1).JoinWith(" "); + int controllerClientIndex; + if (!int.TryParse(parts[1], out controllerClientIndex)) + { + Log.Write("server", "Invalid bot controller client index: {0}", parts[1]); + return false; + } + var botType = parts.Skip(2).JoinWith(" "); // Invalid slot if (bot != null && bot.Bot == null) { - server.SendChatTo( conn, "Can't add bots to a slot with another client" ); + server.SendChatTo(conn, "Can't add bots to a slot with another client"); return true; } @@ -223,7 +233,8 @@ namespace OpenRA.Mods.RA.Server Country = "random", SpawnPoint = 0, Team = 0, - State = Session.ClientState.NotReady + State = Session.ClientState.NotReady, + BotControllerClientIndex = controllerClientIndex }; // pick a random color for the bot @@ -410,7 +421,7 @@ namespace OpenRA.Mods.RA.Server } int clientID; - int.TryParse( s, out clientID ); + int.TryParse(s, out clientID); var connToKick = server.conns.SingleOrDefault( c => server.GetClient(c) != null && server.GetClient(c).Index == clientID); if (connToKick == null) @@ -465,7 +476,11 @@ namespace OpenRA.Mods.RA.Server return true; int team; - if (!int.TryParse(parts[1], out team)) { Log.Write("server", "Invalid team: {0}", s ); return false; } + if (!int.TryParse(parts[1], out team)) + { + Log.Write("server", "Invalid team: {0}", s ); + return false; + } targetClient.Team = team; server.SyncLobbyInfo(); @@ -546,7 +561,7 @@ namespace OpenRA.Mods.RA.Server static Session.Slot MakeSlotFromPlayerReference(PlayerReference pr) { if (!pr.Playable) return null; - if (Game.Settings.Server.LockBots || Game.Settings.Server.Dedicated) + if (Game.Settings.Server.LockBots) pr.AllowBots = false; return new Session.Slot { diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs index c235888f40..618653d372 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs @@ -287,8 +287,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic { var slot = orderManager.LobbyInfo.FirstEmptySlot(); var bot = Rules.Info["player"].Traits.WithInterface().Select(t => t.Name).FirstOrDefault(); + var botController = orderManager.LobbyInfo.Clients.Where(c => c.IsAdmin).FirstOrDefault(); if (slot != null && bot != null) - orderManager.IssueOrder(Order.Command("slot_bot {0} {1}".F(slot, bot))); + orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot, botController.Index, bot))); }); } diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs index 12d792dd00..58369cf830 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyUtils.cs @@ -71,8 +71,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic foreach (var b in Rules.Info["player"].Traits.WithInterface().Select(t => t.Name)) { var bot = b; + var botController = orderManager.LobbyInfo.Clients.Where(c => c.IsAdmin).FirstOrDefault(); options.Add(new SlotDropDownOption("Bot: {0}".F(bot), - "slot_bot {0} {1}".F(slot.PlayerReference, bot), + "slot_bot {0} {1} {2}".F(slot.PlayerReference, botController.Index, bot), () => client != null && client.Bot == bot)); }