Add a 'Shutting down' state to the gameserver.

Tell the masterserver about it, so it can quickly remove games
from the list when they are finished, rather than waiting for the
5 minute TTL to expire.
This commit is contained in:
Sam Hegarty
2012-11-22 20:04:27 +13:00
committed by Chris Forbes
parent 3a77082c66
commit 0c104cfc3a
5 changed files with 48 additions and 20 deletions

View File

@@ -313,7 +313,8 @@ namespace OpenRA
{
System.Threading.Thread.Sleep(100);
if((server.GameStarted)&&(server.conns.Count<=1))
if((server.State == Server.ServerState.GameStarted)
&& (server.conns.Count<=1))
{
Console.WriteLine("No one is playing, shutting down...");
server.Shutdown();

View File

@@ -26,6 +26,13 @@ using XTimer = System.Timers.Timer;
namespace OpenRA.Server
{
public enum ServerState : int
{
WaitingPlayers = 1,
GameStarted = 2,
ShuttingDown = 3
}
public class Server
{
// Valid player connections
@@ -40,7 +47,7 @@ namespace OpenRA.Server
TypeDictionary ServerTraits = new TypeDictionary();
public Session lobbyInfo;
public bool GameStarted = false;
public readonly IPAddress Ip;
public readonly int Port;
int randomSeed;
@@ -51,16 +58,31 @@ namespace OpenRA.Server
public Map Map;
XTimer gameTimeout;
volatile bool shutdown = false;
protected volatile ServerState pState = new ServerState();
public ServerState State
{
get { return pState; }
protected set { pState = value; }
}
public void Shutdown()
{
shutdown = true;
State = ServerState.ShuttingDown;
}
public void EndGame()
{
foreach (var t in ServerTraits.WithInterface<IEndGame>())
t.GameEnded(this);
if (Settings.AllowUPnP)
RemovePortforward();
}
public Server(IPEndPoint endpoint, string[] mods, ServerSettings settings, ModData modData)
{
Log.AddChannel("server", "server.log");
pState = ServerState.WaitingPlayers;
listener = new TcpListener(endpoint);
listener.Start();
var localEndpoint = (IPEndPoint)listener.LocalEndpoint;
@@ -140,10 +162,9 @@ namespace OpenRA.Server
foreach( var c in preConns ) checkRead.Add( c.socket );
Socket.Select( checkRead, null, null, timeout );
if (shutdown)
if (State == ServerState.ShuttingDown)
{
if (Settings.AllowUPnP)
RemovePortforward();
EndGame();
break;
}
@@ -159,15 +180,13 @@ namespace OpenRA.Server
foreach (var t in ServerTraits.WithInterface<ITick>())
t.Tick(this);
if (shutdown)
if (State == ServerState.ShuttingDown)
{
if (Settings.AllowUPnP)
RemovePortforward();
EndGame();
break;
}
}
GameStarted = false;
foreach (var t in ServerTraits.WithInterface<INotifyServerShutdown>())
t.ServerShutdown(this);
@@ -245,7 +264,7 @@ namespace OpenRA.Server
{
try
{
if (GameStarted)
if (State == ServerState.GameStarted)
{
Log.Write("server", "Rejected connection from {0}; game is already started.",
newConn.socket.RemoteEndPoint);
@@ -498,13 +517,13 @@ namespace OpenRA.Server
OpenRA.Network.Session.Client dropClient = lobbyInfo.Clients.Where(c1 => c1.Index == toDrop.PlayerIndex).Single();
if (GameStarted)
if (State == ServerState.GameStarted)
SendDisconnected(toDrop); /* Report disconnection */
lobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex);
// reassign admin if necessary
if ( lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin && !GameStarted)
if ( lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers)
{
if (lobbyInfo.Clients.Where(c1 => c1.Bot == null).Count() > 0)
{
@@ -530,7 +549,7 @@ namespace OpenRA.Server
public void SyncLobbyInfo()
{
if (!GameStarted) /* don't do this while the game is running, it breaks things. */
if (State != ServerState.GameStarted) /* don't do this while the game is running, it breaks things. */
DispatchOrders(null, 0,
new ServerOrder("SyncInfo", lobbyInfo.Serialize()).Serialize());
@@ -540,7 +559,7 @@ namespace OpenRA.Server
public void StartGame()
{
GameStarted = true;
State = ServerState.GameStarted;
listener.Stop();
Console.WriteLine("Game started");

View File

@@ -20,6 +20,7 @@ namespace OpenRA.Server
public interface INotifyServerShutdown { void ServerShutdown(Server server); }
public interface IStartGame { void GameStarted(Server server); }
public interface IClientJoined { void ClientJoined(Server server, Connection conn); }
public interface IEndGame { void GameEnded(Server server); }
public interface ITick
{
void Tick(Server server);
@@ -28,7 +29,7 @@ namespace OpenRA.Server
public abstract class ServerTrait {}
public class DebugServerTrait : ServerTrait, IInterpretCommand, IStartGame, INotifySyncLobbyInfo, INotifyServerStart, INotifyServerShutdown
public class DebugServerTrait : ServerTrait, IInterpretCommand, IStartGame, INotifySyncLobbyInfo, INotifyServerStart, INotifyServerShutdown, IEndGame
{
public bool InterpretCommand(Server server, Connection conn, Session.Client client, string cmd)
{
@@ -55,5 +56,10 @@ namespace OpenRA.Server
{
Console.WriteLine("ServerShutdown()");
}
public void GameEnded(Server server)
{
Console.WriteLine("GameEnded()");
}
}
}

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Mods.RA.Server
public static bool ValidateCommand(S server, Connection conn, Session.Client client, string cmd)
{
if (server.GameStarted)
if (server.State == ServerState.GameStarted)
{
server.SendChatTo(conn, "Cannot change state when game started. ({0})".F(cmd));
return false;

View File

@@ -17,7 +17,7 @@ using S = OpenRA.Server.Server;
namespace OpenRA.Mods.RA.Server
{
public class MasterServerPinger : ServerTrait, ITick, INotifySyncLobbyInfo, IStartGame
public class MasterServerPinger : ServerTrait, ITick, INotifySyncLobbyInfo, IStartGame, IEndGame
{
const int MasterPingInterval = 60 * 3; // 3 minutes. server has a 5 minute TTL for games, so give ourselves a bit
// of leeway.
@@ -36,6 +36,7 @@ namespace OpenRA.Mods.RA.Server
public void LobbyInfoSynced(S server) { PingMasterServer(server); }
public void GameStarted(S server) { PingMasterServer(server); }
public void GameEnded(S server) { PingMasterServer(server); }
int lastPing = 0;
bool isInitialPing = true;
@@ -60,10 +61,11 @@ namespace OpenRA.Mods.RA.Server
using (var wc = new WebClient())
{
wc.Proxy = null;
wc.DownloadData(
server.Settings.MasterServer + url.F(
server.Settings.ExternalPort, Uri.EscapeUriString(server.Settings.Name),
server.GameStarted ? 2 : 1, // todo: post-game states, etc.
(int) server.State,
server.lobbyInfo.Clients.Count,
Game.CurrentMods.Select(f => "{0}@{1}".F(f.Key, f.Value.Version)).JoinWith(","),
server.lobbyInfo.GlobalSettings.Map,