Skip to content

Commit f526eb7

Browse files
committed
add more stats options
1 parent 1db2301 commit f526eb7

File tree

12 files changed

+97
-60
lines changed

12 files changed

+97
-60
lines changed

samples/ConsoleGame/Game.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ public void Update()
6363
if (nonGameState.IsRunning)
6464
UpdateState();
6565

66-
session.UpdateNetworkStats(nonGameState.RemotePlayer);
6766
view.Draw(in currentState, nonGameState);
6867
}
6968

samples/ConsoleGame/Program.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,10 @@
3333
.WithInputDelayFrames(2)
3434
.WithLogLevel(LogLevel.Information)
3535
.UsePlugin<PluginSample>()
36-
.WithNetworkStats()
36+
.WithPackageStats()
3737
.ConfigureProtocol(options =>
3838
{
39-
options.NumberOfSyncRoundtrips = 10;
40-
// p.LogNetworkStats = true;
39+
options.NumberOfSyncRoundTrips = 10;
4140
// p.NetworkLatency = TimeSpan.FromMilliseconds(300);
4241
// p.DelayStrategy = Backdash.Network.DelayStrategy.Constant;
4342
// options.DisconnectTimeoutEnabled = false;

samples/SpaceWar.Lobby/Scenes/LobbyScene.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,10 +416,10 @@ NetcodeSessionBuilder<PlayerInputs> NetcodeSessionBuilder() =>
416416
.WithLogLevel(LogLevel.Warning)
417417
.ConfigureProtocol(options =>
418418
{
419-
options.NumberOfSyncRoundtrips = 10;
419+
options.NumberOfSyncRoundTrips = 10;
420420
options.DisconnectTimeout = TimeSpan.FromSeconds(3);
421421
options.DisconnectNotifyStart = TimeSpan.FromSeconds(1);
422-
options.LogNetworkStats = false;
422+
options.NetworkPackageStatsEnabled = false;
423423
// options.NetworkLatency = Backdash.Data.FrameSpan.Of(3).Duration();
424424
});
425425

samples/SpaceWar/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ static INetcodeSession<PlayerInputs> ParseSessionArgs(string[] args)
3030
.WithLogLevel(LogLevel.Warning)
3131
.ConfigureProtocol(options =>
3232
{
33-
options.NumberOfSyncRoundtrips = 10;
33+
options.NumberOfSyncRoundTrips = 10;
3434
options.DisconnectTimeout = TimeSpan.FromSeconds(3);
3535
options.DisconnectNotifyStart = TimeSpan.FromSeconds(1);
36-
options.LogNetworkStats = false;
36+
options.NetworkPackageStatsEnabled = false;
3737
// options.NetworkLatency = Backdash.Data.FrameSpan.Of(3).Duration();
3838
});
3939

src/Backdash/Network/PeerConnection.cs

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ IStateStore stateStore
6969
qualityReportTimer = new(options.QualityReportInterval);
7070
qualityReportTimer.Elapsed += OnQualityReportTick;
7171

72-
networkStatsTimer = new(options.NetworkStatsInterval);
72+
networkStatsTimer = new(options.NetworkPackageStatsInterval);
7373
networkStatsTimer.Elapsed += OnNetworkStatsTick;
7474

7575
consistencyCheckTimer = new(options.ConsistencyCheckInterval);
@@ -92,21 +92,25 @@ public void Dispose()
9292
qualityReportTimer.Elapsed -= OnQualityReportTick;
9393
networkStatsTimer.Elapsed -= OnNetworkStatsTick;
9494
consistencyCheckTimer.Elapsed -= OnConsistencyCheck;
95-
networkStatsTimer.Dispose();
96-
qualityReportTimer.Dispose();
95+
9796
keepAliveTimer.Dispose();
9897
resendInputsTimer.Dispose();
98+
qualityReportTimer.Dispose();
99+
networkStatsTimer.Dispose();
99100
consistencyCheckTimer.Dispose();
100101
}
101102

102103
void StartTimers()
103104
{
104105
keepAliveTimer.Start();
105106
qualityReportTimer.Start();
106-
networkStatsTimer.Start();
107107
resendInputsTimer.Start();
108108

109+
if (options.NetworkPackageStatsEnabled)
110+
networkStatsTimer.Start();
111+
109112
if (state.Player.IsSpectator()) return;
113+
110114
if (options.ConsistencyCheckEnabled)
111115
consistencyCheckTimer.Start();
112116
}
@@ -115,10 +119,13 @@ void StopTimers()
115119
{
116120
keepAliveTimer.Stop();
117121
qualityReportTimer.Stop();
118-
networkStatsTimer.Stop();
119122
resendInputsTimer.Stop();
120123

124+
if (options.NetworkPackageStatsEnabled)
125+
networkStatsTimer.Stop();
126+
121127
if (state.Player.IsSpectator()) return;
128+
122129
if (options.ConsistencyCheckEnabled)
123130
consistencyCheckTimer.Stop();
124131
}
@@ -153,6 +160,8 @@ public void Update()
153160
break;
154161
case ProtocolStatus.Running:
155162
CheckDisconnection();
163+
if (options.CalculateRemotePlayerStats)
164+
GetNetworkStats(ref state.Player.NetworkStats);
156165
break;
157166
case ProtocolStatus.Disconnected:
158167
break;
@@ -209,30 +218,25 @@ public void GetNetworkStats(ref PeerNetworkStats info)
209218
info.LastAckedFrame = inbox.LastAckedFrame;
210219
info.RemoteFramesBehind = state.Fairness.RemoteFrameAdvantage;
211220
info.LocalFramesBehind = state.Fairness.LocalFrameAdvantage;
212-
info.Send.TotalBytes = stats.Send.TotalBytesWithHeaders;
213-
info.Send.Count = stats.Send.TotalPackets;
214-
info.Send.LastTime = Stopwatch.GetElapsedTime(stats.Send.LastTime);
215-
info.Send.PackagesPerSecond = stats.Send.PackagesPerSecond;
216-
info.Send.Bandwidth = stats.Send.Bandwidth;
217221
info.Send.LastFrame = inputBuffer.LastSent.Frame;
218-
info.Received.TotalBytes = stats.Received.TotalBytesWithHeaders;
219-
info.Received.LastTime = Stopwatch.GetElapsedTime(stats.Received.LastTime);
220-
info.Received.Count = stats.Received.TotalPackets;
221-
info.Received.PackagesPerSecond = stats.Received.PackagesPerSecond;
222-
info.Received.Bandwidth = stats.Received.Bandwidth;
223222
info.Received.LastFrame = inbox.LastReceivedInput.Frame;
223+
224+
if (!options.NetworkPackageStatsEnabled) return;
225+
info.Send.Fill(stats.Send);
226+
info.Received.Fill(stats.Received);
224227
}
225228

