com.amanotes.prefabpool 1.1.0 → 1.2.0

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.0] - 2026-05-20
4
+
5
+ ### Added
6
+ - `PoolEntry.EnsureCapacity(int count, Transform poolParent)` — pre-fills pool to target count without coroutine overhead
7
+ - `PoolEntry.PoolCount` property — returns current pooled instance count
8
+ - `PoolGroup.FindEntry(string prefabId)` — O(n) linear search replacing LINQ `Find()` with fallback support
9
+ - `PoolGroup.IsGameplay` field — marks group for runtime instantiation warnings
10
+ - Runtime instantiation warning in Editor/Development builds when `IsGameplay` is true
11
+
12
+ ### Changed
13
+ - `PoolEntry.Get()` / `Return()` uses per-instance `IPoolPrefab[]` cache (`_poolPrefabCache`) — eliminates `GetComponents<IPoolPrefab>()` GC per Get/Return call
14
+ - `PoolEntry.PreAllocate()` yields every 3 instances (`PreAllocBatchSize`) to spread across frames
15
+ - `PrefabPool.Get()` uses `PoolGroup.FindEntry()` instead of LINQ lambda
16
+
17
+ ### Fixed
18
+ - `PoolEntry.ReturnAll()` clears `_poolPrefabCache` to prevent stale references
19
+
3
20
  ## [1.1.0] - 2026-04-21
4
21
 
5
22
  ### Added
@@ -1,6 +1,6 @@
1
1
  # PrefabPool API Reference
2
2
 
3
- **Package:** `com.amanotes.prefabpool` | **Version:** 1.0.1 | **Namespace:** `Amanotes.Core`
3
+ **Package:** `com.amanotes.prefabpool` | **Version:** 1.2.0 | **Namespace:** `Amanotes.Core`
4
4
 
5
5
  Generic object pooling system to eliminate garbage collection spikes from frequent instantiation/destruction.
6
6
 
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # PrefabPool
2
2
 
3
3
  **Package:** `com.amanotes.prefabpool`
4
- **Version:** 1.0.3
4
+ **Version:** 1.2.0
5
5
 
6
6
  Generic object pooling system for Unity with lifecycle callbacks and material pooling support.
7
7
 
@@ -22,8 +22,24 @@ namespace Amanotes.Core
22
22
  [NonSerialized] private readonly List<GameObject> _pool = new List<GameObject>();
23
23
  [NonSerialized] private PoolGroup _parentGroup;
24
24
 
25
+ // Per-instance IPoolPrefab cache — components don't change on pooled prefabs
26
+ [NonSerialized] private readonly Dictionary<int, IPoolPrefab[]> _poolPrefabCache = new Dictionary<int, IPoolPrefab[]>(32);
27
+ [NonSerialized] private static readonly List<IPoolPrefab> _tempPoolPrefabs = new List<IPoolPrefab>(8);
28
+
25
29
  public void SetParentGroup(PoolGroup parentGroup) => _parentGroup = parentGroup;
26
30
 
31
+ private IPoolPrefab[] GetCachedPoolPrefabs(GameObject go)
32
+ {
33
+ var instanceId = go.GetInstanceID();
34
+ if (_poolPrefabCache.TryGetValue(instanceId, out var cached)) return cached;
35
+
36
+ go.GetComponents(_tempPoolPrefabs);
37
+ cached = _tempPoolPrefabs.Count > 0 ? _tempPoolPrefabs.ToArray() : System.Array.Empty<IPoolPrefab>();
38
+ _tempPoolPrefabs.Clear();
39
+ _poolPrefabCache[instanceId] = cached;
40
+ return cached;
41
+ }
42
+
27
43
  public GameObject Get(Transform poolParent, Transform spawnParent, Vector3 localPosition)
28
44
  {
29
45
  GameObject resultGameObject = null;
@@ -44,9 +60,12 @@ namespace Amanotes.Core
44
60
  bool fromPool = resultGameObject != null;
45
61
  if (resultGameObject == null)
46
62
  {
47
- // Create prefab inside the pool's transform
48
63
  resultGameObject = UnityObject.Instantiate(prefab, poolParent.position, Quaternion.identity, poolParent);
49
64
  resultGameObject.hideFlags = HideFlags.DontSave;
65
+ #if UNITY_EDITOR || DEVELOPMENT_BUILD
66
+ if (_parentGroup != null && _parentGroup.IsGameplay)
67
+ Debug.LogWarning($"[Pool] Runtime instantiate '{id}' — prewarm undercount");
68
+ #endif
50
69
  }
51
70
 
52
71
  var t = resultGameObject.transform;
@@ -55,11 +74,8 @@ namespace Amanotes.Core
55
74
  t.localRotation = Quaternion.identity;
56
75
  resultGameObject.SetActive(true);
57
76
 
58
- var poolComponents = resultGameObject.GetComponents<IPoolPrefab>();
59
- foreach (var pp in poolComponents)
60
- {
61
- pp.OnGet();
62
- }
77
+ var prefabs = GetCachedPoolPrefabs(resultGameObject);
78
+ for (var i = 0; i < prefabs.Length; i++) prefabs[i].OnGet();
63
79
 
64
80
  return resultGameObject;
65
81
  }
@@ -68,11 +84,8 @@ namespace Amanotes.Core
68
84
  {
69
85
  if (gameObject == null) return;
70
86
 
71
- var poolComponents = gameObject.GetComponents<IPoolPrefab>();
72
- foreach (var pp in poolComponents)
73
- {
74
- pp.OnReturn();
75
- }
87
+ var prefabs = GetCachedPoolPrefabs(gameObject);
88
+ for (var i = 0; i < prefabs.Length; i++) prefabs[i].OnReturn();
76
89
 
77
90
  var t = gameObject.transform;
78
91
  gameObject.SetActive(false);
@@ -94,10 +107,26 @@ namespace Amanotes.Core
94
107
  }
95
108
  }
96
109
  _pool.Clear();
110
+ _poolPrefabCache.Clear();
97
111
  }
98
112
 
99
113
  public void PurgeDestroyed() => _pool.RemoveAll(obj => obj == null);
100
114
 
115
+ public int PoolCount => _pool.Count;
116
+
117
+ public void EnsureCapacity(int count, Transform poolParent)
118
+ {
119
+ while (_pool.Count < count)
120
+ {
121
+ var instance = UnityObject.Instantiate(prefab, poolParent.position, Quaternion.identity, poolParent);
122
+ instance.hideFlags = HideFlags.DontSave;
123
+ instance.SetActive(false);
124
+ _pool.Add(instance);
125
+ }
126
+ }
127
+
128
+ private const int PreAllocBatchSize = 3;
129
+
101
130
  public IEnumerator PreAllocate(Transform poolParent)
102
131
  {
103
132
  for (var i = 0; i < prewarmCount; i++)
@@ -106,6 +135,9 @@ namespace Amanotes.Core
106
135
  instance.hideFlags = HideFlags.DontSave;
107
136
  instance.SetActive(false);
108
137
  _pool.Add(instance);
138
+
139
+ if ((i + 1) % PreAllocBatchSize == 0)
140
+ yield return null;
109
141
  }
110
142
 
111
143
  yield return null;
@@ -120,6 +152,7 @@ namespace Amanotes.Core
120
152
 
121
153
  [NonSerialized] private IPrefabPool _prefabPool;
122
154
  [NonSerialized] private Transform _spawnParent;
155
+ [NonSerialized] public bool IsGameplay;
123
156
 
124
157
  public void Register(IPrefabPool prefabPool, Transform spawnParent)
125
158
  {
@@ -144,6 +177,13 @@ namespace Amanotes.Core
144
177
  return _prefabPool?.Get(this, prefabId, localPosition, customParent);
145
178
  }
146
179
 
180
+ public PoolEntry FindEntry(string prefabId)
181
+ {
182
+ for (var i = 0; i < entries.Count; i++)
183
+ if (entries[i].id == prefabId) return entries[i];
184
+ return fallbackEntry;
185
+ }
186
+
147
187
  public T Get<T>(string prefabId, Vector3 localPosition = default) where T : class
148
188
  {
149
189
  var go = Get(prefabId, localPosition);
@@ -338,13 +378,8 @@ namespace Amanotes.Core
338
378
  if (_isDestroyed || group == null) return null;
339
379
  if (string.IsNullOrEmpty(prefabId)) return null;
340
380
 
341
- var entry = group.entries.Find(e => e.id == prefabId);
342
- if (entry == null)
343
- {
344
- // Try fallback entry if available
345
- entry = group.fallbackEntry;
346
- if (entry == null) return null;
347
- }
381
+ var entry = group.FindEntry(prefabId);
382
+ if (entry == null) return null;
348
383
 
349
384
  var p = customParent == null ? group.SpawnParent : customParent;
350
385
  var result = entry.Get(transform, p, localPosition);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.amanotes.prefabpool",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "displayName": "[Ama] Prefab Pool",
5
5
  "description": "Generic object pooling system for Unity",
6
6
  "unity": "2022.3",