|
|
|
|
@@ -32,6 +32,13 @@ namespace OpenRA.Server
|
|
|
|
|
ShuttingDown = 3
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum ServerType
|
|
|
|
|
{
|
|
|
|
|
Local = 0,
|
|
|
|
|
Multiplayer = 1,
|
|
|
|
|
Dedicated = 2
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class Server
|
|
|
|
|
{
|
|
|
|
|
public readonly string TwoHumansRequiredText = "This server requires at least two human players to start a match.";
|
|
|
|
|
@@ -39,7 +46,7 @@ namespace OpenRA.Server
|
|
|
|
|
public readonly IPAddress Ip;
|
|
|
|
|
public readonly int Port;
|
|
|
|
|
public readonly MersenneTwister Random = new MersenneTwister();
|
|
|
|
|
public readonly bool Dedicated;
|
|
|
|
|
public readonly ServerType Type;
|
|
|
|
|
|
|
|
|
|
// Valid player connections
|
|
|
|
|
public List<Connection> Conns = new List<Connection>();
|
|
|
|
|
@@ -122,7 +129,7 @@ namespace OpenRA.Server
|
|
|
|
|
t.GameEnded(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Server(IPEndPoint endpoint, ServerSettings settings, ModData modData, bool dedicated)
|
|
|
|
|
public Server(IPEndPoint endpoint, ServerSettings settings, ModData modData, ServerType type)
|
|
|
|
|
{
|
|
|
|
|
Log.AddChannel("server", "server.log", true);
|
|
|
|
|
|
|
|
|
|
@@ -131,7 +138,7 @@ namespace OpenRA.Server
|
|
|
|
|
var localEndpoint = (IPEndPoint)listener.LocalEndpoint;
|
|
|
|
|
Ip = localEndpoint.Address;
|
|
|
|
|
Port = localEndpoint.Port;
|
|
|
|
|
Dedicated = dedicated;
|
|
|
|
|
Type = type;
|
|
|
|
|
Settings = settings;
|
|
|
|
|
|
|
|
|
|
Settings.Name = OpenRA.Settings.SanitizedServerName(Settings.Name);
|
|
|
|
|
@@ -157,10 +164,10 @@ namespace OpenRA.Server
|
|
|
|
|
RandomSeed = randomSeed,
|
|
|
|
|
Map = settings.Map,
|
|
|
|
|
ServerName = settings.Name,
|
|
|
|
|
EnableSingleplayer = settings.EnableSingleplayer || !dedicated,
|
|
|
|
|
EnableSingleplayer = settings.EnableSingleplayer || Type != ServerType.Dedicated,
|
|
|
|
|
EnableSyncReports = settings.EnableSyncReports,
|
|
|
|
|
GameUid = Guid.NewGuid().ToString(),
|
|
|
|
|
Dedicated = dedicated
|
|
|
|
|
Dedicated = Type == ServerType.Dedicated
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -216,7 +223,7 @@ namespace OpenRA.Server
|
|
|
|
|
delayedActions.PerformActions(0);
|
|
|
|
|
|
|
|
|
|
// PERF: Dedicated servers need to drain the action queue to remove references blocking the GC from cleaning up disposed objects.
|
|
|
|
|
if (dedicated)
|
|
|
|
|
if (Type == ServerType.Dedicated)
|
|
|
|
|
Game.PerformDelayedActions();
|
|
|
|
|
|
|
|
|
|
foreach (var t in serverTraits.WithInterface<ITick>())
|
|
|
|
|
@@ -434,7 +441,7 @@ namespace OpenRA.Server
|
|
|
|
|
// Send initial ping
|
|
|
|
|
SendOrderTo(newConn, "Ping", Game.RunTime.ToString(CultureInfo.InvariantCulture));
|
|
|
|
|
|
|
|
|
|
if (Dedicated)
|
|
|
|
|
if (Type == ServerType.Dedicated)
|
|
|
|
|
{
|
|
|
|
|
var motdFile = Platform.ResolvePath(Platform.SupportDirPrefix, "motd.txt");
|
|
|
|
|
if (!File.Exists(motdFile))
|
|
|
|
|
@@ -502,9 +509,9 @@ namespace OpenRA.Server
|
|
|
|
|
|
|
|
|
|
delayedActions.Add(() =>
|
|
|
|
|
{
|
|
|
|
|
var notAuthenticated = Dedicated && profile == null && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Any());
|
|
|
|
|
var blacklisted = Dedicated && profile != null && Settings.ProfileIDBlacklist.Contains(profile.ProfileID);
|
|
|
|
|
var notWhitelisted = Dedicated && Settings.ProfileIDWhitelist.Any() &&
|
|
|
|
|
var notAuthenticated = Type == ServerType.Dedicated && profile == null && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Any());
|
|
|
|
|
var blacklisted = Type == ServerType.Dedicated && profile != null && Settings.ProfileIDBlacklist.Contains(profile.ProfileID);
|
|
|
|
|
var notWhitelisted = Type == ServerType.Dedicated && Settings.ProfileIDWhitelist.Any() &&
|
|
|
|
|
(profile == null || !Settings.ProfileIDWhitelist.Contains(profile.ProfileID));
|
|
|
|
|
|
|
|
|
|
if (notAuthenticated)
|
|
|
|
|
@@ -534,7 +541,7 @@ namespace OpenRA.Server
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (Dedicated && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Any()))
|
|
|
|
|
if (Type == ServerType.Dedicated && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Any()))
|
|
|
|
|
{
|
|
|
|
|
Log.Write("server", "Rejected connection from {0}; Not authenticated.", newConn.Socket.RemoteEndPoint);
|
|
|
|
|
SendOrderTo(newConn, "ServerError", "Server requires players to have an OpenRA forum account");
|
|
|
|
|
@@ -616,7 +623,7 @@ namespace OpenRA.Server
|
|
|
|
|
{
|
|
|
|
|
DispatchOrdersToClients(conn, 0, Order.FromTargetString("Message", text, true).Serialize());
|
|
|
|
|
|
|
|
|
|
if (Dedicated)
|
|
|
|
|
if (Type == ServerType.Dedicated)
|
|
|
|
|
Console.WriteLine("[{0}] {1}".F(DateTime.Now.ToString(Settings.TimestampFormat), text));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -731,7 +738,7 @@ namespace OpenRA.Server
|
|
|
|
|
|
|
|
|
|
case "LoadGameSave":
|
|
|
|
|
{
|
|
|
|
|
if (Dedicated || State >= ServerState.GameStarted)
|
|
|
|
|
if (Type == ServerType.Dedicated || State >= ServerState.GameStarted)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// Sanitize potentially malicious input
|
|
|
|
|
@@ -834,7 +841,7 @@ namespace OpenRA.Server
|
|
|
|
|
|
|
|
|
|
// Client was the server admin
|
|
|
|
|
// TODO: Reassign admin for game in progress via an order
|
|
|
|
|
if (Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers)
|
|
|
|
|
if (Type == ServerType.Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers)
|
|
|
|
|
{
|
|
|
|
|
// Remove any bots controlled by the admin
|
|
|
|
|
LobbyInfo.Clients.RemoveAll(c => c.Bot != null && c.BotControllerClientIndex == toDrop.PlayerIndex);
|
|
|
|
|
@@ -856,10 +863,10 @@ namespace OpenRA.Server
|
|
|
|
|
foreach (var t in serverTraits.WithInterface<INotifyServerEmpty>())
|
|
|
|
|
t.ServerEmpty(this);
|
|
|
|
|
|
|
|
|
|
if (Conns.Any() || Dedicated)
|
|
|
|
|
if (Conns.Any() || Type == ServerType.Dedicated)
|
|
|
|
|
SyncLobbyClients();
|
|
|
|
|
|
|
|
|
|
if (!Dedicated && dropClient.IsAdmin)
|
|
|
|
|
if (Type != ServerType.Dedicated && dropClient.IsAdmin)
|
|
|
|
|
Shutdown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -952,7 +959,7 @@ namespace OpenRA.Server
|
|
|
|
|
|
|
|
|
|
// Enable game saves for singleplayer missions only
|
|
|
|
|
// TODO: Enable for multiplayer (non-dedicated servers only) once the lobby UI has been created
|
|
|
|
|
LobbyInfo.GlobalSettings.GameSavesEnabled = !Dedicated && LobbyInfo.NonBotClients.Count() == 1;
|
|
|
|
|
LobbyInfo.GlobalSettings.GameSavesEnabled = Type != ServerType.Dedicated && LobbyInfo.NonBotClients.Count() == 1;
|
|
|
|
|
|
|
|
|
|
SyncLobbyInfo();
|
|
|
|
|
State = ServerState.GameStarted;
|
|
|
|
|
|