diff --git a/com.community.netcode.extensions/Runtime/NetworkObjectPool/NetworkObjectPool.cs b/com.community.netcode.extensions/Runtime/NetworkObjectPool/NetworkObjectPool.cs
index 9ee44852..cd980b2d 100644
--- a/com.community.netcode.extensions/Runtime/NetworkObjectPool/NetworkObjectPool.cs
+++ b/com.community.netcode.extensions/Runtime/NetworkObjectPool/NetworkObjectPool.cs
@@ -7,10 +7,16 @@
namespace Netcode.Extensions
{
- public class NetworkObjectPool : MonoBehaviour
+ ///
+ /// Object Pool for networked objects, used for controlling how objects are spawned by Netcode. Netcode by default will allocate new memory when spawning new
+ /// objects. With this Networked Pool, we're using custom spawning to reuse objects.
+ /// Hooks to NetworkManager's prefab handler to intercept object spawning and do custom actions
+ ///
+ public class NetworkObjectPool : NetworkBehaviour
{
- [SerializeField]
- NetworkManager m_NetworkManager;
+ private static NetworkObjectPool _instance;
+
+ public static NetworkObjectPool Singleton=> _instance;
[SerializeField]
List PooledPrefabsList;
@@ -19,11 +25,41 @@ public class NetworkObjectPool : MonoBehaviour
Dictionary> pooledObjects = new Dictionary>();
+ private bool m_HasInitialized = false;
+
public void Awake()
+ {
+ if (_instance != null && _instance != this)
+ {
+ Destroy(this.gameObject);
+ }
+ else
+ {
+ _instance = this;
+ }
+ }
+
+ public override void OnNetworkSpawn()
{
InitializePool();
}
+ public override void OnNetworkDespawn()
+ {
+ ClearPool();
+ }
+
+ public override void OnDestroy()
+ {
+ if (_instance == this)
+ {
+ _instance = null;
+ }
+
+ base.OnDestroy();
+ }
+
+
public void OnValidate()
{
for (var i = 0; i < PooledPrefabsList.Count; i++)
@@ -31,8 +67,23 @@ public void OnValidate()
var prefab = PooledPrefabsList[i].Prefab;
if (prefab != null)
{
- Assert.IsNotNull(prefab.GetComponent(), $"{nameof(NetworkObjectPool)}: Pooled prefab \"{prefab.name}\" at index {i.ToString()} has no {nameof(NetworkObject)} component.");
+ Assert.IsNotNull(
+ prefab.GetComponent(),
+ $"{nameof(NetworkObjectPool)}: Pooled prefab \"{prefab.name}\" at index {i.ToString()} has no {nameof(NetworkObject)} component."
+ );
+
+ }
+
+ var prewarmCount = PooledPrefabsList[i].PrewarmCount;
+ if (prewarmCount < 0)
+ {
+ Debug.LogWarning($"{nameof(NetworkObjectPool)}: Pooled prefab at index {i.ToString()} has a negative prewarm count! Making it not negative.");
+ var thisPooledPrefab = PooledPrefabsList[i];
+ thisPooledPrefab.PrewarmCount *= -1;
+ PooledPrefabsList[i] = thisPooledPrefab;
}
+
+
}
}
@@ -59,15 +110,12 @@ public NetworkObject GetNetworkObject(GameObject prefab, Vector3 position, Quate
}
///
- /// Return an object to the pool (and reset them).
+ /// Return an object to the pool (reset objects before returning).
///
public void ReturnNetworkObject(NetworkObject networkObject, GameObject prefab)
{
var go = networkObject.gameObject;
-
- // In this simple example pool we just disable objects while they are in the pool. But we could call a function on the object here for more flexibility.
go.SetActive(false);
- go.transform.SetParent(transform);
pooledObjects[prefab].Enqueue(networkObject);
}
@@ -95,15 +143,14 @@ private void RegisterPrefabInternal(GameObject prefab, int prewarmCount)
var prefabQueue = new Queue();
pooledObjects[prefab] = prefabQueue;
-
for (int i = 0; i < prewarmCount; i++)
{
var go = CreateInstance(prefab);
ReturnNetworkObject(go.GetComponent(), prefab);
}
- // Register netcode Spawn handlers
- m_NetworkManager.PrefabHandler.AddHandler(prefab, new DummyPrefabInstanceHandler(prefab, this));
+ // Register Netcode Spawn handlers
+ NetworkManager.Singleton.PrefabHandler.AddHandler(prefab, new PooledPrefabInstanceHandler(prefab, this));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -115,7 +162,7 @@ private GameObject CreateInstance(GameObject prefab)
///
/// This matches the signature of
///
- ///
+ ///
///
///
///
@@ -135,7 +182,6 @@ private NetworkObject GetNetworkObjectInternal(GameObject prefab, Vector3 positi
// Here we must reverse the logic in ReturnNetworkObject.
var go = networkObject.gameObject;
- go.transform.SetParent(null);
go.SetActive(true);
go.transform.position = position;
@@ -147,12 +193,27 @@ private NetworkObject GetNetworkObjectInternal(GameObject prefab, Vector3 positi
///
/// Registers all objects in to the cache.
///
- private void InitializePool()
+ public void InitializePool()
{
+ if (m_HasInitialized) return;
foreach (var configObject in PooledPrefabsList)
{
RegisterPrefabInternal(configObject.Prefab, configObject.PrewarmCount);
}
+ m_HasInitialized = true;
+ }
+
+ ///
+ /// Unregisters all objects in from the cache.
+ ///
+ public void ClearPool()
+ {
+ foreach (var prefab in prefabs)
+ {
+ // Unregister Netcode Spawn handlers
+ NetworkManager.Singleton.PrefabHandler.RemoveHandler(prefab);
+ }
+ pooledObjects.Clear();
}
}
@@ -163,25 +224,28 @@ struct PoolConfigObject
public int PrewarmCount;
}
- class DummyPrefabInstanceHandler : INetworkPrefabInstanceHandler
+ class PooledPrefabInstanceHandler : INetworkPrefabInstanceHandler
{
GameObject m_Prefab;
NetworkObjectPool m_Pool;
- public DummyPrefabInstanceHandler(GameObject prefab, NetworkObjectPool pool)
+ public PooledPrefabInstanceHandler(GameObject prefab, NetworkObjectPool pool)
{
m_Prefab = prefab;
m_Pool = pool;
}
- public NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation)
+ NetworkObject INetworkPrefabInstanceHandler.Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation)
{
- return m_Pool.GetNetworkObject(m_Prefab, position, rotation);
+ var netObject = m_Pool.GetNetworkObject(m_Prefab, position, rotation);
+ return netObject;
}
- public void Destroy(NetworkObject networkObject)
+ void INetworkPrefabInstanceHandler.Destroy(NetworkObject networkObject)
{
m_Pool.ReturnNetworkObject(networkObject, m_Prefab);
}
}
+
+}
}