diff --git a/OpenRA.Game/Network/Order.cs b/OpenRA.Game/Network/Order.cs
index 015851a406..271202841b 100755
--- a/OpenRA.Game/Network/Order.cs
+++ b/OpenRA.Game/Network/Order.cs
@@ -199,7 +199,12 @@ namespace OpenRA
{
return new Order("HandshakeResponse", null, false) { IsImmediate = true, TargetString = text };
}
-
+
+ public static Order Pong(string pingTime)
+ {
+ return new Order("Pong", null, false) { IsImmediate = true, TargetString = pingTime };
+ }
+
public static Order PauseGame(bool paused)
{
return new Order("PauseGame", null, false) { TargetString = paused ? "Pause" : "UnPause" };
diff --git a/OpenRA.Game/Network/Session.cs b/OpenRA.Game/Network/Session.cs
index a57135b012..98301611b3 100644
--- a/OpenRA.Game/Network/Session.cs
+++ b/OpenRA.Game/Network/Session.cs
@@ -62,6 +62,8 @@ namespace OpenRA.Network
public bool IsReady { get { return State == ClientState.Ready; } }
public bool IsObserver { get { return Slot == null; } }
public int Ping = -1;
+ public int PingJitter = -1;
+ public int[] PingHistory = {};
}
public class Slot
diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs
index c16408fe1d..ed65a20529 100755
--- a/OpenRA.Game/Network/UnitOrders.cs
+++ b/OpenRA.Game/Network/UnitOrders.cs
@@ -190,6 +190,11 @@ namespace OpenRA.Network
Game.Debug("{0} has reciprocated",targetPlayer.PlayerName);
}
+ break;
+ }
+ case "Ping":
+ {
+ orderManager.IssueOrder(Order.Pong(order.TargetString));
break;
}
default:
diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs
index d15a9df43e..b962608669 100644
--- a/OpenRA.Game/Server/Server.cs
+++ b/OpenRA.Game/Server/Server.cs
@@ -290,8 +290,9 @@ namespace OpenRA.Server
SyncClientToPlayerReference(client, Map.Players[client.Slot]);
lobbyInfo.Clients.Add(client);
- //Assume that first validated client is server admin
- if(lobbyInfo.Clients.Where(c1 => c1.Bot == null).Count()==1)
+
+ // Assume that first validated client is server admin
+ if (lobbyInfo.Clients.Where(c1 => c1.Bot == null).Count() == 1)
client.IsAdmin=true;
OpenRA.Network.Session.Client clientAdmin = lobbyInfo.Clients.Where(c1 => c1.IsAdmin).Single();
@@ -305,6 +306,9 @@ namespace OpenRA.Server
SyncLobbyInfo();
SendChat(newConn, "has joined the game.");
+ // Send initial ping
+ SendOrderTo(newConn, "Ping", Environment.TickCount.ToString());
+
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]));
@@ -456,6 +460,31 @@ namespace OpenRA.Server
foreach (var c in conns.Except(conn).ToArray())
DispatchOrdersToClient(c, fromIndex, 0, so.Serialize());
break;
+ case "Pong":
+ {
+ int pingSent;
+ if (!int.TryParse(so.Data, out pingSent))
+ {
+ Log.Write("server", "Invalid order pong payload: {0}", so.Data);
+ break;
+ }
+
+ var history = fromClient.PingHistory.ToList();
+ history.Add(Environment.TickCount - pingSent);
+
+ // Cap ping history at 5 values (25 seconds)
+ if (history.Count > 5)
+ history.RemoveRange(0, history.Count - 5);
+
+ fromClient.Ping = history.Sum() / history.Count;
+ fromClient.PingJitter = (history.Max() - history.Min())/2;
+ fromClient.PingHistory = history.ToArray();
+
+ if (State == ServerState.WaitingPlayers)
+ SyncLobbyInfo();
+
+ break;
+ }
}
}
diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj
index 9af3413a88..df0d79d224 100644
--- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj
+++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj
@@ -429,6 +429,7 @@
+
diff --git a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs
index 0fbb96e0fd..1d2b742c82 100644
--- a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs
+++ b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs
@@ -100,22 +100,6 @@ namespace OpenRA.Mods.RA.Server
server.StartGame();
return true;
}},
- { "lag",
- s =>
- {
- int lag;
- 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);
-
- server.lobbyInfo.GlobalSettings.OrderLatency = lag;
- server.SyncLobbyInfo();
- return true;
- }},
{ "slot",
s =>
{
diff --git a/OpenRA.Mods.RA/ServerTraits/PlayerPinger.cs b/OpenRA.Mods.RA/ServerTraits/PlayerPinger.cs
new file mode 100644
index 0000000000..cf94efda72
--- /dev/null
+++ b/OpenRA.Mods.RA/ServerTraits/PlayerPinger.cs
@@ -0,0 +1,41 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
+ * This file is part of OpenRA, which is free software. It is made
+ * available to you under the terms of the GNU General Public License
+ * as published by the Free Software Foundation. For more information,
+ * see COPYING.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using OpenRA.Server;
+using OpenRA.Network;
+using S = OpenRA.Server.Server;
+
+namespace OpenRA.Mods.RA.Server
+{
+ public class PlayerPinger : ServerTrait, ITick
+ {
+ int PingInterval = 5000; // Ping every 5 seconds
+
+ // TickTimeout is in microseconds
+ public int TickTimeout { get { return PingInterval * 100; } }
+
+ int lastPing = 0;
+ bool isInitialPing = true;
+ public void Tick(S server)
+ {
+ if ((Environment.TickCount - lastPing > PingInterval) || isInitialPing)
+ {
+ isInitialPing = false;
+ lastPing = Environment.TickCount;
+ foreach (var p in server.conns)
+ server.SendOrderTo(p, "Ping", Environment.TickCount.ToString());
+ }
+ }
+ }
+}
diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml
index d45403031f..a306881e58 100644
--- a/mods/cnc/mod.yaml
+++ b/mods/cnc/mod.yaml
@@ -112,6 +112,7 @@ LoadScreen: CncLoadScreen
ServerTraits:
LobbyCommands
+ PlayerPinger
MasterServerPinger
ChromeMetrics:
diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml
index 1af3dc4afa..477dd592b6 100644
--- a/mods/d2k/mod.yaml
+++ b/mods/d2k/mod.yaml
@@ -89,6 +89,7 @@ LoadScreen: D2kLoadScreen
ServerTraits:
LobbyCommands
+ PlayerPinger
MasterServerPinger
ChromeMetrics:
diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml
index bbe96b670d..ae392c4e35 100644
--- a/mods/ra/mod.yaml
+++ b/mods/ra/mod.yaml
@@ -103,6 +103,7 @@ LoadScreen: RALoadScreen
ServerTraits:
LobbyCommands
+ PlayerPinger
MasterServerPinger
ChromeMetrics: