com.amanotes.prefabpool 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41,6 +41,7 @@ namespace Amanotes.Core
41
41
  _pool.RemoveAt(lastIndex);
42
42
  }
43
43
 
44
+ bool fromPool = resultGameObject != null;
44
45
  if (resultGameObject == null)
45
46
  {
46
47
  // Create prefab inside the pool's transform
@@ -48,13 +49,12 @@ namespace Amanotes.Core
48
49
  resultGameObject.hideFlags = HideFlags.DontSave;
49
50
  }
50
51
 
51
- // Move to spawn parent when retrieved
52
52
  var t = resultGameObject.transform;
53
53
  t.SetParent(spawnParent, false);
54
54
  t.localPosition = localPosition;
55
55
  t.localRotation = Quaternion.identity;
56
+ resultGameObject.SetActive(true);
56
57
 
57
- // Call OnGet on any IPoolPrefab components
58
58
  var poolComponents = resultGameObject.GetComponents<IPoolPrefab>();
59
59
  foreach (var pp in poolComponents)
60
60
  {
@@ -68,7 +68,6 @@ namespace Amanotes.Core
68
68
  {
69
69
  if (gameObject == null) return;
70
70
 
71
- // Call OnReturn on any IPoolPrefab components
72
71
  var poolComponents = gameObject.GetComponents<IPoolPrefab>();
73
72
  foreach (var pp in poolComponents)
74
73
  {
@@ -76,8 +75,12 @@ namespace Amanotes.Core
76
75
  }
77
76
 
78
77
  var t = gameObject.transform;
78
+ gameObject.SetActive(false);
79
79
  t.SetParent(poolParent, false);
80
80
  t.localPosition = Vector3.zero;
81
+ #if UNITY_EDITOR
82
+ gameObject.name = id;
83
+ #endif
81
84
  _pool.Add(gameObject);
82
85
  }
83
86
 
@@ -93,12 +96,15 @@ namespace Amanotes.Core
93
96
  _pool.Clear();
94
97
  }
95
98
 
99
+ public void PurgeDestroyed() => _pool.RemoveAll(obj => obj == null);
100
+
96
101
  public IEnumerator PreAllocate(Transform poolParent)
97
102
  {
98
103
  for (var i = 0; i < prewarmCount; i++)
99
104
  {
100
105
  var instance = UnityObject.Instantiate(prefab, poolParent.position, Quaternion.identity, poolParent);
101
106
  instance.hideFlags = HideFlags.DontSave;
107
+ instance.SetActive(false);
102
108
  _pool.Add(instance);
103
109
  }
104
110
 
@@ -120,16 +126,16 @@ namespace Amanotes.Core
120
126
  _prefabPool = prefabPool;
121
127
  _spawnParent = spawnParent;
122
128
 
123
- // Set parent group reference for each entry
124
129
  foreach (var entry in entries)
125
130
  {
126
131
  entry.SetParentGroup(this);
132
+ entry.PurgeDestroyed();
127
133
  }
128
134
 
129
- // Set parent group reference for fallback entry
130
135
  if (fallbackEntry != null)
131
136
  {
132
137
  fallbackEntry.SetParentGroup(this);
138
+ fallbackEntry.PurgeDestroyed();
133
139
  }
134
140
  }
135
141
 
@@ -257,6 +263,7 @@ namespace Amanotes.Core
257
263
  {
258
264
  [NonSerialized] private bool _isDestroyed = false;
259
265
  [NonSerialized] private bool _isReady = false;
266
+ [NonSerialized] private bool _isInitializing = false;
260
267
  [NonSerialized] private readonly Dictionary<string, PoolGroup> _groups = new Dictionary<string, PoolGroup>();
261
268
  [NonSerialized] private readonly Dictionary<int, PoolEntry> _instanceTypeMap = new Dictionary<int, PoolEntry>();
262
269
  [NonSerialized] private readonly Dictionary<GameObject, PoolEntry> _customPool = new Dictionary<GameObject, PoolEntry>();
@@ -307,6 +314,7 @@ namespace Amanotes.Core
307
314
 
308
315
  _groups[group.id] = group;
309
316
  group.Register(this, spawnParent);
317
+ PurgeStaleInstanceMap();
310
318
  }
311
319
 
312
320
  public void SetSpawnParent(string groupId, Transform spawnParent)
@@ -352,10 +360,23 @@ namespace Amanotes.Core
352
360
  }
353
361
  }
354
362
 
363
+ private void PurgeStaleInstanceMap()
364
+ {
365
+ #if UNITY_EDITOR
366
+ if (_instanceTypeMap.Count == 0) return;
367
+ var stale = new List<int>();
368
+ foreach (var kvp in _instanceTypeMap)
369
+ {
370
+ if (EditorUtility.InstanceIDToObject(kvp.Key) == null) stale.Add(kvp.Key);
371
+ }
372
+ foreach (var id in stale) _instanceTypeMap.Remove(id);
373
+ #endif
374
+ }
375
+
355
376
  public IEnumerator Initialize()
356
377
  {
357
- if (_isReady) yield break;
358
- _isReady = false;
378
+ if (_isReady || _isInitializing) yield break;
379
+ _isInitializing = true;
359
380
 
360
381
  #if UNITY_EDITOR
361
382
  EditorApplication.playModeStateChanged -= HandlePlayModeChanged;
@@ -377,6 +398,7 @@ namespace Amanotes.Core
377
398
  }
378
399
  }
379
400
 
401
+ _isInitializing = false;
380
402
  _isReady = true;
381
403
  }
382
404
 
@@ -401,23 +423,27 @@ namespace Amanotes.Core
401
423
  entry.DestroyPool();
402
424
  }
403
425
 
404
- // Destroy fallback entry if available
405
426
  if (group.fallbackEntry != null)
406
427
  {
407
428
  group.fallbackEntry.DestroyPool();
408
429
  }
409
430
  }
410
-
411
431
  _groups.Clear();
412
432
 
433
+ foreach (var entry in _customPool.Values)
434
+ {
435
+ entry.DestroyPool();
436
+ }
437
+ _customPool.Clear();
438
+
413
439
  #if UNITY_EDITOR
414
440
  foreach (var kvp in _instanceTypeMap)
415
441
  {
416
442
  var obj = EditorUtility.InstanceIDToObject(kvp.Key);
417
443
  if (obj != null) UnityObject.DestroyImmediate(obj);
418
444
  }
419
- _instanceTypeMap.Clear();
420
445
  #endif
446
+ _instanceTypeMap.Clear();
421
447
  }
422
448
  }
423
449
  }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "PrefabPool.Tests",
3
+ "rootNamespace": "Amanotes.Core",
4
+ "references": [
5
+ "PrefabPool",
6
+ "Unity.PerformanceTesting"
7
+ ],
8
+ "optionalUnityReferences": [
9
+ "TestAssemblies"
10
+ ]
11
+ }
@@ -0,0 +1,7 @@
1
+ fileFormatVersion: 2
2
+ guid: f4f4c6bd22a404f98bd5cc47335df5d8
3
+ AssemblyDefinitionImporter:
4
+ externalObjects: {}
5
+ userData:
6
+ assetBundleName:
7
+ assetBundleVariant:
@@ -0,0 +1,224 @@
1
+ using System.Collections;
2
+ using System.Collections.Generic;
3
+ using NUnit.Framework;
4
+ using UnityEngine;
5
+ using UnityEngine.TestTools;
6
+ using UnityObject = UnityEngine.Object;
7
+
8
+ namespace Amanotes.Core
9
+ {
10
+ public class PrefabPoolGroupTests
11
+ {
12
+ private PrefabPool _pool;
13
+ private PoolGroup _groupA;
14
+ private PoolGroup _groupB;
15
+ private GameObject _prefabA;
16
+ private GameObject _prefabB;
17
+ private Transform _spawnParentA;
18
+ private Transform _spawnParentB;
19
+
20
+ [SetUp]
21
+ public void SetUp()
22
+ {
23
+ var poolObject = new GameObject("TestPool");
24
+ _pool = poolObject.AddComponent<PrefabPool>();
25
+
26
+ var spawnParentObjectA = new GameObject("SpawnParentA");
27
+ _spawnParentA = spawnParentObjectA.transform;
28
+
29
+ var spawnParentObjectB = new GameObject("SpawnParentB");
30
+ _spawnParentB = spawnParentObjectB.transform;
31
+
32
+ _prefabA = new GameObject("PrefabA");
33
+ _prefabA.AddComponent<MockPoolPrefab>();
34
+
35
+ _prefabB = new GameObject("PrefabB");
36
+ _prefabB.AddComponent<MockPoolPrefab>();
37
+
38
+ _groupA = new PoolGroup
39
+ {
40
+ id = "GroupA",
41
+ entries = new List<PoolEntry>
42
+ {
43
+ new PoolEntry
44
+ {
45
+ id = "PrefabA",
46
+ prefab = _prefabA,
47
+ prewarmCount = 5
48
+ }
49
+ }
50
+ };
51
+
52
+ _groupB = new PoolGroup
53
+ {
54
+ id = "GroupB",
55
+ entries = new List<PoolEntry>
56
+ {
57
+ new PoolEntry
58
+ {
59
+ id = "PrefabB",
60
+ prefab = _prefabB,
61
+ prewarmCount = 5
62
+ }
63
+ }
64
+ };
65
+
66
+ _pool.RegisterGroup(_groupA, _spawnParentA);
67
+ _pool.RegisterGroup(_groupB, _spawnParentB);
68
+ }
69
+
70
+ [TearDown]
71
+ public void TearDown()
72
+ {
73
+ if (_pool != null)
74
+ {
75
+ _pool.DestroyPool();
76
+ UnityObject.DestroyImmediate(_pool.gameObject);
77
+ }
78
+
79
+ if (_spawnParentA != null)
80
+ {
81
+ UnityObject.DestroyImmediate(_spawnParentA.gameObject);
82
+ }
83
+
84
+ if (_spawnParentB != null)
85
+ {
86
+ UnityObject.DestroyImmediate(_spawnParentB.gameObject);
87
+ }
88
+
89
+ if (_prefabA != null)
90
+ {
91
+ UnityObject.DestroyImmediate(_prefabA);
92
+ }
93
+
94
+ if (_prefabB != null)
95
+ {
96
+ UnityObject.DestroyImmediate(_prefabB);
97
+ }
98
+
99
+ var allObjects = UnityObject.FindObjectsOfType<GameObject>();
100
+ foreach (var obj in allObjects)
101
+ {
102
+ if (obj.hideFlags == HideFlags.DontSave)
103
+ {
104
+ UnityObject.DestroyImmediate(obj);
105
+ }
106
+ }
107
+ }
108
+
109
+ [UnityTest]
110
+ public IEnumerator PoolGroupIsolation_MultipleGroups_ObjectsNeverCrossBetweenGroups()
111
+ {
112
+ yield return _pool.Initialize();
113
+
114
+ for (int i = 0; i < 100; i++)
115
+ {
116
+ var objFromA = _groupA.Get("PrefabA");
117
+ Assert.IsNotNull(objFromA, $"Iteration {i}: GroupA should return valid GameObject");
118
+
119
+ var objFromB = _groupB.Get("PrefabB");
120
+ Assert.IsNotNull(objFromB, $"Iteration {i}: GroupB should return valid GameObject");
121
+
122
+ var instanceIdA = objFromA.GetInstanceID();
123
+ var instanceIdB = objFromB.GetInstanceID();
124
+
125
+ Assert.AreNotEqual(instanceIdA, instanceIdB,
126
+ $"Iteration {i}: Objects from different groups should have different instance IDs");
127
+
128
+ Assert.IsTrue(objFromA.name.Contains("PrefabA"),
129
+ $"Iteration {i}: Object from GroupA should be PrefabA instance");
130
+ Assert.IsTrue(objFromB.name.Contains("PrefabB"),
131
+ $"Iteration {i}: Object from GroupB should be PrefabB instance");
132
+
133
+ _groupA.Return(objFromA);
134
+ _groupB.Return(objFromB);
135
+
136
+ var reusedFromA = _groupA.Get("PrefabA");
137
+ var reusedFromB = _groupB.Get("PrefabB");
138
+
139
+ Assert.AreEqual(instanceIdA, reusedFromA.GetInstanceID(),
140
+ $"Iteration {i}: GroupA should reuse its own objects");
141
+ Assert.AreEqual(instanceIdB, reusedFromB.GetInstanceID(),
142
+ $"Iteration {i}: GroupB should reuse its own objects");
143
+
144
+ Assert.IsTrue(reusedFromA.name.Contains("PrefabA"),
145
+ $"Iteration {i}: GroupA should never return PrefabB instances");
146
+ Assert.IsTrue(reusedFromB.name.Contains("PrefabB"),
147
+ $"Iteration {i}: GroupB should never return PrefabA instances");
148
+
149
+ _groupA.Return(reusedFromA);
150
+ _groupB.Return(reusedFromB);
151
+ }
152
+ }
153
+
154
+ [UnityTest]
155
+ public IEnumerator ReturnGroupRouting_ReturnToGroup_SubsequentGetRetrievesSameInstanceFromSameGroup()
156
+ {
157
+ yield return _pool.Initialize();
158
+
159
+ for (int i = 0; i < 100; i++)
160
+ {
161
+ var objA1 = _groupA.Get("PrefabA");
162
+ var objA2 = _groupA.Get("PrefabA");
163
+ var objB1 = _groupB.Get("PrefabB");
164
+ var objB2 = _groupB.Get("PrefabB");
165
+
166
+ Assert.IsNotNull(objA1, $"Iteration {i}: GroupA Get 1 should return valid GameObject");
167
+ Assert.IsNotNull(objA2, $"Iteration {i}: GroupA Get 2 should return valid GameObject");
168
+ Assert.IsNotNull(objB1, $"Iteration {i}: GroupB Get 1 should return valid GameObject");
169
+ Assert.IsNotNull(objB2, $"Iteration {i}: GroupB Get 2 should return valid GameObject");
170
+
171
+ var instanceIdA1 = objA1.GetInstanceID();
172
+ var instanceIdA2 = objA2.GetInstanceID();
173
+ var instanceIdB1 = objB1.GetInstanceID();
174
+ var instanceIdB2 = objB2.GetInstanceID();
175
+
176
+ _groupA.Return(objA1);
177
+ _groupA.Return(objA2);
178
+ _groupB.Return(objB1);
179
+ _groupB.Return(objB2);
180
+
181
+ var reusedA1 = _groupA.Get("PrefabA");
182
+ var reusedA2 = _groupA.Get("PrefabA");
183
+ var reusedB1 = _groupB.Get("PrefabB");
184
+ var reusedB2 = _groupB.Get("PrefabB");
185
+
186
+ var reusedInstanceIdsA = new HashSet<int>
187
+ {
188
+ reusedA1.GetInstanceID(),
189
+ reusedA2.GetInstanceID()
190
+ };
191
+ var reusedInstanceIdsB = new HashSet<int>
192
+ {
193
+ reusedB1.GetInstanceID(),
194
+ reusedB2.GetInstanceID()
195
+ };
196
+
197
+ Assert.IsTrue(reusedInstanceIdsA.Contains(instanceIdA1),
198
+ $"Iteration {i}: Object returned to GroupA should be retrieved from GroupA");
199
+ Assert.IsTrue(reusedInstanceIdsA.Contains(instanceIdA2),
200
+ $"Iteration {i}: Object returned to GroupA should be retrieved from GroupA");
201
+
202
+ Assert.IsTrue(reusedInstanceIdsB.Contains(instanceIdB1),
203
+ $"Iteration {i}: Object returned to GroupB should be retrieved from GroupB");
204
+ Assert.IsTrue(reusedInstanceIdsB.Contains(instanceIdB2),
205
+ $"Iteration {i}: Object returned to GroupB should be retrieved from GroupB");
206
+
207
+ Assert.IsFalse(reusedInstanceIdsA.Contains(instanceIdB1),
208
+ $"Iteration {i}: GroupA should not return objects from GroupB");
209
+ Assert.IsFalse(reusedInstanceIdsA.Contains(instanceIdB2),
210
+ $"Iteration {i}: GroupA should not return objects from GroupB");
211
+
212
+ Assert.IsFalse(reusedInstanceIdsB.Contains(instanceIdA1),
213
+ $"Iteration {i}: GroupB should not return objects from GroupA");
214
+ Assert.IsFalse(reusedInstanceIdsB.Contains(instanceIdA2),
215
+ $"Iteration {i}: GroupB should not return objects from GroupA");
216
+
217
+ _groupA.Return(reusedA1);
218
+ _groupA.Return(reusedA2);
219
+ _groupB.Return(reusedB1);
220
+ _groupB.Return(reusedB2);
221
+ }
222
+ }
223
+ }
224
+ }
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: 52ad4e4f94f0b41ff9df7f00bcbdd701
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -0,0 +1,257 @@
1
+ using System.Collections;
2
+ using NUnit.Framework;
3
+ using UnityEngine;
4
+ using UnityEngine.TestTools;
5
+ using UnityObject = UnityEngine.Object;
6
+
7
+ namespace Amanotes.Core
8
+ {
9
+ public class PrefabPoolLifecycleTests
10
+ {
11
+ private PrefabPool _pool;
12
+ private GameObject _testPrefab;
13
+ private PoolGroup _testGroup;
14
+ private Transform _spawnParent;
15
+
16
+ [SetUp]
17
+ public void SetUp()
18
+ {
19
+ var poolObject = new GameObject("TestPool");
20
+ _pool = poolObject.AddComponent<PrefabPool>();
21
+
22
+ var spawnParentObject = new GameObject("SpawnParent");
23
+ _spawnParent = spawnParentObject.transform;
24
+
25
+ _testPrefab = new GameObject("TestPrefab");
26
+ _testPrefab.AddComponent<MockPoolPrefab>();
27
+
28
+ _testGroup = new PoolGroup
29
+ {
30
+ id = "TestGroup",
31
+ entries = new System.Collections.Generic.List<PoolEntry>
32
+ {
33
+ new PoolEntry
34
+ {
35
+ id = "TestPrefab",
36
+ prefab = _testPrefab,
37
+ prewarmCount = 5
38
+ }
39
+ }
40
+ };
41
+
42
+ _pool.RegisterGroup(_testGroup, _spawnParent);
43
+ }
44
+
45
+ [TearDown]
46
+ public void TearDown()
47
+ {
48
+ if (_pool != null)
49
+ {
50
+ _pool.DestroyPool();
51
+ UnityObject.DestroyImmediate(_pool.gameObject);
52
+ }
53
+
54
+ if (_spawnParent != null)
55
+ {
56
+ UnityObject.DestroyImmediate(_spawnParent.gameObject);
57
+ }
58
+
59
+ if (_testPrefab != null)
60
+ {
61
+ UnityObject.DestroyImmediate(_testPrefab);
62
+ }
63
+
64
+ var allObjects = UnityObject.FindObjectsOfType<GameObject>();
65
+ foreach (var obj in allObjects)
66
+ {
67
+ if (obj.hideFlags == HideFlags.DontSave)
68
+ {
69
+ UnityObject.DestroyImmediate(obj);
70
+ }
71
+ }
72
+ }
73
+
74
+ [UnityTest]
75
+ public IEnumerator PoolObjectRoundTrip_GetReturnGet_ReuseSameInstance()
76
+ {
77
+ yield return _pool.Initialize();
78
+
79
+ for (int i = 0; i < 100; i++)
80
+ {
81
+ var firstGet = _testGroup.Get("TestPrefab");
82
+ Assert.IsNotNull(firstGet, $"Iteration {i}: First Get should return valid GameObject");
83
+
84
+ var firstInstanceId = firstGet.GetInstanceID();
85
+
86
+ _testGroup.Return(firstGet);
87
+
88
+ var secondGet = _testGroup.Get("TestPrefab");
89
+ Assert.IsNotNull(secondGet, $"Iteration {i}: Second Get should return valid GameObject");
90
+
91
+ var secondInstanceId = secondGet.GetInstanceID();
92
+
93
+ Assert.AreEqual(firstInstanceId, secondInstanceId,
94
+ $"Iteration {i}: Get-Return-Get should reuse same instance (validates pooling eliminates instantiation)");
95
+
96
+ _testGroup.Return(secondGet);
97
+ }
98
+ }
99
+
100
+ [UnityTest]
101
+ public IEnumerator LifecycleCallbackInvocation_GetReturnCycle_InvokesOnGetAndOnReturnExactlyOnce()
102
+ {
103
+ yield return _pool.Initialize();
104
+
105
+ for (int i = 0; i < 100; i++)
106
+ {
107
+ var obj = _testGroup.Get("TestPrefab");
108
+ Assert.IsNotNull(obj, $"Iteration {i}: Get should return valid GameObject");
109
+
110
+ var mock = obj.GetComponent<MockPoolPrefab>();
111
+ Assert.IsNotNull(mock, $"Iteration {i}: GameObject should have MockPoolPrefab component");
112
+
113
+ mock.ResetCounts();
114
+
115
+ var objAgain = _testGroup.Get("TestPrefab");
116
+ var mockAgain = objAgain.GetComponent<MockPoolPrefab>();
117
+ mockAgain.ResetCounts();
118
+
119
+ _testGroup.Return(obj);
120
+
121
+ Assert.AreEqual(1, mock.returnCallCount,
122
+ $"Iteration {i}: OnReturn should be called exactly once during Return");
123
+ Assert.AreEqual(0, mock.getCallCount,
124
+ $"Iteration {i}: OnGet should not be called during Return");
125
+
126
+ var reusedObj = _testGroup.Get("TestPrefab");
127
+ var reusedMock = reusedObj.GetComponent<MockPoolPrefab>();
128
+
129
+ Assert.AreEqual(1, reusedMock.getCallCount,
130
+ $"Iteration {i}: OnGet should be called exactly once during Get");
131
+
132
+ _testGroup.Return(objAgain);
133
+ _testGroup.Return(reusedObj);
134
+ }
135
+ }
136
+
137
+ [UnityTest]
138
+ public IEnumerator PreallocationCorrectness_PrewarmCount_CreatesExactNumberOfPreallocatedObjects()
139
+ {
140
+ for (int iteration = 0; iteration < 100; iteration++)
141
+ {
142
+ var prewarmCount = UnityEngine.Random.Range(1, 20);
143
+
144
+ var poolObject = new GameObject($"TestPool_{iteration}");
145
+ var pool = poolObject.AddComponent<PrefabPool>();
146
+
147
+ var spawnParentObject = new GameObject($"SpawnParent_{iteration}");
148
+ var spawnParent = spawnParentObject.transform;
149
+
150
+ var prefab = new GameObject($"Prefab_{iteration}");
151
+ prefab.AddComponent<MockPoolPrefab>();
152
+
153
+ var group = new PoolGroup
154
+ {
155
+ id = $"Group_{iteration}",
156
+ entries = new System.Collections.Generic.List<PoolEntry>
157
+ {
158
+ new PoolEntry
159
+ {
160
+ id = "TestPrefab",
161
+ prefab = prefab,
162
+ prewarmCount = prewarmCount
163
+ }
164
+ }
165
+ };
166
+
167
+ pool.RegisterGroup(group, spawnParent);
168
+
169
+ yield return pool.Initialize();
170
+
171
+ var retrievedObjects = new System.Collections.Generic.List<GameObject>();
172
+
173
+ for (int i = 0; i < prewarmCount; i++)
174
+ {
175
+ var obj = group.Get("TestPrefab");
176
+ Assert.IsNotNull(obj, $"Iteration {iteration}: Should retrieve pre-allocated object {i}");
177
+ retrievedObjects.Add(obj);
178
+ }
179
+
180
+ Assert.AreEqual(prewarmCount, retrievedObjects.Count,
181
+ $"Iteration {iteration}: Should retrieve exactly {prewarmCount} pre-allocated objects");
182
+
183
+ foreach (var obj in retrievedObjects)
184
+ {
185
+ group.Return(obj);
186
+ }
187
+
188
+ pool.DestroyPool();
189
+ UnityObject.DestroyImmediate(poolObject);
190
+ UnityObject.DestroyImmediate(spawnParentObject);
191
+ UnityObject.DestroyImmediate(prefab);
192
+ }
193
+ }
194
+
195
+ [UnityTest]
196
+ public IEnumerator DynamicPoolExpansion_GetBeyondCapacity_SuccessfullyReturnsValidGameObjects()
197
+ {
198
+ for (int iteration = 0; iteration < 100; iteration++)
199
+ {
200
+ var initialCapacity = UnityEngine.Random.Range(2, 10);
201
+ var extraRequests = UnityEngine.Random.Range(5, 15);
202
+
203
+ var poolObject = new GameObject($"TestPool_{iteration}");
204
+ var pool = poolObject.AddComponent<PrefabPool>();
205
+
206
+ var spawnParentObject = new GameObject($"SpawnParent_{iteration}");
207
+ var spawnParent = spawnParentObject.transform;
208
+
209
+ var prefab = new GameObject($"Prefab_{iteration}");
210
+ prefab.AddComponent<MockPoolPrefab>();
211
+
212
+ var group = new PoolGroup
213
+ {
214
+ id = $"Group_{iteration}",
215
+ entries = new System.Collections.Generic.List<PoolEntry>
216
+ {
217
+ new PoolEntry
218
+ {
219
+ id = "TestPrefab",
220
+ prefab = prefab,
221
+ prewarmCount = initialCapacity
222
+ }
223
+ }
224
+ };
225
+
226
+ pool.RegisterGroup(group, spawnParent);
227
+
228
+ yield return pool.Initialize();
229
+
230
+ var retrievedObjects = new System.Collections.Generic.List<GameObject>();
231
+
232
+ var totalRequests = initialCapacity + extraRequests;
233
+
234
+ for (int i = 0; i < totalRequests; i++)
235
+ {
236
+ var obj = group.Get("TestPrefab");
237
+ Assert.IsNotNull(obj,
238
+ $"Iteration {iteration}: Get beyond capacity should succeed (request {i + 1}/{totalRequests})");
239
+ retrievedObjects.Add(obj);
240
+ }
241
+
242
+ Assert.AreEqual(totalRequests, retrievedObjects.Count,
243
+ $"Iteration {iteration}: Should retrieve {totalRequests} objects (capacity {initialCapacity} + expansion {extraRequests})");
244
+
245
+ foreach (var obj in retrievedObjects)
246
+ {
247
+ group.Return(obj);
248
+ }
249
+
250
+ pool.DestroyPool();
251
+ UnityObject.DestroyImmediate(poolObject);
252
+ UnityObject.DestroyImmediate(spawnParentObject);
253
+ UnityObject.DestroyImmediate(prefab);
254
+ }
255
+ }
256
+ }
257
+ }
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: 9c6969a47577843fb977ab5e2c7c1ad2
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant: