203 lines
6.6 KiB
C#
203 lines
6.6 KiB
C#
|
|
|
|
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using UnityEngine;
|
|
|
|
namespace FishNet.Managing.Statistic
|
|
{
|
|
[System.Serializable]
|
|
public class NetworkTraficStatistics
|
|
{
|
|
#region Public.
|
|
/// <summary>
|
|
/// Called when NetworkTraffic is updated for the client.
|
|
/// </summary>
|
|
public event Action<NetworkTrafficArgs> OnClientNetworkTraffic;
|
|
/// <summary>
|
|
/// Called when NetworkTraffic is updated for the server.
|
|
/// </summary>
|
|
public event Action<NetworkTrafficArgs> OnServerNetworkTraffic;
|
|
#endregion
|
|
|
|
#region Serialized.
|
|
/// <summary>
|
|
/// How often to update traffic statistics.
|
|
/// </summary>
|
|
[Tooltip("How often to update traffic statistics.")]
|
|
[SerializeField]
|
|
[Range(0f, 10f)]
|
|
private float _updateInteval = 1f;
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
[Tooltip("True to update client statistics.")]
|
|
[SerializeField]
|
|
private bool _updateClient;
|
|
/// <summary>
|
|
/// True to update client statistics.
|
|
/// </summary>
|
|
public bool UpdateClient
|
|
{
|
|
get => _updateClient;
|
|
private set => _updateClient = value;
|
|
}
|
|
/// <summary>
|
|
/// Sets UpdateClient value.
|
|
/// </summary>
|
|
/// <param name="update"></param>
|
|
public void SetUpdateClient(bool update)
|
|
{
|
|
UpdateClient = update;
|
|
}
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
[Tooltip("True to update server statistics.")]
|
|
[SerializeField]
|
|
private bool _updateServer;
|
|
/// <summary>
|
|
/// True to update client statistics.
|
|
/// </summary>
|
|
public bool UpdateServer
|
|
{
|
|
get => _updateServer;
|
|
private set => _updateServer = value;
|
|
}
|
|
/// <summary>
|
|
/// Sets UpdateServer value.
|
|
/// </summary>
|
|
/// <param name="update"></param>
|
|
public void SetUpdateServer(bool update)
|
|
{
|
|
UpdateServer = update;
|
|
}
|
|
#endregion
|
|
|
|
#region Private.
|
|
/// <summary>
|
|
/// NetworkManager for this statistics.
|
|
/// </summary>
|
|
private NetworkManager _networkManager;
|
|
/// <summary>
|
|
/// Bytes sent to the server from local client.
|
|
/// </summary>
|
|
private ulong _client_toServerBytes;
|
|
/// <summary>
|
|
/// Bytes received on the local client from the server.
|
|
/// </summary>
|
|
private ulong _client_fromServerBytes;
|
|
/// <summary>
|
|
/// Bytes sent to all clients from the local server.
|
|
/// </summary>
|
|
private ulong _server_toClientsBytes;
|
|
/// <summary>
|
|
/// Bytes received on the local server from all clients.
|
|
/// </summary>
|
|
private ulong _server_fromClientsBytes;
|
|
/// <summary>
|
|
/// Next time network traffic updates may invoke.
|
|
/// </summary>
|
|
private float _nextUpdateTime;
|
|
/// <summary>
|
|
/// Size suffixes as text.
|
|
/// </summary>
|
|
private static readonly string[] _sizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
|
|
#endregion
|
|
|
|
internal void InitializeOnce_Internal(NetworkManager manager)
|
|
{
|
|
_networkManager = manager;
|
|
manager.TimeManager.OnPreTick += TimeManager_OnPreTick;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called before the TimeManager ticks.
|
|
/// </summary>
|
|
private void TimeManager_OnPreTick()
|
|
{
|
|
if (Time.unscaledTime < _nextUpdateTime)
|
|
return;
|
|
_nextUpdateTime = Time.unscaledTime + _updateInteval;
|
|
|
|
if (UpdateClient && _networkManager.IsClient)
|
|
OnClientNetworkTraffic?.Invoke(new NetworkTrafficArgs(_client_toServerBytes, _client_fromServerBytes));
|
|
if (UpdateServer && _networkManager.IsServer)
|
|
OnServerNetworkTraffic?.Invoke(new NetworkTrafficArgs(_server_fromClientsBytes, _server_toClientsBytes));
|
|
|
|
_client_toServerBytes = 0;
|
|
_client_fromServerBytes = 0;
|
|
_server_toClientsBytes = 0;
|
|
_server_fromClientsBytes = 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the local client sends data.
|
|
/// </summary>
|
|
internal void LocalClientSentData(ulong dataLength)
|
|
{
|
|
_client_toServerBytes = Math.Min(_client_toServerBytes + dataLength, ulong.MaxValue);
|
|
}
|
|
/// <summary>
|
|
/// Called when the local client receives data.
|
|
/// </summary>
|
|
public void LocalClientReceivedData(ulong dataLength)
|
|
{
|
|
_client_fromServerBytes = Math.Min(_client_fromServerBytes + dataLength, ulong.MaxValue);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Called when the local client sends data.
|
|
/// </summary>
|
|
internal void LocalServerSentData(ulong dataLength)
|
|
{
|
|
_server_toClientsBytes = Math.Min(_server_toClientsBytes + dataLength, ulong.MaxValue);
|
|
}
|
|
/// <summary>
|
|
/// Called when the local client receives data.
|
|
/// </summary>
|
|
public void LocalServerReceivedData(ulong dataLength)
|
|
{
|
|
_server_fromClientsBytes = Math.Min(_server_fromClientsBytes + dataLength, ulong.MaxValue);
|
|
}
|
|
|
|
|
|
//Attribution: https://stackoverflow.com/questions/14488796/does-net-provide-an-easy-way-convert-bytes-to-kb-mb-gb-etc
|
|
/// <summary>
|
|
/// Formats passed in bytes value to the largest possible data type with 2 decimals.
|
|
/// </summary>
|
|
public static string FormatBytesToLargest(ulong bytes)
|
|
{
|
|
int decimalPlaces = 2;
|
|
if (bytes == 0)
|
|
{
|
|
decimalPlaces = 0;
|
|
return string.Format("{0:n" + decimalPlaces + "} bytes", 0);
|
|
}
|
|
|
|
// mag is 0 for bytes, 1 for KB, 2, for MB, etc.
|
|
int mag = (int)Math.Log(bytes, 1024);
|
|
|
|
// 1L << (mag * 10) == 2 ^ (10 * mag)
|
|
// [i.e. the number of bytes in the unit corresponding to mag]
|
|
decimal adjustedSize = (decimal)bytes / (1L << (mag * 10));
|
|
|
|
// make adjustment when the value is large enough that
|
|
// it would round up to 1000 or more
|
|
if (Math.Round(adjustedSize, decimalPlaces) >= 1000)
|
|
{
|
|
mag += 1;
|
|
adjustedSize /= 1024;
|
|
}
|
|
|
|
//Don't show decimals for bytes.
|
|
if (mag == 0)
|
|
decimalPlaces = 0;
|
|
|
|
return string.Format("{0:n" + decimalPlaces + "} {1}", adjustedSize, _sizeSuffixes[mag]);
|
|
}
|
|
}
|
|
|
|
|
|
} |