Skip to content

Commit

Permalink
Network timing synchronization.
Browse files Browse the repository at this point in the history
Lidgren NetTime.Now is now synchronized to IGameTiming.RealTime.

NetChannel is now a nested class of NetManager.

Add IGameTiming.ServerTime, INetChannel.RemoteTimeOffset, INetChannel.RemoteTime
  • Loading branch information
PJB3005 committed Feb 9, 2021
1 parent c5a961d commit 6973d43
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 89 deletions.
2 changes: 1 addition & 1 deletion Lidgren.Network/Lidgren.Network
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ protected override void Update(FrameEventArgs args)

_contents.Text = $@"Paused: {_gameTiming.Paused}, CurTick: {_gameTiming.CurTick}/{_gameTiming.CurTick-1}, CurServerTick: {_gameState.CurServerTick}, Pred: {_gameTiming.CurTick.Value - _gameState.CurServerTick.Value-1}
CurTime: {_gameTiming.CurTime:hh\:mm\:ss\.ff}, RealTime: {_gameTiming.RealTime:hh\:mm\:ss\.ff}, CurFrame: {_gameTiming.CurFrame}
TickTimingAdjustment: {_gameTiming.TickTimingAdjustment}";
ServerTime: {_gameTiming.ServerTime}, TickTimingAdjustment: {_gameTiming.TickTimingAdjustment}";

MinimumSizeChanged();
}
Expand Down
13 changes: 12 additions & 1 deletion Robust.Shared/Interfaces/Network/INetChannel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Net;
using System;
using System.Net;
using Robust.Shared.Network;

namespace Robust.Shared.Interfaces.Network
Expand Down Expand Up @@ -34,6 +35,16 @@ public interface INetChannel

LoginType AuthType { get; }

/// <summary>
/// Offset between local RealTime and remote RealTime.
/// </summary>
TimeSpan RemoteTimeOffset { get; }

/// <summary>
/// Remote RealTime.
/// </summary>
TimeSpan RemoteTime { get; }

/// <summary>
/// Average round trip time in milliseconds between the remote peer and us.
/// </summary>
Expand Down
9 changes: 9 additions & 0 deletions Robust.Shared/Interfaces/Timing/IGameTiming.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ public interface IGameTiming
/// </summary>
TimeSpan RealTime { get; }

/// <summary>
/// The <see cref="RealTime"/> of the server.
/// </summary>
/// <remarks>
/// 0 if we are the client and we are not connected to a server.
/// <see cref="RealTime"/> if we are the server.
/// </remarks>
TimeSpan ServerTime { get; }

/// <summary>
/// The simulated time it took to render the last frame.
/// </summary>
Expand Down
84 changes: 0 additions & 84 deletions Robust.Shared/Network/NetChannel.cs

This file was deleted.

87 changes: 87 additions & 0 deletions Robust.Shared/Network/NetManager.NetChannel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using System.Net;
using Lidgren.Network;
using Robust.Shared.Interfaces.Network;

namespace Robust.Shared.Network
{
public partial class NetManager
{
private class NetChannel : INetChannel
{
private readonly NetManager _manager;
private readonly NetConnection _connection;

/// <inheritdoc />
public long ConnectionId => _connection.RemoteUniqueIdentifier;

/// <inheritdoc />
public INetManager NetPeer => _manager;

public string UserName { get; }
public LoginType AuthType { get; }
public TimeSpan RemoteTimeOffset => TimeSpan.FromSeconds(_connection.RemoteTimeOffset);
public TimeSpan RemoteTime => _manager._timing.RealTime + RemoteTimeOffset;

/// <inheritdoc />
public short Ping => (short) Math.Round(_connection.AverageRoundtripTime * 1000);

/// <inheritdoc />
public bool IsConnected => _connection.Status == NetConnectionStatus.Connected;

/// <inheritdoc />
public IPEndPoint RemoteEndPoint => _connection.RemoteEndPoint;

/// <summary>
/// Exposes the lidgren connection.
/// </summary>
public NetConnection Connection => _connection;

public NetUserId UserId { get; }

// Only used on server, contains the encryption to use for this channel.
public NetEncryption? Encryption { get; set; }

/// <summary>
/// Creates a new instance of a NetChannel.
/// </summary>
/// <param name="manager">The server this channel belongs to.</param>
/// <param name="connection">The raw NetConnection to the remote peer.</param>
internal NetChannel(NetManager manager, NetConnection connection, NetUserId userId, string userName,
LoginType loginType)
{
_manager = manager;
_connection = connection;
UserId = userId;
UserName = userName;
AuthType = loginType;
}

/// <inheritdoc />
public T CreateNetMessage<T>()
where T : NetMessage
{
return _manager.CreateNetMessage<T>();
}

/// <inheritdoc />
public void SendMessage(NetMessage message)
{
if (_manager.IsClient)
{
_manager.ClientSendMessage(message);
return;
}

_manager.ServerSendMessage(message, this);
}

/// <inheritdoc />
public void Disconnect(string reason)
{
if (_connection.Status == NetConnectionStatus.Connected)
_connection.Disconnect(reason);
}
}
}
}
22 changes: 22 additions & 0 deletions Robust.Shared/Network/NetManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Utility;
Expand Down Expand Up @@ -112,6 +113,7 @@ public partial class NetManager : IClientNetManager, IServerNetManager, IDisposa

