Skip to content

Commit b1c5da8

Browse files
NetworkObjectPool feature parity with the version in the Unity Multiplayer Samples Boss Room sample project (#176)
* Updating the NetworkObjectPool to have feature parity with the version in the Multiplayer Samples BossRoom project (it's now a NetworkBehaviour instead of a MonoBehaviour, uses the NetworkManager.Singleton, initializes the pool in OnNetworkSpawn, and it's a singleton) * feature parity with the NetworkObjectPool in the Unity Multiplayer Samples Co-op Boss Room sample project.
1 parent 31bcb21 commit b1c5da8

File tree

1 file changed

+83
-19
lines changed

1 file changed

+83
-19
lines changed

com.community.netcode.extensions/Runtime/NetworkObjectPool/NetworkObjectPool.cs

Lines changed: 83 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,16 @@
77

88
namespace Netcode.Extensions
99
{
10-
public class NetworkObjectPool : MonoBehaviour
10+
/// <summary>
11+
/// Object Pool for networked objects, used for controlling how objects are spawned by Netcode. Netcode by default will allocate new memory when spawning new
12+
/// objects. With this Networked Pool, we're using custom spawning to reuse objects.
13+
/// Hooks to NetworkManager's prefab handler to intercept object spawning and do custom actions
14+
/// </summary>
15+
public class NetworkObjectPool : NetworkBehaviour
1116
{
12-
[SerializeField]
13-
NetworkManager m_NetworkManager;
17+
private static NetworkObjectPool _instance;
18+
19+
public static NetworkObjectPool Singleton=> _instance;
1420

1521
[SerializeField]
1622
List<PoolConfigObject> PooledPrefabsList;
@@ -19,20 +25,65 @@ public class NetworkObjectPool : MonoBehaviour
1925

2026
Dictionary<GameObject, Queue<NetworkObject>> pooledObjects = new Dictionary<GameObject, Queue<NetworkObject>>();
2127

28+
private bool m_HasInitialized = false;
29+
2230
public void Awake()
31+
{
32+
if (_instance != null && _instance != this)
33+
{
34+
Destroy(this.gameObject);
35+
}
36+
else
37+
{
38+
_instance = this;
39+
}
40+
}
41+
42+
public override void OnNetworkSpawn()
2343
{
2444
InitializePool();
2545
}
2646

47+
public override void OnNetworkDespawn()
48+
{
49+
ClearPool();
50+
}
51+
52+
public override void OnDestroy()
53+
{
54+
if (_instance == this)
55+
{
56+
_instance = null;
57+
}
58+
59+
base.OnDestroy();
60+
}
61+
62+
2763
public void OnValidate()
2864
{
2965
for (var i = 0; i < PooledPrefabsList.Count; i++)
3066
{
3167
var prefab = PooledPrefabsList[i].Prefab;
3268
if (prefab != null)
3369
{
34-
Assert.IsNotNull(prefab.GetComponent<NetworkObject>(), $"{nameof(NetworkObjectPool)}: Pooled prefab \"{prefab.name}\" at index {i.ToString()} has no {nameof(NetworkObject)} component.");
70+
Assert.IsNotNull(
71+
prefab.GetComponent<NetworkObject>(),
72+
$"{nameof(NetworkObjectPool)}: Pooled prefab \"{prefab.name}\" at index {i.ToString()} has no {nameof(NetworkObject)} component."
73+
);
74+
75+
}
76+
77+
var prewarmCount = PooledPrefabsList[i].PrewarmCount;
78+
if (prewarmCount < 0)
79+
{
80+
Debug.LogWarning($"{nameof(NetworkObjectPool)}: Pooled prefab at index {i.ToString()} has a negative prewarm count! Making it not negative.");
81+
var thisPooledPrefab = PooledPrefabsList[i];
82+
thisPooledPrefab.PrewarmCount *= -1;
83+
PooledPrefabsList[i] = thisPooledPrefab;
3584
}
85+
86+
3687
}
3788
}
3889

@@ -59,15 +110,12 @@ public NetworkObject GetNetworkObject(GameObject prefab, Vector3 position, Quate
59110
}
60111

61112
/// <summary>
62-
/// Return an object to the pool (and reset them).
113+
/// Return an object to the pool (reset objects before returning).
63114
/// </summary>
64115
public void ReturnNetworkObject(NetworkObject networkObject, GameObject prefab)
65116
{
66117
var go = networkObject.gameObject;
67-
68-
// 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.
69118
go.SetActive(false);
70-
go.transform.SetParent(transform);
71119
pooledObjects[prefab].Enqueue(networkObject);
72120
}
73121

@@ -95,15 +143,14 @@ private void RegisterPrefabInternal(GameObject prefab, int prewarmCount)
95143

96144
var prefabQueue = new Queue<NetworkObject>();
97145
pooledObjects[prefab] = prefabQueue;
98-
99146
for (int i = 0; i < prewarmCount; i++)
100147
{
101148
var go = CreateInstance(prefab);
102149
ReturnNetworkObject(go.GetComponent<NetworkObject>(), prefab);
103150
}
104151

105-
// Register netcode Spawn handlers
106-
m_NetworkManager.PrefabHandler.AddHandler(prefab, new DummyPrefabInstanceHandler(prefab, this));
152+
// Register Netcode Spawn handlers
153+
NetworkManager.Singleton.PrefabHandler.AddHandler(prefab, new PooledPrefabInstanceHandler(prefab, this));
107154
}
108155

109156
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -115,7 +162,7 @@ private GameObject CreateInstance(GameObject prefab)
115162
/// <summary>
116163
/// This matches the signature of <see cref="NetworkSpawnManager.SpawnHandlerDelegate"/>
117164
/// </summary>
118-
/// <param name="prefabHash"></param>
165+
/// <param name="prefab"></param>
119166
/// <param name="position"></param>
120167
/// <param name="rotation"></param>
121168
/// <returns></returns>
@@ -135,7 +182,6 @@ private NetworkObject GetNetworkObjectInternal(GameObject prefab, Vector3 positi
135182

136183
// Here we must reverse the logic in ReturnNetworkObject.
137184
var go = networkObject.gameObject;
138-
go.transform.SetParent(null);
139185
go.SetActive(true);
140186

141187
go.transform.position = position;
@@ -147,12 +193,27 @@ private NetworkObject GetNetworkObjectInternal(GameObject prefab, Vector3 positi
147193
/// <summary>
148194
/// Registers all objects in <see cref="PooledPrefabsList"/> to the cache.
149195
/// </summary>
150-
private void InitializePool()
196+
public void InitializePool()
151197
{
198+
if (m_HasInitialized) return;
152199
foreach (var configObject in PooledPrefabsList)
153200
{
154201
RegisterPrefabInternal(configObject.Prefab, configObject.PrewarmCount);
155202
}
203+
m_HasInitialized = true;
204+
}
205+
206+
/// <summary>
207+
/// Unregisters all objects in <see cref="PooledPrefabsList"/> from the cache.
208+
/// </summary>
209+
public void ClearPool()
210+
{
211+
foreach (var prefab in prefabs)
212+
{
213+
// Unregister Netcode Spawn handlers
214+
NetworkManager.Singleton.PrefabHandler.RemoveHandler(prefab);
215+
}
216+
pooledObjects.Clear();
156217
}
157218
}
158219

@@ -163,25 +224,28 @@ struct PoolConfigObject
163224
public int PrewarmCount;
164225
}
165226

166-
class DummyPrefabInstanceHandler : INetworkPrefabInstanceHandler
227+
class PooledPrefabInstanceHandler : INetworkPrefabInstanceHandler
167228
{
168229
GameObject m_Prefab;
169230
NetworkObjectPool m_Pool;
170231

171-
public DummyPrefabInstanceHandler(GameObject prefab, NetworkObjectPool pool)
232+
public PooledPrefabInstanceHandler(GameObject prefab, NetworkObjectPool pool)
172233
{
173234
m_Prefab = prefab;
174235
m_Pool = pool;
175236
}
176237

177-
public NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation)
238+
NetworkObject INetworkPrefabInstanceHandler.Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation)
178239
{
179-
return m_Pool.GetNetworkObject(m_Prefab, position, rotation);
240+
var netObject = m_Pool.GetNetworkObject(m_Prefab, position, rotation);
241+
return netObject;
180242
}
181243

182-
public void Destroy(NetworkObject networkObject)
244+
void INetworkPrefabInstanceHandler.Destroy(NetworkObject networkObject)
183245
{
184246
m_Pool.ReturnNetworkObject(networkObject, m_Prefab);
185247
}
186248
}
249+
250+
}
187251
}

0 commit comments

Comments
 (0)