[Add] FishNet

This commit is contained in:
2026-03-30 20:11:57 +07:00
parent ee793a3361
commit c22c08753a
1797 changed files with 197950 additions and 1 deletions
@@ -0,0 +1,2 @@
// Remove V5
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 1fb953771006e0541ba76e564a90c21d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
assetPath: Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficArgs.cs
uploadId: 866910
@@ -0,0 +1,290 @@
#if UNITY_EDITOR || DEVELOPMENT_BUILD
#define DEVELOPMENT
#endif
using System;
using System.Collections.Generic;
using FishNet.Editing;
using FishNet.Transporting;
using GameKit.Dependencies.Utilities;
using Unity.Profiling;
using UnityEngine;
namespace FishNet.Managing.Statistic
{
[Serializable]
public partial class NetworkTrafficStatistics
{
#region Types.
public enum EnabledMode : byte
{
/// <summary>
/// Not enabled.
/// </summary>
Disabled = 0,
/// <summary>
/// Enabled for development only.
/// </summary>
Development = 1,
/// <summary>
/// Enabled for release and development.
/// </summary>
Release = 2,
/// <summary>
/// Enable for release, development, and headless.
/// </summary>
Headless = 3,
}
#endregion
#region Public.
/// <summary>
/// Called when NetworkTraffic is updated.
/// </summary>
/// <remarks>This API is for internal use and may change at any time.</remarks>
public event NetworkTrafficUpdateDel OnNetworkTraffic;
public delegate void NetworkTrafficUpdateDel(uint tick, BidirectionalNetworkTraffic serverTraffic, BidirectionalNetworkTraffic clientTraffic);
#endregion
#region Serialized.
/// <summary>
/// When to enable network traffic statistics.
/// </summary>
public EnabledMode EnableMode => _enableMode;
[Tooltip("When to enable network traffic statistics.")]
[SerializeField]
private EnabledMode _enableMode = EnabledMode.Disabled;
/// <summary>
/// True to update client statistics.
/// </summary>
public bool UpdateClient
{
get => _updateClient;
private set => _updateClient = value;
}
[Tooltip("True to update client statistics.")]
[SerializeField]
private bool _updateClient;
/// <summary>
/// Sets UpdateClient value.
/// </summary>
/// <param name = "update"></param>
public void SetUpdateClient(bool update) => UpdateClient = update;
/// <summary>
/// True to update client statistics.
/// </summary>
public bool UpdateServer
{
get => _updateServer;
private set => _updateServer = value;
}
[Tooltip("True to update server statistics.")]
[SerializeField]
private bool _updateServer;
/// <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>
/// Latest tick statistics for data on the local server.
/// </summary>
private BidirectionalNetworkTraffic _serverTraffic;
/// <summary>
/// Latest tick statistics for data on the local client.
/// </summary>
private BidirectionalNetworkTraffic _clientTraffic;
/// <summary>
/// Size suffixes as text.
/// </summary>
private static readonly string[] _sizeSuffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
/// <summary>
/// True if initialized.
/// </summary>
private bool _initializedOnce;
#endregion
#region Private Profiler Markers
private static readonly ProfilerMarker _pm_OnPreTick = new("NetworkTrafficStatistics.TimeManager_OnPreTick()");
#endregion
#region Consts.
/// <summary>
/// Id for unspecified packets.
/// </summary>
internal const PacketId UNSPECIFIED_PACKETID = (PacketId)ushort.MaxValue;
#endregion
internal void InitializeOnce_Internal(NetworkManager manager)
{
if (_initializedOnce)
return;
/* Only subscribe if enabled. Always unsubscribe even if not enabled -- doing so is safe. */
if (!IsEnabled())
return;
manager.TimeManager.OnPreTick += TimeManager_OnPreTick;
_networkManager = manager;
/* Do not bother caching once destroyed. Losing a single instance of each
* isn't going to hurt anything, and if destroyed everything is probably
* shutting down anyway. */
_serverTraffic = ResettableObjectCaches<BidirectionalNetworkTraffic>.Retrieve();
_clientTraffic = ResettableObjectCaches<BidirectionalNetworkTraffic>.Retrieve();
_initializedOnce = true;
}
/// <summary>
/// Called before the TimeManager ticks.
/// </summary>
private void TimeManager_OnPreTick()
{
using (_pm_OnPreTick.Auto())
{
/* Since we are sending last ticks data at the end of the tick,
* the tick used will always be 1 less than current tick. */
long trafficTick = _networkManager.TimeManager.LocalTick - 1;
//Invalid tick.
if (trafficTick <= 0)
return;
if (_networkManager.IsClientStarted || _networkManager.IsServerStarted)
OnNetworkTraffic?.Invoke((uint)trafficTick, _serverTraffic, _clientTraffic);
/* It's important to remember that after actions are invoked
* the traffic stat fields are reset. Each listener should use
* the MultiwayTrafficCollection.Clone method to get a copy,
* and should cache that copy when done. */
_clientTraffic.Reinitialize();
_serverTraffic.Reinitialize();
}
}
/// <summary>
/// Called when a packet bundle is received. This is any number of packets bundled into a single transmission.
/// </summary>
internal void PacketBundleReceived(bool asServer)
{
//Debug.LogError("Inbound and outbound bidirection datas should count up how many packet bundles are received. This is so the bundle headers can be calculated appropriately.");
}
/// <summary>
/// Called when data is being sent from the local server or client for a specific packet.
/// </summary>
internal void AddOutboundPacketIdData(PacketId typeSource, string details, int bytes, GameObject gameObject, bool asServer)
{
if (bytes <= 0)
return;
if (TryGetBidirectionalNetworkTraffic(asServer, out BidirectionalNetworkTraffic networkTraffic))
networkTraffic.OutboundTraffic.AddPacketIdData(typeSource, details, (ulong)bytes, gameObject);
}
/// <summary>
/// Called when data is being sent from the local server or client as it's going to the socket.
/// </summary>
internal void AddOutboundSocketData(ulong bytes, bool asServer)
{
if (bytes > int.MaxValue)
bytes = int.MaxValue;
else if (bytes <= 0)
return;
if (TryGetBidirectionalNetworkTraffic(asServer, out BidirectionalNetworkTraffic networkTraffic))
networkTraffic.OutboundTraffic.AddSocketData(bytes);
}
/// <summary>
/// Called when data is being received on the local server or client for a specific packet.
/// </summary>
internal void AddInboundPacketIdData(PacketId typeSource, string details, int bytes, GameObject gameObject, bool asServer)
{
if (bytes <= 0)
return;
if (TryGetBidirectionalNetworkTraffic(asServer, out BidirectionalNetworkTraffic networkTraffic))
networkTraffic.InboundTraffic.AddPacketIdData(typeSource, details, (ulong)bytes, gameObject);
}
/// <summary>
/// Called when data is being received on the local server or client as it's coming from the socket.
/// </summary>
internal void AddInboundSocketData(ulong bytes, bool asServer)
{
if (bytes > int.MaxValue)
bytes = int.MaxValue;
else if (bytes <= 0)
return;
if (TryGetBidirectionalNetworkTraffic(asServer, out BidirectionalNetworkTraffic networkTraffic))
networkTraffic.InboundTraffic.AddSocketData(bytes);
}
/// <summary>
/// Gets current statistics for server or client.
/// </summary>
private bool TryGetBidirectionalNetworkTraffic(bool asServer, out BidirectionalNetworkTraffic networkTraffic)
{
networkTraffic = asServer ? _serverTraffic : _clientTraffic;
return networkTraffic != null;
}
/// <summary>
/// Formats passed in bytes value to the largest possible data type with 2 decimals.
/// </summary>
public static string FormatBytesToLargest(float bytes)
{
string[] units = { "B", "kB", "MB", "GB", "TB", "PB" };
int unitIndex = 0;
while (bytes >= 1024 && unitIndex < units.Length - 1)
{
bytes /= 1024;
unitIndex++;
}
return $"{bytes:0.00} {units[unitIndex]}";
}
/// <summary>
/// Returns if enabled or not.
/// </summary>
public bool IsEnabled()
{
if (_enableMode == EnabledMode.Disabled)
return false;
int modeValue = (int)_enableMode;
//Never enabled for server builds.
#if UNITY_SERVER
return modeValue >= (int)EnabledMode.Headless;
#endif
if (_enableMode == EnabledMode.Disabled)
return false;
// If not in dev mode then return true if to run in release.
#if !DEVELOPMENT
return modeValue >= (int)EnabledMode.Release;
// Always run in dev mode if not disabled.
#else
return true;
#endif
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 9cc04f6ae0339c94e9153396dce3f46e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
assetPath: Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficStatistics.cs
uploadId: 866910
@@ -0,0 +1,66 @@
using UnityEngine;
namespace FishNet.Managing.Statistic
{
[DisallowMultipleComponent]
[AddComponentMenu("FishNet/Manager/StatisticsManager")]
public class StatisticsManager : MonoBehaviour
{
/// <summary>
/// True to operate while in release. This may cause allocations and impact performance.
/// </summary>
[Tooltip("True to operate while in release. This may cause allocations and impact performance.")]
[SerializeField]
private bool _runInRelease;
/// <summary>
/// Statistics for NetworkTraffic.
/// </summary>
[Tooltip("Statistics for NetworkTraffic.")]
[SerializeField]
private NetworkTrafficStatistics _networkTraffic;
/// <summary>
/// NetworkManager this is for.
/// </summary>
private NetworkManager _networkManager;
internal void InitializeOnce_Internal(NetworkManager manager)
{
_networkManager = manager;
}
/// <summary>
/// Gets NetworkTrafficStatistics reference.
/// </summary>
public bool TryGetNetworkTrafficStatistics(out NetworkTrafficStatistics statistics)
{
statistics = null;
/* Cannot run in the current build type. */
#if (!UNITY_EDITOR && !DEVELOPMENT_BUILD) || UNITY_SERVER
if (!_runInRelease)
{
_networkTraffic = null;
return false;
}
#endif
//NetworkManager must be set to work.
if (_networkManager == null)
{
if (!TryGetComponent(out _networkManager))
return false;
}
//Hot-load if needed.
if (_networkTraffic == null)
_networkTraffic = new();
_networkTraffic.InitializeOnce_Internal(_networkManager);
if (_networkTraffic.IsEnabled())
statistics = _networkTraffic;
return statistics != null;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 756c28cd3141c4140ae776188ee26729
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
assetPath: Assets/FishNet/Runtime/Managing/Statistic/StatisticsManager.cs
uploadId: 866910
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 359124f57d1c41a4090c0bdefac453a8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
assetPath: Assets/FishNet/Runtime/Managing/Statistic/Types.cs
uploadId: 866910