Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .idea/.idea.Intersect/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ public ServerStatusRequestPacket(byte[] responseKey) : base(responseKey)
}

[Key(2)] public byte[] VersionData { get; set; }
}

[Key(3)] public byte[] StateToken { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ public partial class ServerStatusResponsePacket : UnconnectedResponsePacket
{
[Key(1)]
public NetworkStatus Status { get; set; }
}

[Key(2)] public byte[] StateToken { get; set; }
}
126 changes: 88 additions & 38 deletions Intersect.Client.Core/MonoGame/Network/MonoSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Intersect.Core;
using Intersect.Framework.Core;
using Intersect.Network.Packets.Unconnected.Client;
using Intersect.Network.Packets.Unconnected.Server;
using Intersect.Rsa;
using Microsoft.Extensions.Logging;

Expand Down Expand Up @@ -97,6 +98,9 @@ public override IClient Network
private int? _lastPort;
private IPEndPoint? _lastEndpoint;
private volatile bool _resolvingHost;
private int _ping;

private ServerStatusRequestMetadata? _serverStatusRequestMetadata;

public static MonoSocket Instance { get; private set; } = default!;

Expand All @@ -108,7 +112,7 @@ internal MonoSocket(IClientContext context)

public override bool IsConnected => Network.IsConnected;

public override int Ping => Network.Ping;
public override int Ping => _ping < 0 ? Network.Ping : _ping;

private bool TryResolveEndPoint([NotNullWhen(true)] out IPEndPoint? endPoint)
{
Expand Down Expand Up @@ -210,60 +214,80 @@ public override void Update()
OnDataReceived(dequeued.Value);
}

// ReSharper disable once InvertIf
if (Globals.GameState == GameStates.Menu)
switch (Globals.GameState)
{
var now = Timing.Global.MillisecondsUtc;
// ReSharper disable once InvertIf
if (_nextServerStatusPing <= now || MainMenu.LastNetworkStatusChangeTime < 0)
case GameStates.InGame:
case GameStates.Error:
case GameStates.Intro:
case GameStates.Loading:
_ping = -1;
break;

case GameStates.Menu:
{
if (!_resolvingHost)
var now = Timing.Global.MillisecondsUtc;
// ReSharper disable once InvertIf
if (_nextServerStatusPing <= now || MainMenu.LastNetworkStatusChangeTime < 0)
{
_resolvingHost = true;
Task.Run(
() =>
{
try
if (!_resolvingHost)
{
_resolvingHost = true;
Task.Run(
() =>
{
if (TryResolveEndPoint(out var serverEndpoint))
try
{
var network = Network;
if (network == default)
if (TryResolveEndPoint(out var serverEndpoint))
{
ApplicationContext.Context.Value?.Logger.LogInformation("No network created to poll for server status.");
var network = Network;
if (network == default)
{
ApplicationContext.Context.Value?.Logger.LogInformation("No network created to poll for server status.");
}
else
{
ServerStatusRequestMetadata requestMetadata = new()
{
RequestTime = DateTime.UtcNow,
StateToken = Guid.NewGuid(),
};

network.SendUnconnected(
serverEndpoint,
new ServerStatusRequestPacket
{
StateToken = requestMetadata.StateToken.ToByteArray(),
VersionData = SharedConstants.VersionData,
}
);

_serverStatusRequestMetadata = requestMetadata;
}
}
else
else if (!ClientNetwork.UnresolvableHostNames.Contains(_lastHost))
{
network.SendUnconnected(
serverEndpoint,
new ServerStatusRequestPacket
{
VersionData = SharedConstants.VersionData,
}
);
ApplicationContext.Context.Value?.Logger.LogInformation($"Unable to resolve '{_lastHost}:{_lastPort}'");
}
}
else if (!ClientNetwork.UnresolvableHostNames.Contains(_lastHost))
catch (Exception exception)
{
ApplicationContext.Context.Value?.Logger.LogInformation($"Unable to resolve '{_lastHost}:{_lastPort}'");
ApplicationContext.Context.Value?.Logger.LogError(exception, "Error resolving host");
}

_resolvingHost = false;
}
catch (Exception exception)
{
ApplicationContext.Context.Value?.Logger.LogError(exception, "Error resolving host");
}
);
}

_resolvingHost = false;
}
);
}
if (MainMenu.LastNetworkStatusChangeTime + (int)(ServerStatusPingInterval * 1.5f) < now)
{
MainMenu.SetNetworkStatus(NetworkStatus.Offline);
}

if (MainMenu.LastNetworkStatusChangeTime + (int)(ServerStatusPingInterval * 1.5f) < now)
{
MainMenu.SetNetworkStatus(NetworkStatus.Offline);
_nextServerStatusPing = now + ServerStatusPingInterval;
}

_nextServerStatusPing = now + ServerStatusPingInterval;
break;
}
}
}
Expand All @@ -279,4 +303,30 @@ public override void Dispose()
_network?.Dispose();
_network = default;
}

