Created
March 19, 2023 09:16
-
-
Save malj/905ebcc8dbedaddcfe2bb15907bbc884 to your computer and use it in GitHub Desktop.
Unity MonoBehaviour ECS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
using UnityEngine; | |
/// <summary> | |
/// Enumerable component cache with methods for querying components based on their types. | |
/// </summary> | |
class World : IEnumerable<MonoBehaviour> | |
{ | |
public static readonly World Default = new(); | |
readonly Dictionary<Type, HashSet<MonoBehaviour>> cache = new(); | |
public IEnumerator<MonoBehaviour> GetEnumerator() => | |
cache.SelectMany(entry => entry.Value).Distinct().GetEnumerator(); | |
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |
public event Action<MonoBehaviour> Added; | |
public event Action<MonoBehaviour> Removed; | |
public bool Add(MonoBehaviour component) | |
{ | |
var added = false; | |
if (component && !component.destroyCancellationToken.IsCancellationRequested) | |
{ | |
foreach (var key in GetKeys(component)) | |
{ | |
if (!cache.TryGetValue(key, out var components)) | |
{ | |
components = cache[key] = new(); | |
} | |
if (components.Add(component)) | |
{ | |
added = true; | |
} | |
} | |
if (added) | |
{ | |
var registration = component.destroyCancellationToken.Register(() => Remove(component)); | |
Removed += OnComponentRemoved; | |
void OnComponentRemoved(MonoBehaviour removedComponent) | |
{ | |
if (component == removedComponent) | |
{ | |
Removed -= OnComponentRemoved; | |
registration.Dispose(); | |
} | |
} | |
Added?.Invoke(component); | |
} | |
} | |
return added; | |
} | |
public bool Remove(MonoBehaviour component) | |
{ | |
var removed = false; | |
if (component) | |
{ | |
foreach (var key in GetKeys(component)) | |
{ | |
if (cache[key].Remove(component)) | |
{ | |
removed = true; | |
if (cache[key].Count == 0) | |
{ | |
cache.Remove(key); | |
} | |
} | |
} | |
if (removed) | |
{ | |
Removed?.Invoke(component); | |
} | |
} | |
return removed; | |
} | |
public void Clear() | |
{ | |
var components = Removed != null ? this.ToList() : null; | |
cache.Clear(); | |
components?.ForEach(Removed); | |
} | |
static IEnumerable<Type> GetKeys(MonoBehaviour component) | |
{ | |
var type = component.GetType(); | |
while (type != typeof(MonoBehaviour)) | |
{ | |
yield return type; | |
foreach (var interfaceType in type.GetInterfaces()) | |
{ | |
yield return interfaceType; | |
} | |
type = type.BaseType; | |
} | |
} | |
public IEnumerable<T> Query<T>(bool includeDisabled = false) | |
where T : class => | |
cache.TryGetValue(typeof(T), out var components) | |
? components.Where(component => includeDisabled || component.enabled).Cast<T>() | |
: Enumerable.Empty<T>(); | |
public IEnumerable<(T1, T2)> Query<T1, T2>(bool includeDisabled = false) | |
where T1 : class | |
where T2 : class => | |
from x in Query<T1>(includeDisabled) | |
join y in Query<T2>(includeDisabled) on (x as MonoBehaviour).gameObject equals (y as MonoBehaviour).gameObject | |
select (x, y); | |
public IEnumerable<(T1, T2, T3)> Query<T1, T2, T3>(bool includeDisabled = false) | |
where T1 : class | |
where T2 : class | |
where T3 : class => | |
from xs in Query<T1, T2>(includeDisabled) | |
join y in Query<T3>(includeDisabled) on (xs.Item1 as MonoBehaviour).gameObject equals (y as MonoBehaviour) | |
.gameObject | |
select (xs.Item1, xs.Item2, y); | |
public IEnumerable<(T1, T2, T3, T4)> Query<T1, T2, T3, T4>(bool includeDisabled = false) | |
where T1 : class | |
where T2 : class | |
where T3 : class | |
where T4 : class => | |
from xs in Query<T1, T2, T3>(includeDisabled) | |
join y in Query<T4>(includeDisabled) on (xs.Item1 as MonoBehaviour).gameObject equals (y as MonoBehaviour) | |
.gameObject | |
select (xs.Item1, xs.Item2, xs.Item3, y); | |
public IEnumerable<(T1, T2, T3, T4, T5)> Query<T1, T2, T3, T4, T5>(bool includeDisabled = false) | |
where T1 : class | |
where T2 : class | |
where T3 : class | |
where T4 : class | |
where T5 : class => | |
from xs in Query<T1, T2, T3, T4>(includeDisabled) | |
join y in Query<T5>(includeDisabled) on (xs.Item1 as MonoBehaviour).gameObject equals (y as MonoBehaviour) | |
.gameObject | |
select (xs.Item1, xs.Item2, xs.Item3, xs.Item4, y); | |
public IEnumerable<(T1, T2, T3, T4, T5, T6)> Query<T1, T2, T3, T4, T5, T6>(bool includeDisabled = false) | |
where T1 : class | |
where T2 : class | |
where T3 : class | |
where T4 : class | |
where T5 : class | |
where T6 : class => | |
from xs in Query<T1, T2, T3, T4, T5>(includeDisabled) | |
join y in Query<T6>(includeDisabled) on (xs.Item1 as MonoBehaviour).gameObject equals (y as MonoBehaviour) | |
.gameObject | |
select (xs.Item1, xs.Item2, xs.Item3, xs.Item4, xs.Item5, y); | |
public IEnumerable<(T1, T2, T3, T4, T5, T6, T7)> Query<T1, T2, T3, T4, T5, T6, T7>(bool includeDisabled = false) | |
where T1 : class | |
where T2 : class | |
where T3 : class | |
where T4 : class | |
where T5 : class | |
where T6 : class | |
where T7 : class => | |
from xs in Query<T1, T2, T3, T4, T5, T6>(includeDisabled) | |
join y in Query<T7>(includeDisabled) on (xs.Item1 as MonoBehaviour).gameObject equals (y as MonoBehaviour) | |
.gameObject | |
select (xs.Item1, xs.Item2, xs.Item3, xs.Item4, xs.Item5, xs.Item6, y); | |
public IEnumerable<(T1, T2, T3, T4, T5, T6, T7, T8)> Query<T1, T2, T3, T4, T5, T6, T7, T8>( | |
bool includeDisabled = false) | |
where T1 : class | |
where T2 : class | |
where T3 : class | |
where T4 : class | |
where T5 : class | |
where T6 : class | |
where T7 : class | |
where T8 : class => | |
from xs in Query<T1, T2, T3, T4, T5, T6, T7>(includeDisabled) | |
join y in Query<T8>(includeDisabled) on (xs.Item1 as MonoBehaviour).gameObject equals (y as MonoBehaviour) | |
.gameObject | |
select (xs.Item1, xs.Item2, xs.Item3, xs.Item4, xs.Item5, xs.Item6, xs.Item7, y); | |
public IEnumerable<(T1, T2, T3, T4, T5, T6, T7, T8, T9)> Query<T1, T2, T3, T4, T5, T6, T7, T8, T9>( | |
bool includeDisabled = false) | |
where T1 : class | |
where T2 : class | |
where T3 : class | |
where T4 : class | |
where T5 : class | |
where T6 : class | |
where T7 : class | |
where T8 : class | |
where T9 : class => | |
from xs in Query<T1, T2, T3, T4, T5, T6, T7, T8>(includeDisabled) | |
join y in Query<T9>(includeDisabled) on (xs.Item1 as MonoBehaviour).gameObject equals (y as MonoBehaviour) | |
.gameObject | |
select (xs.Item1, xs.Item2, xs.Item3, xs.Item4, xs.Item5, xs.Item6, xs.Item7, xs.Item8, y); | |
public IEnumerable<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)> Query<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>( | |
bool includeDisabled = false) | |
where T1 : class | |
where T2 : class | |
where T3 : class | |
where T4 : class | |
where T5 : class | |
where T6 : class | |
where T7 : class | |
where T8 : class | |
where T9 : class | |
where T10 : class => | |
from xs in Query<T1, T2, T3, T4, T5, T6, T7, T8, T9>(includeDisabled) | |
join y in Query<T10>(includeDisabled) on (xs.Item1 as MonoBehaviour).gameObject equals (y as MonoBehaviour) | |
.gameObject | |
select (xs.Item1, xs.Item2, xs.Item3, xs.Item4, xs.Item5, xs.Item6, xs.Item7, xs.Item8, xs.Item9, y); | |
public IEnumerable<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)> Query<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, | |
T11>(bool includeDisabled = false) | |
where T1 : class | |
where T2 : class | |
where T3 : class | |
where T4 : class | |
where T5 : class | |
where T6 : class | |
where T7 : class | |
where T8 : class | |
where T9 : class | |
where T10 : class | |
where T11 : class => | |
from xs in Query<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(includeDisabled) | |
join y in Query<T11>(includeDisabled) on (xs.Item1 as MonoBehaviour).gameObject equals (y as MonoBehaviour) | |
.gameObject | |
select (xs.Item1, xs.Item2, xs.Item3, xs.Item4, xs.Item5, xs.Item6, xs.Item7, xs.Item8, xs.Item9, xs.Item10, y); | |
public IEnumerable<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)> Query<T1, T2, T3, T4, T5, T6, T7, T8, T9, | |
T10, T11, T12>(bool includeDisabled = false) | |
where T1 : class | |
where T2 : class | |
where T3 : class | |
where T4 : class | |
where T5 : class | |
where T6 : class | |
where T7 : class | |
where T8 : class | |
where T9 : class | |
where T10 : class | |
where T11 : class | |
where T12 : class => | |
from xs in Query<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(includeDisabled) | |
join y in Query<T12>(includeDisabled) on (xs.Item1 as MonoBehaviour).gameObject equals (y as MonoBehaviour) | |
.gameObject | |
select (xs.Item1, xs.Item2, xs.Item3, xs.Item4, xs.Item5, xs.Item6, xs.Item7, xs.Item8, xs.Item9, xs.Item10, | |
xs.Item11, y); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment