Merge pull request #3244 from pchote/bot-surrender
Improvements to player drop behavior
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<MustBeDestroyed>()
|
||||
.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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user