using System; using System.Collections.Generic; using System.Linq; namespace MfGames.Gallium; /// /// Extension methods for IEnumerable<Entity> that split the entity into two /// sequences, one that contains the /// various components and the other list which does not. /// public static class SplitEntityExtensions { /// /// Splits the enumeration of entities into two separate enumerations, ones that /// have the given generic components /// and those which do not. /// /// The entities to split into two lists. /// /// An additional test function to determine if the entity is /// included in the has list. If null, then entities with all the components will /// be included. /// /// /// A component to require to be in included in the first /// list. /// /// A pair of enumerations, ones with the components and ones without. public static SplitEntityEnumerations SplitEntity ( this IEnumerable entities, Func? test = null) { test ??= ( e, v1) => true; return entities.SplitEntity( typeof(T1), ( e, v1) => test(e, (T1)v1)); } /// /// Splits the enumeration of entities into two separate enumerations, ones that /// have the given generic components /// and those which do not. /// /// The entities to split into two lists. /// /// An additional test function to determine if the entity is /// included in the has list. If null, then entities with all the components will /// be included. /// /// /// A component to require to be in included in the first list. /// /// /// A component to require to be in included in the first list. /// /// A pair of enumerations, ones with the components and ones without. public static SplitEntityEnumerations SplitEntity ( this IEnumerable entities, Func? test = null) { test ??= ( e, v1, v2) => true; return entities.SplitEntity( typeof(T1), typeof(T2), ( e, v1, v2) => test(e, (T1)v1, (T2)v2)); } /// /// Splits the enumeration of entities into two separate enumerations, ones that /// have the given generic components /// and those which do not. /// /// The entities to split into two lists. /// /// An additional test function to determine if the entity is /// included in the has list. If null, then entities with all the components will /// be included. /// /// /// A component to require to be in included in the first list. /// /// /// A component to require to be in included in the first list. /// /// /// A component to require to be in included in the first list. /// /// A pair of enumerations, ones with the components and ones without. public static SplitEntityEnumerations SplitEntity ( this IEnumerable entities, Func? test = null) { test ??= ( e, v1, v2, v3) => true; return entities.SplitEntity( typeof(T1), typeof(T2), typeof(T3), ( e, v1, v2, v3) => test(e, (T1)v1, (T2)v2, (T3)v3)); } /// /// Splits the enumeration of entities into two separate enumerations, ones that /// have the given generic components /// and those which do not. /// /// The entities to split into two lists. /// /// An additional test function to determine if the entity is /// included in the has list. If null, then entities with all the components will /// be included. /// /// /// A component to require to be in included in the first list. /// /// /// A component to require to be in included in the first list. /// /// /// A component to require to be in included in the first list. /// /// /// A component to require to be in included in the first list. /// /// A pair of enumerations, ones with the components and ones without. public static SplitEntityEnumerations SplitEntity ( this IEnumerable entities, Func? test = null) { test ??= ( e, v1, v2, v3, v4) => true; return entities.SplitEntity( typeof(T1), typeof(T2), typeof(T3), typeof(T4), ( e, v1, v2, v3, v4) => test(e, (T1)v1, (T2)v2, (T3)v3, (T4)v4)); } /// /// Splits the enumeration of entities into two separate enumerations, ones that /// have the given component types and those which do not. /// /// The entities to split into two lists. /// The type of a required component. /// /// An additional test function to determine if the entity is /// included in the has list. If null, then entities with all the components will /// be included. /// /// A pair of enumerations, ones with the components and ones without. public static SplitEntityEnumerations SplitEntity( this IEnumerable entities, Type t1, Func test) { return SplitEntity(entities, a => a.Has(t1) && test(a, a.Get(t1))); } /// /// Splits the enumeration of entities into two separate enumerations, ones that /// have the given component types and those which do not. /// /// The entities to split into two lists. /// The type of a required component. /// The type of a required component. /// /// An additional test function to determine if the entity is /// included in the has list. If null, then entities with all the components will /// be included. /// /// A pair of enumerations, ones with the components and ones without. public static SplitEntityEnumerations SplitEntity( this IEnumerable entities, Type t1, Type t2, Func test) { return SplitEntity(entities, a => a.HasAll(t1, t2)); } /// /// Splits the enumeration of entities into two separate enumerations, ones that /// have the given component types and those which do not. /// /// The entities to split into two lists. /// The type of a required component. /// The type of a required component. /// The type of a required component. /// /// An additional test function to determine if the entity is /// included in the has list. If null, then entities with all the components will /// be included. /// /// A pair of enumerations, ones with the components and ones without. public static SplitEntityEnumerations SplitEntity( this IEnumerable entities, Type t1, Type t2, Type t3, Func test) { return SplitEntity(entities, a => a.HasAll(t1, t2, t3)); } /// /// Splits the enumeration of entities into two separate enumerations, ones that /// have the given component types and those which do not. /// /// The entities to split into two lists. /// The type of a required component. /// The type of a required component. /// The type of a required component. /// The type of a required component. /// /// An additional test function to determine if the entity is /// included in the has list. If null, then entities with all the components will /// be included. /// /// A pair of enumerations, ones with the components and ones without. public static SplitEntityEnumerations SplitEntity( this IEnumerable entities, Type t1, Type t2, Type t3, Type t4, Func test) { return SplitEntity( entities, a => a.HasAll(t1, t2, t3, t4) && test( a, a.Get(t1), a.Get(t2), a.Get(t3), a.Get(t4))); } private static SplitEntityEnumerations SplitEntity( IEnumerable entities, Func keySelector) { if (entities == null) { throw new ArgumentNullException(nameof(entities)); } IEnumerable> group = entities .GroupBy(keySelector, a => a) .ToList(); IEnumerable? has = group .Where(a => a.Key) .SelectMany(a => a); IEnumerable? hasNot = group .Where(a => !a.Key) .SelectMany(a => a); return new SplitEntityEnumerations(has, hasNot); } }