{"id":35145032,"url":"https://github.com/mistyuk/poolmaster","last_synced_at":"2026-04-28T10:03:11.233Z","repository":{"id":329505547,"uuid":"1119861315","full_name":"mistyuk/PoolMaster","owner":"mistyuk","description":"High-performance Unity pooling for Unity 6.0–6.4 (Built-in/URP/HDRP). ObjectPooling, render pipeline agnostic.","archived":false,"fork":false,"pushed_at":"2025-12-20T19:26:04.000Z","size":166,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-22T11:40:11.562Z","etag":null,"topics":["csharp","gamedev","hdrp","object-pooling","performance","pooling","render-pipeline","unity","unity3d","unity6","urp"],"latest_commit_sha":null,"homepage":"https://github.com/mistyuk/PoolMaster","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mistyuk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":["https://discord.com/users/misty2023"]}},"created_at":"2025-12-20T01:45:02.000Z","updated_at":"2025-12-20T19:26:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mistyuk/PoolMaster","commit_stats":null,"previous_names":["mistyuk/poolmaster"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/mistyuk/PoolMaster","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mistyuk%2FPoolMaster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mistyuk%2FPoolMaster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mistyuk%2FPoolMaster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mistyuk%2FPoolMaster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mistyuk","download_url":"https://codeload.github.com/mistyuk/PoolMaster/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mistyuk%2FPoolMaster/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32375633,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-28T09:24:15.638Z","status":"ssl_error","status_checked_at":"2026-04-28T09:24:15.071Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","gamedev","hdrp","object-pooling","performance","pooling","render-pipeline","unity","unity3d","unity6","urp"],"created_at":"2025-12-28T13:37:42.705Z","updated_at":"2026-04-28T10:03:11.220Z","avatar_url":"https://github.com/mistyuk.png","language":"C#","funding_links":["https://discord.com/users/misty2023"],"categories":[],"sub_categories":[],"readme":"# PoolMaster\n\n**PoolMaster** is a high-performance, production-ready object pooling system for Unity. Designed for both 2D and 3D games, it provides a comprehensive solution for managing GameObject lifecycles efficiently, reducing GC pressure, and maximizing runtime performance.\n\n[![Unity](https://img.shields.io/badge/Unity-6.0%E2%80%936.4-black)](https://unity.com/)\n[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\n---\n\n### Getting Started\n\nFor the fastest setup, start with the No‑Code Quick Start: [Documentation/no-code-quick-start.md](Documentation/no-code-quick-start.md)\n\n---\n\n## Features\n\n- Zero-allocation pooling — minimal GC, fast hot paths\n- Type-safe API — generic Pool\u003cT\u003e with safety\n- Batch ops — spawn/despawn many at once\n- Command buffers — thread-safe enqueue, main-thread flush\n- Diagnostics — real-time metrics + editor window\n- Configurable — precise control over pool behavior\n- Events — decoupled, opt-in hooks\n- Collection pooling — reuse lists/dicts/sets\n- Easy integration — IPoolable + helpers\n\n## Compatibility\n\n- Supported Unity: 6.0 – 6.4 (stable)\n- Render Pipelines: Built-in, URP, HDRP\n\n## Links\n\n- Add me on Discord: [misty2023](https://discord.com/users/misty2023)\n\n## Installation\n\n### Option 1: Unity Package Manager (Recommended)\n1. Open Package Manager (`Window \u003e Package Manager`)\n2. Click `+` and select `Add package from git URL`\n3. Enter: `https://github.com/mistyuk/PoolMaster.git`\n\n### Option 2: Manual Installation\n1. Download the latest release from [GitHub](https://github.com/mistyuk/PoolMaster/releases)\n2. Extract to your `Assets/Plugins/PoolMaster` folder\n\n---\n\n## Quick Start\n\n**Choose your path:** No code setup or full API control.\n\n### Path 1: No-Code Setup (60 seconds)\n\nPerfect for beginners or rapid prototyping. Zero programming required.\n\n#### Step 1: Add Manager\n1. **Hierarchy** → Right-click → **Create Empty** → Name it `PoolMaster`\n2. **Add Component** → `PoolMaster Manager`\n\n#### Step 2: Create Pool\n1. Select `PoolMaster` → Inspector → **Add New Pool**\n2. Drag your prefab → Set **Prewarm Amount** = `10`\n\n#### Step 3: Auto-Spawn\n1. Create empty GameObject → Name it `Spawner`\n2. **Add Component** → `PoolMaster Spawner`\n3. Drag prefab → **Spawn On** = `On Start`\n\n#### Step 4: Auto-Return\n1. Select your prefab (in Project) → **Add Component** → `PoolMaster Return To Pool`\n2. **Return Condition** = `After Time` → **Lifetime** = `2` seconds\n\n**Press Play** - Objects spawn, live 2 seconds, return to pool automatically.\n\n\u003e **Full no-code guide:** See [Documentation/no-code-quick-start.md](Documentation/no-code-quick-start.md)\n\n---\n\n### Path 2: Code Setup (Programmer API)\n\nFull control for advanced users. Type-safe, high-performance pooling.\n\n#### Step 1: Configure Pool\n\n```csharp\nusing UnityEngine;\nusing PoolMaster;\n\npublic class BulletSpawner : MonoBehaviour\n{\n    [SerializeField] private GameObject bulletPrefab;\n    \n    void Start()\n    {\n        var request = new PoolRequest\n        {\n            prefab = bulletPrefab,\n            initialPoolSize = 20,\n            shouldPrewarm = true\n        };\n        \n        PoolingManager.Instance.GetOrCreatePool\u003cBullet\u003e(request);\n    }\n}\n```\n\n#### Step 2: Spawn from Pool\n\n```csharp\nvoid Update()\n{\n    if (Input.GetKeyDown(KeyCode.Space))\n    {\n        var bullet = PoolingManager.Instance.Spawn(\n            bulletPrefab, \n            transform.position, \n            Quaternion.identity\n        );\n    }\n}\n```\n\n#### Step 3: Implement IPoolable\n\n```csharp\nusing UnityEngine;\nusing PoolMaster;\n\npublic class Bullet : MonoBehaviour, IPoolable\n{\n    public IPool ParentPool { get; set; }\n    public bool IsPooled { get; private set; }\n    \n    public void OnSpawned()\n    {\n        IsPooled = true;\n        GetComponent\u003cRigidbody\u003e().velocity = transform.forward * 20f;\n    }\n    \n    public void OnDespawned()\n    {\n        IsPooled = false;\n    }\n    \n    public void PoolReset()\n    {\n        GetComponent\u003cRigidbody\u003e().velocity = Vector3.zero;\n    }\n    \n    void OnCollisionEnter(Collision collision)\n    {\n        ParentPool?.Despawn(gameObject);\n    }\n}\n```\n\n**That's it.** Spawn uses the pool, collision returns to pool.\n\n---\n\n## API Reference\n\n### Core Classes\n\n#### PoolingManager\nCentral singleton for managing all pools.\n\n```csharp\n// Get or create a pool\nvar pool = PoolingManager.Instance.GetOrCreatePool\u003cT\u003e(request);\n\n// Spawn objects\nGameObject obj = PoolingManager.Instance.Spawn(prefab, position, rotation);\nGameObject obj = PoolingManager.Instance.Spawn(prefab); // At origin\n\n// Despawn objects\nPoolingManager.Instance.Despawn(obj);\n\n// Batch operations\nint count = PoolingManager.Instance.SpawnBatch(\n    prefab, \n    positions, \n    rotations, \n    parent\n);\n\n// Get pool by prefab or ID\nIPool pool = PoolingManager.Instance.GetPool(prefab);\nIPool pool = PoolingManager.Instance.GetPool(\"poolId\");\n\n// Global snapshot\nPoolSnapshot snapshot = PoolingManager.Instance.CaptureSnapshot();\n```\n\n#### Pool\u003cT\u003e\nGeneric type-safe pool implementation.\n\n```csharp\n// Create pool directly\nvar pool = new Pool\u003cBullet\u003e(\n    prefab, \n    request, \n    poolParent, \n    poolId\n);\n\n// Pool operations\nGameObject obj = pool.Spawn(position, rotation, parent);\nbool success = pool.Despawn(obj);\npool.PrewarmPool(count);\npool.Clear();\npool.DestroyPool();\n\n// Pool info\nint active = pool.ActiveCount;\nint inactive = pool.InactiveCount;\nint total = pool.Capacity;\nPoolMetrics metrics = pool.Metrics;\n```\n\n#### PoolRequest\nConfiguration for pool creation.\n\n```csharp\nvar request = new PoolRequest\n{\n    prefab = bulletPrefab,\n    initialPoolSize = 50,              // Initial capacity\n    shouldPrewarm = true,              // Create objects immediately\n    maxPoolSize = 200,                 // Max objects to keep pooled\n    allowExpansion = true,             // Grow beyond initial size\n    cullExcessObjects = true,          // Remove excess objects\n    cullThreshold = 100,               // Cull when over this count\n    initializationTiming = PoolInitializationTiming.OnAwake,\n    usePoolContainer = true,           // Parent container\n    containerName = \"Bullet Pool\"\n};\n```\n\n#### CollectionPool\nStatic utility for pooling collections.\n\n```csharp\n// Lists\nvar list = CollectionPool.GetList\u003cGameObject\u003e();\n// ... use list ...\nCollectionPool.Return(list);\n\n// HashSets\nvar set = CollectionPool.GetHashSet\u003cint\u003e();\nCollectionPool.Return(set);\n\n// Dictionaries\nvar dict = CollectionPool.GetDictionary\u003cstring, GameObject\u003e();\nCollectionPool.Return(dict);\n```\n\n### Extension Methods\n\n```csharp\n// GameObject extensions\ngameObject.ReturnToPool();\n\n// Batch spawning\npool.SpawnBatch(positions, rotations, parent);\nint count = pool.DespawnBatch(objects);\n```\n\n### Events\n\n```csharp\n// Pool lifecycle\nPoolingEvents.OnPoolCreated += (poolId, prefab) =\u003e {};\nPoolingEvents.OnPoolDestroyed += (poolId, prefab) =\u003e {};\nPoolingEvents.OnPoolPrewarmed += (poolId, count) =\u003e {};\n\n// Object lifecycle\nPoolingEvents.OnObjectSpawned += (obj, poolId) =\u003e {};\nPoolingEvents.OnObjectDespawned += (obj, poolId) =\u003e {};\nPoolingEvents.OnObjectCreated += (obj, poolId) =\u003e {};\nPoolingEvents.OnObjectDestroyed += (obj, poolId) =\u003e {};\n\n// Performance\nPoolingEvents.OnPoolExpanded += (poolId, newCapacity) =\u003e {};\nPoolingEvents.OnPoolCulled += (poolId, objectsDestroyed) =\u003e {};\n```\n\n## Performance Benchmarks\n\nPerformance comparison vs traditional `Instantiate/Destroy`:\n\n| Operation | Instantiate/Destroy | PoolMaster | Improvement |\n|-----------|---------------------|------------|-------------|\n| Spawn Single Object | ~0.8ms | ~0.002ms | **400x faster** |\n| Spawn 100 Objects | ~80ms | ~0.2ms | **400x faster** |\n| Despawn Single Object | ~0.3ms | ~0.001ms | **300x faster** |\n| GC Allocations (1000 cycles) | ~120 MB | ~0.5 MB | **240x less** |\n| Frame time impact (60fps) | 5-15ms spikes | \u003c0.1ms | **No hitching** |\n\n### Batch Operations Performance\n\n| Batch Size | Individual Spawn | Batch Spawn | Improvement |\n|------------|------------------|-------------|-------------|\n| 10 objects | ~0.02ms | ~0.008ms | **2.5x faster** |\n| 50 objects | ~0.1ms | ~0.03ms | **3.3x faster** |\n| 100 objects | ~0.2ms | ~0.05ms | **4x faster** |\n| 500 objects | ~1.0ms | ~0.2ms | **5x faster** |\n\n*Benchmarks run on Unity 6000.0.62f1 LTS, Intel i9-13950HX, 32GB RAM DDR5 5200mhz, RTX 4070 mGPU*\n\n## 🛰️ Advanced Usage\n\n### Command Buffer System\n\nFor thread-safe enqueueing from Jobs or background threads:\n\n```csharp\n// Get command buffer for a pool\nvar buffer = PoolingManager.Instance.GetCommandBuffer(\"bullets\");\n\n// Enqueue spawn (thread-safe)\nbuffer.EnqueueSpawn(position, rotation, parent);\n\n// Async spawning\nvar gameObject = await buffer.SpawnAsync(position, rotation);\n\n// Batch enqueueing\nbuffer.EnqueueSpawnBatch(positions, rotations, parent);\nvar objects = await buffer.SpawnBatchAsync(positions, rotations);\n\n// Commands are automatically flushed each frame in LateUpdate\n```\n\n### Pool Metrics \u0026 Diagnostics\n\n```csharp\n// Get metrics\nPoolMetrics metrics = pool.Metrics;\n\nDebug.Log($\"Total Spawned: {metrics.TotalSpawned}\");\nDebug.Log($\"Total Despawned: {metrics.TotalDespawned}\");\nDebug.Log($\"Reuse Efficiency: {metrics.ReuseEfficiency:P}\");\nDebug.Log($\"Current Active: {metrics.CurrentActive}\");\nDebug.Log($\"Expansion Count: {metrics.ExpansionCount}\");\n\n// Open diagnostics window\n// Window \u003e PoolMaster \u003e Diagnostics\n```\n\n### Pre-warming Strategies\n\n```csharp\n// 1. On Awake (before scene starts)\nvar request = new PoolRequest\n{\n    prefab = prefab,\n    initialPoolSize = 50,\n    shouldPrewarm = true,\n    initializationTiming = PoolInitializationTiming.OnAwake\n};\n\n// 2. On Start (after scene initialized)\nrequest.initializationTiming = PoolInitializationTiming.OnStart;\n\n// 3. Lazy (only when first needed)\nrequest.initializationTiming = PoolInitializationTiming.Lazy;\n\n// 4. Next frame (avoid loading hitches)\nrequest.initializationTiming = PoolInitializationTiming.NextFrame;\n\n// 5. On event (custom timing)\nrequest.initializationTiming = PoolInitializationTiming.OnEvent;\nrequest.eventId = \"level_loaded\";\n// Then trigger:\nPoolingManager.Instance.BootstrapPools(PoolInitializationTiming.OnEvent, \"level_loaded\");\n```\n\n### Working with Particles\n\nUse the included `PooledVfx` component for automatic particle system management:\n\n```csharp\npublic class PooledVfx : PoolableMonoBehaviour\n{\n    [SerializeField] private bool autoReturnWhenFinished = true;\n    [SerializeField] private float maxLifetime = 10f;\n    \n    // Automatically returns to pool when particles finish\n}\n```\n\n### Custom Pool Control\n\n```csharp\nif (pool is IPoolControl poolControl)\n{\n    // Advanced operations\n    poolControl.PrewarmPool(count);\n    poolControl.Clear();\n    poolControl.CullExcess(maxCount);\n    poolControl.DestroyPool();\n    \n    // Batch operations\n    poolControl.SpawnBatch(positions, rotations, parent);\n    poolControl.DespawnBatch(objects);\n}\n```\n\n## 🔧 Configuration\n\n### Enable Debug Logging\n\nAdd `ENABLE_POOL_LOGS` to your Scripting Define Symbols:\n1. `Edit \u003e Project Settings \u003e Player \u003e Other Settings`\n2. Add `ENABLE_POOL_LOGS` to Scripting Define Symbols\n3. Logs will completely compile out when the symbol is removed (zero overhead)\n\n### Assembly Definitions\n\nPoolMaster uses assembly definitions for clean separation:\n- `PoolMaster` - Core runtime assembly\n- `PoolMaster.Editor` - Editor-only tools\n\nTo reference PoolMaster in your code, add `PoolMaster` to your assembly definition references.\n\n## Migration Guide\n\n### From Unity's Built-in ObjectPool\n\n```csharp\n// Before (Unity ObjectPool)\nusing UnityEngine.Pool;\n\nvar pool = new ObjectPool\u003cGameObject\u003e(\n    createFunc: () =\u003e Instantiate(prefab),\n    actionOnGet: (obj) =\u003e obj.SetActive(true),\n    actionOnRelease: (obj) =\u003e obj.SetActive(false),\n    actionOnDestroy: (obj) =\u003e Destroy(obj),\n    collectionCheck: true,\n    defaultCapacity: 20,\n    maxSize: 100\n);\n\nvar obj = pool.Get();\npool.Release(obj);\n\n// After (PoolMaster)\nusing PoolMaster;\n\nvar request = new PoolRequest\n{\n    prefab = prefab,\n    initialPoolSize = 20,\n    maxPoolSize = 100,\n    shouldPrewarm = true\n};\n\nPoolingManager.Instance.GetOrCreatePool\u003cMyComponent\u003e(request);\nvar obj = PoolingManager.Instance.Spawn(prefab, position, rotation);\nPoolingManager.Instance.Despawn(obj);\n```\n\n### From Manual Pooling\n\n```csharp\n// Before (Manual pooling)\nQueue\u003cGameObject\u003e pool = new Queue\u003cGameObject\u003e();\n\nGameObject Spawn()\n{\n    if (pool.Count \u003e 0)\n    {\n        var obj = pool.Dequeue();\n        obj.SetActive(true);\n        return obj;\n    }\n    return Instantiate(prefab);\n}\n\nvoid Despawn(GameObject obj)\n{\n    obj.SetActive(false);\n    pool.Enqueue(obj);\n}\n\n// After (PoolMaster)\nusing PoolMaster;\n\n// One-time setup\nvar request = new PoolRequest { prefab = prefab, initialPoolSize = 10 };\nPoolingManager.Instance.GetOrCreatePool\u003cMyComponent\u003e(request);\n\n// Use anywhere\nvar obj = PoolingManager.Instance.Spawn(prefab, position, rotation);\nobj.ReturnToPool(); // Extension method\n```\n\n## Best Practices\n\n1. **Always implement IPoolable** - Even if empty, it ensures proper lifecycle hooks\n2. **Use PoolableMonoBehaviour** - Handles common cleanup patterns automatically\n3. **Pre-warm pools on load** - Avoid runtime hitches with `shouldPrewarm = true`\n4. **Set reasonable max sizes** - Use `maxPoolSize` to prevent unbounded memory growth\n5. **Enable culling** - Use `cullExcessObjects = true` to manage memory\n6. **Use batch operations** - Spawn/despawn multiple objects in one call when possible\n7. **Profile your pools** - Use the diagnostics window to optimize pool sizes\n8. **Disable logs in production** - Remove `ENABLE_POOL_LOGS` for zero logging overhead\n\n## FAQ\n\n**Q: Can I use PoolMaster with addressables?**  \nA: Yes! Pass the loaded addressable as the prefab parameter.\n\n**Q: Does it work with nested prefabs?**  \nA: Yes, PoolMaster handles any GameObject prefab regardless of hierarchy.\n\n**Q: What about pooling across scene loads?**  \nA: PoolingManager persists across scenes with `DontDestroyOnLoad`. Pools survive scene transitions.\n\n**Q: Can I have multiple pools for the same prefab?**  \nA: Yes, provide unique `poolId` parameters when creating pools.\n\n**Q: Is it thread-safe?**  \nA: Core pooling must happen on the main thread, but use `PoolCommandBuffer` for thread-safe enqueueing.\n\n**Q: Does it work with ECS/DOTS?**  \nA: PoolMaster is designed for GameObject-based workflows. For DOTS, use Unity's native entity pooling.\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## Credits\n\nCreated by Max Thomas Coates, Misty. \n\n## Contributing\n\n- Enable repo hooks: `git config core.hooksPath .githooks`\n- Verify CSharpier: `csharpier --version` (required for formatting)\n- Format manually if needed: `csharpier format .`\n\nSee full dev setup: [DEVELOPING.md](DEVELOPING.md)\n\n## 🐛 Support\n\n- **Issues**: [GitHub Issues](https://github.com/yourusername/PoolMaster/issues)\n- **Discussions**: [GitHub Discussions](https://github.com/yourusername/PoolMaster/discussions)\n- **Discord**: misty2023\n\n---\n\n⭐ **If PoolMaster helps your project, consider giving it a star on GitHub!**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmistyuk%2Fpoolmaster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmistyuk%2Fpoolmaster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmistyuk%2Fpoolmaster/lists"}