diff --git a/.editorconfig b/.editorconfig index d75a7f0..d8478e1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,7 +4,7 @@ root = true [*] charset = utf-8 end_of_line = lf -insert_final_newline = true +insert_final_newline = false indent_style = space indent_size = 4 @@ -31,11 +31,22 @@ dotnet_naming_rule.private_instance_fields_rule.import_to_resharper = as_predefi dotnet_naming_rule.private_instance_fields_rule.severity = warning dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols +dotnet_naming_rule.private_static_fields_override_rule.import_to_resharper = False +dotnet_naming_rule.private_static_fields_override_rule.severity = warning +dotnet_naming_rule.private_static_fields_override_rule.style = upper_camel_case_style +dotnet_naming_rule.private_static_fields_override_rule.symbols = private_static_fields_override_symbols dotnet_naming_rule.private_static_fields_rule.import_to_resharper = as_predefined dotnet_naming_rule.private_static_fields_rule.resharper_style = AaBb, aaBb dotnet_naming_rule.private_static_fields_rule.severity = warning dotnet_naming_rule.private_static_fields_rule.style = upper_camel_case_style dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols +dotnet_naming_rule.private_static_fields_rule_1.import_to_resharper = True +dotnet_naming_rule.private_static_fields_rule_1.resharper_description = PrivateStaticFields +dotnet_naming_rule.private_static_fields_rule_1.resharper_guid = 2ec29786-2764-45cc-849e-7a476ce55db8 +dotnet_naming_rule.private_static_fields_rule_1.resharper_style = AaBb, aaBb +dotnet_naming_rule.private_static_fields_rule_1.severity = warning +dotnet_naming_rule.private_static_fields_rule_1.style = upper_camel_case_style +dotnet_naming_rule.private_static_fields_rule_1.symbols = private_static_fields_symbols_1 dotnet_naming_rule.private_static_readonly_rule.import_to_resharper = as_predefined dotnet_naming_rule.private_static_readonly_rule.severity = warning dotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style @@ -54,9 +65,17 @@ dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field dotnet_naming_symbols.private_constants_symbols.required_modifiers = const dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_fields_override_symbols.applicable_accessibilities = local,private +dotnet_naming_symbols.private_static_fields_override_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_fields_override_symbols.required_modifiers = const,static dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static +dotnet_naming_symbols.private_static_fields_symbols_1.applicable_accessibilities = local,private +dotnet_naming_symbols.private_static_fields_symbols_1.applicable_kinds = field +dotnet_naming_symbols.private_static_fields_symbols_1.required_modifiers = static +dotnet_naming_symbols.private_static_fields_symbols_1.resharper_applicable_kinds = field +dotnet_naming_symbols.private_static_fields_symbols_1.resharper_required_modifiers = static dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static, readonly @@ -75,11 +94,14 @@ dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggest # ReSharper properties resharper_alignment_tab_fill_style = optimal_fill resharper_align_multiline_binary_expressions_chain = false +resharper_align_multiline_statement_conditions = false resharper_apply_on_completion = true -resharper_autodetect_indent_settings = true resharper_blank_lines_after_control_transfer_statements = 1 +resharper_blank_lines_after_multiline_statements = 1 resharper_blank_lines_around_single_line_auto_property = 1 resharper_blank_lines_around_single_line_property = 1 +resharper_blank_lines_before_control_transfer_statements = 1 +resharper_blank_lines_before_multiline_statements = 1 resharper_blank_lines_before_single_line_comment = 1 resharper_braces_for_for = required resharper_braces_for_foreach = required @@ -124,6 +146,8 @@ resharper_keep_existing_declaration_block_arrangement = true resharper_keep_existing_declaration_parens_arrangement = false resharper_keep_existing_embedded_block_arrangement = true resharper_keep_existing_enum_arrangement = true +resharper_keep_existing_linebreaks = true +resharper_keep_user_linebreaks = true resharper_min_blank_lines_after_imports = 1 resharper_nested_ternary_style = expanded resharper_new_line_before_while = true @@ -133,7 +157,7 @@ resharper_place_type_constraints_on_same_line = false resharper_protobuf_insert_final_newline = true resharper_qualified_using_at_nested_scope = true resharper_resx_alignment_tab_fill_style = optimal_fill -resharper_T4_alignment_tab_fill_style = optimal_fill +resharper_t4_alignment_tab_fill_style = optimal_fill resharper_t4_insert_final_newline = true resharper_use_continuous_indent_inside_initializer_braces = false resharper_use_indents_from_main_language_in_file = false @@ -146,7 +170,7 @@ resharper_wrap_before_extends_colon = true resharper_wrap_before_first_type_parameter_constraint = true resharper_wrap_before_type_parameter_langle = true resharper_wrap_chained_binary_expressions = chop_if_long -resharper_wrap_chained_method_calls = chop_if_long +resharper_wrap_chained_method_calls = chop_always resharper_wrap_object_and_collection_initializer_style = chop_always resharper_xmldoc_alignment_tab_fill_style = optimal_fill resharper_xmldoc_indent_child_elements = ZeroIndent @@ -162,6 +186,7 @@ resharper_arrange_type_modifiers_highlighting = hint resharper_built_in_type_reference_style_for_member_access_highlighting = hint resharper_built_in_type_reference_style_highlighting = hint resharper_check_namespace_highlighting = none +resharper_class_never_instantiated_global_highlighting = none resharper_convert_to_auto_property_highlighting = none resharper_localizable_element_highlighting = none resharper_redundant_comma_in_attribute_list_highlighting = none @@ -205,3 +230,8 @@ tab_width = 4 indent_style = space indent_size = 4 tab_width = 4 + +[*.{appxmanifest,asax,ascx,aspx,axaml,build,c,c++,cc,cginc,compute,cp,cpp,cs,cshtml,cu,cuh,cxx,dtd,fx,fxh,h,hh,hlsl,hlsli,hlslinc,hpp,hxx,inc,inl,ino,ipp,master,mpp,mq4,mq5,mqh,nuspec,paml,razor,resw,resx,skin,tpp,usf,ush,vb,xaml,xamlx,xoml,xsd}] +indent_style = space +indent_size = 4 +tab_width = 4 diff --git a/Gallium.sln.DotSettings b/Gallium.sln.DotSettings index 06b6404..094c9a3 100644 --- a/Gallium.sln.DotSettings +++ b/Gallium.sln.DotSettings @@ -85,7 +85,10 @@ 1 1 False + False True + 1 + 1 EXPANDED NEVER NEVER @@ -115,7 +118,9 @@ CHOP_IF_LONG CHOP_IF_LONG 80 + CHOP_ALWAYS CHOP_IF_LONG + CHOP_IF_LONG OPTIMAL_FILL OPTIMAL_FILL OPTIMAL_FILL diff --git a/README.md b/README.md index 60ca291..32532cc 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # Gallium CIL -A small Entity-Component-System (ECS) that is built around LINQ calls and IEnumerable objects. +A small Entity-Component-System (ECS) that is built around LINQ calls and `IEnumerable` objects. \ No newline at end of file diff --git a/src/Gallium/Entity.cs b/src/Gallium/Entity.cs index a3d5078..0d98577 100644 --- a/src/Gallium/Entity.cs +++ b/src/Gallium/Entity.cs @@ -64,20 +64,6 @@ namespace Gallium return this.Has(typeof(T1)); } - /// - /// Gets a value indicating whether the entity has components of the given types - /// registered. - /// - /// The first component type. - /// - /// True if there are components of the given type exists, otherwise - /// false. - /// - public bool HasAll() - { - return this.Has(); - } - /// /// Gets a value indicating whether the entity has components of the given types /// registered. @@ -90,7 +76,7 @@ namespace Gallium /// public bool HasAll() { - return this.Has() && this.Has(); + return this.HasAll(typeof(T1), typeof(T2)); } /// @@ -106,7 +92,7 @@ namespace Gallium /// public bool HasAll() { - return this.Has() && this.Has() && this.Has(); + return this.HasAll(typeof(T1), typeof(T2), typeof(T3)); } /// @@ -123,10 +109,7 @@ namespace Gallium /// public bool HasAll() { - return this.Has() - && this.Has() - && this.Has() - && this.Has(); + return this.HasAll(typeof(T1), typeof(T2), typeof(T3), typeof(T4)); } /// @@ -140,6 +123,54 @@ namespace Gallium return this.Components.ContainsKey(type); } + /// + /// Gets a value indicating whether the entity has components for all the given + /// types. + /// + /// The component type. + /// The component type. + /// True if the type exists, otherwise false. + public bool HasAll( + Type t1, + Type t2) + { + return this.Has(t1) && this.Components.ContainsKey(t2); + } + + /// + /// Gets a value indicating whether the entity has components for all the given + /// types. + /// + /// The component type. + /// The component type. + /// The component type. + /// True if the type exists, otherwise false. + public bool HasAll( + Type t1, + Type t2, + Type t3) + { + return this.HasAll(t1, t2) && this.Components.ContainsKey(t3); + } + + /// + /// Gets a value indicating whether the entity has components for all the given + /// types. + /// + /// The component type. + /// The component type. + /// The component type. + /// The component type. + /// True if the type exists, otherwise false. + public bool HasAll( + Type t1, + Type t2, + Type t3, + Type t4) + { + return this.HasAll(t1, t2, t3) && this.Components.ContainsKey(t4); + } + /// /// Retrieves a registered component of the given type. /// @@ -191,10 +222,12 @@ namespace Gallium if (this.Has()) { value = this.Get(); + return true; } value = default!; + return false; } @@ -208,17 +241,21 @@ namespace Gallium /// The first component type. /// The second component type. /// True if found, otherwise false. - public bool TryGet(out T1 value1, out T2 value2) + public bool TryGet( + out T1 value1, + out T2 value2) { if (this.HasAll()) { value1 = this.Get(); value2 = this.Get(); + return true; } value1 = default!; value2 = default!; + return false; } @@ -229,6 +266,7 @@ namespace Gallium /// /// The value if contained in the entity. /// The value if contained in the entity. + /// The value if contained in the entity. /// The first component type. /// The second component type. /// The third component type. @@ -243,12 +281,14 @@ namespace Gallium value1 = this.Get(); value2 = this.Get(); value3 = this.Get(); + return true; } value1 = default!; value2 = default!; value3 = default!; + return false; } @@ -259,6 +299,8 @@ namespace Gallium /// /// The value if contained in the entity. /// The value if contained in the entity. + /// The value if contained in the entity. + /// The value if contained in the entity. /// The first component type. /// The second component type. /// The third component type. @@ -276,6 +318,7 @@ namespace Gallium value2 = this.Get(); value3 = this.Get(); value4 = this.Get(); + return true; } @@ -283,6 +326,7 @@ namespace Gallium value2 = default!; value3 = default!; value4 = default!; + return false; } @@ -291,18 +335,18 @@ namespace Gallium /// component already registered. /// /// The component to register. - /// The component type. + /// The component type. /// The entity for chaining. /// - public Entity Set(TType component) + public Entity Set(T1 component) { if (component == null) { throw new ArgumentNullException(nameof(component)); } - if (this.Components.TryGetValue(typeof(TType), out object? value) - && value is TType + if (this.Components.TryGetValue(typeof(T1), out object? value) + && value is T1 && value.Equals(component)) { return this; @@ -310,7 +354,7 @@ namespace Gallium return this with { - Components = this.Components.SetItem(typeof(TType), component), + Components = this.Components.SetItem(typeof(T1), component), }; } @@ -318,30 +362,30 @@ namespace Gallium /// Adds a component to the entity. /// /// The component to register. - /// The component type. + /// The component type. /// /// The same entity if the component is already registered, otherwise a /// cloned entity with the new component. /// /// - public Entity Add(TType component) + public Entity Add(T1 component) { if (component == null) { throw new ArgumentNullException(nameof(component)); } - if (this.Has()) + if (this.Has()) { throw new ArgumentException( "An element with the same type (" - + typeof(TType).FullName + + typeof(T1).FullName + ") already exists.", nameof(component)); } - if (this.Components.TryGetValue(typeof(TType), out object? value) - && value is TType + if (this.Components.TryGetValue(typeof(T1), out object? value) + && value is T1 && value.Equals(component)) { return this; @@ -349,7 +393,7 @@ namespace Gallium return this with { - Components = this.Components.Add(typeof(TType), component), + Components = this.Components.Add(typeof(T1), component), }; } @@ -392,7 +436,7 @@ namespace Gallium /// Gets the identifier of the entity. This should be treated as an /// opaque field. /// - public int Id { get; private set; } + public int Id { get; private init; } /// /// Creates a copy of the entity, including copying the identifier. diff --git a/src/Gallium/MergeEnumerableEntityExtensions.cs b/src/Gallium/JoinEntityExtensions.cs similarity index 69% rename from src/Gallium/MergeEnumerableEntityExtensions.cs rename to src/Gallium/JoinEntityExtensions.cs index 044f101..56f11fa 100644 --- a/src/Gallium/MergeEnumerableEntityExtensions.cs +++ b/src/Gallium/JoinEntityExtensions.cs @@ -4,7 +4,7 @@ using System.Linq; namespace Gallium { - public static class MergeEnumerableEntityExtensions + public static class JoinEntityExtensions { /// /// Merges two sets of entities using the identifier to determine which @@ -18,21 +18,12 @@ namespace Gallium /// The collection of entities to merge from. /// The callback to merge the two. /// An sequence of entities, merged and unmerged. - public static IEnumerable MergeEntities( + public static IEnumerable JoinEntity( this IEnumerable input, ICollection other, Func merge) { - return input - .Select( - entity => - { - Entity? found = other.FirstOrDefault(y => y == entity); - - return found == null - ? entity - : merge(entity, found); - }); + return input.Join(other, a => a.Id, a => a.Id, merge); } } } diff --git a/src/Gallium/SelectManyEntityExtensions.cs b/src/Gallium/SelectManyEntityExtensions.cs new file mode 100644 index 0000000..72909e4 --- /dev/null +++ b/src/Gallium/SelectManyEntityExtensions.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Gallium; + +/// +/// An extension method that handle SelectManyEntity which extracts all the +/// entities that match the given components, +/// passes the results to a select many callback, and then optionally includes the +/// ones that didn't have the components +/// before return. +/// +public static class SelectManyEntityExtensions +{ + /// + /// Pulls out all the entities that match the given components into an enumeration, + /// passes it into the callback + /// function, and then optionally merges the entities that did not match before + /// returning. + /// + /// The entities to process + /// + /// The callback function to manipulate the list of + /// entities. + /// + /// + /// If true, the include entities + /// without components. + /// + /// The type of the first component. + /// An enumeration of entities. + public static IEnumerable SelectManyEntity( + this IEnumerable entities, + Func, IEnumerable> selectMany, + bool includeEntitiesWithoutComponents = true) + { + SplitEntityEnumerations split = entities.SplitEntity(); + IEnumerable results = selectMany(split.HasAll); + + if (includeEntitiesWithoutComponents) + { + results = results.Union(split.NotHasAll); + } + + return results; + } + + /// + /// Pulls out all the entities that match the given components into an enumeration, + /// passes it into the callback + /// function, and then optionally merges the entities that did not match before + /// returning. + /// + /// The entities to process + /// + /// The callback function to manipulate the list of + /// entities. + /// + /// + /// If true, the include entities + /// without components. + /// + /// The type of the first component. + /// The type of the second component. + /// An enumeration of entities. + public static IEnumerable SelectManyEntity( + this IEnumerable entities, + Func, IEnumerable> selectMany, + bool includeEntitiesWithoutComponents = true) + { + SplitEntityEnumerations split = entities.SplitEntity(); + IEnumerable results = selectMany(split.HasAll); + + if (includeEntitiesWithoutComponents) + { + results = results.Union(split.NotHasAll); + } + + return results; + } + + /// + /// Pulls out all the entities that match the given components into an enumeration, + /// passes it into the callback + /// function, and then optionally merges the entities that did not match before + /// returning. + /// + /// The entities to process + /// + /// The callback function to manipulate the list of + /// entities. + /// + /// + /// If true, the include entities + /// without components. + /// + /// The type of the first component. + /// The type of the second component. + /// The type of the second component. + /// An enumeration of entities. + public static IEnumerable SelectManyEntity( + this IEnumerable entities, + Func, IEnumerable> selectMany, + bool includeEntitiesWithoutComponents = true) + { + SplitEntityEnumerations split = entities.SplitEntity(); + IEnumerable results = selectMany(split.HasAll); + + if (includeEntitiesWithoutComponents) + { + results = results.Union(split.NotHasAll); + } + + return results; + } + + /// + /// Pulls out all the entities that match the given components into an enumeration, + /// passes it into the callback + /// function, and then optionally merges the entities that did not match before + /// returning. + /// + /// The entities to process + /// + /// The callback function to manipulate the list of + /// entities. + /// + /// + /// If true, the include entities + /// without components. + /// + /// The type of the first component. + /// The type of the second component. + /// The type of the second component. + /// The type of the second component. + /// An enumeration of entities. + public static IEnumerable SelectManyEntity( + this IEnumerable entities, + Func, IEnumerable> selectMany, + bool includeEntitiesWithoutComponents = true) + { + SplitEntityEnumerations split = entities.SplitEntity(); + IEnumerable results = selectMany(split.HasAll); + + if (includeEntitiesWithoutComponents) + { + results = results.Union(split.NotHasAll); + } + + return results; + } +} diff --git a/src/Gallium/SplitEntityEnumerations.cs b/src/Gallium/SplitEntityEnumerations.cs new file mode 100644 index 0000000..b58acec --- /dev/null +++ b/src/Gallium/SplitEntityEnumerations.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Gallium; + +public record SplitEntityEnumerations( + IEnumerable HasAll, + IEnumerable NotHasAll) +{ + /// + /// Gets a sequence of all entities that have all the given components. + /// + public IEnumerable HasAll { get; } = HasAll; + + /// + /// Gets the sequence of all entities that do not have all the given components. + /// + public IEnumerable NotHasAll { get; } = NotHasAll; +} diff --git a/src/Gallium/SplitEntityExtensions.cs b/src/Gallium/SplitEntityExtensions.cs new file mode 100644 index 0000000..5ccce4d --- /dev/null +++ b/src/Gallium/SplitEntityExtensions.cs @@ -0,0 +1,298 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace 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); + } +} diff --git a/src/Gallium/WhereAllComponentsExtensions.cs b/src/Gallium/WhereAllComponentsExtensions.cs deleted file mode 100644 index 5d642c9..0000000 --- a/src/Gallium/WhereAllComponentsExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Gallium -{ - public static class WhereAllComponentsExtensions - { - public static IEnumerable WhereAllComponents( - this IEnumerable entities) - { - return entities.Where(x => x.Has()); - } - - public static IEnumerable WhereAllComponents( - this IEnumerable entities) - { - return entities.Where(x => x.Has() && x.Has()); - } - - public static IEnumerable WhereAllComponents( - this IEnumerable entities) - { - return entities.Where( - x => x.Has() && x.Has() && x.Has()); - } - - public static IEnumerable WhereAllComponents( - this IEnumerable entities) - { - return entities.Where( - x => x.Has() && x.Has() && x.Has() && x.Has()); - } - } -} diff --git a/src/Gallium/WhereComponentsExtensions.cs b/src/Gallium/WhereEntityExtensions.cs similarity index 63% rename from src/Gallium/WhereComponentsExtensions.cs rename to src/Gallium/WhereEntityExtensions.cs index d7f1e98..6e02104 100644 --- a/src/Gallium/WhereComponentsExtensions.cs +++ b/src/Gallium/WhereEntityExtensions.cs @@ -4,45 +4,39 @@ using System.Linq; namespace Gallium { - public static class WhereComponentsExtensions + public static class WhereEntityExtensions { - public static IEnumerable WhereComponents( + public static IEnumerable WhereEntity( this IEnumerable entities, Func include) { return entities.Where(x => x.Has() && include(x, x.Get())); } - public static IEnumerable WhereComponents( + public static IEnumerable WhereEntity( this IEnumerable entities, Func include) { return entities.Where( - x => x.Has() - && x.Has() + x => x.HasAll() && include(x, x.Get(), x.Get())); } - public static IEnumerable WhereComponents( + public static IEnumerable WhereEntity( this IEnumerable entities, Func include) { return entities.Where( - x => x.Has() - && x.Has() - && x.Has() + x => x.HasAll() && include(x, x.Get(), x.Get(), x.Get())); } - public static IEnumerable WhereComponents( + public static IEnumerable WhereEntity( this IEnumerable entities, Func include) { return entities.Where( - x => x.Has() - && x.Has() - && x.Has() - && x.Has() + x => x.HasAll() && include( x, x.Get(), diff --git a/src/Gallium/WhereEntityHasExtensions.cs b/src/Gallium/WhereEntityHasExtensions.cs new file mode 100644 index 0000000..e769486 --- /dev/null +++ b/src/Gallium/WhereEntityHasExtensions.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Gallium +{ + public static class WhereEntityHasExtensions + { + public static IEnumerable WhereEntityHas( + this IEnumerable entities) + { + return entities.Where(x => x.Has()); + } + + public static IEnumerable WhereEntityHasAll( + this IEnumerable entities) + { + return entities.Where(x => x.HasAll()); + } + + public static IEnumerable WhereEntityHasAll( + this IEnumerable entities) + { + return entities.Where(x => x.HasAll()); + } + + public static IEnumerable WhereEntityHasAll( + this IEnumerable entities) + { + return entities.Where(x => x.HasAll()); + } + } +} diff --git a/src/Gallium/WhereEntityNotHasExtensions.cs b/src/Gallium/WhereEntityNotHasExtensions.cs new file mode 100644 index 0000000..a3cde88 --- /dev/null +++ b/src/Gallium/WhereEntityNotHasExtensions.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Gallium +{ + public static class WhereEntityNotHasExtensions + { + public static IEnumerable WhereEntityNotHas(this IEnumerable entities) + { + return entities.Where(x => !x.Has()); + } + + public static IEnumerable WhereEntityNotHasAll(this IEnumerable entities) + { + return entities.Where(x => !x.HasAll()); + } + + public static IEnumerable WhereEntityNotHasAll(this IEnumerable entities) + { + return entities.Where(x => !x.HasAll()); + } + + public static IEnumerable WhereEntityNotHasAll(this IEnumerable entities) + { + return entities.Where(x => !x.HasAll()); + } + } +} diff --git a/src/Gallium/WhereNotAllComponentExtensions.cs b/src/Gallium/WhereNotAllComponentExtensions.cs deleted file mode 100644 index b9e4fe5..0000000 --- a/src/Gallium/WhereNotAllComponentExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Gallium -{ - public static class WhereNotAllComponentExtensions - { - public static IEnumerable WhereNotComponent( - this IEnumerable entities) - { - return entities.Where(x => !x.Has()); - } - - public static IEnumerable WhereNotAllComponents( - this IEnumerable entities) - { - return entities.Where(x => !x.Has()); - } - - - public static IEnumerable WhereNotAllComponents( - this IEnumerable entities) - { - return entities.Where(x => !x.HasAll()); - } - - public static IEnumerable WhereNotAllComponents( - this IEnumerable entities) - { - return entities.Where( - x => !x.HasAll()); - } - - public static IEnumerable WhereNotAllComponents( - this IEnumerable entities) - { - return entities.Where( - x => !x.Has() - || !x.Has() - || !x.Has() - || !x.Has()); - } - } -} diff --git a/tests/Gallium.Tests/EnumerableEntityTests.cs b/tests/Gallium.Tests/EnumerableEntityTests.cs index 2d72544..28e9823 100644 --- a/tests/Gallium.Tests/EnumerableEntityTests.cs +++ b/tests/Gallium.Tests/EnumerableEntityTests.cs @@ -73,7 +73,7 @@ namespace Gallium.Tests Assert.Equal( new[] { "1", "3" }, - entities.WhereAllComponents().Select(x => x.Get()).ToArray()); + entities.WhereEntityHas().Select(x => x.Get()).ToArray()); } [Fact] @@ -88,7 +88,7 @@ namespace Gallium.Tests Assert.Equal( new[] { "2" }, - entities.WhereAllComponents().Select(x => x.Get()).ToArray()); + entities.WhereEntityHasAll().Select(x => x.Get()).ToArray()); } [Fact] @@ -106,7 +106,7 @@ namespace Gallium.Tests Assert.Equal( new[] { "1" }, - entities.WhereAllComponents() + entities.WhereEntityHasAll() .Select(x => x.Get()) .ToArray()); } @@ -123,7 +123,7 @@ namespace Gallium.Tests Assert.Equal( new[] { "2" }, - entities.WhereNotComponent().Select(x => x.Get()).ToArray()); + entities.WhereEntityNotHas().Select(x => x.Get()).ToArray()); } [Fact] @@ -138,7 +138,7 @@ namespace Gallium.Tests Assert.Equal( new[] { "1", "3" }, - entities.WhereNotAllComponents() + entities.WhereEntityNotHasAll() .Select(x => x.Get()) .ToArray()); } @@ -158,7 +158,7 @@ namespace Gallium.Tests Assert.Equal( new string[] { "1", "3" }, - entities.WhereNotAllComponents() + entities.WhereEntityNotHasAll() .Select(x => x.Get()) .ToArray()); }