226229
public bool GetPeerConnectStatus(int id, out Frame frame)
227230
{
228-
frame = state.PeerConnectStatuses[id].LastFrame;
229-
return !state.PeerConnectStatuses[id].Disconnected;
231+
var peer = state.PeerConnectStatuses[id];
232+
frame = peer.LastFrame;
233+
return !peer.Disconnected;
230234
}
231235

232236
public IPeerObserver<ProtocolMessage> GetUdpObserver() => inbox;
233237
public void Synchronize() => syncRequest.Synchronize();
234238

235-
public void CheckDisconnection()
239+
void CheckDisconnection()
236240
{
237241
if (state.Stats.Received.LastTime <= 0 || !disconnectCheckEnabled) return;
238242
var lastReceivedTime = Stopwatch.GetElapsedTime(state.Stats.Received.LastTime);
@@ -339,20 +343,13 @@ void OnQualityReportTick(object? sender, ElapsedEventArgs e)
339343
void OnNetworkStatsTick(object? sender, ElapsedEventArgs e)
340344
{
341345
const int packageHeaderSize = UdpSocket.UdpHeaderSize + UdpSocket.IpAddressHeaderSize;
342-
if (state.CurrentStatus is not ProtocolStatus.Running)
346+
if (state.CurrentStatus is not ProtocolStatus.Running || !options.NetworkPackageStatsEnabled)
343347
return;
344348

345349
var elapsed = Stopwatch.GetElapsedTime(startedAt);
346-
var seconds = elapsed.TotalSeconds;
347350
UpdateStats(ref state.Stats.Send);
348351
UpdateStats(ref state.Stats.Received);
349352

350-
if (options.LogNetworkStats)
351-
{
352-
logger.Write(LogLevel.Information, $"Network Stats(send): {state.Stats.Send}");
353-
logger.Write(LogLevel.Information, $"Network Stats(recv): {state.Stats.Received}");
354-
}
355-
356353
return;
357354

358355
void UpdateStats(ref ProtocolState.PackagesStats stats)
@@ -361,7 +358,7 @@ void UpdateStats(ref ProtocolState.PackagesStats stats)
361358
stats.TotalBytesWithHeaders = stats.TotalBytes + totalUdpHeaderSize;
362359
stats.TotalBytesWithHeaders = stats.TotalBytes + totalUdpHeaderSize;
363360
stats.PackagesPerSecond = (float)(stats.TotalPackets * 1000f / elapsed.TotalMilliseconds);
364-
stats.Bandwidth = stats.TotalBytesWithHeaders / seconds;
361+
stats.Bandwidth = stats.TotalBytesWithHeaders / elapsed.TotalSeconds;
365362
stats.UdpOverhead =
366363
(float)(100.0 * (packageHeaderSize * stats.TotalPackets) / stats.TotalBytes.ByteCount);
367364
}

src/Backdash/Network/Protocol/Comm/ProtocolInbox.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,12 @@ bool OnSyncReply(ref readonly ProtocolMessage msg, ref ProtocolMessage replyMsg)
246246

247247
logger.Write(LogLevel.Debug,
248248
$"Checking sync state ({state.Sync.RemainingRoundTrips} round trips remaining)");
249-
if (options.NumberOfSyncRoundtrips >= state.Sync.RemainingRoundTrips)
249+
if (options.NumberOfSyncRoundTrips >= state.Sync.RemainingRoundTrips)
250250
state.Sync.TotalRoundTripsPing = TimeSpan.Zero;
251251
state.Sync.TotalRoundTripsPing += elapsed;
252252
if (--state.Sync.RemainingRoundTrips == 0)
253253
{
254-
var ping = state.Sync.TotalRoundTripsPing / options.NumberOfSyncRoundtrips;
254+
var ping = state.Sync.TotalRoundTripsPing / options.NumberOfSyncRoundTrips;
255255
logger.Write(LogLevel.Information,
256256
$"Player {state.Player.Index} Synchronized! (Ping: {ping.TotalMilliseconds:f4})");
257257
state.CurrentStatus = ProtocolStatus.Running;
@@ -269,8 +269,8 @@ bool OnSyncReply(ref readonly ProtocolMessage msg, ref ProtocolMessage replyMsg)
269269
new(ProtocolEvent.Synchronizing, state.Player)
270270
{
271271
Synchronizing = new(
272-
TotalSteps: options.NumberOfSyncRoundtrips,
273-
CurrentStep: options.NumberOfSyncRoundtrips - state.Sync.RemainingRoundTrips
272+
TotalSteps: options.NumberOfSyncRoundTrips,
273+
CurrentStep: options.NumberOfSyncRoundTrips - state.Sync.RemainingRoundTrips
274274
),
275275
}
276276
);

src/Backdash/Network/Protocol/Comm/ProtocolSynchronizer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public void CreateReplyMessage(in SyncRequest request, ref ProtocolMessage reply
5050

5151
public void Synchronize()
5252
{
53-
state.Sync.RemainingRoundTrips = options.NumberOfSyncRoundtrips;
53+
state.Sync.RemainingRoundTrips = options.NumberOfSyncRoundTrips;
5454
state.CurrentStatus = ProtocolStatus.Syncing;
5555
retryCounter = 0;
5656
active = true;
@@ -72,7 +72,7 @@ public void Update()
7272
return;
7373
}
7474

75-
var firstIteration = state.Sync.RemainingRoundTrips == options.NumberOfSyncRoundtrips;
75+
var firstIteration = state.Sync.RemainingRoundTrips == options.NumberOfSyncRoundTrips;
7676
var interval = firstIteration ? options.SyncFirstRetryInterval : options.SyncRetryInterval;
7777
var elapsed = Stopwatch.GetElapsedTime(lastRequest);
7878
if (elapsed < interval)

src/Backdash/Network/Protocol/ProtocolState.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public sealed class Statistics
5555
public PackagesStats Received = new();
5656
}
5757

58-
public struct PackagesStats : IUtf8SpanFormattable
58+
public sealed class PackagesStats : IUtf8SpanFormattable
5959
{
6060
public long LastTime;
6161
public int TotalPackets;
@@ -65,7 +65,7 @@ public struct PackagesStats : IUtf8SpanFormattable
6565
public ByteSize Bandwidth;
6666
public ByteSize TotalBytesWithHeaders;
6767

68-
public readonly bool TryFormat(
68+
public bool TryFormat(
6969
Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format,
7070
IFormatProvider? provider
7171
)

src/Backdash/Options/ProtocolOptions.cs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public sealed record ProtocolOptions
4141
/// Number of synchronization roundtrips to consider two clients synchronized.
4242
/// </summary>
4343
/// <value>Defaults to <c>10</c></value>
44-
public int NumberOfSyncRoundtrips { get; set; } = 10;
44+
public int NumberOfSyncRoundTrips { get; set; } = 10;
4545

4646
/// <summary>
4747
/// Distance to check out-of-order packets.
@@ -73,12 +73,6 @@ public sealed record ProtocolOptions
7373
/// <seealso cref="Backdash.Network.DelayStrategy" />
7474
public DelayStrategy DelayStrategy { get; set; } = DelayStrategy.Gaussian;
7575

76-
/// <summary>
77-
/// When true, session log network stats periodically.
78-
/// </summary>
79-
/// <value>Defaults to <see lanword="false" /></value>
80-
public bool LogNetworkStats { get; set; }
81-
8276
/// <summary>
8377
/// The time to wait before the first <see cref="PeerEvent.ConnectionInterrupted" /> timeout will be sent.
8478
/// </summary>
@@ -136,7 +130,27 @@ public sealed record ProtocolOptions
136130
/// </summary>
137131
/// <value>Defaults to <c>1000</c> milliseconds</value>
138132
/// <seealso cref="PeerNetworkStats" />
139-
public TimeSpan NetworkStatsInterval { get; set; } = TimeSpan.FromMilliseconds(1000);
133+
/// <seealso cref="NetworkPackageStatsEnabled" />
134+
public TimeSpan NetworkPackageStatsInterval { get; set; } = TimeSpan.FromMilliseconds(1000);
135+
136+
/// <summary>
137+
/// When true, session will use calculate packages stats.
138+
/// </summary>
139+
/// <seealso cref="NetworkPackageStatsInterval"/>
140+
/// <seealso cref="PeerNetworkStats.PackagesInfo"/>
141+
/// <seealso cref="PeerNetworkStats.Send"/>
142+
/// <seealso cref="PeerNetworkStats.Received"/>
143+
/// <value>Defaults to <see lanword="true" /></value>
144+
public bool NetworkPackageStatsEnabled { get; set; } = false;
145+
146+
/// <summary>
147+
/// When true, the session will calculate the remote player stats on each frame.
148+
/// </summary>
149+
/// <value>Defaults to <see lanword="true" /></value>
150+
/// <seealso cref="NetcodePlayer.NetworkStats"/>
151+
/// <seealso cref="NetworkPackageStatsEnabled"/>
152+
/// <seealso cref="INetcodeSession.UpdateNetworkStats"/>
153+
public bool CalculateRemotePlayerStats { get; set; } = true;
140154

141155
/// <summary>
142156
/// When the time from the last send input until now is greater than this, resends pending inputs.
@@ -184,5 +198,4 @@ public sealed record ProtocolOptions
184198
/// Custom receive socket address size
185199
/// </summary>
186200
public int ReceiveSocketAddressSize { get; set; }
187-
188201
}

src/Backdash/Player/PeerNetworkStats.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
using System.Diagnostics;
12
using System.Diagnostics.CodeAnalysis;
23
using Backdash.Data;
4+
using Backdash.Network.Protocol;
35
using Backdash.Options;
46

57
namespace Backdash;
68

79
/// <summary>
810
/// Holds current session network stats.
9-
/// Calculated in intervals of <see cref="ProtocolOptions.NetworkStatsInterval" />.
11+
/// Calculated in intervals of <see cref="ProtocolOptions.NetworkPackageStatsInterval" />.
1012
/// </summary>
1113
[Serializable]
1214
public sealed class PeerNetworkStats
@@ -78,6 +80,15 @@ public void Reset()
7880
LastFrame = Frame.Zero;
7981
Bandwidth = ByteSize.Zero;
8082
}
83+
84+
internal void Fill(ProtocolState.PackagesStats stats)
85+
{
86+
TotalBytes = stats.TotalBytesWithHeaders;
87+
Count = stats.TotalPackets;
88+
LastTime = Stopwatch.GetElapsedTime(stats.LastTime);
89+
PackagesPerSecond = stats.PackagesPerSecond;
90+
Bandwidth = stats.Bandwidth;
91+
}
8192
}
8293

8394
/// <summary>Reset all values to default</summary>

0 commit comments

Comments
 (0)