public void NotifyServerStatusResponse(ServerStatusResponsePacket responsePacket)
{
var now = DateTime.UtcNow;

if (_serverStatusRequestMetadata is not {} requestMetadata)
{
return;
}

Guid responseStateToken = new(responsePacket.StateToken);
if (requestMetadata.StateToken != responseStateToken)
{
return;
}

var elapsed = now - requestMetadata.RequestTime;
_ping = (int)elapsed.TotalMilliseconds;
_serverStatusRequestMetadata = null;
}

private record struct ServerStatusRequestMetadata
{
public DateTime RequestTime { get; init; }
public Guid StateToken { get; init; }
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Intersect.Client.Interface.Menu;
using Intersect.Client.MonoGame.Network;
using Intersect.Core;
using Intersect.Network;
using Intersect.Network.Packets.Unconnected.Server;
Expand All @@ -13,6 +14,7 @@ public override bool Handle(IPacketSender packetSender, ServerStatusResponsePack
{
try
{
MonoSocket.Instance?.NotifyServerStatusResponse(packet);
MainMenu.SetNetworkStatus(packet.Status);
return true;
}
Expand All @@ -22,4 +24,4 @@ public override bool Handle(IPacketSender packetSender, ServerStatusResponsePack
return false;
}
}
}
}
37 changes: 2 additions & 35 deletions Intersect.Network/ClientNetwork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,41 +72,8 @@ public int Ping

if (Configuration.Host is not { } hostNameOrAddress || UnresolvableHostNames.Contains(hostNameOrAddress))
{
return -1;
}

try
{
// TODO: Add feature-specific log filtering, this one gets annoying
// ApplicationContext.Logger.LogTrace("Sending ping to server");

// Send a ping to the server. Timeout: 5000ms (5 seconds). Packet size: 32 bytes. TTL: 64. Don't fragment.
var reply = _ping.Send(hostNameOrAddress, 5000, [], new PingOptions(64, true));
if (reply is { Status: IPStatus.Success })
{
// Return the roundtrip time in milliseconds (ms) as an integer value (no decimals).
return (int)reply.RoundtripTime;
}
}
catch (PingException pingException)
{
if (pingException.InnerException is SocketException { SocketErrorCode: SocketError.HostNotFound })
{
UnresolvableHostNames.Add(hostNameOrAddress);
ApplicationContext.Logger.LogWarning(
pingException,
"Invalid hostname '{HostNameOrAddress}' will not be pinged again",
hostNameOrAddress
);
}
else
{
ApplicationContext.Logger.LogWarning(pingException, "Error sending ping request");
}
}
catch (Exception exception)
{
ApplicationContext.Logger.LogWarning(exception, "Unknown error sending ping request");
// Return a distinct ping value for unresolved host addresses so that it's clear why it's not showing
return -2;
}

return -1;
Expand Down
16 changes: 12 additions & 4 deletions Intersect.Network/LiteNetLib/LiteNetLibInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -483,14 +483,22 @@ public void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketRead

public void OnNetworkLatencyUpdate(NetPeer peer, int latency)
{
#if !DIAGNOSTIC
if (latency < 1)

#if DIAGNOSTIC
var logLatencyUpdate = true;
#else
if (latency < 0)
{
return;
}

var logLatencyUpdate = latency > 0;
#endif

ApplicationContext.CurrentContext.Logger.LogTrace("LATENCY {Peer} {Latency}ms", peer, latency);
if (logLatencyUpdate)
{
ApplicationContext.CurrentContext.Logger.LogTrace("LATENCY {Peer} {Latency}ms", peer, latency);
}

if (!_connectionIdLookup.TryGetValue(peer.Id, out var connectionId))
{
Expand Down Expand Up @@ -616,4 +624,4 @@ public void OnConnectionRequest(ConnectionRequest request)

ApplicationContext.Context.Value?.Logger.LogDebug($"Approved {peer} ({connection.Guid})");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public override bool Handle(IPacketSender packetSender, ServerStatusRequestPacke
{
ResponseKey = packet.ResponseKey,
Status = NetworkStatus.VersionMismatch,
StateToken = packet.StateToken,
}
);
}
Expand All @@ -27,6 +28,7 @@ public override bool Handle(IPacketSender packetSender, ServerStatusRequestPacke
{
ResponseKey = packet.ResponseKey,
Status = NetworkStatus.ServerFull,
StateToken = packet.StateToken,
}
);
}
Expand All @@ -36,7 +38,8 @@ public override bool Handle(IPacketSender packetSender, ServerStatusRequestPacke
{
ResponseKey = packet.ResponseKey,
Status = NetworkStatus.Online,
StateToken = packet.StateToken,
}
);
}
}
}
Loading