Merge pull request #3000 from Mailaender/dynamic-orderlag

Display Ping of joining Clients in Lobby and use it to calculate OrderLatency
This commit is contained in:
Chris Forbes
2013-04-20 16:57:00 -07:00
6 changed files with 88 additions and 14 deletions

View File

@@ -61,6 +61,7 @@ namespace OpenRA.Network
public bool IsAdmin;
public bool IsReady { get { return State == ClientState.Ready; } }
public bool IsObserver { get { return Slot == null; } }
public int Ping = -1;
}
public class Slot
@@ -82,7 +83,7 @@ namespace OpenRA.Network
public string Map;
public string[] Ban;
public string[] Mods = { "ra" }; // mod names
public int OrderLatency = 3;
public int OrderLatency = 3; // net tick frames (x 120 = ms)
public int RandomSeed = 0;
public bool FragileAlliances = false; // Allow diplomatic stance changes after game start.
public bool AllowCheats = false;

View File

@@ -164,8 +164,7 @@ namespace OpenRA.Network
&& !orderManager.GameStarted)
{
orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency;
Game.Debug(
"Order lag is now {0} frames.".F(orderManager.LobbyInfo.GlobalSettings.OrderLatency));
Game.Debug("Order lag is now {0} frames.".F(orderManager.LobbyInfo.GlobalSettings.OrderLatency));
}
Game.SyncLobbyInfo();
break;

View File

@@ -12,6 +12,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Threading;
namespace OpenRA.Server
{
@@ -22,8 +24,9 @@ namespace OpenRA.Server
public ReceiveState State = ReceiveState.Header;
public int ExpectLength = 8;
public int Frame = 0;
public int MostRecentFrame = 0;
public string RemoteAddress;
public int Latency = -1;
/* client data */
public int PlayerIndex;
@@ -97,7 +100,36 @@ namespace OpenRA.Server
} break;
}
}
}}
}
bool hasBeenPinged;
public void Ping()
{
if (!hasBeenPinged)
{
hasBeenPinged = true;
var pingSender = new Ping();
pingSender.PingCompleted += new PingCompletedEventHandler(pongRecieved);
AutoResetEvent waiter = new AutoResetEvent(false);
pingSender.SendAsync(RemoteAddress, waiter);
}
}
void pongRecieved(object sender, PingCompletedEventArgs e)
{
if (e.Cancelled || e.Error != null)
Latency = -1;
else
{
PingReply pong = e.Reply;
if (pong != null && pong.Status == IPStatus.Success)
Latency = (int)pong.RoundtripTime;
else
Latency = -1;
}
}
}
public enum ReceiveState { Header, Data };
}

View File

@@ -59,6 +59,8 @@ namespace OpenRA.Server
public Map Map;
XTimer gameTimeout;
int highestLatency;
protected volatile ServerState pState = new ServerState();
public ServerState State
{
@@ -215,6 +217,9 @@ namespace OpenRA.Server
DispatchOrdersToClient(newConn, 0, 0, new ServerOrder("HandshakeRequest", request.Serialize()).Serialize());
}
catch (Exception) { DropClient(newConn); }
newConn.RemoteAddress = ((IPEndPoint)newConn.socket.RemoteEndPoint).Address.ToString();
newConn.Ping();
}
void ValidateClient(Connection newConn, string data)
@@ -266,8 +271,7 @@ namespace OpenRA.Server
// Check if IP is banned
if (lobbyInfo.GlobalSettings.Ban != null)
{
var remote_addr = ((IPEndPoint)newConn.socket.RemoteEndPoint).Address.ToString();
if (lobbyInfo.GlobalSettings.Ban.Contains(remote_addr))
if (lobbyInfo.GlobalSettings.Ban.Contains(newConn.RemoteAddress))
{
Console.WriteLine("Rejected connection from "+client.Name+"("+newConn.socket.RemoteEndPoint+"); Banned.");
Log.Write("server", "Rejected connection from {0}; Banned.",
@@ -282,6 +286,8 @@ namespace OpenRA.Server
preConns.Remove(newConn);
conns.Add(newConn);
client.Ping = newConn.Latency;
// Enforce correct PlayerIndex and Slot
client.Index = newConn.PlayerIndex;
client.Slot = lobbyInfo.FirstEmptySlot();
@@ -296,15 +302,17 @@ namespace OpenRA.Server
OpenRA.Network.Session.Client clientAdmin = lobbyInfo.Clients.Where(c1 => c1.IsAdmin).Single();
Log.Write("server", "Client {0}: Accepted connection from {1}",
newConn.PlayerIndex, newConn.socket.RemoteEndPoint);
Log.Write("server", "Client {0}: Accepted connection from {1} with {2} ms ping latency.",
newConn.PlayerIndex, newConn.socket.RemoteEndPoint, newConn.Latency);
foreach (var t in ServerTraits.WithInterface<IClientJoined>())
t.ClientJoined(this, newConn);
SyncLobbyInfo();
SendChat(newConn, "has joined the game.");
SetDynamicOrderLag();
SyncLobbyInfo();
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]));
@@ -495,6 +503,9 @@ namespace OpenRA.Server
}
}
if (highestLatency == toDrop.Latency)
SetDynamicOrderLag();
DispatchOrders( toDrop, toDrop.MostRecentFrame, new byte[] { 0xbf } );
if (conns.Count != 0 || lobbyInfo.GlobalSettings.Dedicated)
@@ -510,6 +521,23 @@ namespace OpenRA.Server
catch { }
}
public void SetDynamicOrderLag()
{
foreach (var conn in conns)
{
if (conn.Latency > highestLatency)
highestLatency = conn.Latency;
}
Log.Write("server", "Measured {0} ms as the highest connection round trip time.".F(highestLatency));
lobbyInfo.GlobalSettings.OrderLatency = highestLatency / 120;
if (lobbyInfo.GlobalSettings.OrderLatency < 1) // should never be 0
lobbyInfo.GlobalSettings.OrderLatency = 1;
Log.Write("server", "Order lag has been adjusted to {0} frames.".F(lobbyInfo.GlobalSettings.OrderLatency));
}
public void SyncLobbyInfo()
{
if (State != ServerState.GameStarted) /* don't do this while the game is running, it breaks things. */

View File

@@ -478,6 +478,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
template.Get<LabelWidget>("NAME").GetText = () => client.Name;
if (client.IsAdmin)
template.Get<LabelWidget>("NAME").Font = "Bold";
if (client.Ping > -1)
template.Get<LabelWidget>("NAME").GetColor = () => LobbyUtils.GetPingColor(client.Ping);
var color = template.Get<ColorBlockWidget>("COLOR");
color.GetColor = () => client.ColorRamp.GetColor(0);

View File

@@ -26,6 +26,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (c.IsAdmin)
name.Font = "Bold";
name.Text = c.Name;
if (c.Ping > -1)
name.TextColor = GetPingColor(c.Ping);
name.OnEnterKey = () =>
{
name.Text = name.Text.Trim();
@@ -189,5 +191,14 @@ namespace OpenRA.Mods.RA.Widgets.Logic
Game.Renderer.Fonts["Bold"].DrawTextWithContrast(client.Name, position + new int2(5, 5), Color.White, Color.Black, 1);
}
}
public static Color GetPingColor(int ping)
{
if (ping > 720) // OrderLag > 6
return Color.Red;
if (ping > 360) // OrderLag > 3
return Color.Orange;
return Color.LimeGreen;
}
}
}