[Dependency] private readonly IConfigurationManagerInternal _config = default!;
[Dependency] private readonly IAuthManager _authManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;

/// <summary>
/// Holds lookup table for NetMessage.Id -> NetMessage.Type
Expand Down Expand Up @@ -235,6 +237,8 @@ public void Initialize(bool isServer)
throw new InvalidOperationException("NetManager has already been initialized.");
}

SynchronizeNetTime();

IsServer = isServer;

_config.OnValueChanged(CVars.NetVerbose, NetVerboseChanged);
Expand Down Expand Up @@ -265,6 +269,24 @@ public void Initialize(bool isServer)
}
}

private void SynchronizeNetTime()
{
// Synchronize Lidgren NetTime with our RealTime.

for (var i = 0; i < 10; i++)
{
// Try and set this in a loop to avoid any JIT hang fuckery or similar.
// Loop until the time is within acceptable margin.
// Fixing this "properly" would basically require re-architecturing Lidgren to do DI stuff
// so we can more sanely wire these together.
NetTime.SetNow(_timing.RealTime.TotalSeconds);
var dev = TimeSpan.FromSeconds(NetTime.Now) - _timing.RealTime;

if (Math.Abs(dev.TotalMilliseconds) < 0.05)
break;
}
}

private void UpdateNetMessageFunctions(MsgStringTableEntries.Entry[] entries)
{
foreach (var entry in entries)
Expand Down
25 changes: 23 additions & 2 deletions Robust.Shared/Timing/GameTiming.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Utility;
using Robust.Shared.Log;

namespace Robust.Shared.Timing
{
Expand All @@ -20,6 +20,8 @@ public class GameTiming : IGameTiming
private readonly List<long> _realFrameTimes = new(NumFrames);
private TimeSpan _lastRealTime;

[Dependency] private readonly INetManager _netManager = default!;

/// <summary>
/// Default constructor.
/// </summary>
Expand Down Expand Up @@ -87,6 +89,25 @@ public TimeSpan CurTime
/// </summary>
public TimeSpan RealTime => _realTimer.Elapsed;

public TimeSpan ServerTime
{
get
{
if (_netManager.IsServer)
{
return RealTime;
}

var clientNetManager = (IClientNetManager) _netManager;
if (clientNetManager.ServerChannel == null)
{
return TimeSpan.Zero;
}

return clientNetManager.ServerChannel.RemoteTime;
}
}

/// <summary>
/// The simulated time it took to render the last frame.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions Robust.UnitTesting/RobustIntegrationTest.NetManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Threading.Channels;
using System.Threading.Tasks;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Utility;

Expand All @@ -14,6 +16,7 @@ public partial class RobustIntegrationTest
{
internal sealed class IntegrationNetManager : IClientNetManager, IServerNetManager
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
public bool IsServer { get; private set; }
public bool IsClient => !IsServer;
public bool IsRunning { get; private set; }
Expand Down Expand Up @@ -371,6 +374,8 @@ private sealed class IntegrationNetChannel : INetChannel
public NetUserId UserId { get; }
public string UserName { get; }
public LoginType AuthType => LoginType.GuestAssigned;
public TimeSpan RemoteTimeOffset => TimeSpan.Zero; // TODO: Fix this
public TimeSpan RemoteTime => _owner._gameTiming.RealTime + RemoteTimeOffset;
public short Ping => default;

public IntegrationNetChannel(IntegrationNetManager owner, ChannelWriter<object> otherChannel, int uid,
Expand Down

0 comments on commit 6973d43

Please sign in to comment.