Code/Render/RendererPool.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;
namespace MANIFOLD.BHLib {
/// <summary>
/// Manages renderer pools.
/// </summary>
public static class RendererPool {
public class Pool {
public readonly GameObject prefab;
public readonly int initialCapacity;
public HashSet<GameObject> objects = new HashSet<GameObject>();
public int capacity;
public Pool(GameObject prefab, int capacity) {
this.prefab = prefab;
initialCapacity = capacity;
objects = new HashSet<GameObject>();
AddCapacity(capacity);
}
public GameObject Request() {
if (objects.Count == 0) {
return CreateNewInstance();
}
var obj = objects.First();
obj.Enabled = true;
objects.Remove(obj);
return obj;
}
public void Release(GameObject obj) {
objects.Add(obj);
obj.Parent = PoolRoot;
obj.Enabled = false;
}
public void AddCapacity(int capacity) {
for (int i = 0; i < capacity; i++) {
Release(CreateNewInstance());
}
this.capacity = capacity;
}
private GameObject CreateNewInstance() {
return prefab.Clone();
}
}
public static GameObject PoolRoot { get; private set; }
private static Dictionary<GameObject, Pool> pools = new();
private static Dictionary<GameObject, Pool> directory = new();
public static void CreatePool(GameObject prefab, int capacity) {
if (!PoolRoot.IsValid()) {
CreatePoolRoot();
}
if (pools.ContainsKey(prefab)) {
var pool = pools[prefab];
if (pool.capacity < capacity) {
pool.AddCapacity(capacity - pool.capacity);
}
} else {
pools.Add(prefab, new Pool(prefab, capacity));
}
}
public static GameObject Request(GameObject prefab) {
if (Game.ActiveScene.IsEditor) return null; // return immediately in editor mode
if (!pools.ContainsKey(prefab)) {
throw new InvalidOperationException("No pool was created for this prefab");
}
var pool = pools[prefab];
var obj = pool.Request();
directory.Add(obj, pool);
return obj;
}
public static void Release(GameObject obj) {
if (!directory.ContainsKey(obj)) {
throw new InvalidOperationException("This object doesn't belong to a pool");
}
var pool = directory[obj];
pool.Release(obj);
directory.Remove(obj);
}
private static void CreatePoolRoot() {
PoolRoot = Game.ActiveScene.CreateObject();
PoolRoot.Name = "RendererPool_Root";
pools.Clear(); // if the root is gone then assume all pools are broken
directory.Clear();
}
}
}