feat(NetworkIdentity): Reuse Network IDs

- Uses a Queue (FIFO) with delay time in seconds
- Configurable in Network Manager (Enabled & Delay)
- Pool shown in NI Info Panel
This commit is contained in:
MrGadget 2024-01-12 11:37:14 -05:00
parent 832eb79876
commit 668dc91ffb
3 changed files with 80 additions and 3 deletions

View File

@ -264,17 +264,52 @@ internal static void ResetClientStatics()
internal static void ResetServerStatics()
{
poolNetworkIds = true;
reuseDelay = 1;
netIdPool.Clear();
nextNetworkId = 1;
}
/// <summary>Gets the NetworkIdentity from the sceneIds dictionary with the corresponding id</summary>
public static NetworkIdentity GetSceneIdentity(ulong id) => sceneIds[id];
#region NetworkID Handling
internal static bool poolNetworkIds = true;
internal static byte reuseDelay = 1;
internal struct NetworkIdPool
{
public uint poolNetId;
public double timeAvailable;
}
// pool of NetworkIds that can be reused
internal static readonly Queue<NetworkIdPool> netIdPool = new Queue<NetworkIdPool>();
static uint nextNetworkId = 1;
internal static uint GetNextNetworkId() => nextNetworkId++;
internal static uint GetNextNetworkId()
{
if (poolNetworkIds && netIdPool.TryPeek(out NetworkIdPool entry) && entry.timeAvailable < NetworkTime.time)
{
//Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, $"[GetNextNetworkId] Reusing NetworkId {entry.poolNetId}.");
netIdPool.Dequeue();
return entry.poolNetId;
}
return nextNetworkId++;
}
/// <summary>Resets nextNetworkId = 1</summary>
public static void ResetNextNetworkId() => nextNetworkId = 1;
public static void ResetNextNetworkId()
{
netIdPool.Clear();
nextNetworkId = 1;
}
#endregion
/// <summary>The delegate type for the clientAuthorityCallback.</summary>
public delegate void ClientAuthorityCallback(NetworkConnectionToClient conn, NetworkIdentity identity, bool authorityState);
@ -628,6 +663,9 @@ void OnDestroy()
NetworkServer.Destroy(gameObject);
}
if (isServer && poolNetworkIds && netId > 0)
netIdPool.Enqueue(new NetworkIdPool { poolNetId = netId, timeAvailable = NetworkTime.time + reuseDelay });
if (isLocalPlayer)
{
// previously there was a bug where isLocalPlayer was
@ -1298,7 +1336,14 @@ internal void Reset()
isOwned = false;
NotifyAuthority();
netId = 0;
if (netId > 0)
{
if (poolNetworkIds)
netIdPool.Enqueue(new NetworkIdPool { poolNetId = netId, timeAvailable = NetworkTime.time + reuseDelay });
netId = 0;
}
connectionToServer = null;
connectionToClient = null;

View File

@ -63,6 +63,13 @@ public class NetworkManager : MonoBehaviour
// [Tooltip("Client broadcasts 'sendRate' times per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE.")]
// public int clientSendRate = 30; // 33 ms
[Header("Network ID Pooling")]
[Tooltip("Reuse network IDs when objects are unspawned or destroyed?")]
public bool poolNetworkIds = true;
[Range(1, 30)]
[Tooltip("Delay in seconds before network IDs are reused")]
public byte reuseDelay = 1;
/// <summary>Automatically switch to this scene upon going offline (on start / on disconnect / on shutdown).</summary>
[Header("Scene Management")]
[Scene]
@ -321,6 +328,10 @@ void SetupServer()
NetworkServer.disconnectInactiveTimeout = disconnectInactiveTimeout;
NetworkServer.exceptionsDisconnect = exceptionsDisconnect;
// Setup reuseable network IDs
NetworkIdentity.poolNetworkIds = poolNetworkIds;
NetworkIdentity.reuseDelay = reuseDelay;
if (runInBackground)
Application.runInBackground = true;

View File

@ -113,6 +113,8 @@ public override void OnPreviewGUI(Rect r, GUIStyle background)
Y = DrawObservers(identity, initialX, Y);
Y = DrawNetworkIDPool(initialX, Y);
_ = DrawOwner(identity, initialX, Y);
}
@ -191,6 +193,25 @@ float DrawObservers(NetworkIdentity identity, float initialX, float Y)
return Y;
}
float DrawNetworkIDPool(float initialX, float Y)
{
if (NetworkIdentity.netIdPool.Count > 0)
{
Rect poolRect = new Rect(initialX, Y + 10, 200, 20);
GUI.Label(poolRect, new GUIContent("Network ID Pool"), styles.componentName);
poolRect.x += 20;
poolRect.y += poolRect.height;
foreach (var entry in NetworkIdentity.netIdPool)
{
GUI.Label(poolRect, $"[{entry.poolNetId}] {entry.timeAvailable:0.000}", styles.labelStyle);
poolRect.y += poolRect.height;
Y = poolRect.y;
}
}
return Y;
}
float DrawOwner(NetworkIdentity identity, float initialX, float Y)
{
if (identity.connectionToClient != null)