From 9069d98365dbe0a4360533a36e094d860519ca2c Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Mon, 22 Apr 2013 20:36:36 +1200 Subject: [PATCH] Reimplement pinging via the orders channel. --- OpenRA.Game/Network/Order.cs | 7 +++- OpenRA.Game/Network/Session.cs | 2 + OpenRA.Game/Network/UnitOrders.cs | 5 +++ OpenRA.Game/Server/Server.cs | 33 +++++++++++++++- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 1 + OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs | 16 -------- OpenRA.Mods.RA/ServerTraits/PlayerPinger.cs | 41 ++++++++++++++++++++ mods/cnc/mod.yaml | 1 + mods/d2k/mod.yaml | 1 + mods/ra/mod.yaml | 1 + 10 files changed, 89 insertions(+), 19 deletions(-) create mode 100644 OpenRA.Mods.RA/ServerTraits/PlayerPinger.cs 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: