using UnityEngine;
using System.Collections.Generic;
///
/// EntityRegistry — Zero-allocation replacement for FindObjectsOfType.
/// Each MonoBehaviour type auto-registers in OnEnable/OnDisable via EntityRegistryMember.
/// Access all instances via EntityRegistry.All (read-only list, no allocation).
///
/// Usage:
/// 1) Add EntityRegistryMember component, or
/// 2) Call EntityRegistry.Register(this) in OnEnable / Unregister in OnDisable
/// 3) Query: foreach (var bag in EntityRegistry.All) { ... }
///
public static class EntityRegistry where T : class
{
private static readonly List _instances = new List(32);
private static readonly List _readOnly = _instances; // Same ref, cast prevents mutation at call sites
/// All currently active instances. Do NOT modify this list.
public static List All => _readOnly;
/// Alias for All — convenience method matching GetAll() convention.
public static List GetAll() => _readOnly;
/// Number of active instances.
public static int Count => _instances.Count;
public static void Register(T instance)
{
if (instance != null && !_instances.Contains(instance))
_instances.Add(instance);
}
public static void Unregister(T instance)
{
_instances.Remove(instance);
}
///
/// Find nearest instance to a world position.
/// Returns null if no instances. O(n) but n is small (≤10 for bags/characters).
///
public static T FindNearest(Vector3 position, System.Func getPosition, System.Func filter = null)
{
T nearest = null;
float nearestSqrDist = float.MaxValue;
for (int i = 0; i < _instances.Count; i++)
{
T instance = _instances[i];
if (instance == null) continue;
if (filter != null && !filter(instance)) continue;
float sqrDist = (getPosition(instance) - position).sqrMagnitude;
if (sqrDist < nearestSqrDist)
{
nearestSqrDist = sqrDist;
nearest = instance;
}
}
return nearest;
}
///
/// Find all instances within radius. Uses pre-allocated result list to avoid allocation.
/// Caller should process results immediately (list is reused).
///
private static readonly List _withinRadiusResults = new List(16);
public static List FindWithinRadius(Vector3 position, float radius, System.Func getPosition, System.Func filter = null)
{
_withinRadiusResults.Clear();
float sqrRadius = radius * radius;
for (int i = 0; i < _instances.Count; i++)
{
T instance = _instances[i];
if (instance == null) continue;
if (filter != null && !filter(instance)) continue;
float sqrDist = (getPosition(instance) - position).sqrMagnitude;
if (sqrDist <= sqrRadius)
_withinRadiusResults.Add(instance);
}
return _withinRadiusResults;
}
/// Call on scene unload to prevent stale references.
public static void Clear() => _instances.Clear();
}