Infra

Object Pooling

Generic rent/return instance pooling on the client. Client-only.

Unity package
com.crossplay.pooling
Depends on
core
Shape
client-only · no server half

Unity seams you implement 2

The client half's sockets. Bind your implementation in the client context and Crossplay's client calls it — this is where your models, animators, UI and controls plug in.

IObjectPool<T> unity SPI

A generic rent/return pool for plain C# objects. The pool never knows what T is — snapshots, path buffers, message views, whatever the game churns through. Bounded: instances returned past MaxRetained are simply dropped for the GC. Main-thread only (no locks), like the rest of the client stack.

  • T Rent()

    Takes an instance from the pool, creating a new one only when the pool is empty.

  • void Return(T item)

    Gives an instance back for reuse. Dropped (not retained) once the pool is full.

  • void Prewarm(int count)

    Fills the pool up to count idle instances ahead of demand.

  • void Clear()

    Drops every idle instance (rented ones are unaffected).

  • int CountIdle

    Instances currently idle in the pool.

  • long Created

    Instances created by the pool over its lifetime.

  • long Reused

    Rents served from an idle instance (a saved allocation).

IPoolable unity SPI

Optional lifecycle hook for components on pooled GameObjects. Implement it on anything that must reset when its instance is recycled (trail renderers, timers, cached state). Discovered once per instance (including inactive children) when the pool first creates it.

  • void OnRentedFromPool()

    The instance was just handed out (active, positioned, parented).

  • void OnReturnedToPool()

    The instance is about to be parked (still active; deactivated right after).

Unity services you inject 1

Crossplay binds these in the client context. Inject and call them from your own MonoBehaviours and presenters.

IGameObjectPool

A keyed rent/return pool for GameObject instances. It pools and spawns ANYTHING — avatars, NPCs, effects, projectiles, UI items — and never knows or cares what the object is: the game supplies a key (its own vocabulary) plus either a factory delegate or an Addressables key, and gets instances that are reused instead of Instantiate/Destroy-churned. Purely optional infrastructure: nothing in Crossplay requires it; a game routes its spawn paths through it (e.g. an ICharacterFactory decorator) or doesn't. Per-key retention limits come from PoolingOptions. Main-thread only, like all Unity object lifetime.

  • GameObject Rent(object key, Func<GameObject> create, Vector3 position, Quaternion rotation, Transform parent = null)

    Rents an instance for key: reuses a parked one when available, otherwise creates via create. The instance comes back active, parented, and positioned. Returns null only if create returned null.

  • UniTask<GameObject> RentAsync(string addressableKey, Vector3 position, Quaternion rotation, Transform parent = null, CancellationToken ct = default)

    Rents an instance whose template is the Addressables prefab at addressableKey (loaded once per key and cached until Clear). Same reuse semantics as Rent.

  • bool Return(GameObject instance)

    Hands an instance back for reuse. Returns false when the instance didn't come from this pool (callers fall back to their own Destroy) or was already returned. Over-cap returns destroy the instance and still count as handled (true).

  • bool Owns(GameObject instance)

    True when instance is a live rented instance of this pool.

  • void Prewarm(object key, Func<GameObject> create, int count)

    Creates parked instances for key up to count idle.

  • UniTask PrewarmAsync(string addressableKey, int count, CancellationToken ct = default)

    Addressables flavor of Prewarm (prefab loaded once and cached).

  • void Clear()

    Destroys all parked instances and releases cached Addressables prefab handles. Rented instances are unaffected (they can still be returned afterwards).

  • PoolStats Stats

    Aggregate lifetime counters across all keys.

  • bool TryGetStats(object key, out PoolStats stats)

    Lifetime counters for one key; false when the key has never been used.