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:
@@ -61,6 +61,7 @@ namespace OpenRA.Network
|
|||||||
public bool IsAdmin;
|
public bool IsAdmin;
|
||||||
public bool IsReady { get { return State == ClientState.Ready; } }
|
public bool IsReady { get { return State == ClientState.Ready; } }
|
||||||
public bool IsObserver { get { return Slot == null; } }
|
public bool IsObserver { get { return Slot == null; } }
|
||||||
|
public int Ping = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Slot
|
public class Slot
|
||||||
@@ -82,7 +83,7 @@ namespace OpenRA.Network
|
|||||||
public string Map;
|
public string Map;
|
||||||
public string[] Ban;
|
public string[] Ban;
|
||||||
public string[] Mods = { "ra" }; // mod names
|
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 int RandomSeed = 0;
|
||||||
public bool FragileAlliances = false; // Allow diplomatic stance changes after game start.
|
public bool FragileAlliances = false; // Allow diplomatic stance changes after game start.
|
||||||
public bool AllowCheats = false;
|
public bool AllowCheats = false;
|
||||||
|
|||||||
@@ -164,8 +164,7 @@ namespace OpenRA.Network
|
|||||||
&& !orderManager.GameStarted)
|
&& !orderManager.GameStarted)
|
||||||
{
|
{
|
||||||
orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency;
|
orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency;
|
||||||
Game.Debug(
|
Game.Debug("Order lag is now {0} frames.".F(orderManager.LobbyInfo.GlobalSettings.OrderLatency));
|
||||||
"Order lag is now {0} frames.".F(orderManager.LobbyInfo.GlobalSettings.OrderLatency));
|
|
||||||
}
|
}
|
||||||
Game.SyncLobbyInfo();
|
Game.SyncLobbyInfo();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace OpenRA.Server
|
namespace OpenRA.Server
|
||||||
{
|
{
|
||||||
@@ -22,8 +24,9 @@ namespace OpenRA.Server
|
|||||||
public ReceiveState State = ReceiveState.Header;
|
public ReceiveState State = ReceiveState.Header;
|
||||||
public int ExpectLength = 8;
|
public int ExpectLength = 8;
|
||||||
public int Frame = 0;
|
public int Frame = 0;
|
||||||
|
|
||||||
public int MostRecentFrame = 0;
|
public int MostRecentFrame = 0;
|
||||||
|
public string RemoteAddress;
|
||||||
|
public int Latency = -1;
|
||||||
|
|
||||||
/* client data */
|
/* client data */
|
||||||
public int PlayerIndex;
|
public int PlayerIndex;
|
||||||
@@ -97,7 +100,36 @@ namespace OpenRA.Server
|
|||||||
} break;
|
} 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 };
|
public enum ReceiveState { Header, Data };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ namespace OpenRA.Server
|
|||||||
public Map Map;
|
public Map Map;
|
||||||
XTimer gameTimeout;
|
XTimer gameTimeout;
|
||||||
|
|
||||||
|
int highestLatency;
|
||||||
|
|
||||||
protected volatile ServerState pState = new ServerState();
|
protected volatile ServerState pState = new ServerState();
|
||||||
public ServerState State
|
public ServerState State
|
||||||
{
|
{
|
||||||
@@ -215,6 +217,9 @@ namespace OpenRA.Server
|
|||||||
DispatchOrdersToClient(newConn, 0, 0, new ServerOrder("HandshakeRequest", request.Serialize()).Serialize());
|
DispatchOrdersToClient(newConn, 0, 0, new ServerOrder("HandshakeRequest", request.Serialize()).Serialize());
|
||||||
}
|
}
|
||||||
catch (Exception) { DropClient(newConn); }
|
catch (Exception) { DropClient(newConn); }
|
||||||
|
|
||||||
|
newConn.RemoteAddress = ((IPEndPoint)newConn.socket.RemoteEndPoint).Address.ToString();
|
||||||
|
newConn.Ping();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidateClient(Connection newConn, string data)
|
void ValidateClient(Connection newConn, string data)
|
||||||
@@ -266,8 +271,7 @@ namespace OpenRA.Server
|
|||||||
// Check if IP is banned
|
// Check if IP is banned
|
||||||
if (lobbyInfo.GlobalSettings.Ban != null)
|
if (lobbyInfo.GlobalSettings.Ban != null)
|
||||||
{
|
{
|
||||||
var remote_addr = ((IPEndPoint)newConn.socket.RemoteEndPoint).Address.ToString();
|
if (lobbyInfo.GlobalSettings.Ban.Contains(newConn.RemoteAddress))
|
||||||
if (lobbyInfo.GlobalSettings.Ban.Contains(remote_addr))
|
|
||||||
{
|
{
|
||||||
Console.WriteLine("Rejected connection from "+client.Name+"("+newConn.socket.RemoteEndPoint+"); Banned.");
|
Console.WriteLine("Rejected connection from "+client.Name+"("+newConn.socket.RemoteEndPoint+"); Banned.");
|
||||||
Log.Write("server", "Rejected connection from {0}; Banned.",
|
Log.Write("server", "Rejected connection from {0}; Banned.",
|
||||||
@@ -282,6 +286,8 @@ namespace OpenRA.Server
|
|||||||
preConns.Remove(newConn);
|
preConns.Remove(newConn);
|
||||||
conns.Add(newConn);
|
conns.Add(newConn);
|
||||||
|
|
||||||
|
client.Ping = newConn.Latency;
|
||||||
|
|
||||||
// Enforce correct PlayerIndex and Slot
|
// Enforce correct PlayerIndex and Slot
|
||||||
client.Index = newConn.PlayerIndex;
|
client.Index = newConn.PlayerIndex;
|
||||||
client.Slot = lobbyInfo.FirstEmptySlot();
|
client.Slot = lobbyInfo.FirstEmptySlot();
|
||||||
@@ -296,22 +302,24 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
OpenRA.Network.Session.Client clientAdmin = lobbyInfo.Clients.Where(c1 => c1.IsAdmin).Single();
|
OpenRA.Network.Session.Client clientAdmin = lobbyInfo.Clients.Where(c1 => c1.IsAdmin).Single();
|
||||||
|
|
||||||
Log.Write("server", "Client {0}: Accepted connection from {1}",
|
Log.Write("server", "Client {0}: Accepted connection from {1} with {2} ms ping latency.",
|
||||||
newConn.PlayerIndex, newConn.socket.RemoteEndPoint);
|
newConn.PlayerIndex, newConn.socket.RemoteEndPoint, newConn.Latency);
|
||||||
|
|
||||||
foreach (var t in ServerTraits.WithInterface<IClientJoined>())
|
foreach (var t in ServerTraits.WithInterface<IClientJoined>())
|
||||||
t.ClientJoined(this, newConn);
|
t.ClientJoined(this, newConn);
|
||||||
|
|
||||||
SyncLobbyInfo();
|
|
||||||
SendChat(newConn, "has joined the game.");
|
SendChat(newConn, "has joined the game.");
|
||||||
|
|
||||||
if ( File.Exists("{0}motd_{1}.txt".F(Platform.SupportDir, lobbyInfo.GlobalSettings.Mods[0])) )
|
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]));
|
var motd = System.IO.File.ReadAllText("{0}motd_{1}.txt".F(Platform.SupportDir, lobbyInfo.GlobalSettings.Mods[0]));
|
||||||
SendChatTo(newConn, motd);
|
SendChatTo(newConn, motd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( lobbyInfo.GlobalSettings.Dedicated )
|
if (lobbyInfo.GlobalSettings.Dedicated)
|
||||||
{
|
{
|
||||||
if (client.IsAdmin)
|
if (client.IsAdmin)
|
||||||
SendChatTo(newConn, " You are admin now!");
|
SendChatTo(newConn, " You are admin now!");
|
||||||
@@ -494,7 +502,10 @@ namespace OpenRA.Server
|
|||||||
SendChat(toDrop, "Admin left! {0} is a new admin now!".F(lastClient.Name));
|
SendChat(toDrop, "Admin left! {0} is a new admin now!".F(lastClient.Name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (highestLatency == toDrop.Latency)
|
||||||
|
SetDynamicOrderLag();
|
||||||
|
|
||||||
DispatchOrders( toDrop, toDrop.MostRecentFrame, new byte[] { 0xbf } );
|
DispatchOrders( toDrop, toDrop.MostRecentFrame, new byte[] { 0xbf } );
|
||||||
|
|
||||||
if (conns.Count != 0 || lobbyInfo.GlobalSettings.Dedicated)
|
if (conns.Count != 0 || lobbyInfo.GlobalSettings.Dedicated)
|
||||||
@@ -510,6 +521,23 @@ namespace OpenRA.Server
|
|||||||
catch { }
|
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()
|
public void SyncLobbyInfo()
|
||||||
{
|
{
|
||||||
if (State != ServerState.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. */
|
||||||
@@ -542,7 +570,7 @@ namespace OpenRA.Server
|
|||||||
t.GameStarted(this);
|
t.GameStarted(this);
|
||||||
|
|
||||||
// Check TimeOut
|
// Check TimeOut
|
||||||
if ( Settings.TimeOut > 10000 )
|
if (Settings.TimeOut > 10000)
|
||||||
{
|
{
|
||||||
gameTimeout = new XTimer(Settings.TimeOut);
|
gameTimeout = new XTimer(Settings.TimeOut);
|
||||||
gameTimeout.Elapsed += (_,e) =>
|
gameTimeout.Elapsed += (_,e) =>
|
||||||
|
|||||||
@@ -478,6 +478,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
template.Get<LabelWidget>("NAME").GetText = () => client.Name;
|
template.Get<LabelWidget>("NAME").GetText = () => client.Name;
|
||||||
if (client.IsAdmin)
|
if (client.IsAdmin)
|
||||||
template.Get<LabelWidget>("NAME").Font = "Bold";
|
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");
|
var color = template.Get<ColorBlockWidget>("COLOR");
|
||||||
color.GetColor = () => client.ColorRamp.GetColor(0);
|
color.GetColor = () => client.ColorRamp.GetColor(0);
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
if (c.IsAdmin)
|
if (c.IsAdmin)
|
||||||
name.Font = "Bold";
|
name.Font = "Bold";
|
||||||
name.Text = c.Name;
|
name.Text = c.Name;
|
||||||
|
if (c.Ping > -1)
|
||||||
|
name.TextColor = GetPingColor(c.Ping);
|
||||||
name.OnEnterKey = () =>
|
name.OnEnterKey = () =>
|
||||||
{
|
{
|
||||||
name.Text = name.Text.Trim();
|
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);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user