├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── Arch.AOT.SourceGenerator
├── Arch.AOT.SourceGenerator.csproj
├── ComponentType.cs
├── Extensions
│ └── StringBuilderExtensions.cs
└── SourceGenerator.cs
├── Arch.EventBus
├── Arch.EventBus.csproj
├── EventBus.cs
├── Hooks.cs
├── IMethodSymbolExtensions.cs
└── SourceGenerator.cs
├── Arch.Extended.Sample
├── Arch.Extended.Sample.csproj
├── Components.cs
├── Extensions.cs
├── Game.cs
├── Program.cs
├── Serializer.cs
└── Systems.cs
├── Arch.Extended.sln
├── Arch.Extended.sln.DotSettings
├── Arch.LowLevel.Tests
├── Arch.LowLevel.Tests.csproj
├── ArrayTest.cs
├── Jagged
│ └── JaggedArrayTest.cs
├── ResourcesTest.cs
├── UnsafeArrayTest.cs
├── UnsafeListTest.cs
├── UnsafeQueueTest.cs
├── UnsafeStackTest.cs
└── Usings.cs
├── Arch.LowLevel
├── Arch.LowLevel.csproj
├── Array.cs
├── Enumerators.cs
├── Jagged
│ ├── JaggedArray.cs
│ ├── SparseJaggedArray.cs
│ ├── UnsafeJaggedArray.cs
│ └── UnsafeSparseJaggedArray.cs
├── Resources.cs
├── UnsafeArray.cs
├── UnsafeList.cs
├── UnsafeQueue.cs
└── UnsafeStack.cs
├── Arch.Persistence.Tests
├── Arch.Persistence.Tests.csproj
├── PersistenceTest.cs
└── Usings.cs
├── Arch.Persistence
├── Arch.Persistence.csproj
├── Binary.cs
├── Json.cs
├── Serializer.cs
└── StreamBufferWriter.cs
├── Arch.Relationships.Tests
├── Arch.Relationships.Tests.csproj
├── RelationshipTest.cs
└── Usings.cs
├── Arch.Relationships
├── Arch.Relationships.csproj
├── EntityRelationshipExtensions.cs
├── Enumerators.cs
├── InRelationship.cs
├── Relationship.cs
└── WorldRelationshipExtensions.cs
├── Arch.System.SourceGenerator.SnapshotTests
├── .editorconfig
├── Arch.System.SourceGenerator.SnapshotTests.csproj
└── SnapshotTest.cs
├── Arch.System.SourceGenerator.Tests
├── .editorconfig
├── .gitignore
├── Arch.System.SourceGenerator.Tests.csproj
├── AttributeQueryCompilation
│ ├── AttributeQuerySystem.cs
│ └── ExpectedGeneration
│ │ ├── AttributeQuerySystem.IncrementA(Entity).g.cs
│ │ ├── AttributeQuerySystem.IncrementAAndB(Entity).g.cs
│ │ ├── AttributeQuerySystem.IncrementAAndBExclusive(Entity).g.cs
│ │ ├── AttributeQuerySystem.IncrementANotB(Entity).g.cs
│ │ ├── AttributeQuerySystem.IncrementAOrB(Entity).g.cs
│ │ └── AttributeQuerySystem.IncrementAOrBNotC(Entity).g.cs
├── BasicCompilation
│ ├── BasicSystem.cs
│ └── ExpectedGeneration
│ │ ├── BasicSystem.Basic(IntComponentA).g.cs
│ │ └── BasicSystem.BasicStatic(IntComponentA).g.cs
├── DataParamCompilation
│ ├── DataParamSystem.cs
│ └── ExpectedGeneration
│ │ ├── DataParamSystem.AssignEntityDataParamWithEntityRight(in Entity, in IntComponentA, ref Entity).g.cs
│ │ ├── DataParamSystem.CountANoParams(ref int).g.cs
│ │ ├── DataParamSystem.CountATwiceWithParams(ref int, in IntComponentA, ref int, in IntComponentB).g.cs
│ │ ├── DataParamSystem.CountAWithEntityAndParamLeft(ref int, in IntComponentA, in Entity).g.cs
│ │ ├── DataParamSystem.CountAWithEntityAndParamRight(in Entity, in IntComponentA, ref int).g.cs
│ │ ├── DataParamSystem.CountAWithEntityLeft(ref int, in Entity).g.cs
│ │ ├── DataParamSystem.CountAWithEntityRight(in Entity, ref int).g.cs
│ │ ├── DataParamSystem.CountAWithParamsLeft(ref int, in IntComponentA).g.cs
│ │ ├── DataParamSystem.CountAWithParamsMiddle(in IntComponentA, ref int, in IntComponentB).g.cs
│ │ └── DataParamSystem.CountAWithParamsRight(in IntComponentA, ref int).g.cs
├── GeneratedUpdateCompilation
│ ├── ExpectedGeneration
│ │ ├── GeneratedUpdateSystem.AutoRunA().g.cs
│ │ ├── GeneratedUpdateSystem.AutoRunB().g.cs
│ │ └── GeneratedUpdateSystem.g.cs
│ └── GeneratedUpdateSystem.cs
├── ParamQueryCompilation
│ ├── ExpectedGeneration
│ │ ├── ParamQuerySystem.IncrementA(ref IntComponentA).g.cs
│ │ ├── ParamQuerySystem.IncrementAAndB(ref IntComponentA, ref IntComponentB).g.cs
│ │ ├── ParamQuerySystem.IncrementANotC(ref IntComponentA).g.cs
│ │ └── ParamQuerySystem.IncrementOnlyAWithB(ref IntComponentA, in IntComponentB).g.cs
│ └── ParamQuerySystem.cs
├── Shared
│ ├── BaseTestSystem.cs
│ └── IntComponents.cs
└── SystemsTest.cs
├── Arch.System.SourceGenerator
├── Arch.System.SourceGenerator.csproj
├── Extensions
│ ├── IMethodSymbolExtensions.cs
│ └── StringBuilderExtensions.cs
├── Model.cs
├── Query.cs
└── SourceGenerator.cs
├── Arch.System
├── Arch.System.csproj
├── Attributes.cs
├── Systems.cs
└── Templates
│ ├── GenericAttributes.cs
│ ├── GenericAttributes.tt
│ └── Helpers.ttinclude
├── Directory.Build.targets
├── LICENSE.MD
├── README.md
└── scripts
└── UnityPublish.sh
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | push:
4 | branches: [master]
5 | pull_request:
6 | branches: [master]
7 |
8 | jobs:
9 | build:
10 | name: Test
11 | runs-on: ${{ matrix.os }}
12 | strategy:
13 | fail-fast: false
14 | matrix:
15 | build: [linux-debug, linux-release]
16 | include:
17 | - build: linux-debug
18 | os: ubuntu-latest
19 | config: debug
20 | - build: linux-release
21 | os: ubuntu-latest
22 | config: release
23 | steps:
24 | - uses: actions/checkout@v3
25 | - uses: actions/setup-dotnet@v3
26 | with:
27 | dotnet-version: |
28 | 6.0.x
29 | 7.0.x
30 | # workaround for actions/setup-dotnet#155
31 | - name: Clear package cache
32 | run: dotnet clean Arch.Extended.sln && dotnet nuget locals all --clear
33 | - name: Restore packages
34 | run: dotnet restore Arch.Extended.sln
35 | - name: Build
36 | run: dotnet build Arch.Extended.sln -c ${{ matrix.config }} --no-restore
37 | - name: Test
38 | run: dotnet test Arch.Extended.sln -c ${{ matrix.config }} -l "console;verbosity=detailed"
39 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | bin/
3 | obj/
4 | /packages/
5 | riderModule.iml
6 | /_ReSharper.Caches/
7 |
8 | # Common IntelliJ Platform excludes
9 |
10 | # User specific
11 | **/.idea/**/workspace.xml
12 | **/.idea/**/tasks.xml
13 | **/.idea/shelf/*
14 | **/.idea/dictionaries
15 | **/.idea/httpRequests/
16 |
17 | # Sensitive or high-churn files
18 | **/.idea/**/dataSources/
19 | **/.idea/**/dataSources.ids
20 | **/.idea/**/dataSources.xml
21 | **/.idea/**/dataSources.local.xml
22 | **/.idea/**/sqlDataSources.xml
23 | **/.idea/**/dynamic.xml
24 |
25 | # Rider
26 | # Rider auto-generates .iml files, and contentModel.xml
27 | .idea
28 | **/.idea/**/*.iml
29 | **/.idea/**/contentModel.xml
30 | **/.idea/**/modules.xml
31 |
32 | *.suo
33 | *.user
34 | .vs/
35 | [Bb]in/
36 | [Oo]bj/
37 | _UpgradeReport_Files/
38 | [Pp]ackages/
39 |
40 | Thumbs.db
41 | Desktop.ini
42 | .DS_Store
43 | Footer
44 | © 2022 GitHub, Inc.
45 | Footer navigation
46 | Terms
47 |
48 |
--------------------------------------------------------------------------------
/Arch.AOT.SourceGenerator/Arch.AOT.SourceGenerator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | enable
6 | enable
7 | latest
8 |
9 | true
10 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
11 | true
12 | snupkg
13 |
14 | Arch.AOT.SourceGenerator
15 | Arch.AOT.SourceGenerator
16 | 1.0.1
17 | genaray
18 | Apache-2.0
19 | A source generator for arch to support AOT.
20 | Updated to Arch 1.7 and up.
21 | c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;
22 |
23 | https://github.com/genaray/Arch.Extended
24 | https://github.com/genaray/Arch.Extended.git
25 | git
26 | true
27 |
28 | 11
29 | true
30 | Apache2.0
31 |
32 | en-US
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Arch.AOT.SourceGenerator/ComponentType.cs:
--------------------------------------------------------------------------------
1 | namespace Arch.AOT.SourceGenerator;
2 |
3 | ///
4 | /// The struct
5 | /// represents an Component (Their type with meta data) for use in the generated code.
6 | ///
7 | public struct ComponentType
8 | {
9 | ///
10 | /// The type name of the component.
11 | ///
12 | public string TypeName { get; }
13 | ///
14 | /// If the component has zero fields.
15 | ///
16 | public bool IsZeroSize { get; }
17 | ///
18 | /// If the component is a value type.
19 | ///
20 | public bool IsValueType { get; }
21 |
22 | ///
23 | /// Creates a new instance of the .
24 | ///
25 | /// The type name.
26 | /// If its zero sized.
27 | /// If its a value type.
28 | public ComponentType(string typeName, bool isZeroSize, bool isValueType)
29 | {
30 | TypeName = typeName;
31 | IsZeroSize = isZeroSize;
32 | IsValueType = isValueType;
33 | }
34 | }
--------------------------------------------------------------------------------
/Arch.AOT.SourceGenerator/Extensions/StringBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace Arch.AOT.SourceGenerator.Extensions;
4 |
5 | ///
6 | /// The class
7 | /// adds code-generating methods to the string-builder for outsourcing them.
8 | ///
9 | public static class StringBuilderExtensions
10 | {
11 | ///
12 | /// Appends the component types to the string builder in the form of a generated class.
13 | ///
14 | /// The target string builder.
15 | /// The types to append.
16 | ///
17 | public static StringBuilder AppendComponentTypes(this StringBuilder sb, IList componentTypes)
18 | {
19 | // Lists the component registration commands line by line.
20 | var components = new StringBuilder();
21 | foreach (var type in componentTypes)
22 | {
23 | var componentType = type;
24 | components.AppendComponentType(ref componentType);
25 | }
26 |
27 | sb.AppendLine(
28 | $$"""
29 | using System.Runtime.CompilerServices;
30 | using Arch.Core.Utils;
31 |
32 | namespace Arch.AOT.SourceGenerator
33 | {
34 | internal static class GeneratedComponentRegistry
35 | {
36 | [ModuleInitializer]
37 | public static void Initialize()
38 | {
39 | {{components}}
40 | }
41 | }
42 | }
43 | """
44 | );
45 | return sb;
46 | }
47 |
48 | ///
49 | /// Appends a single component type to the string builder as a new line.
50 | ///
51 | /// The string builder.
52 | /// The component type to add.
53 | ///
54 | public static StringBuilder AppendComponentType(this StringBuilder sb, ref ComponentType componentType)
55 | {
56 | //var size = componentType.IsValueType ? $"Unsafe.SizeOf<{componentType.TypeName}>()" : "IntPtr.Size";
57 | //sb.AppendLine($"ComponentRegistry.Add(typeof({componentType.TypeName}), new ComponentType(ComponentRegistry.Size + 1, {size}));");
58 |
59 | sb.AppendLine($"ArrayRegistry.Add<{componentType.TypeName}>();");
60 | return sb;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Arch.AOT.SourceGenerator/SourceGenerator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 | using System.Text;
3 | using Arch.AOT.SourceGenerator.Extensions;
4 | using Microsoft.CodeAnalysis;
5 | using Microsoft.CodeAnalysis.CSharp;
6 | using Microsoft.CodeAnalysis.CSharp.Syntax;
7 | using Microsoft.CodeAnalysis.Text;
8 |
9 | namespace Arch.AOT.SourceGenerator;
10 |
11 | ///
12 | /// Incremental generator that generates a class that adds all components to the ComponentRegistry.
13 | ///
14 | [Generator(LanguageNames.CSharp)]
15 | public sealed class ComponentRegistryGenerator : IIncrementalGenerator
16 | {
17 | ///
18 | /// A of annotated components (their types) found via the source-gen.
19 | ///
20 | private readonly List _componentTypes = new();
21 |
22 | ///
23 | /// The attribute to mark components with in order to be found by this source-gen.
24 | ///
25 | private const string AttributeTemplate = """
26 | using System;
27 |
28 | namespace Arch.AOT.SourceGenerator
29 | {
30 | [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
31 | public sealed class ComponentAttribute : Attribute { }
32 | }
33 | """;
34 | public void Initialize(IncrementalGeneratorInitializationContext context)
35 | {
36 | // Register the attribute.
37 | context.RegisterPostInitializationOutput(initializationContext =>
38 | {
39 | initializationContext.AddSource("Components.Attributes.g.cs", SourceText.From(AttributeTemplate, Encoding.UTF8));
40 | });
41 |
42 | var provider = context.SyntaxProvider.CreateSyntaxProvider(
43 | ShouldTypeBeRegistered,
44 | GetMemberDeclarationsForSourceGen).Where(t => t.attributeFound).Select((t, _) => t.Item1
45 | );
46 |
47 | context.RegisterSourceOutput(
48 | context.CompilationProvider.Combine(provider.Collect()), (productionContext, tuple) => GenerateCode(productionContext, tuple.Left, tuple.Right)
49 | );
50 | }
51 |
52 | ///
53 | /// Determines if a node should be considered for code generation.
54 | ///
55 | ///
56 | ///
57 | ///
58 | private static bool ShouldTypeBeRegistered(SyntaxNode node, CancellationToken cancellationToken)
59 | {
60 | if (node is not TypeDeclarationSyntax typeDeclarationSyntax)
61 | {
62 | return false;
63 | }
64 |
65 | return typeDeclarationSyntax.AttributeLists.Count != 0;
66 | }
67 |
68 | ///
69 | /// Make sure the type is annotated with the Component attribute.
70 | ///
71 | ///
72 | ///
73 | ///
74 | private static (TypeDeclarationSyntax, bool attributeFound) GetMemberDeclarationsForSourceGen(GeneratorSyntaxContext context, CancellationToken cancellationToken)
75 | {
76 | var typeDeclarationSyntax = (TypeDeclarationSyntax) context.Node;
77 |
78 | // Stop here if we can't get the type symbol for some reason.
79 | if (ModelExtensions.GetDeclaredSymbol(context.SemanticModel, typeDeclarationSyntax) is not ITypeSymbol symbol)
80 | {
81 | return (typeDeclarationSyntax, false);
82 | }
83 |
84 | // Go through all the attributes.
85 | foreach (var attributeData in symbol.GetAttributes())
86 | {
87 | if (attributeData.AttributeClass is null)
88 | {
89 | continue;
90 | }
91 |
92 | // If the attribute is the Component attribute, we can stop here and return true.
93 | if (string.Equals(attributeData.AttributeClass.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), "global::Arch.AOT.SourceGenerator.ComponentAttribute",
94 | StringComparison.Ordinal))
95 | {
96 | return (typeDeclarationSyntax, true);
97 | }
98 | }
99 |
100 | // No attribute found, return false.
101 | return (typeDeclarationSyntax, false);
102 | }
103 |
104 | private void GenerateCode(SourceProductionContext productionContext, Compilation compilation, ImmutableArray typeList)
105 | {
106 | var sb = new StringBuilder();
107 | _componentTypes.Clear();
108 |
109 | foreach (var type in typeList)
110 | {
111 | // Get the symbol for the type.
112 | var symbol = ModelExtensions.GetDeclaredSymbol(compilation.GetSemanticModel(type.SyntaxTree), type);
113 |
114 | // If the symbol is not a type symbol, we can't do anything with it.
115 | if (symbol is not ITypeSymbol typeSymbol)
116 | {
117 | continue;
118 | }
119 |
120 | // Check if there are any fields in the type.
121 | var hasZeroFields = true;
122 | foreach (var member in typeSymbol.GetMembers())
123 | {
124 | if (member is not IFieldSymbol) continue;
125 |
126 | hasZeroFields = false;
127 | break;
128 | }
129 |
130 | var typeName = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
131 | _componentTypes.Add(new ComponentType(typeName, hasZeroFields, typeSymbol.IsValueType));
132 | }
133 |
134 | sb.AppendComponentTypes(_componentTypes);
135 | productionContext.AddSource("GeneratedComponentRegistry.g.cs",CSharpSyntaxTree.ParseText(sb.ToString()).GetRoot().NormalizeWhitespace().ToFullString());
136 | }
137 | }
--------------------------------------------------------------------------------
/Arch.EventBus/Arch.EventBus.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | enable
5 | enable
6 | netstandard2.0
7 | 11
8 | Arch.Bus
9 |
10 | true
11 | snupkg
12 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
13 |
14 | Arch.EventBus
15 | Arch.EventBus
16 | 1.0.2
17 | genaray
18 | Apache-2.0
19 | A basic EventBus using source generation.
20 | Fixed some issues with source generation.
21 |
22 | c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;
23 |
24 | https://github.com/genaray/Arch.Extended
25 | https://github.com/genaray/Arch.Extended.git
26 | git
27 | true
28 |
29 | 11
30 | true
31 | Apache2.0
32 |
33 | en-US
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Arch.EventBus/Hooks.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Microsoft.CodeAnalysis;
3 |
4 | namespace Arch.Bus;
5 |
6 | public struct Hooks
7 | {
8 | public List Instances;
9 | }
10 |
11 | public struct ClassHooks
12 | {
13 | public ITypeSymbol PartialClass;
14 | public IList EventHooks;
15 | }
16 |
17 | ///
18 | /// The struct
19 | /// represents a hook for an event from the eventbus inside an class instance.
20 | ///
21 | public struct EventHook
22 | {
23 |
24 | ///
25 | /// The event type.
26 | ///
27 | public ITypeSymbol EventType;
28 |
29 | ///
30 | /// The method symbol of the static event receiver which should be called.
31 | ///
32 | public IMethodSymbol MethodSymbol;
33 | }
34 |
35 | public static class Hookersxtensions
36 | {
37 |
38 | ///
39 | /// Appends add operations for a set of to hook the local class instance into the EventBus instance lists for receiving events.
40 | /// EventBus.SomeClass_SomeEvent_SomeEvent.Add(this); ...
41 | ///
42 | /// The .
43 | /// The of that will be hooked in to receive instance events.
44 | ///
45 | public static StringBuilder Hook(this StringBuilder sb, IList receivingMethods)
46 | {
47 | foreach (var eventReceivingMethod in receivingMethods)
48 | {
49 | var containingSymbol = eventReceivingMethod.MethodSymbol.ContainingSymbol;
50 | var methodName = eventReceivingMethod.MethodSymbol.Name;
51 |
52 | // Remove weird chars to also support value tuples flawlessly, otherwhise they are listed like (World world, int int) in code which destroys everything
53 | var eventType = eventReceivingMethod.EventType.ToString();
54 | eventType = eventType.Replace("(","").Replace(")","").Replace(".","_").Replace(",","_").Replace(" ","");
55 |
56 | sb.AppendLine($"EventBus.{containingSymbol.Name}_{methodName}_{eventType}.Add(this);");
57 | }
58 | return sb;
59 | }
60 |
61 | ///
62 | /// Appends remove operations for a set of to unhook the local class instance from the EventBus instance lists for receiving events.
63 | /// EventBus.SomeClass_SomeEvent_SomeEvent.Remove(this); ...
64 | ///
65 | /// The .
66 | /// The of that will be hooked in to receive instance events.
67 | ///
68 | public static StringBuilder Unhook(this StringBuilder sb, IList receivingMethods)
69 | {
70 | foreach (var eventReceivingMethod in receivingMethods)
71 | {
72 | var containingSymbol = eventReceivingMethod.MethodSymbol.ContainingSymbol;
73 | var methodName = eventReceivingMethod.MethodSymbol.Name;
74 |
75 | // Remove weird chars to also support value tuples flawlessly, otherwhise they are listed like (World world, int int) in code which destroys everything
76 | var eventType = eventReceivingMethod.EventType.ToString();
77 | eventType = eventType.Replace("(","").Replace(")","").Replace(".","_").Replace(",","_").Replace(" ","");
78 |
79 | sb.AppendLine($"EventBus.{containingSymbol.Name}_{methodName}_{eventType}.Remove(this);");
80 | }
81 | return sb;
82 | }
83 |
84 | ///
85 | /// Appends a of and generates proper hook and unhook methods for their partial class instances.
86 | ///
87 | /// The .
88 | /// The of itself, used to generate the hooks in code.
89 | ///
90 | public static StringBuilder AppendHookList(this StringBuilder sb, List hooks)
91 | {
92 | // Loop over all hooks to create the hook and unhook functions.
93 | foreach (var hook in hooks)
94 | {
95 |
96 | var hookIntoEventbus = new StringBuilder().Hook(hook.EventHooks);
97 | var unhookFromEventBus = new StringBuilder().Unhook(hook.EventHooks);
98 |
99 | var template = $$"""
100 | namespace {{hook.PartialClass.ContainingNamespace}}{
101 |
102 | public partial class {{hook.PartialClass.Name}}{
103 |
104 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
105 | public void Hook()
106 | {
107 | {{hookIntoEventbus}}
108 | }
109 |
110 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
111 | public void Unhook()
112 | {
113 | {{unhookFromEventBus}}
114 | }
115 | }
116 | }
117 | """;
118 | sb.AppendLine(template);
119 | }
120 |
121 | return sb;
122 | }
123 |
124 | ///
125 | /// Appends a and generates it.
126 | ///
127 | /// The .
128 | /// The itself, used to generate the hooks in code.
129 | ///
130 | public static StringBuilder AppendHooks(this StringBuilder sb, ref Hooks hooks)
131 | {
132 | var callerMethods = new StringBuilder().AppendHookList(hooks.Instances);
133 | var template = $$"""
134 | using System.Runtime.CompilerServices;
135 | using Arch.Bus;
136 | {{callerMethods}}
137 | """;
138 | return sb.Append(template);
139 | }
140 | }
--------------------------------------------------------------------------------
/Arch.EventBus/IMethodSymbolExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 |
3 | namespace Arch.Bus;
4 |
5 | public static class IMethodSymbolExtensions
6 | {
7 |
8 | ///
9 | /// Searches attributes of a and returns the first one found.
10 | ///
11 | /// The instance.
12 | /// The attributes name.
13 | /// The attribute wrapped in an .
14 | public static AttributeData GetAttributeData(this IMethodSymbol ms, string name)
15 | {
16 | foreach (var attribute in ms.GetAttributes())
17 | {
18 | var classSymbol = attribute.AttributeClass;
19 | if(!classSymbol.Name.Contains(name)) continue;
20 |
21 | return attribute;
22 | }
23 |
24 | return default;
25 | }
26 |
27 | ///
28 | /// Gets all the types of a as s and adds them to a list.
29 | /// If the attribute is generic it will add the generic parameters, if its non generic it will add the non generic types from the constructor.
30 | ///
31 | /// The .
32 | /// The where the found s are added to.
33 | public static void GetAttributeTypes(this AttributeData data, List array)
34 | {
35 | if (data is not null && data.AttributeClass.IsGenericType)
36 | {
37 | array.AddRange(data.AttributeClass.TypeArguments);
38 | }
39 | else if (data is not null && !data.AttributeClass.IsGenericType)
40 | {
41 | var constructorArguments = data.ConstructorArguments[0].Values;
42 | var constructorArgumentsTypes = constructorArguments.Select(constant => constant.Value as ITypeSymbol).ToList();
43 | array.AddRange(constructorArgumentsTypes);
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/Arch.Extended.Sample/Arch.Extended.Sample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 | Arch.Extended
9 | 12
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Arch.Extended.Sample/Components.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.Serialization;
2 | using Arch.AOT.SourceGenerator;
3 | using Arch.Core;
4 | using MessagePack;
5 | using Microsoft.Xna.Framework;
6 | using Microsoft.Xna.Framework.Graphics;
7 |
8 | namespace Arch.Extended;
9 |
10 | ///
11 | /// The position of an entity.
12 | ///
13 | public struct Position
14 | {
15 |
16 | ///
17 | /// Its position.
18 | ///
19 | public Vector2 Vector2;
20 |
21 | ///
22 | /// Constructs a new instance.
23 | ///
24 | /// The x position.
25 | /// The y position.
26 | public Position(float x, float y)
27 | {
28 | Vector2 = new Vector2(x, y);
29 | }
30 |
31 | ///
32 | /// Constructs a new instance.
33 | /// Mostly required for .
34 | ///
35 | /// The , the position.
36 | public Position(Vector2 vector2)
37 | {
38 | Vector2 = vector2;
39 | }
40 | };
41 |
42 | ///
43 | /// The velocity of an entity.
44 | ///
45 | public struct Velocity
46 | {
47 |
48 | ///
49 | /// Its velocity.
50 | ///
51 | public Vector2 Vector2;
52 |
53 | ///
54 | /// Constructs a new instance.
55 | ///
56 | /// The x velocity.
57 | /// The y velocity.
58 | public Velocity(float x, float y)
59 | {
60 | Vector2 = new Vector2(x, y);
61 | }
62 |
63 | ///
64 | /// Constructs a new instance.
65 | /// Mostly required for .
66 | ///
67 | /// The , the velocity.
68 | public Velocity(Vector2 vector2)
69 | {
70 | Vector2 = vector2;
71 | }
72 | }
73 |
74 | ///
75 | /// The sprite/texture of an entity.
76 | ///
77 | public struct Sprite
78 | {
79 | ///
80 | /// The used.
81 | ///
82 | [IgnoreDataMember]
83 | public Texture2D Texture2D;
84 |
85 | ///
86 | /// The id of the texture, for serialisation.
87 | ///
88 | public byte TextureId;
89 |
90 | ///
91 | /// The used.
92 | ///
93 | public Color Color;
94 |
95 | ///
96 | /// Constructs a new instance.
97 | ///
98 | /// Its .
99 | /// Its .
100 | public Sprite(Texture2D texture2D, Color color)
101 | {
102 | Texture2D = texture2D;
103 | Color = color;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/Arch.Extended.Sample/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using Microsoft.Xna.Framework;
3 | using Microsoft.Xna.Framework.Graphics;
4 |
5 | namespace Arch.Extended;
6 |
7 | public static class TextureExtensions
8 | {
9 | ///
10 | /// Creates a square texture and returns it.
11 | ///
12 | ///
13 | ///
14 | ///
15 | public static Texture2D CreateSquareTexture(GraphicsDevice graphicsDevice, int size)
16 | {
17 | var texture = new Texture2D(graphicsDevice, size, size);
18 | var data = new Color[size*size];
19 | for(var i=0; i < data.Length; ++i) data[i] = Color.White;
20 | texture.SetData(data);
21 |
22 | return texture;
23 | }
24 | }
25 |
26 | public static class RandomExtensions
27 | {
28 | ///
29 | /// Creates a random inside the and returns it.
30 | ///
31 | /// The instance.
32 | /// A in which a is generated.
33 | /// The generated .
34 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
35 | public static Vector2 NextVector2(this Random random, in Rectangle rectangle)
36 | {
37 | return new Vector2(random.Next(rectangle.X, rectangle.X+rectangle.Width), random.Next(rectangle.Y, rectangle.Y+rectangle.Height));
38 | }
39 |
40 | ///
41 | /// Creates a random between two floats.
42 | ///
43 | /// The instance.
44 | /// The minimum value.
45 | /// The maximum value.
46 | /// A between those to floats.
47 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
48 | public static Vector2 NextVector2(this Random random, float min, float max)
49 | {
50 | return new Vector2((float)(random.NextDouble() * (max - min) + min), (float)(random.NextDouble() * (max - min) + min));
51 | }
52 |
53 | ///
54 | /// Creates a random .
55 | ///
56 | /// The instance.
57 | /// A .
58 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
59 | public static Color NextColor(this Random random)
60 | {
61 | return new Color(random.Next(0,255),random.Next(0,255),random.Next(0,255));
62 | }
63 | }
--------------------------------------------------------------------------------
/Arch.Extended.Sample/Program.cs:
--------------------------------------------------------------------------------
1 | // See https://aka.ms/new-console-template for more information
2 |
3 | using Microsoft.Xna.Framework;
4 | using Game = Arch.Extended.Game;
5 |
6 |
7 | // Info :
8 | // This sample demonstrates a example usage of arch.
9 | // Especially a few different iteration techniques for entity iterations.
10 | // Its not a full demonstration of all features.
11 | // Hit "delete" to remove velocity from all entities
12 |
13 | // Disclaimer :
14 | // You can spawn in to 1 million entities, then the performance starts dropping.
15 | // The bottleneck is not the ECS framework, its actually the rendering ( Monogame Spritebatch ).
16 |
17 | Console.WriteLine("Sample App starts...");
18 | using var game = new Game();
19 | game.Run();
20 |
21 | Environment.Exit(0);
--------------------------------------------------------------------------------
/Arch.Extended.Sample/Serializer.cs:
--------------------------------------------------------------------------------
1 | using MessagePack;
2 | using MessagePack.Formatters;
3 | using Microsoft.Xna.Framework;
4 | using Microsoft.Xna.Framework.Graphics;
5 | using Utf8Json;
6 |
7 | namespace Arch.Extended;
8 |
9 | ///
10 | /// The class
11 | /// is a for (de)serialising a .
12 | ///
13 | public class SpriteSerializer : IJsonFormatter, IMessagePackFormatter
14 | {
15 | ///
16 | /// The to create s from.
17 | ///
18 | public GraphicsDevice GraphicsDevice { get; set; }
19 |
20 | public void Serialize(ref JsonWriter writer, Sprite value, IJsonFormatterResolver formatterResolver)
21 | {
22 | writer.WriteBeginObject();
23 |
24 | // Write color
25 | writer.WritePropertyName("color");
26 | writer.WriteUInt32(value.Color.PackedValue);
27 | writer.WriteValueSeparator();
28 |
29 | // Write texture id
30 | writer.WritePropertyName("textureId");
31 | writer.WriteUInt16(value.TextureId);
32 |
33 | writer.WriteEndObject();
34 | }
35 |
36 | public Sprite Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
37 | {
38 | reader.ReadIsBeginObject();
39 |
40 | // Read color
41 | reader.ReadPropertyName();
42 | var packedColor = reader.ReadUInt32();
43 | reader.ReadIsValueSeparator();
44 |
45 | // Read textureid
46 | reader.ReadPropertyName();
47 | var textureId = reader.ReadUInt16();
48 |
49 | // Create color and texture
50 | var color = new Color { PackedValue = packedColor };
51 | var texture = textureId switch
52 | {
53 | 1 => TextureExtensions.CreateSquareTexture(GraphicsDevice, 10),
54 | _ => TextureExtensions.CreateSquareTexture(GraphicsDevice, 10)
55 | };
56 |
57 | reader.ReadIsEndObject();
58 | return new Sprite(texture, color);
59 | }
60 |
61 | public void Serialize(ref MessagePackWriter writer, Sprite value, MessagePackSerializerOptions options)
62 | {
63 | // Write color
64 | writer.WriteUInt32(value.Color.PackedValue);
65 |
66 | // Write texture id
67 | writer.WriteUInt16(value.TextureId);
68 | }
69 |
70 | public Sprite Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
71 | {
72 | // Read color
73 | var packedColor = reader.ReadUInt32();
74 |
75 | // Read textureid
76 | var textureId = reader.ReadUInt16();
77 |
78 | // Create color and texture
79 | var color = new Color { PackedValue = packedColor };
80 | var texture = textureId switch
81 | {
82 | 1 => TextureExtensions.CreateSquareTexture(GraphicsDevice, 10),
83 | _ => TextureExtensions.CreateSquareTexture(GraphicsDevice, 10)
84 | };
85 |
86 | return new Sprite(texture, color);
87 | }
88 | }
--------------------------------------------------------------------------------
/Arch.Extended.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.8.34408.163
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arch.System.SourceGenerator", "Arch.System.SourceGenerator\Arch.System.SourceGenerator.csproj", "{CBF9A4D4-5E31-4457-8F7B-EBC01EB86AF2}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arch.Extended.Sample", "Arch.Extended.Sample\Arch.Extended.Sample.csproj", "{ED61027D-1586-4349-A6F8-17665C786678}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arch.System", "Arch.System\Arch.System.csproj", "{39363918-BFC7-43BF-8307-F5581225FB41}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arch.EventBus", "Arch.EventBus\Arch.EventBus.csproj", "{8BBA34D1-7DAB-4410-8762-09F7CC543D1E}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arch.LowLevel", "Arch.LowLevel\Arch.LowLevel.csproj", "{00B44305-AB3D-438B-9EB9-8EF1ED2E8394}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arch.LowLevel.Tests", "Arch.LowLevel.Tests\Arch.LowLevel.Tests.csproj", "{9E2F4FCC-1875-49A6-98F1-1D2DA8460984}"
17 | EndProject
18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arch.Persistence", "Arch.Persistence\Arch.Persistence.csproj", "{4E946A7C-5AB3-4AD6-8B80-D27563CF1D6A}"
19 | EndProject
20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arch.Relationships", "Arch.Relationships\Arch.Relationships.csproj", "{533453B9-957E-401E-B639-DC81DD0265EC}"
21 | EndProject
22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arch.Relationships.Tests", "Arch.Relationships.Tests\Arch.Relationships.Tests.csproj", "{EDAFD1B8-5FC3-4002-B2AD-5B976B809D1C}"
23 | EndProject
24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arch.System.SourceGenerator.SnapshotTests", "Arch.System.SourceGenerator.SnapshotTests\Arch.System.SourceGenerator.SnapshotTests.csproj", "{156F6B43-B5F7-48FB-BBDB-85B3968BBE56}"
25 | EndProject
26 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arch.System.SourceGenerator.Tests", "Arch.System.SourceGenerator.Tests\Arch.System.SourceGenerator.Tests.csproj", "{FDDA22B1-43DF-48E6-82CE-BC528C8349B9}"
27 | EndProject
28 | Global
29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
30 | Debug|Any CPU = Debug|Any CPU
31 | Release|Any CPU = Release|Any CPU
32 | EndGlobalSection
33 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
34 | {CBF9A4D4-5E31-4457-8F7B-EBC01EB86AF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {CBF9A4D4-5E31-4457-8F7B-EBC01EB86AF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {CBF9A4D4-5E31-4457-8F7B-EBC01EB86AF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {CBF9A4D4-5E31-4457-8F7B-EBC01EB86AF2}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {ED61027D-1586-4349-A6F8-17665C786678}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {ED61027D-1586-4349-A6F8-17665C786678}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {ED61027D-1586-4349-A6F8-17665C786678}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {ED61027D-1586-4349-A6F8-17665C786678}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {39363918-BFC7-43BF-8307-F5581225FB41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {39363918-BFC7-43BF-8307-F5581225FB41}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {39363918-BFC7-43BF-8307-F5581225FB41}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {39363918-BFC7-43BF-8307-F5581225FB41}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {8BBA34D1-7DAB-4410-8762-09F7CC543D1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {8BBA34D1-7DAB-4410-8762-09F7CC543D1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {8BBA34D1-7DAB-4410-8762-09F7CC543D1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {8BBA34D1-7DAB-4410-8762-09F7CC543D1E}.Release|Any CPU.Build.0 = Release|Any CPU
50 | {00B44305-AB3D-438B-9EB9-8EF1ED2E8394}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51 | {00B44305-AB3D-438B-9EB9-8EF1ED2E8394}.Debug|Any CPU.Build.0 = Debug|Any CPU
52 | {00B44305-AB3D-438B-9EB9-8EF1ED2E8394}.Release|Any CPU.ActiveCfg = Release|Any CPU
53 | {00B44305-AB3D-438B-9EB9-8EF1ED2E8394}.Release|Any CPU.Build.0 = Release|Any CPU
54 | {9E2F4FCC-1875-49A6-98F1-1D2DA8460984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
55 | {9E2F4FCC-1875-49A6-98F1-1D2DA8460984}.Debug|Any CPU.Build.0 = Debug|Any CPU
56 | {9E2F4FCC-1875-49A6-98F1-1D2DA8460984}.Release|Any CPU.ActiveCfg = Release|Any CPU
57 | {9E2F4FCC-1875-49A6-98F1-1D2DA8460984}.Release|Any CPU.Build.0 = Release|Any CPU
58 | {4E946A7C-5AB3-4AD6-8B80-D27563CF1D6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
59 | {4E946A7C-5AB3-4AD6-8B80-D27563CF1D6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
60 | {4E946A7C-5AB3-4AD6-8B80-D27563CF1D6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
61 | {4E946A7C-5AB3-4AD6-8B80-D27563CF1D6A}.Release|Any CPU.Build.0 = Release|Any CPU
62 | {533453B9-957E-401E-B639-DC81DD0265EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
63 | {533453B9-957E-401E-B639-DC81DD0265EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
64 | {533453B9-957E-401E-B639-DC81DD0265EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
65 | {533453B9-957E-401E-B639-DC81DD0265EC}.Release|Any CPU.Build.0 = Release|Any CPU
66 | {EDAFD1B8-5FC3-4002-B2AD-5B976B809D1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
67 | {EDAFD1B8-5FC3-4002-B2AD-5B976B809D1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
68 | {EDAFD1B8-5FC3-4002-B2AD-5B976B809D1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
69 | {EDAFD1B8-5FC3-4002-B2AD-5B976B809D1C}.Release|Any CPU.Build.0 = Release|Any CPU
70 | {156F6B43-B5F7-48FB-BBDB-85B3968BBE56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
71 | {156F6B43-B5F7-48FB-BBDB-85B3968BBE56}.Debug|Any CPU.Build.0 = Debug|Any CPU
72 | {156F6B43-B5F7-48FB-BBDB-85B3968BBE56}.Release|Any CPU.ActiveCfg = Release|Any CPU
73 | {156F6B43-B5F7-48FB-BBDB-85B3968BBE56}.Release|Any CPU.Build.0 = Release|Any CPU
74 | {FDDA22B1-43DF-48E6-82CE-BC528C8349B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
75 | {FDDA22B1-43DF-48E6-82CE-BC528C8349B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
76 | {FDDA22B1-43DF-48E6-82CE-BC528C8349B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
77 | {FDDA22B1-43DF-48E6-82CE-BC528C8349B9}.Release|Any CPU.Build.0 = Release|Any CPU
78 | EndGlobalSection
79 | GlobalSection(SolutionProperties) = preSolution
80 | HideSolutionNode = FALSE
81 | EndGlobalSection
82 | EndGlobal
83 |
--------------------------------------------------------------------------------
/Arch.Extended.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | /usr/local/share/dotnet/sdk/8.0.101/MSBuild.dll
3 | 4294967293
--------------------------------------------------------------------------------
/Arch.LowLevel.Tests/Arch.LowLevel.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Arch.LowLevel.Tests/ArrayTest.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace Arch.LowLevel.Tests;
4 | using static Assert;
5 |
6 | ///
7 | /// Checks related methods.
8 | ///
9 | [TestFixture]
10 | public class ArrayTest
11 | {
12 | ///
13 | /// Checks if is capable of allocating space and adding items.
14 | ///
15 | [Test]
16 | public void ArrayCreate()
17 | {
18 | var array = new Array(3);
19 | array[0] = 1;
20 | array[1] = 2;
21 | array[2] = 3;
22 |
23 | That(array.Count, Is.EqualTo(3));
24 | }
25 |
26 | [Test]
27 | public void ArrayEnumerator()
28 | {
29 | var array = new Array(3);
30 | array[0] = 1;
31 | array[1] = 2;
32 | array[2] = 3;
33 |
34 | var count = 1;
35 | foreach (var item in array)
36 | That(item, Is.EqualTo(count++));
37 | }
38 |
39 | [Test]
40 | public void ArrayEmptyIsEmpty()
41 | {
42 | var empty = Array.Empty();
43 | That(empty, Is.Empty);
44 | }
45 |
46 | [Test]
47 | public void ArrayFill()
48 | {
49 | var array = new Array(35);
50 | Array.Fill(ref array, 8);
51 |
52 | for (var i = 0; i < array.Length; i++)
53 | That(array[i], Is.EqualTo(8));
54 | }
55 |
56 | [Test]
57 | public void ArrayCopy()
58 | {
59 | var src = new Array(15);
60 | var dst = new Array(6);
61 |
62 | for (var i = 0; i < src.Length; i++)
63 | src[i] = i;
64 |
65 | Array.Fill(ref dst);
66 | Array.Copy(ref src, 4, ref dst, 1, 4);
67 |
68 | Multiple(() =>
69 | {
70 | That(dst[0], Is.EqualTo(0));
71 | That(dst[1], Is.EqualTo(4));
72 | That(dst[2], Is.EqualTo(5));
73 | That(dst[3], Is.EqualTo(6));
74 | That(dst[4], Is.EqualTo(7));
75 | That(dst[5], Is.EqualTo(0));
76 | });
77 | }
78 |
79 | [Test]
80 | public void ArrayResizeShrink()
81 | {
82 | var array = new Array(19);
83 | for (var i = 0; i < array.Length; i++)
84 | array[i] = i;
85 |
86 | var resized = Array.Resize(ref array, 8);
87 | for (var i = 0; i < resized.Length; i++)
88 | That(resized[i], Is.EqualTo(i));
89 | }
90 |
91 | [Test]
92 | public void ArrayResizeGrow()
93 | {
94 | var array = new Array(8);
95 | for (var i = 0; i < array.Length; i++)
96 | array[i] = i;
97 |
98 | var resized = Array.Resize(ref array, 19);
99 | for (var i = 0; i < array.Length; i++)
100 | That(resized[i], Is.EqualTo(i));
101 | }
102 |
103 | [Test]
104 | public void ArrayEquals()
105 | {
106 | var a = new Array(8);
107 | var b = a;
108 |
109 | That(a, Is.EqualTo(b));
110 | That(a == b, Is.True);
111 | }
112 |
113 | [Test]
114 | public void ArrayNotEquals()
115 | {
116 | var a = new Array(8);
117 | var b = new Array(8);
118 |
119 | That(a, Is.Not.EqualTo(b));
120 | That(a != b, Is.True);
121 | }
122 | }
--------------------------------------------------------------------------------
/Arch.LowLevel.Tests/Jagged/JaggedArrayTest.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using Arch.LowLevel.Jagged;
3 |
4 | namespace Arch.LowLevel.Tests.Jagged;
5 | using static Assert;
6 |
7 | ///
8 | /// Checks related methods.
9 | ///
10 | [TestFixture]
11 | public class JaggedArrayTest
12 | {
13 |
14 | ///
15 | /// Checks if is capable of adding items correctly.
16 | ///
17 | [Test]
18 | public void Add([Values(256,512,1024,2048,4096)] int capacity)
19 | {
20 | // Check add
21 | var jaggedArray = new JaggedArray(16000/Unsafe.SizeOf(), -1, capacity);
22 |
23 | // adding
24 | for (var index = 0; index < jaggedArray.Capacity; index++)
25 | {
26 | jaggedArray.Add(index, index);
27 | }
28 |
29 | // Checking
30 | for (var index = 0; index < jaggedArray.Capacity; index++)
31 | {
32 | var item = jaggedArray[index];
33 | That(item, Is.EqualTo(index));
34 | }
35 |
36 | That(jaggedArray.Capacity, Is.GreaterThan(capacity));
37 | }
38 |
39 | [Test]
40 | public void TryGetValue([Values(256,512,1024,2048,4096)] int capacity)
41 | {
42 | // Initialize the JaggedArray
43 | var jaggedArray = new JaggedArray(16000/Unsafe.SizeOf(), -1, capacity);
44 |
45 | // Add elements to the array
46 | for (var index = 0; index < jaggedArray.Capacity; index++)
47 | {
48 | jaggedArray.Add(index, index);
49 | }
50 |
51 | // Check values using TryGetValue
52 | for (var index = 0; index < jaggedArray.Capacity; index++)
53 | {
54 | var found = jaggedArray.TryGetValue(index, out int value);
55 | That(found, Is.True);
56 | That(value, Is.EqualTo(index));
57 | }
58 |
59 | // Check for values out of bounds
60 | var outOfBoundsFound = jaggedArray.TryGetValue(jaggedArray.Capacity, out int _);
61 | That(outOfBoundsFound, Is.False);
62 | }
63 |
64 | [Test]
65 | public void TryGetValueRef([Values(256,512,1024,2048,4096)] int capacity)
66 | {
67 | // Initialize the JaggedArray
68 | var jaggedArray = new JaggedArray(16000/Unsafe.SizeOf(), -1, capacity);
69 |
70 | // Add elements to the array
71 | for (var index = 0; index < jaggedArray.Capacity; index++)
72 | {
73 | jaggedArray.Add(index, index);
74 | }
75 |
76 | // Check values using TryGetValue
77 | for (var index = 0; index < jaggedArray.Capacity; index++)
78 | {
79 | bool found;
80 | ref var value = ref jaggedArray.TryGetValue(index, out found);
81 | That(found, Is.True);
82 | That(value, Is.EqualTo(index));
83 | }
84 |
85 | // Check for values out of bounds
86 | ref var outOfBoundsValue = ref jaggedArray.TryGetValue(jaggedArray.Capacity, out bool outOfBoundsFound);
87 | That(outOfBoundsFound, Is.False);
88 | }
89 |
90 |
91 | ///
92 | /// Checks if is capable of adding items correctly.
93 | ///
94 | [Test]
95 | public void Remove([Values(256,512,1024,2048,4096)] int capacity)
96 | {
97 | // Check add
98 | var jaggedArray = new JaggedArray(16000/Unsafe.SizeOf(), -1, capacity);
99 |
100 | // Adding
101 | for (var index = 0; index < jaggedArray.Capacity; index++)
102 | {
103 | jaggedArray.Add(index, index);
104 | }
105 |
106 | // Removing
107 | for (var index = jaggedArray.Capacity-1; index >= 0; index--)
108 | {
109 | jaggedArray.Remove(index);
110 | }
111 |
112 | // Checking
113 | for (var index = 0; index < jaggedArray.Capacity; index++)
114 | {
115 | var item = jaggedArray[index];
116 | That(item, Is.EqualTo(-1));
117 | }
118 | }
119 |
120 | ///
121 | /// Checks if is capable of adding items correctly.
122 | ///
123 | [Test]
124 | public void TrimExcess([Values(2560,5120,10240)] int capacity)
125 | {
126 | // Check add
127 | var jaggedArray = new JaggedArray(16000/Unsafe.SizeOf(), -1, capacity);
128 |
129 | // Adding
130 | for (var index = 0; index < jaggedArray.Capacity; index++)
131 | {
132 | jaggedArray.Add(index, index);
133 | }
134 |
135 | // Removing half of items
136 | for (var index = jaggedArray.Capacity-1; index >= jaggedArray.Capacity/2; index--)
137 | {
138 | jaggedArray.Remove(index);
139 | }
140 |
141 | var buckets = jaggedArray.Buckets;
142 | jaggedArray.TrimExcess();
143 | That(jaggedArray.Buckets, Is.EqualTo((buckets + 2 - 1)/2));
144 |
145 | // Checking first half still having the desired value
146 | for (var index = 0; index < jaggedArray.Capacity/2; index++)
147 | {
148 | var item = jaggedArray[index];
149 | That(item, Is.EqualTo(index));
150 | }
151 | }
152 | }
--------------------------------------------------------------------------------
/Arch.LowLevel.Tests/ResourcesTest.cs:
--------------------------------------------------------------------------------
1 | using static NUnit.Framework.Assert;
2 |
3 | namespace Arch.LowLevel.Tests;
4 |
5 | ///
6 | /// Checks and HashCode related methods.
7 | ///
8 | [TestFixture]
9 | public class ResourcesTest
10 | {
11 |
12 | ///
13 | /// Checks if is capable of adding s.
14 | ///
15 | [Test]
16 | public void ResourcesAddHandle()
17 | {
18 | // Check add
19 | var resources = new Resources(IntPtr.Size, capacity: 64);
20 | var handle = resources.Add("Handle");
21 | var nextHandle = resources.Add("NextHandle");
22 |
23 | That(handle.Id, Is.EqualTo(0));
24 | That(nextHandle.Id, Is.EqualTo(1));
25 | }
26 |
27 | ///
28 | /// Checks if is capable of adding many more s than the capacity
29 | ///
30 | [Test]
31 | public void ResourcesAddManyHandles()
32 | {
33 | const int count = 10000;
34 |
35 | using var resources = new Resources(capacity: 3);
36 |
37 | var handles = new List>();
38 | for (var i = 0; i < count; i++)
39 | handles.Add(resources.Add(i.ToString()));
40 |
41 | resources.TrimExcess();
42 |
43 | That(resources.Count, Is.EqualTo(count));
44 |
45 | for (var i = 0; i < handles.Count; i++)
46 | That(resources.Get(handles[i]), Is.EqualTo(i.ToString()));
47 | }
48 |
49 | ///
50 | /// Checks if is capable of getting s.
51 | ///
52 | [Test]
53 | public void ResourcesGetHandle()
54 | {
55 | // Check add
56 | var resources = new Resources(IntPtr.Size, capacity: 64);
57 | var handle = resources.Add("Handle");
58 | var nextHandle = resources.Add("NextHandle");
59 |
60 | // Check get
61 | var handleString = resources.Get(in handle);
62 | var nextHandleString = resources.Get(in nextHandle);
63 |
64 | That(handleString, Is.EqualTo("Handle"));
65 | That(nextHandleString, Is.EqualTo("NextHandle"));
66 | }
67 |
68 | ///
69 | /// Checks if is capable of removing s.
70 | ///
71 | [Test]
72 | public void ResourcesRemoveHandle()
73 | {
74 |
75 | // Check add
76 | var resources = new Resources(IntPtr.Size, capacity: 64);
77 | var handle = resources.Add("Handle");
78 | var nextHandle = resources.Add("NextHandle");
79 |
80 | // Check remove
81 | resources.Remove(in handle);
82 | resources.Remove(in nextHandle);
83 |
84 | That(resources._ids.Count, Is.EqualTo(2));
85 | That(resources.Count, Is.EqualTo(0));
86 | }
87 |
88 | ///
89 | /// Checks if is capable of removing s.
90 | ///
91 | [Test]
92 | public void ResourcesRecycleHandle()
93 | {
94 | // Check add
95 | var resources = new Resources(IntPtr.Size, capacity: 64);
96 | var handle = resources.Add("Handle");
97 | var nextHandle = resources.Add("NextHandle");
98 |
99 | // Check remove
100 | resources.Remove(in handle);
101 | resources.Remove(in nextHandle);
102 |
103 | var newHandle = resources.Add("NewString");
104 | That(newHandle.Id, Is.EqualTo(0));
105 | That(resources.Count, Is.EqualTo(1));
106 | }
107 |
108 | ///
109 | /// Checks if is capable of validating a .
110 | ///
111 | [Test]
112 | public void ResourcesHandleValid()
113 | {
114 | // Check add
115 | var resources = new Resources(IntPtr.Size, capacity: 64);
116 | var handle = resources.Add("Handle");
117 | Handle someHandle = Handle.NULL;
118 |
119 | That(resources.IsValid(handle), Is.EqualTo(true));
120 | That(resources.IsValid(someHandle), Is.EqualTo(false));
121 | }
122 |
123 | ///
124 | /// Checks if throws after Dispose
125 | ///
126 | [Test]
127 | public void ResourcesDispose()
128 | {
129 | // Check add
130 | var resources = new Resources(IntPtr.Size, capacity: 64);
131 | var handle = resources.Add("Handle");
132 |
133 | // Check get
134 | That(resources.Get(in handle), Is.EqualTo("Handle"));
135 |
136 | resources.Dispose();
137 |
138 | That(resources.Count, Is.EqualTo(0));
139 |
140 | // Check that get fails
141 | Throws(() =>
142 | {
143 | resources.Get(in handle);
144 | });
145 | }
146 | }
--------------------------------------------------------------------------------
/Arch.LowLevel.Tests/UnsafeArrayTest.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace Arch.LowLevel.Tests;
4 | using static Assert;
5 |
6 | ///
7 | /// Checks related methods.
8 | ///
9 | [TestFixture]
10 | public class UnsafeArrayTest
11 | {
12 | ///
13 | /// Checks if is capable of allocating space and adding items.
14 | ///
15 | [Test]
16 | public void UnsafeArrayCreate()
17 | {
18 | using var array = new UnsafeArray(3);
19 | array[0] = 1;
20 | array[1] = 2;
21 | array[2] = 3;
22 |
23 | That(array.Count, Is.EqualTo(3));
24 | }
25 |
26 | [Test]
27 | public void UnsafeArrayEnumerator()
28 | {
29 | using var array = new UnsafeArray(3);
30 | array[0] = 1;
31 | array[1] = 2;
32 | array[2] = 3;
33 |
34 | var count = 1;
35 | foreach (var item in array)
36 | That(item, Is.EqualTo(count++));
37 | }
38 |
39 | [Test]
40 | public void UnsafeArrayEmptyIsEmpty()
41 | {
42 | var empty = UnsafeArray.Empty();
43 |
44 | That(empty, Is.Empty);
45 |
46 | empty.Dispose();
47 |
48 | That(empty, Is.Empty);
49 | }
50 |
51 | [Test]
52 | public void UnsafeArrayFill()
53 | {
54 | var array = new UnsafeArray(35);
55 | using (array)
56 | {
57 | UnsafeArray.Fill(ref array, 8);
58 |
59 | for (var i = 0; i < array.Length; i++)
60 | That(array[i], Is.EqualTo(8));
61 | }
62 | }
63 |
64 | [Test]
65 | public void UnsafeArrayCopy()
66 | {
67 | var src = new UnsafeArray(15);
68 | var dst = new UnsafeArray(6);
69 | using (src)
70 | using (dst)
71 | {
72 | for (var i = 0; i < src.Length; i++)
73 | src[i] = i;
74 |
75 | UnsafeArray.Fill(ref dst);
76 | UnsafeArray.Copy(ref src, 4, ref dst, 1, 4);
77 |
78 | Multiple(() =>
79 | {
80 | That(dst[0], Is.EqualTo(0));
81 | That(dst[1], Is.EqualTo(4));
82 | That(dst[2], Is.EqualTo(5));
83 | That(dst[3], Is.EqualTo(6));
84 | That(dst[4], Is.EqualTo(7));
85 | That(dst[5], Is.EqualTo(0));
86 | });
87 | }
88 | }
89 |
90 | [Test]
91 | public void UnsafeArrayResizeShrink()
92 | {
93 | var array = new UnsafeArray(19);
94 | for (var i = 0; i < array.Length; i++)
95 | array[i] = i;
96 |
97 | var resized = UnsafeArray.Resize(ref array, 8);
98 | for (var i = 0; i < resized.Length; i++)
99 | That(resized[i], Is.EqualTo(i));
100 |
101 | resized.Dispose();
102 | }
103 |
104 | [Test]
105 | public void UnsafeArrayResizeGrow()
106 | {
107 | var array = new UnsafeArray(8);
108 | for (var i = 0; i < array.Length; i++)
109 | array[i] = i;
110 |
111 | var resized = UnsafeArray.Resize(ref array, 19);
112 | for (var i = 0; i < array.Length; i++)
113 | That(resized[i], Is.EqualTo(i));
114 |
115 | resized.Dispose();
116 | }
117 |
118 | [Test]
119 | public void UnsafeArrayEquals()
120 | {
121 | using var a = new UnsafeArray(8);
122 | var b = a;
123 |
124 | That(a, Is.EqualTo(b));
125 | That(a == b, Is.True);
126 | }
127 |
128 | [Test]
129 | public void UnsafeArrayNotEquals()
130 | {
131 | using var a = new UnsafeArray(8);
132 | using var b = new UnsafeArray(8);
133 |
134 | That(a, Is.Not.EqualTo(b));
135 | That(a != b, Is.True);
136 | }
137 | }
--------------------------------------------------------------------------------
/Arch.LowLevel.Tests/UnsafeQueueTest.cs:
--------------------------------------------------------------------------------
1 | namespace Arch.LowLevel.Tests;
2 | using static NUnit.Framework.Assert;
3 |
4 | ///
5 | /// Checks related methods.
6 | ///
7 | [TestFixture]
8 | public class UnsafeQueueTest
9 | {
10 |
11 | ///
12 | /// Checks if is capable of adding items.
13 | ///
14 | [Test]
15 | public void UnsafeQueueEnqueue()
16 | {
17 | using var queue = new UnsafeQueue(8);
18 |
19 | for (var i = 0; i < 20; i++)
20 | queue.Enqueue(i);
21 |
22 | That(queue, Has.Count.EqualTo(20));
23 | That(queue.Peek(), Is.EqualTo(0));
24 | }
25 |
26 | ///
27 | /// Checks if is capable of being converted into a span.
28 | ///
29 | [Test]
30 | public void UnsafeQueueAsSpan()
31 | {
32 | using var queue = new UnsafeQueue(8);
33 |
34 | for (var i = 0; i < 9; i++)
35 | queue.Enqueue(i);
36 |
37 | var span = queue.AsSpan();
38 |
39 | CollectionAssert.AreEqual(new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, span.ToArray());
40 | }
41 |
42 | ///
43 | /// Checks if is capable of peeking itemss.
44 | ///
45 | [Test]
46 | public void UnsafeQueuePeek()
47 | {
48 | using var queue = new UnsafeQueue(8);
49 | queue.Enqueue(1);
50 | queue.Enqueue(2);
51 |
52 | That(queue.Peek(), Is.EqualTo(1));
53 | queue.Enqueue(3);
54 | That(queue.Peek(), Is.EqualTo(1));
55 | }
56 |
57 | ///
58 | /// Checks if is capable of popping itemss.
59 | ///
60 | [Test]
61 | public void UnsafeQueueDequeue()
62 | {
63 | using var queue = new UnsafeQueue(8);
64 | queue.Enqueue(1);
65 | queue.Enqueue(2);
66 | queue.Enqueue(3);
67 |
68 | That(queue.Dequeue(), Is.EqualTo(1));
69 | That(queue.Dequeue(), Is.EqualTo(2));
70 | That(queue.Dequeue(), Is.EqualTo(3));
71 |
72 | Throws(() =>
73 | {
74 | queue.Dequeue();
75 | });
76 |
77 | Throws(() =>
78 | {
79 | queue.Peek();
80 | });
81 | }
82 |
83 | [Test]
84 | public void UnsafeQueueClear()
85 | {
86 | using var queue = new UnsafeQueue(8);
87 |
88 | for (var i = 0; i < 20; i++)
89 | queue.Enqueue(i);
90 |
91 | That(queue, Has.Count.EqualTo(20));
92 |
93 | queue.Clear();
94 |
95 | That(queue, Is.Empty);
96 | }
97 |
98 | ///
99 | /// Checks if is capable of iterating with its enumerators.
100 | ///
101 | [Test]
102 | public void UnsafeQueueEnumerator()
103 | {
104 | using var queue = new UnsafeQueue(8);
105 | queue.Enqueue(1);
106 | queue.Enqueue(2);
107 | queue.Enqueue(3);
108 |
109 | // Ref iterator
110 | var count = 0;
111 | foreach (ref var item in queue)
112 | {
113 | count++;
114 | }
115 | That(count, Is.EqualTo(3));
116 | }
117 |
118 | ///
119 | /// Checks if can be constructed with invalid parameters.
120 | ///
121 | [Test]
122 | public void UnsafeQueueInvalidConstruction()
123 | {
124 | Throws(() =>
125 | {
126 | new UnsafeQueue(-8);
127 | });
128 | }
129 |
130 | ///
131 | /// Checks if EnsureCapacity functions correctly.
132 | ///
133 | [Test]
134 | public void UnsafeQueueEnsureCapacity()
135 | {
136 | using var queue = new UnsafeQueue(8);
137 |
138 | That(queue.Capacity, Is.AtLeast(8));
139 |
140 | queue.EnsureCapacity(20);
141 | That(queue.Capacity, Is.AtLeast(20));
142 |
143 | queue.EnsureCapacity(10);
144 | That(queue.Capacity, Is.AtLeast(20));
145 | }
146 |
147 | ///
148 | /// Checks if TrimExcess removes all excess capacity.
149 | ///
150 | [Test]
151 | public void UnsafeQueueTrimExcess()
152 | {
153 | using var queue = new UnsafeQueue(8);
154 | for (var i = 0; i < 4; i++)
155 | queue.Enqueue(i);
156 |
157 | That(queue.Capacity, Is.AtLeast(8));
158 |
159 | queue.EnsureCapacity(20);
160 | That(queue.Capacity, Is.AtLeast(20));
161 |
162 | queue.TrimExcess();
163 |
164 | That(queue.Capacity, Is.EqualTo(4));
165 | }
166 | }
--------------------------------------------------------------------------------
/Arch.LowLevel.Tests/Usings.cs:
--------------------------------------------------------------------------------
1 | global using NUnit.Framework;
--------------------------------------------------------------------------------
/Arch.LowLevel/Arch.LowLevel.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0; net6.0; netstandard2.1
5 | enable
6 | enable
7 | true
8 |
9 | true
10 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
11 | true
12 | snupkg
13 |
14 | Arch.LowLevel
15 | Arch.LowLevel
16 | 1.1.5
17 | genaray
18 | Apache-2.0
19 | LowLevel tools for arch.
20 | Refactored JaggedArrays.
21 | Increased performance of JaggedArrays.
22 | Added Array, a new class that acts as a Wrapper around normal generic Arrays for unsafe operations.
23 | Added tests.
24 | Bug fixes.
25 | c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;
26 |
27 | https://github.com/genaray/Arch.Extended
28 | https://github.com/genaray/Arch.Extended.git
29 | git
30 | true
31 |
32 | 11
33 | true
34 | Apache2.0
35 |
36 | en-US
37 |
38 | true
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Arch.LowLevel/Enumerators.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Runtime.CompilerServices;
3 |
4 | namespace Arch.LowLevel;
5 |
6 | ///
7 | /// The is a basic implementation of an enumerator for the >.
8 | ///
9 | ///
10 | public unsafe ref struct Enumerator
11 | {
12 | private readonly Span _list;
13 | private readonly int _count;
14 | private int _index;
15 |
16 | ///
17 | /// Creates an instance of the .
18 | ///
19 | /// The .
20 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
21 | internal Enumerator(Span list)
22 | {
23 | _list = list;
24 | _count = list.Length;
25 | _index = -1;
26 | }
27 |
28 | ///
29 | /// Returns the current item.
30 | ///
31 | public readonly ref T Current => ref _list[_index];
32 |
33 | ///
34 | /// Moves to the next item.
35 | ///
36 | ///
37 | public bool MoveNext()
38 | {
39 | return unchecked(++_index < _count);
40 | }
41 |
42 | ///
43 | /// Resets the enumerator.
44 | ///
45 | public void Reset()
46 | {
47 | _index = -1;
48 | }
49 | }
50 |
51 | ///
52 | /// The is a basic implementation of the interface for the .
53 | ///
54 | ///
55 | public unsafe struct UnsafeIEnumerator : IEnumerator where T : unmanaged
56 | {
57 | private readonly T* _list;
58 | private readonly int _count;
59 | private int _index;
60 |
61 | ///
62 | /// Creates an instance of the .
63 | ///
64 | /// The .
65 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
66 | internal UnsafeIEnumerator(T* list, int count)
67 | {
68 | _list = list;
69 | _count = count;
70 | _index = -1;
71 | }
72 |
73 | ///
74 | /// Returns the current item.
75 | ///
76 | public T Current => _list[_index];
77 |
78 | ///
79 | /// Returns the current item.
80 | ///
81 | object IEnumerator.Current => _list[_index];
82 |
83 | ///
84 | /// Disposes this enumerator.
85 | ///
86 | public void Dispose() { } // nop
87 |
88 | ///
89 | /// Moves to the next item.
90 | ///
91 | ///
92 | public bool MoveNext()
93 | {
94 | return unchecked(++_index < _count);
95 | }
96 |
97 | ///
98 | /// Resets the enumerator.
99 | ///
100 | public void Reset()
101 | {
102 | _index = -1;
103 | }
104 | }
105 |
106 | ///
107 | /// The is a basic implementation of the interface for the .
108 | ///
109 | ///
110 | public unsafe ref struct UnsafeEnumerator where T : unmanaged
111 | {
112 | private readonly T* _list;
113 | private readonly int _count;
114 | private int _index;
115 |
116 | ///
117 | /// Creates an instance of the .
118 | ///
119 | /// The .
120 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
121 | internal UnsafeEnumerator(T* list, int count)
122 | {
123 | _list = list;
124 | _count = count;
125 | _index = -1;
126 | }
127 |
128 | ///
129 | /// Returns the current item.
130 | ///
131 | public ref T Current => ref _list[_index];
132 |
133 | ///
134 | /// Moves to the next item.
135 | ///
136 | ///
137 | public bool MoveNext()
138 | {
139 | return unchecked(++_index < _count);
140 | }
141 |
142 | ///
143 | /// Resets the enumerator.
144 | ///
145 | public void Reset()
146 | {
147 | _index = -1;
148 | }
149 | }
150 |
151 | ///
152 | /// The is a basic implementation of the interface for iterating backwards.
153 | ///
154 | ///
155 | public unsafe struct ReverseIEnumerator : IEnumerator where T : unmanaged
156 | {
157 | private readonly T* _list;
158 | private readonly int _count;
159 | private int _index;
160 |
161 | ///
162 | /// Creates an instance of the .
163 | ///
164 | /// The .
165 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
166 | internal ReverseIEnumerator(T* list, int count)
167 | {
168 | _list = list;
169 | _count = count;
170 | _index = count+1;
171 | }
172 |
173 | ///
174 | /// Returns the current item.
175 | ///
176 | public T Current => _list[_index-1];
177 |
178 | ///
179 | /// Returns the current item.
180 | ///
181 | object IEnumerator.Current => _list[_index-1];
182 |
183 | ///
184 | /// Disposes this enumerator.
185 | ///
186 | public void Dispose() { } // nop
187 |
188 | ///
189 | /// Moves to the next item.
190 | ///
191 | ///
192 | public bool MoveNext()
193 | {
194 | return unchecked(--_index > 0);
195 | }
196 |
197 | ///
198 | /// Resets the enumerator.
199 | ///
200 | public void Reset()
201 | {
202 | _index = _count+1;
203 | }
204 | }
205 | ///
206 | /// The is a basic implementation of the interface for iterating backwards.
207 | ///
208 | ///
209 | public unsafe ref struct UnsafeReverseEnumerator where T : unmanaged
210 | {
211 | private readonly T* _list;
212 | private readonly int _count;
213 | private int _index;
214 |
215 | ///
216 | /// Creates an instance of the .
217 | ///
218 | /// The .
219 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
220 | internal UnsafeReverseEnumerator(T* list, int count)
221 | {
222 | _list = list;
223 | _count = count;
224 | _index = count+1;
225 | }
226 |
227 | ///
228 | /// Returns the current item.
229 | ///
230 | public ref T Current => ref _list[_index-1];
231 |
232 | ///
233 | /// Moves to the next item.
234 | ///
235 | ///
236 | public bool MoveNext()
237 | {
238 | return unchecked(--_index > 0);
239 | }
240 |
241 | ///
242 | /// Resets the enumerator.
243 | ///
244 | public void Reset()
245 | {
246 | _index = _count+1;
247 | }
248 | }
--------------------------------------------------------------------------------
/Arch.LowLevel/Resources.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using Arch.LowLevel.Jagged;
3 |
4 | [assembly: InternalsVisibleTo("Arch.LowLevel.Tests")]
5 | namespace Arch.LowLevel;
6 |
7 | ///
8 | /// The struct
9 | /// represents a reference to an managed resource.
10 | /// This is used commonly for referencing managed resources from components.
11 | ///
12 | /// The type of the managed resource.
13 | public readonly record struct Handle
14 | {
15 |
16 | ///
17 | /// A null which is invalid and used for camparison.
18 | ///
19 | public static readonly Handle NULL = new(-1);
20 |
21 | ///
22 | /// The id, its index inside a array.
23 | ///
24 | public readonly int Id = -1;
25 |
26 | ///
27 | /// Public default constructor.
28 | ///
29 | public Handle()
30 | {
31 | Id = -1;
32 | }
33 |
34 | ///
35 | /// Initializes a new instance of the class.
36 | ///
37 | ///
38 | internal Handle(int id)
39 | {
40 | Id = id;
41 | }
42 | }
43 |
44 | ///
45 | /// The class,
46 | /// represents an collection of managed resources which can be accesed by a .
47 | ///
48 | ///
49 | public sealed class Resources : IDisposable
50 | {
51 |
52 | ///
53 | /// The which stores the managed resources on the index.
54 | ///
55 | private JaggedArray _array;
56 |
57 | ///
58 | /// A list of recycled ids, used to fill in old gaps.
59 | ///
60 | internal Queue _ids;
61 |
62 | ///
63 | /// Creates an instance.
64 | ///
65 | /// The capacity of the bucket.
66 | public Resources(int capacity = 64)
67 | {
68 | _array = new JaggedArray(capacity, capacity);
69 | _ids = new Queue(capacity);
70 | }
71 |
72 | ///
73 | /// Creates an instance.
74 | ///
75 | /// The size of the generic type in bytes.
76 | /// The capcity, how many items of that type should fit into the array.
77 | public Resources(int size, int capacity = 64)
78 | {
79 | _array = new JaggedArray(160000/size, capacity);
80 | _ids = new Queue(capacity);
81 | }
82 |
83 | ///
84 | /// The amount of registered s.
85 | ///
86 | public int Count
87 | {
88 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
89 | get;
90 |
91 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
92 | private set;
93 | }
94 |
95 | ///
96 | /// Creates a for the given resource.
97 | ///
98 | /// The resource instance.
99 | ///
100 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
101 | public Handle Add(in T item)
102 | {
103 | // Create handle
104 | var recyled = _ids.TryDequeue(out var id);
105 | id = recyled ? id : Count;
106 | var handle = new Handle(id);
107 |
108 | // Resize array and fill it in
109 | _array.EnsureCapacity(id+1);
110 | _array.Add(id, item);
111 |
112 | Count++;
113 | return handle;
114 | }
115 |
116 | ///
117 | /// Checks if the is valid.
118 | ///
119 | /// The .
120 | /// True or false.
121 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
122 | public bool IsValid(in Handle handle)
123 | {
124 | return handle.Id > -1 && handle.Id <= _array.Capacity;
125 | }
126 |
127 | ///
128 | /// Returns a resource for the given .
129 | ///
130 | /// The .
131 | /// The resource.
132 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
133 | public ref T Get(in Handle handle)
134 | {
135 | return ref _array[handle.Id];
136 | }
137 |
138 | ///
139 | /// Removes a and its resource.
140 | ///
141 | /// The .
142 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
143 | public void Remove(in Handle handle)
144 | {
145 | _array.Remove(handle.Id);
146 | _ids.Enqueue(handle.Id);
147 |
148 | Count--;
149 | }
150 |
151 | ///
152 | /// Trims the resources and releases unused memory if possible.
153 | ///
154 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
155 | public void TrimExcess()
156 | {
157 | _array.TrimExcess();
158 | _ids.TrimExcess();
159 | }
160 |
161 | ///
162 | /// Disposes this instance.
163 | ///
164 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
165 | public void Dispose()
166 | {
167 | _array = null;
168 | _ids = null;
169 | Count = 0;
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/Arch.Persistence.Tests/Arch.Persistence.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Arch.Persistence.Tests/PersistenceTest.cs:
--------------------------------------------------------------------------------
1 | using Arch.Core;
2 | using Arch.Core.Extensions;
3 | using CommunityToolkit.HighPerformance;
4 | using static NUnit.Framework.Assert;
5 | using Throws = NUnit.Framework.Throws;
6 |
7 | namespace Arch.Persistence.Tests;
8 |
9 | ///
10 | /// The struct
11 | /// represents a test component that is being (de)serialized.
12 | ///
13 | public record struct Transform
14 | {
15 | public float X;
16 | public float Y;
17 | }
18 |
19 | ///
20 | /// The struct
21 | /// represents a test component that is being (de)serialized.
22 | ///
23 | public record struct MetaData
24 | {
25 | public string Name;
26 | }
27 |
28 | public class Tests
29 | {
30 |
31 | private ArchBinarySerializer _binarySerializer;
32 | private ArchJsonSerializer _jsonSerializer;
33 | private World _world;
34 |
35 | [SetUp]
36 | public void Setup()
37 | {
38 | _binarySerializer = new ArchBinarySerializer();
39 | _jsonSerializer = new ArchJsonSerializer();
40 |
41 | _world = World.Create();
42 | for (var index = 0; index < 1000; index++)
43 | {
44 | _world.Create(new Transform { X = index, Y = index }, new MetaData{ Name = index.ToString()});
45 | }
46 | }
47 |
48 | ///
49 | /// Checks if a world is being serialized and deserialized correctly using the .
50 | ///
51 | [Test]
52 | public void BinaryWorldSerialization()
53 | {
54 | var bytes = _binarySerializer.Serialize(_world);
55 | var newWorld = _binarySerializer.Deserialize(bytes);
56 |
57 | // Equal in structure?
58 | That(newWorld.Capacity, Is.EqualTo(_world.Capacity));
59 | That(newWorld.Size, Is.EqualTo(_world.Size));
60 | That(newWorld.Archetypes.Count, Is.EqualTo(_world.Archetypes.Count));
61 |
62 | // Are archetypes equal?
63 | for (var index = 0; index < _world.Archetypes.Count; index++)
64 | {
65 | var archetype = _world.Archetypes[index];
66 | var newArchetype = newWorld.Archetypes[index];
67 |
68 | That(archetype.ChunkCapacity, Is.EqualTo(newArchetype.ChunkCapacity));
69 | That(archetype.EntityCount, Is.EqualTo(newArchetype.EntityCount));
70 | }
71 |
72 | // Are entities equal?
73 | var entities = new Entity[_world.Size];
74 | _world.GetEntities(new QueryDescription().WithNone(), entities.AsSpan());
75 |
76 | var newEntities = new Entity[newWorld.Size];
77 | newWorld.GetEntities(new QueryDescription(), newEntities.AsSpan());
78 |
79 | for (var index = 0; index < entities.Length; index++)
80 | {
81 | var entity = entities[index];
82 | var newEntity = newEntities[index];
83 |
84 | That(entity.Id, Is.EqualTo(newEntity.Id));
85 | That(entity.Get(), Is.EqualTo(newEntity.Get()));
86 | That(entity.Get(), Is.EqualTo(newEntity.Get()));
87 | }
88 | }
89 |
90 | ///
91 | /// Checks if an entity is being serialized and deserialized correctly using the .
92 | ///
93 | [Test]
94 | public void BinaryEntitySerialization()
95 | {
96 | var entity = _world.Archetypes[0].GetChunk(0).Entity(0);
97 | var bytes = _binarySerializer.Serialize(_world, entity);
98 |
99 | var newWorld = World.Create();
100 | var newEntity = _binarySerializer.Deserialize(newWorld, bytes);
101 |
102 | That(newEntity.Get(), Is.EqualTo(entity.Get()));
103 | That(newEntity.Get(), Is.EqualTo(entity.Get()));
104 | }
105 |
106 | ///
107 | /// Checks if a world is being serialized and deserialized correctly using the .
108 | ///
109 | [Test]
110 | public void JsonWorldSerialization()
111 | {
112 | var bytes = _jsonSerializer.Serialize(_world);
113 | var newWorld = _jsonSerializer.Deserialize(bytes);
114 |
115 | // Equal in structure?
116 | That(newWorld.Capacity, Is.EqualTo(_world.Capacity));
117 | That(newWorld.Size, Is.EqualTo(_world.Size));
118 | That(newWorld.Archetypes.Count, Is.EqualTo(_world.Archetypes.Count));
119 |
120 | // Are archetypes equal?
121 | for (var index = 0; index < _world.Archetypes.Count; index++)
122 | {
123 | var archetype = _world.Archetypes[index];
124 | var newArchetype = newWorld.Archetypes[index];
125 |
126 | That(archetype.ChunkCapacity, Is.EqualTo(newArchetype.ChunkCapacity));
127 | That(archetype.EntityCount, Is.EqualTo(newArchetype.EntityCount));
128 | }
129 |
130 | // Are entities equal?
131 | var entities = new Entity[_world.Size];
132 | _world.GetEntities(new QueryDescription().WithNone(), entities.AsSpan());
133 |
134 | var newEntities = new Entity[newWorld.Size];
135 | newWorld.GetEntities(new QueryDescription(), newEntities.AsSpan());
136 |
137 | for (var index = 0; index < entities.Length; index++)
138 | {
139 | var entity = entities[index];
140 | var newEntity = newEntities[index];
141 |
142 | That(entity.Id, Is.EqualTo(newEntity.Id));
143 | That(entity.Get(), Is.EqualTo(newEntity.Get()));
144 | That(entity.Get(), Is.EqualTo(newEntity.Get()));
145 | }
146 | }
147 |
148 |
149 | ///
150 | /// Checks if an entity is being serialized and deserialized correctly using the .
151 | ///
152 | [Test]
153 | public void JsonEntitySerialization()
154 | {
155 | var entity = _world.Archetypes[0].GetChunk(0).Entity(0);
156 | var bytes = _jsonSerializer.Serialize(_world, entity);
157 |
158 | var newWorld = World.Create();
159 | var newEntity = _jsonSerializer.Deserialize(newWorld, bytes);
160 |
161 | That(newEntity.Get(), Is.EqualTo(entity.Get()));
162 | That(newEntity.Get(), Is.EqualTo(entity.Get()));
163 | }
164 | }
--------------------------------------------------------------------------------
/Arch.Persistence.Tests/Usings.cs:
--------------------------------------------------------------------------------
1 | global using NUnit.Framework;
--------------------------------------------------------------------------------
/Arch.Persistence/Arch.Persistence.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | enable
5 | enable
6 | net6.0;net7.0;netstandard2.1
7 | 11
8 |
9 | true
10 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
11 | true
12 | snupkg
13 |
14 | Arch.Persistence
15 | A Persistence-Framework for Arch.
16 | Apache2.0
17 | https://github.com/genaray/Arch.Extended
18 | https://github.com/genaray/Arch.Extended.git
19 | git
20 | c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;
21 | Updated to Arch 2.0.0
22 | 2.0.0
23 | en-US
24 |
25 | true
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Arch.Persistence/StreamBufferWriter.cs:
--------------------------------------------------------------------------------
1 | using System.Buffers;
2 |
3 | namespace Arch.Persistence;
4 |
5 | ///
6 | /// The class
7 | /// is a small wrapper around a implementing a .
8 | /// It buffers incoming bytes in an internally stored array and flushes it regulary into the -.
9 | ///
10 | public sealed class StreamBufferWriter : IBufferWriter, IDisposable
11 | {
12 | ///
13 | /// The buffer.
14 | ///
15 | private byte[] _buffer;
16 |
17 | ///
18 | /// The .
19 | ///
20 | private readonly Stream _destination;
21 |
22 | ///
23 | /// If this instance owns the stream.
24 | ///
25 | private readonly bool _ownsStream;
26 |
27 | ///
28 | /// The current position and the amount of total leased bytes.
29 | ///
30 | private int _position, _leased;
31 |
32 | ///
33 | /// Creates a new instance.
34 | ///
35 | /// The .
36 | /// The buffer-size of the .
37 | /// If it owns the stream.
38 | public StreamBufferWriter(Stream destination, int bufferSize = 1024, bool ownsStream = true)
39 | {
40 | const int minBufferSize = 128;
41 | if (bufferSize < minBufferSize)
42 | {
43 | bufferSize = minBufferSize;
44 | }
45 |
46 | _buffer = ArrayPool.Shared.Rent(bufferSize);
47 | _ownsStream = ownsStream;
48 | _destination = destination;
49 | }
50 |
51 | ///
52 | /// Leases an amount of bytes from the .
53 | ///
54 | /// The total amount.
55 | /// The leased amount.
56 | private int Lease(int sizeHint)
57 | {
58 | var available = _buffer.Length - _position;
59 | if (available < sizeHint && _position != 0)
60 | { // try to get more
61 | Flush();
62 | available = _buffer.Length - _position;
63 | }
64 |
65 | _leased = available;
66 | return available;
67 | }
68 |
69 | ///
70 | /// Flushes the buffered bytes to the .
71 | ///
72 | /// If it also should flush the .
73 | public void Flush(bool flushUnderlyingStream = false)
74 | {
75 | if (_position != 0)
76 | {
77 | _destination.Write(_buffer, 0, _position);
78 | _position = 0;
79 | }
80 | if (flushUnderlyingStream)
81 | {
82 | _destination.Flush();
83 | }
84 | }
85 |
86 | ///
87 | /// Advances the buffer, notifies this instance that there was something new written into the memory.
88 | ///
89 | /// The amount of bytes written.
90 | /// Throws if we are out of memory.
91 | void IBufferWriter.Advance(int count)
92 | {
93 | if (count > _leased || count < 0) throw new ArgumentOutOfRangeException(nameof(count));
94 | _position += count;
95 | _leased = 0;
96 | }
97 |
98 | ///
99 | /// Returns a partion of the as a .
100 | ///
101 | /// The total amount.
102 | /// The new instance.
103 | Memory IBufferWriter.GetMemory(int sizeHint)
104 | {
105 | var actual = Lease(sizeHint);
106 | return new Memory(_buffer, _position, actual);
107 | }
108 |
109 | ///
110 | /// Returns a partion of the as a .
111 | ///
112 | /// The total amount.
113 | /// The new instance.
114 | Span IBufferWriter.GetSpan(int sizeHint)
115 | {
116 | var actual = Lease(sizeHint);
117 | return new Span(_buffer, _position, actual);
118 | }
119 |
120 | ///
121 | /// Disposes this instance, flushes and releases all memory.
122 | ///
123 | public void Dispose()
124 | {
125 | Flush(true);
126 |
127 | var tmp = _buffer;
128 | _buffer = null;
129 | ArrayPool.Shared.Return(tmp);
130 |
131 | if (_ownsStream)
132 | {
133 | _destination.Dispose();
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/Arch.Relationships.Tests/Arch.Relationships.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 | false
9 |
10 | Arch.Relationships.Tests
11 |
12 |
13 |
14 | TRACE;
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Arch.Relationships.Tests/Usings.cs:
--------------------------------------------------------------------------------
1 | global using NUnit.Framework;
--------------------------------------------------------------------------------
/Arch.Relationships/Arch.Relationships.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | enable
5 | enable
6 | net7.0;net6.0;netstandard2.1
7 | 11
8 |
9 | true
10 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
11 | true
12 | snupkg
13 |
14 | Arch.Relationships
15 | Simple Entity-Relationships for Arch.
16 | Apache2.0
17 | https://github.com/genaray/Arch.Extended
18 | https://github.com/genaray/Arch.Extended.git
19 | git
20 | c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;
21 | Relationships now use less memory and are serializable.
22 | genaray
23 | 1.0.1
24 | en-US
25 |
26 | true
27 |
28 |
29 |
30 | TRACE;EVENTS
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Arch.Relationships/EntityRelationshipExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.Contracts;
2 | using System.Runtime.CompilerServices;
3 | using Arch.Core;
4 |
5 | namespace Arch.Relationships;
6 |
7 | #if !PURE_ECS
8 |
9 | ///
10 | /// The class
11 | /// stores several methods to forward relationship methods from the to the .
12 | ///
13 | public static class EntityRelationshipExtensions
14 | {
15 |
16 | ///
17 | /// Adds a new relationship to the .
18 | ///
19 | /// The source of the relationship.
20 | /// The target of the relationship.
21 | /// The relationship type.
22 | /// The relationship instance.
23 | public static void AddRelationship(this in Entity source, Entity target, T relationship = default)
24 | {
25 | var world = World.Worlds[source.WorldId];
26 | world.AddRelationship(source, target, relationship);
27 | }
28 |
29 | ///
30 | /// Sets a relationship to the by updating its relationship data.
31 | ///
32 | /// The source of the relationship.
33 | /// The target of the relationship.
34 | /// The relationship type.
35 | /// The relationship instance.
36 | public static void SetRelationship(this in Entity source, Entity target, T relationship = default)
37 | {
38 | var world = World.Worlds[source.WorldId];
39 | world.SetRelationship(source, target, relationship);
40 | }
41 |
42 | ///
43 | /// Checks if an has a certain relationship.
44 | ///
45 | /// The relationship type.
46 | /// The source of the relationship.
47 | /// The target of the relationship.
48 | /// True if it has the desired relationship, otherwise false.
49 | [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
50 | public static bool HasRelationship(this in Entity source, Entity target)
51 | {
52 | var world = World.Worlds[source.WorldId];
53 | return world.HasRelationship(source, target);
54 | }
55 |
56 | ///
57 | /// Checks if an has a certain relationship.
58 | ///
59 | /// The relationship type.
60 | /// The source of the relationship.
61 | /// True if it has the desired relationship, otherwise false.
62 | [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
63 | public static bool HasRelationship(this in Entity source)
64 | {
65 | var world = World.Worlds[source.WorldId];
66 | return world.HasRelationship(source);
67 | }
68 |
69 | ///
70 | /// Returns a relationship of an .
71 | ///
72 | /// The relationship type.
73 | /// The source of the relationship.
74 | /// The target of the relationship.
75 | /// The relationship.
76 | [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
77 | public static T GetRelationship(this in Entity source, Entity target)
78 | {
79 | var world = World.Worlds[source.WorldId];
80 | return world.GetRelationship(source, target);
81 | }
82 |
83 | ///
84 | /// Returns a relationship of an .
85 | ///
86 | /// The relationship type.
87 | /// The source of the relationship.
88 | /// The .
89 | [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
90 | public static ref Relationship GetRelationships(this in Entity source)
91 | {
92 | var world = World.Worlds[source.WorldId];
93 | return ref world.GetRelationships(source);
94 | }
95 |
96 | ///
97 | /// Tries to return an s relationship of the specified type.
98 | /// Will copy the relationship if its a struct.
99 | ///
100 | /// The relationship type.
101 | /// The source of the relationship.
102 | /// The target of the relationship.
103 | /// The found relationship.
104 | /// True if it exists, otherwise false.
105 | [MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
106 | public static bool TryGetRelationship(this in Entity source, Entity target, out T relationship)
107 | {
108 | var world = World.Worlds[source.WorldId];
109 | return world.TryGetRelationship(source, target, out relationship);
110 | }
111 |
112 | ///
113 | /// Removes a relationship from an .
114 | ///
115 | /// The relationship type.
116 | /// The to remove the relationship from.
117 | /// The target of the relationship.
118 | public static void RemoveRelationship(this in Entity source, Entity target)
119 | {
120 | var world = World.Worlds[source.WorldId];
121 | world.RemoveRelationship(source, target);
122 | }
123 | }
124 |
125 | #endif
126 |
--------------------------------------------------------------------------------
/Arch.Relationships/Enumerators.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 | using Arch.Core;
5 | using Arch.Core.Extensions.Dangerous;
6 | using CommunityToolkit.HighPerformance;
7 |
8 | namespace Arch.Relationships;
9 |
10 | ///
11 | /// The struct
12 | /// is a enumerator to enumerate a passed in an efficient way.
13 | ///
14 | ///
15 | ///
16 | public struct SortedListEnumerator
17 | {
18 | private SortedList sortedList;
19 | private int currentIndex;
20 |
21 | public SortedListEnumerator(SortedList list)
22 | {
23 | sortedList = list;
24 | currentIndex = -1;
25 | }
26 |
27 | public KeyValuePair Current
28 | {
29 | get
30 | {
31 | if (currentIndex == -1 || currentIndex >= sortedList.Count)
32 | throw new InvalidOperationException();
33 |
34 | var key = sortedList.Keys[currentIndex];
35 | var value = sortedList.Values[currentIndex];
36 | return new KeyValuePair(key, value);
37 | }
38 | }
39 |
40 | public bool MoveNext()
41 | {
42 | currentIndex++;
43 | return currentIndex < sortedList.Count;
44 | }
45 |
46 | public void Reset()
47 | {
48 | currentIndex = -1;
49 | }
50 | }
--------------------------------------------------------------------------------
/Arch.Relationships/InRelationship.cs:
--------------------------------------------------------------------------------
1 | using Arch.Core;
2 | using Arch.Core.Utils;
3 |
4 | namespace Arch.Relationships;
5 |
6 |
7 | ///
8 | /// The struct
9 | /// represents a reference to a .
10 | /// It sits on an to indicate in which other s it is involved in.
11 | ///
12 | internal readonly struct InRelationship
13 | {
14 | ///
15 | /// The id of the -Component that this points to.
16 | /// Basically the the is in.
17 | /// TODO: Uhmm... how the heck do we convert the Id back to the ?
18 | ///
19 | public readonly int ComponentTypeId;
20 |
21 | ///
22 | /// Creates a new instance.
23 | ///
24 | /// The that represents the relation.
25 | internal InRelationship(ComponentType targetRelation)
26 | {
27 | ComponentTypeId = targetRelation.Id;
28 | }
29 |
30 | ///
31 | /// Creates a new instance.
32 | /// Mostly for binary serialization.
33 | ///
34 | /// The .
35 | internal InRelationship(int componentTypeId)
36 | {
37 | ComponentTypeId = componentTypeId;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Arch.Relationships/Relationship.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using Arch.Core;
3 |
4 | namespace Arch.Relationships;
5 |
6 | ///
7 | /// The interface
8 | /// is an interface that provides all methods required to act as a relationship.
9 | ///
10 | internal interface IRelationship
11 | {
12 | ///
13 | /// The amount of relationships currently in the buffer.
14 | ///
15 | int Count
16 | {
17 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
18 | get;
19 | }
20 |
21 | ///
22 | /// Removes the buffer as a component from the given world and entity.
23 | ///
24 | ///
25 | ///
26 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
27 | internal void Destroy(World world, Entity source);
28 |
29 | ///
30 | /// Removes the relationship targeting from this buffer.
31 | ///
32 | /// The in the relationship to remove.
33 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
34 | void Remove(Entity target);
35 | }
36 |
37 | ///
38 | /// A buffer storing relationships of and .
39 | ///
40 | /// The type of the second relationship element.
41 | public class Relationship : IRelationship
42 | {
43 |
44 | ///
45 | /// Its relations.
46 | ///
47 | internal readonly SortedList Elements;
48 |
49 | ///
50 | /// Initializes a new instance of an .
51 | ///
52 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
53 | internal Relationship()
54 | {
55 | Elements = new SortedList();
56 | }
57 |
58 | ///
59 | /// Initializes a new instance of an .
60 | /// Mostly for binary serialization.
61 | ///
62 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
63 | internal Relationship(SortedList elements)
64 | {
65 | Elements = elements;
66 | }
67 |
68 | ///
69 | int IRelationship.Count
70 | {
71 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
72 | get => Elements.Count;
73 | }
74 |
75 | ///
76 | internal int Count
77 | {
78 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
79 | get => ((IRelationship) this).Count;
80 | }
81 |
82 | ///
83 | /// Adds a relationship to this buffer.
84 | ///
85 | /// The instance of the relationship.
86 | /// The target of the relationship.
87 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
88 | internal void Add(in T relationship, Entity target)
89 | {
90 | Elements.Add(target, relationship);
91 | }
92 |
93 | ///
94 | /// Sets the stored for the given .
95 | ///
96 | /// The .
97 | /// The data to store.
98 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
99 | public void Set(Entity entity, T data = default)
100 | {
101 | Elements[entity] = data;
102 | }
103 |
104 | ///
105 | /// Determines whether the given contains the passed or not.
106 | ///
107 | /// The .
108 | /// True or false.
109 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
110 | public bool Contains(Entity entity)
111 | {
112 | return Elements.ContainsKey(entity);
113 | }
114 |
115 | ///
116 | /// Returns the stored for the given .
117 | ///
118 | /// The .
119 | /// The stored .
120 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
121 | public T Get(Entity entity)
122 | {
123 | return Elements[entity];
124 | }
125 |
126 | ///
127 | /// Returns the stored for the given .
128 | ///
129 | /// The .
130 | /// The stored .
131 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
132 | public bool TryGetValue(Entity entity, out T value)
133 | {
134 | return Elements.TryGetValue(entity, out value);
135 | }
136 |
137 | ///
138 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
139 | void IRelationship.Remove(Entity target)
140 | {
141 | Elements.Remove(target);
142 | }
143 |
144 | ///
145 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
146 | internal void Remove(Entity target)
147 | {
148 | ((IRelationship) this).Remove(target);
149 | }
150 |
151 | ///
152 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
153 | void IRelationship.Destroy(World world, Entity source)
154 | {
155 | world.Remove>(source);
156 | }
157 |
158 | ///
159 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
160 | internal void Destroy(World world, Entity source)
161 | {
162 | ((IRelationship) this).Destroy(world, source);
163 | }
164 |
165 | ///
166 | /// Creates a new .
167 | ///
168 | /// The new .
169 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
170 | public SortedListEnumerator GetEnumerator()
171 | {
172 | return new SortedListEnumerator(Elements);
173 | }
174 | };
175 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.SnapshotTests/Arch.System.SourceGenerator.SnapshotTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0
4 | enable
5 | enable
6 | false
7 | latest
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | all
17 | runtime; build; native; contentfiles; analyzers; buildtransitive
18 |
19 |
20 | all
21 | runtime; build; native; contentfiles; analyzers; buildtransitive
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/.gitignore:
--------------------------------------------------------------------------------
1 | Generated/
2 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/Arch.System.SourceGenerator.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0
4 | enable
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | true
13 |
14 |
15 | all
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 |
18 |
19 | all
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | true
32 | Generated
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/AttributeQuerySystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Arch.Core;
4 | using NUnit.Framework;
5 |
6 | namespace Arch.System.SourceGenerator.Tests;
7 |
8 | ///
9 | /// Tests queries with different attribute combinations.
10 | ///
11 | internal partial class AttributeQuerySystem : BaseTestSystem
12 | {
13 | public AttributeQuerySystem(World world) : base(world) { }
14 |
15 | [Query]
16 | [All(typeof(IntComponentA))]
17 | public void IncrementA(Entity e)
18 | {
19 | ref var a = ref World.Get(e);
20 | a.Value++;
21 | }
22 |
23 | [Query]
24 | [Any(typeof(IntComponentA), typeof(IntComponentB))]
25 | public void IncrementAOrB(Entity e)
26 | {
27 | ref var a = ref World.TryGetRef(e, out bool aExists);
28 | ref var b = ref World.TryGetRef(e, out bool bExists);
29 |
30 | if (aExists)
31 | {
32 | a.Value++;
33 | }
34 |
35 | if (bExists)
36 | {
37 | b.Value++;
38 | }
39 | }
40 |
41 | [Query]
42 | [Any(typeof(IntComponentA), typeof(IntComponentB))]
43 | [None(typeof(IntComponentC))]
44 | public void IncrementAOrBNotC(Entity e)
45 | {
46 | ref var a = ref World.TryGetRef(e, out bool aExists);
47 | ref var b = ref World.TryGetRef(e, out bool bExists);
48 |
49 | if (aExists)
50 | {
51 | a.Value++;
52 | }
53 |
54 | if (bExists)
55 | {
56 | b.Value++;
57 | }
58 | }
59 |
60 | [Query]
61 | [All(typeof(IntComponentA), typeof(IntComponentB))]
62 | public void IncrementAAndB(Entity e)
63 | {
64 | ref var a = ref World.Get(e);
65 | a.Value++;
66 | ref var b = ref World.Get(e);
67 | b.Value++;
68 | }
69 |
70 | [Query]
71 | [All(typeof(IntComponentA))]
72 | [None(typeof(IntComponentB))]
73 | public void IncrementANotB(Entity e)
74 | {
75 | ref var a = ref World.Get(e);
76 | a.Value++;
77 | }
78 |
79 | [Query]
80 | [Exclusive(typeof(IntComponentA), typeof(IntComponentB))]
81 | public void IncrementAAndBExclusive(Entity e)
82 | {
83 | ref var a = ref World.Get(e);
84 | a.Value++;
85 | ref var b = ref World.Get(e);
86 | b.Value++;
87 | }
88 |
89 | private (Entity Entity, Dictionary ComponentValues)[]
90 | _expectedComponentValues = Array.Empty<(Entity, Dictionary)>();
91 |
92 | public override void Setup()
93 | {
94 | _expectedComponentValues = new []
95 | {
96 | (World.Create(new IntComponentA()),
97 | new Dictionary { { typeof(IntComponentA), 0 } }),
98 | (World.Create(new IntComponentB()),
99 | new Dictionary { { typeof(IntComponentB), 0 } }),
100 | (World.Create(new IntComponentA(), new IntComponentB()),
101 | new Dictionary { { typeof(IntComponentA), 0 }, { typeof(IntComponentB), 0 } }),
102 | (World.Create(new IntComponentA(), new IntComponentB(), new IntComponentC()),
103 | new Dictionary { { typeof(IntComponentA), 0 }, { typeof(IntComponentB), 0 }, { typeof(IntComponentC), 0 } })
104 | };
105 | }
106 |
107 | private void TestExpectedValues()
108 | {
109 | foreach (var (e, values) in _expectedComponentValues)
110 | {
111 | foreach (var (type, expectedValue) in values)
112 | {
113 | var component = World.Get(e, type) as IIntComponent;
114 | Assert.That(component, Is.Not.Null);
115 | Assert.That(component.Value, Is.EqualTo(expectedValue));
116 | }
117 | }
118 | }
119 |
120 | public override void Update(in int t)
121 | {
122 | TestExpectedValues();
123 |
124 | IncrementAQuery(World);
125 | _expectedComponentValues[0].ComponentValues[typeof(IntComponentA)]++;
126 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;
127 | _expectedComponentValues[3].ComponentValues[typeof(IntComponentA)]++;
128 | TestExpectedValues();
129 |
130 | IncrementAOrBQuery(World);
131 | _expectedComponentValues[0].ComponentValues[typeof(IntComponentA)]++;
132 | _expectedComponentValues[1].ComponentValues[typeof(IntComponentB)]++;
133 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;
134 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentB)]++;
135 | _expectedComponentValues[3].ComponentValues[typeof(IntComponentA)]++;
136 | _expectedComponentValues[3].ComponentValues[typeof(IntComponentB)]++;
137 | TestExpectedValues();
138 |
139 | IncrementAOrBNotCQuery(World);
140 | _expectedComponentValues[0].ComponentValues[typeof(IntComponentA)]++;
141 | _expectedComponentValues[1].ComponentValues[typeof(IntComponentB)]++;
142 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;
143 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentB)]++;
144 | TestExpectedValues();
145 |
146 | IncrementAAndBQuery(World);
147 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;
148 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentB)]++;
149 | _expectedComponentValues[3].ComponentValues[typeof(IntComponentA)]++;
150 | _expectedComponentValues[3].ComponentValues[typeof(IntComponentB)]++;
151 | TestExpectedValues();
152 |
153 | IncrementANotBQuery(World);
154 | _expectedComponentValues[0].ComponentValues[typeof(IntComponentA)]++;
155 | TestExpectedValues();
156 |
157 | IncrementAAndBExclusiveQuery(World);
158 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;
159 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentB)]++;
160 | TestExpectedValues();
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/ExpectedGeneration/AttributeQuerySystem.IncrementA(Entity).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class AttributeQuerySystem
14 | {
15 | private QueryDescription IncrementA_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private World? _IncrementA_Initialized;
17 | private Query? _IncrementA_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public void IncrementAQuery(World world)
20 | {
21 | if (!ReferenceEquals(_IncrementA_Initialized, world))
22 | {
23 | _IncrementA_Query = world.Query(in IncrementA_QueryDescription);
24 | _IncrementA_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _IncrementA_Query)
28 | {
29 | ref var entityFirstElement = ref chunk.Entity(0);
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);
33 | IncrementA(@e);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/ExpectedGeneration/AttributeQuerySystem.IncrementAAndB(Entity).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class AttributeQuerySystem
14 | {
15 | private QueryDescription IncrementAAndB_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private World? _IncrementAAndB_Initialized;
17 | private Query? _IncrementAAndB_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public void IncrementAAndBQuery(World world)
20 | {
21 | if (!ReferenceEquals(_IncrementAAndB_Initialized, world))
22 | {
23 | _IncrementAAndB_Query = world.Query(in IncrementAAndB_QueryDescription);
24 | _IncrementAAndB_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _IncrementAAndB_Query)
28 | {
29 | ref var entityFirstElement = ref chunk.Entity(0);
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);
33 | IncrementAAndB(@e);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/ExpectedGeneration/AttributeQuerySystem.IncrementAAndBExclusive(Entity).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class AttributeQuerySystem
14 | {
15 | private QueryDescription IncrementAAndBExclusive_QueryDescription = new QueryDescription(all: Signature.Null, any: Signature.Null, none: Signature.Null, exclusive: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)));
16 | private World? _IncrementAAndBExclusive_Initialized;
17 | private Query? _IncrementAAndBExclusive_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public void IncrementAAndBExclusiveQuery(World world)
20 | {
21 | if (!ReferenceEquals(_IncrementAAndBExclusive_Initialized, world))
22 | {
23 | _IncrementAAndBExclusive_Query = world.Query(in IncrementAAndBExclusive_QueryDescription);
24 | _IncrementAAndBExclusive_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _IncrementAAndBExclusive_Query)
28 | {
29 | ref var entityFirstElement = ref chunk.Entity(0);
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);
33 | IncrementAAndBExclusive(@e);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/ExpectedGeneration/AttributeQuerySystem.IncrementANotB(Entity).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class AttributeQuerySystem
14 | {
15 | private QueryDescription IncrementANotB_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), exclusive: Signature.Null);
16 | private World? _IncrementANotB_Initialized;
17 | private Query? _IncrementANotB_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public void IncrementANotBQuery(World world)
20 | {
21 | if (!ReferenceEquals(_IncrementANotB_Initialized, world))
22 | {
23 | _IncrementANotB_Query = world.Query(in IncrementANotB_QueryDescription);
24 | _IncrementANotB_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _IncrementANotB_Query)
28 | {
29 | ref var entityFirstElement = ref chunk.Entity(0);
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);
33 | IncrementANotB(@e);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/ExpectedGeneration/AttributeQuerySystem.IncrementAOrB(Entity).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class AttributeQuerySystem
14 | {
15 | private QueryDescription IncrementAOrB_QueryDescription = new QueryDescription(all: Signature.Null, any: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), none: Signature.Null, exclusive: Signature.Null);
16 | private World? _IncrementAOrB_Initialized;
17 | private Query? _IncrementAOrB_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public void IncrementAOrBQuery(World world)
20 | {
21 | if (!ReferenceEquals(_IncrementAOrB_Initialized, world))
22 | {
23 | _IncrementAOrB_Query = world.Query(in IncrementAOrB_QueryDescription);
24 | _IncrementAOrB_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _IncrementAOrB_Query)
28 | {
29 | ref var entityFirstElement = ref chunk.Entity(0);
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);
33 | IncrementAOrB(@e);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/AttributeQueryCompilation/ExpectedGeneration/AttributeQuerySystem.IncrementAOrBNotC(Entity).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class AttributeQuerySystem
14 | {
15 | private QueryDescription IncrementAOrBNotC_QueryDescription = new QueryDescription(all: Signature.Null, any: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), none: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentC)), exclusive: Signature.Null);
16 | private World? _IncrementAOrBNotC_Initialized;
17 | private Query? _IncrementAOrBNotC_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public void IncrementAOrBNotCQuery(World world)
20 | {
21 | if (!ReferenceEquals(_IncrementAOrBNotC_Initialized, world))
22 | {
23 | _IncrementAOrBNotC_Query = world.Query(in IncrementAOrBNotC_QueryDescription);
24 | _IncrementAOrBNotC_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _IncrementAOrBNotC_Query)
28 | {
29 | ref var entityFirstElement = ref chunk.Entity(0);
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);
33 | IncrementAOrBNotC(@e);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/BasicCompilation/BasicSystem.cs:
--------------------------------------------------------------------------------
1 | using Arch.Core;
2 | using NUnit.Framework;
3 |
4 | namespace Arch.System.SourceGenerator.Tests;
5 |
6 | ///
7 | /// Tests basic query functionality.
8 | ///
9 | internal partial class BasicSystem : BaseTestSystem
10 | {
11 | public BasicSystem(World world) : base(world) { }
12 |
13 | private int _number = 0;
14 | static private int _numberStatic = 0;
15 |
16 | [Query]
17 | public void Basic(IntComponentA _)
18 | {
19 | _number++;
20 | _numberStatic++;
21 | }
22 |
23 | [Query]
24 | public static void BasicStatic(IntComponentA _)
25 | {
26 | _numberStatic++;
27 | }
28 |
29 | public override void Setup()
30 | {
31 | World.Create(new IntComponentA());
32 | }
33 |
34 | public override void Update(in int t)
35 | {
36 | Assert.That(_number, Is.EqualTo(0));
37 | Assert.That(_numberStatic, Is.EqualTo(0));
38 | BasicQuery(World);
39 | Assert.That(_number, Is.EqualTo(1));
40 | Assert.That(_numberStatic, Is.EqualTo(1));
41 | BasicStaticQuery(World);
42 | Assert.That(_number, Is.EqualTo(1));
43 | Assert.That(_numberStatic, Is.EqualTo(2));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/BasicCompilation/ExpectedGeneration/BasicSystem.Basic(IntComponentA).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class BasicSystem
14 | {
15 | private QueryDescription Basic_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private World? _Basic_Initialized;
17 | private Query? _Basic_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public void BasicQuery(World world)
20 | {
21 | if (!ReferenceEquals(_Basic_Initialized, world))
22 | {
23 | _Basic_Query = world.Query(in Basic_QueryDescription);
24 | _Basic_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _Basic_Query)
28 | {
29 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref var @_ = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
33 | Basic(@_);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/BasicCompilation/ExpectedGeneration/BasicSystem.BasicStatic(IntComponentA).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class BasicSystem
14 | {
15 | private static QueryDescription BasicStatic_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _BasicStatic_Initialized;
17 | private static Query? _BasicStatic_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void BasicStaticQuery(World world)
20 | {
21 | if (!ReferenceEquals(_BasicStatic_Initialized, world))
22 | {
23 | _BasicStatic_Query = world.Query(in BasicStatic_QueryDescription);
24 | _BasicStatic_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _BasicStatic_Query)
28 | {
29 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref var @_ = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
33 | BasicStatic(@_);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/DataParamCompilation/DataParamSystem.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using Arch.Core;
3 | using NUnit.Framework;
4 |
5 | namespace Arch.System.SourceGenerator.Tests;
6 |
7 | ///
8 | /// Tests queries using data parameters.
9 | ///
10 | [SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Allow unused params for query headers")]
11 | internal partial class DataParamSystem : BaseTestSystem
12 | {
13 | public DataParamSystem(World world) : base(world) { }
14 |
15 | [Query]
16 | [All(typeof(IntComponentA))]
17 | public static void CountANoParams([Data] ref int count)
18 | {
19 | count++;
20 | }
21 |
22 | [Query]
23 | public static void CountAWithParamsLeft([Data] ref int count, in IntComponentA _)
24 | {
25 | count++;
26 | }
27 |
28 | [Query]
29 | public static void CountAWithParamsRight(in IntComponentA _, [Data] ref int count)
30 | {
31 | count++;
32 | }
33 |
34 | [Query]
35 | public static void CountAWithParamsMiddle(in IntComponentA _, [Data] ref int count, in IntComponentB __)
36 | {
37 | count++;
38 | }
39 |
40 | [Query]
41 | public static void CountATwiceWithParams([Data] ref int count1, in IntComponentA _, [Data] ref int count2, in IntComponentB __)
42 | {
43 | count1++;
44 | count2++;
45 | }
46 |
47 | [Query]
48 | [All(typeof(IntComponentA))]
49 | public static void CountAWithEntityRight(in Entity e, [Data] ref int count)
50 | {
51 | count++;
52 | }
53 |
54 | [Query]
55 | [All(typeof(IntComponentA))]
56 | public static void CountAWithEntityLeft([Data] ref int count, in Entity e)
57 | {
58 | count++;
59 | }
60 |
61 | [Query]
62 | public static void CountAWithEntityAndParamLeft([Data] ref int count, in IntComponentA a, in Entity e)
63 | {
64 | count++;
65 | }
66 |
67 | [Query]
68 | public static void CountAWithEntityAndParamRight(in Entity e, in IntComponentA a, [Data] ref int count)
69 | {
70 | count++;
71 | }
72 |
73 | // compilation fails from https://github.com/genaray/Arch.Extended/issues/89
74 | //[Query]
75 | //public void AssignEntityDataParamRight(in IntComponentA a, [Data] ref Entity outEntity)
76 | //{
77 | // outEntity = _sampleEntity;
78 | //}
79 |
80 | // compilation fails from https://github.com/genaray/Arch.Extended/issues/89
81 | //[Query]
82 | //public void AssignEntityDataParamLeft([Data] ref Entity outEntity, in IntComponentA a)
83 | //{
84 | // outEntity = _sampleEntity;
85 | //}
86 |
87 | [Query]
88 | public static void AssignEntityDataParamWithEntityRight(in Entity e, in IntComponentA a, [Data] ref Entity outEntity)
89 | {
90 | outEntity = e;
91 | }
92 |
93 | // compilation fails from https://github.com/genaray/Arch.Extended/issues/89
94 | //[Query]
95 | //public static void AssignEntityDataParamWithEntityLeft([Data] ref Entity outEntity, in Entity e, in IntComponentA a)
96 | //{
97 | // outEntity = e;
98 | //}
99 |
100 | // Crashes source generator due to ? in filename; see https://github.com/genaray/Arch.Extended/issues/91
101 | //[Query]
102 | //[All(typeof(IntComponentA))]
103 | //public static void CountANullable([Data] ref int? count)
104 | //{
105 | // count ??= 0;
106 | // count++;
107 | //}
108 |
109 | private Entity _sampleEntity;
110 | public override void Setup()
111 | {
112 | _sampleEntity = World.Create(new IntComponentA(), new IntComponentB());
113 | World.Create(new IntComponentA(), new IntComponentB());
114 | }
115 |
116 | public override void Update(in int t)
117 | {
118 | int i = 0;
119 | CountANoParamsQuery(World, ref i);
120 | Assert.That(i, Is.EqualTo(2));
121 |
122 | i = 0;
123 | CountAWithParamsLeftQuery(World, ref i);
124 | Assert.That(i, Is.EqualTo(2));
125 |
126 | i = 0;
127 | CountAWithParamsRightQuery(World, ref i);
128 | Assert.That(i, Is.EqualTo(2));
129 |
130 | i = 0;
131 | CountAWithParamsMiddleQuery(World, ref i);
132 | Assert.That(i, Is.EqualTo(2));
133 |
134 | i = 0;
135 | int i2 = 0;
136 | CountATwiceWithParamsQuery(World, ref i, ref i2);
137 | Assert.Multiple(() =>
138 | {
139 | Assert.That(i, Is.EqualTo(2));
140 | Assert.That(i2, Is.EqualTo(2));
141 | });
142 |
143 | i = 0;
144 | CountAWithEntityRightQuery(World, ref i);
145 | Assert.That(i, Is.EqualTo(2));
146 |
147 | i = 0;
148 | CountAWithEntityLeftQuery(World, ref i);
149 | Assert.That(i, Is.EqualTo(2));
150 |
151 | i = 0;
152 | CountAWithEntityAndParamLeftQuery(World, ref i);
153 | Assert.That(i, Is.EqualTo(2));
154 |
155 | i = 0;
156 | CountAWithEntityAndParamRightQuery(World, ref i);
157 | Assert.That(i, Is.EqualTo(2));
158 |
159 | Entity outEntity = Entity.Null;
160 | //AssignEntityDataParamRightQuery(World, ref outEntity);
161 | //Assert.That(outEntity, Is.EqualTo(_sampleEntity));
162 |
163 | //outEntity = Entity.Null;
164 | //AssignEntityDataParamLeftQuery(World, ref outEntity);
165 | //Assert.That(outEntity, Is.EqualTo(_sampleEntity));
166 |
167 | outEntity = Entity.Null;
168 | AssignEntityDataParamWithEntityRightQuery(World, ref outEntity);
169 | Assert.That(outEntity, Is.Not.EqualTo(Entity.Null));
170 |
171 | //outEntity = Entity.Null;
172 | //AssignEntityDataParamWithEntityLeftQuery(World, ref outEntity);
173 | //Assert.That(outEntity, Is.Not.EqualTo(Entity.Null));
174 |
175 | //int? i3 = null;
176 | //CountANullableQuery(World, ref i3);
177 | //Assert.That(i, Is.EqualTo(2));
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.AssignEntityDataParamWithEntityRight(in Entity, in IntComponentA, ref Entity).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class DataParamSystem
14 | {
15 | private static QueryDescription AssignEntityDataParamWithEntityRight_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _AssignEntityDataParamWithEntityRight_Initialized;
17 | private static Query? _AssignEntityDataParamWithEntityRight_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void AssignEntityDataParamWithEntityRightQuery(World world, ref Arch.Core.Entity @outentity)
20 | {
21 | if (!ReferenceEquals(_AssignEntityDataParamWithEntityRight_Initialized, world))
22 | {
23 | _AssignEntityDataParamWithEntityRight_Query = world.Query(in AssignEntityDataParamWithEntityRight_QueryDescription);
24 | _AssignEntityDataParamWithEntityRight_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _AssignEntityDataParamWithEntityRight_Query)
28 | {
29 | ref var entityFirstElement = ref chunk.Entity(0);
30 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
31 | foreach (var entityIndex in chunk)
32 | {
33 | ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);
34 | ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
35 | AssignEntityDataParamWithEntityRight(in @e, in @a, ref @outentity);
36 | }
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountANoParams(ref int).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class DataParamSystem
14 | {
15 | private static QueryDescription CountANoParams_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _CountANoParams_Initialized;
17 | private static Query? _CountANoParams_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void CountANoParamsQuery(World world, ref int @count)
20 | {
21 | if (!ReferenceEquals(_CountANoParams_Initialized, world))
22 | {
23 | _CountANoParams_Query = world.Query(in CountANoParams_QueryDescription);
24 | _CountANoParams_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _CountANoParams_Query)
28 | {
29 | foreach (var entityIndex in chunk)
30 | {
31 | CountANoParams(ref @count);
32 | }
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountATwiceWithParams(ref int, in IntComponentA, ref int, in IntComponentB).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class DataParamSystem
14 | {
15 | private static QueryDescription CountATwiceWithParams_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _CountATwiceWithParams_Initialized;
17 | private static Query? _CountATwiceWithParams_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void CountATwiceWithParamsQuery(World world, ref int @count1, ref int @count2)
20 | {
21 | if (!ReferenceEquals(_CountATwiceWithParams_Initialized, world))
22 | {
23 | _CountATwiceWithParams_Query = world.Query(in CountATwiceWithParams_QueryDescription);
24 | _CountATwiceWithParams_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _CountATwiceWithParams_Query)
28 | {
29 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
30 | ref var @intcomponentbFirstElement = ref chunk.GetFirst();
31 | foreach (var entityIndex in chunk)
32 | {
33 | ref var @_ = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
34 | ref var @__ = ref Unsafe.Add(ref intcomponentbFirstElement, entityIndex);
35 | CountATwiceWithParams(ref @count1, in @_, ref @count2, in @__);
36 | }
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithEntityAndParamLeft(ref int, in IntComponentA, in Entity).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class DataParamSystem
14 | {
15 | private static QueryDescription CountAWithEntityAndParamLeft_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _CountAWithEntityAndParamLeft_Initialized;
17 | private static Query? _CountAWithEntityAndParamLeft_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void CountAWithEntityAndParamLeftQuery(World world, ref int @count)
20 | {
21 | if (!ReferenceEquals(_CountAWithEntityAndParamLeft_Initialized, world))
22 | {
23 | _CountAWithEntityAndParamLeft_Query = world.Query(in CountAWithEntityAndParamLeft_QueryDescription);
24 | _CountAWithEntityAndParamLeft_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _CountAWithEntityAndParamLeft_Query)
28 | {
29 | ref var entityFirstElement = ref chunk.Entity(0);
30 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
31 | foreach (var entityIndex in chunk)
32 | {
33 | ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);
34 | ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
35 | CountAWithEntityAndParamLeft(ref @count, in @a, in @e);
36 | }
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithEntityAndParamRight(in Entity, in IntComponentA, ref int).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class DataParamSystem
14 | {
15 | private static QueryDescription CountAWithEntityAndParamRight_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _CountAWithEntityAndParamRight_Initialized;
17 | private static Query? _CountAWithEntityAndParamRight_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void CountAWithEntityAndParamRightQuery(World world, ref int @count)
20 | {
21 | if (!ReferenceEquals(_CountAWithEntityAndParamRight_Initialized, world))
22 | {
23 | _CountAWithEntityAndParamRight_Query = world.Query(in CountAWithEntityAndParamRight_QueryDescription);
24 | _CountAWithEntityAndParamRight_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _CountAWithEntityAndParamRight_Query)
28 | {
29 | ref var entityFirstElement = ref chunk.Entity(0);
30 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
31 | foreach (var entityIndex in chunk)
32 | {
33 | ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);
34 | ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
35 | CountAWithEntityAndParamRight(in @e, in @a, ref @count);
36 | }
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithEntityLeft(ref int, in Entity).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class DataParamSystem
14 | {
15 | private static QueryDescription CountAWithEntityLeft_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _CountAWithEntityLeft_Initialized;
17 | private static Query? _CountAWithEntityLeft_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void CountAWithEntityLeftQuery(World world, ref int @count)
20 | {
21 | if (!ReferenceEquals(_CountAWithEntityLeft_Initialized, world))
22 | {
23 | _CountAWithEntityLeft_Query = world.Query(in CountAWithEntityLeft_QueryDescription);
24 | _CountAWithEntityLeft_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _CountAWithEntityLeft_Query)
28 | {
29 | ref var entityFirstElement = ref chunk.Entity(0);
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);
33 | CountAWithEntityLeft(ref @count, in @e);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithEntityRight(in Entity, ref int).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class DataParamSystem
14 | {
15 | private static QueryDescription CountAWithEntityRight_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _CountAWithEntityRight_Initialized;
17 | private static Query? _CountAWithEntityRight_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void CountAWithEntityRightQuery(World world, ref int @count)
20 | {
21 | if (!ReferenceEquals(_CountAWithEntityRight_Initialized, world))
22 | {
23 | _CountAWithEntityRight_Query = world.Query(in CountAWithEntityRight_QueryDescription);
24 | _CountAWithEntityRight_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _CountAWithEntityRight_Query)
28 | {
29 | ref var entityFirstElement = ref chunk.Entity(0);
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref readonly var e = ref Unsafe.Add(ref entityFirstElement, entityIndex);
33 | CountAWithEntityRight(in @e, ref @count);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithParamsLeft(ref int, in IntComponentA).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class DataParamSystem
14 | {
15 | private static QueryDescription CountAWithParamsLeft_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _CountAWithParamsLeft_Initialized;
17 | private static Query? _CountAWithParamsLeft_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void CountAWithParamsLeftQuery(World world, ref int @count)
20 | {
21 | if (!ReferenceEquals(_CountAWithParamsLeft_Initialized, world))
22 | {
23 | _CountAWithParamsLeft_Query = world.Query(in CountAWithParamsLeft_QueryDescription);
24 | _CountAWithParamsLeft_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _CountAWithParamsLeft_Query)
28 | {
29 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref var @_ = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
33 | CountAWithParamsLeft(ref @count, in @_);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithParamsMiddle(in IntComponentA, ref int, in IntComponentB).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class DataParamSystem
14 | {
15 | private static QueryDescription CountAWithParamsMiddle_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _CountAWithParamsMiddle_Initialized;
17 | private static Query? _CountAWithParamsMiddle_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void CountAWithParamsMiddleQuery(World world, ref int @count)
20 | {
21 | if (!ReferenceEquals(_CountAWithParamsMiddle_Initialized, world))
22 | {
23 | _CountAWithParamsMiddle_Query = world.Query(in CountAWithParamsMiddle_QueryDescription);
24 | _CountAWithParamsMiddle_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _CountAWithParamsMiddle_Query)
28 | {
29 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
30 | ref var @intcomponentbFirstElement = ref chunk.GetFirst();
31 | foreach (var entityIndex in chunk)
32 | {
33 | ref var @_ = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
34 | ref var @__ = ref Unsafe.Add(ref intcomponentbFirstElement, entityIndex);
35 | CountAWithParamsMiddle(in @_, ref @count, in @__);
36 | }
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/DataParamCompilation/ExpectedGeneration/DataParamSystem.CountAWithParamsRight(in IntComponentA, ref int).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class DataParamSystem
14 | {
15 | private static QueryDescription CountAWithParamsRight_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _CountAWithParamsRight_Initialized;
17 | private static Query? _CountAWithParamsRight_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void CountAWithParamsRightQuery(World world, ref int @count)
20 | {
21 | if (!ReferenceEquals(_CountAWithParamsRight_Initialized, world))
22 | {
23 | _CountAWithParamsRight_Query = world.Query(in CountAWithParamsRight_QueryDescription);
24 | _CountAWithParamsRight_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _CountAWithParamsRight_Query)
28 | {
29 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref var @_ = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
33 | CountAWithParamsRight(in @_, ref @count);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/GeneratedUpdateCompilation/ExpectedGeneration/GeneratedUpdateSystem.AutoRunA().g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class GeneratedUpdateSystem
14 | {
15 | private QueryDescription AutoRunA_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private World? _AutoRunA_Initialized;
17 | private Query? _AutoRunA_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public void AutoRunAQuery(World world)
20 | {
21 | if (!ReferenceEquals(_AutoRunA_Initialized, world))
22 | {
23 | _AutoRunA_Query = world.Query(in AutoRunA_QueryDescription);
24 | _AutoRunA_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _AutoRunA_Query)
28 | {
29 | foreach (var entityIndex in chunk)
30 | {
31 | AutoRunA();
32 | }
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/GeneratedUpdateCompilation/ExpectedGeneration/GeneratedUpdateSystem.AutoRunB().g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class GeneratedUpdateSystem
14 | {
15 | private QueryDescription AutoRunB_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private World? _AutoRunB_Initialized;
17 | private Query? _AutoRunB_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public void AutoRunBQuery(World world)
20 | {
21 | if (!ReferenceEquals(_AutoRunB_Initialized, world))
22 | {
23 | _AutoRunB_Query = world.Query(in AutoRunB_QueryDescription);
24 | _AutoRunB_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _AutoRunB_Query)
28 | {
29 | foreach (var entityIndex in chunk)
30 | {
31 | AutoRunB();
32 | }
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/GeneratedUpdateCompilation/ExpectedGeneration/GeneratedUpdateSystem.g.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using System.Runtime.InteropServices;
3 | using System;
4 |
5 | namespace Arch.System.SourceGenerator.Tests
6 | {
7 | partial class GeneratedUpdateSystem
8 | {
9 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
10 | public override void Update(in int data)
11 | {
12 | AutoRunAQuery(World);
13 | AutoRunBQuery(World);
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/GeneratedUpdateCompilation/GeneratedUpdateSystem.cs:
--------------------------------------------------------------------------------
1 | using Arch.Core;
2 | using NUnit.Framework;
3 |
4 | namespace Arch.System.SourceGenerator.Tests;
5 |
6 | ///
7 | /// Tests the auto-generated method.
8 | ///
9 | internal partial class GeneratedUpdateSystem : BaseTestSystem
10 | {
11 | public GeneratedUpdateSystem(World world) : base(world) { }
12 |
13 | private int _number = 0;
14 |
15 | [Query]
16 | [All(typeof(IntComponentA))]
17 | public void AutoRunA()
18 | {
19 | Assert.That(_number, Is.EqualTo(0));
20 | _number++;
21 | }
22 |
23 | [Query]
24 | [All(typeof(IntComponentA))]
25 | public void AutoRunB()
26 | {
27 | Assert.That(_number, Is.EqualTo(1));
28 | _number++;
29 | }
30 |
31 | public override void Setup()
32 | {
33 | World.Create(new IntComponentA());
34 | }
35 |
36 | public override void Test()
37 | {
38 | base.Test();
39 | Assert.That(_number, Is.EqualTo(2));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/ParamQueryCompilation/ExpectedGeneration/ParamQuerySystem.IncrementA(ref IntComponentA).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class ParamQuerySystem
14 | {
15 | private static QueryDescription IncrementA_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _IncrementA_Initialized;
17 | private static Query? _IncrementA_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void IncrementAQuery(World world)
20 | {
21 | if (!ReferenceEquals(_IncrementA_Initialized, world))
22 | {
23 | _IncrementA_Query = world.Query(in IncrementA_QueryDescription);
24 | _IncrementA_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _IncrementA_Query)
28 | {
29 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
33 | IncrementA(ref @a);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/ParamQueryCompilation/ExpectedGeneration/ParamQuerySystem.IncrementAAndB(ref IntComponentA, ref IntComponentB).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class ParamQuerySystem
14 | {
15 | private static QueryDescription IncrementAAndB_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _IncrementAAndB_Initialized;
17 | private static Query? _IncrementAAndB_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void IncrementAAndBQuery(World world)
20 | {
21 | if (!ReferenceEquals(_IncrementAAndB_Initialized, world))
22 | {
23 | _IncrementAAndB_Query = world.Query(in IncrementAAndB_QueryDescription);
24 | _IncrementAAndB_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _IncrementAAndB_Query)
28 | {
29 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
30 | ref var @intcomponentbFirstElement = ref chunk.GetFirst();
31 | foreach (var entityIndex in chunk)
32 | {
33 | ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
34 | ref var @b = ref Unsafe.Add(ref intcomponentbFirstElement, entityIndex);
35 | IncrementAAndB(ref @a, ref @b);
36 | }
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/ParamQueryCompilation/ExpectedGeneration/ParamQuerySystem.IncrementANotC(ref IntComponentA).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class ParamQuerySystem
14 | {
15 | private static QueryDescription IncrementANotC_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA)), any: Signature.Null, none: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentC)), exclusive: Signature.Null);
16 | private static World? _IncrementANotC_Initialized;
17 | private static Query? _IncrementANotC_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void IncrementANotCQuery(World world)
20 | {
21 | if (!ReferenceEquals(_IncrementANotC_Initialized, world))
22 | {
23 | _IncrementANotC_Query = world.Query(in IncrementANotC_QueryDescription);
24 | _IncrementANotC_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _IncrementANotC_Query)
28 | {
29 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
30 | foreach (var entityIndex in chunk)
31 | {
32 | ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
33 | IncrementANotC(ref @a);
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/ParamQueryCompilation/ExpectedGeneration/ParamQuerySystem.IncrementOnlyAWithB(ref IntComponentA, in IntComponentB).g.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using Arch.Core;
6 | using Arch.Core.Extensions;
7 | using Arch.Core.Utils;
8 | using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;
9 | using Component = Arch.Core.Component;
10 |
11 | namespace Arch.System.SourceGenerator.Tests
12 | {
13 | partial class ParamQuerySystem
14 | {
15 | private static QueryDescription IncrementOnlyAWithB_QueryDescription = new QueryDescription(all: new Signature(typeof(global::Arch.System.SourceGenerator.Tests.IntComponentA), typeof(global::Arch.System.SourceGenerator.Tests.IntComponentB)), any: Signature.Null, none: Signature.Null, exclusive: Signature.Null);
16 | private static World? _IncrementOnlyAWithB_Initialized;
17 | private static Query? _IncrementOnlyAWithB_Query;
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static void IncrementOnlyAWithBQuery(World world)
20 | {
21 | if (!ReferenceEquals(_IncrementOnlyAWithB_Initialized, world))
22 | {
23 | _IncrementOnlyAWithB_Query = world.Query(in IncrementOnlyAWithB_QueryDescription);
24 | _IncrementOnlyAWithB_Initialized = world;
25 | }
26 |
27 | foreach (ref var chunk in _IncrementOnlyAWithB_Query)
28 | {
29 | ref var @intcomponentaFirstElement = ref chunk.GetFirst();
30 | ref var @intcomponentbFirstElement = ref chunk.GetFirst();
31 | foreach (var entityIndex in chunk)
32 | {
33 | ref var @a = ref Unsafe.Add(ref intcomponentaFirstElement, entityIndex);
34 | ref var @_ = ref Unsafe.Add(ref intcomponentbFirstElement, entityIndex);
35 | IncrementOnlyAWithB(ref @a, in @_);
36 | }
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/ParamQueryCompilation/ParamQuerySystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Arch.Core;
4 | using NUnit.Framework;
5 |
6 | namespace Arch.System.SourceGenerator.Tests;
7 |
8 | ///
9 | /// Tests queries using parameters.
10 | ///
11 | internal partial class ParamQuerySystem : BaseTestSystem
12 | {
13 | public ParamQuerySystem(World world) : base(world) { }
14 |
15 | [Query]
16 | public static void IncrementA(ref IntComponentA a)
17 | {
18 | a.Value++;
19 | }
20 |
21 | [Query]
22 | public static void IncrementOnlyAWithB(ref IntComponentA a, in IntComponentB _)
23 | {
24 | a.Value++;
25 | }
26 |
27 | [Query]
28 | [None(typeof(IntComponentC))]
29 | public static void IncrementANotC(ref IntComponentA a)
30 | {
31 | a.Value++;
32 | }
33 |
34 | [Query]
35 | public static void IncrementAAndB(ref IntComponentA a, ref IntComponentB b)
36 | {
37 | a.Value++;
38 | b.Value++;
39 | }
40 |
41 | private (Entity, Dictionary ComponentValues)[] _expectedComponentValues
42 | = Array.Empty<(Entity, Dictionary ComponentValues)>();
43 |
44 | public override void Setup()
45 | {
46 | _expectedComponentValues = new[]
47 | {
48 | (World.Create(new IntComponentA()),
49 | new Dictionary { { typeof(IntComponentA), 0 } }),
50 | (World.Create(new IntComponentB()),
51 | new Dictionary { { typeof(IntComponentB), 0 } }),
52 | (World.Create(new IntComponentA(), new IntComponentB()),
53 | new Dictionary { { typeof(IntComponentA), 0 }, { typeof(IntComponentB), 0 } }),
54 | (World.Create(new IntComponentA(), new IntComponentB(), new IntComponentC()),
55 | new Dictionary { { typeof(IntComponentA), 0 }, { typeof(IntComponentB), 0 }, { typeof(IntComponentC), 0 } })
56 | };
57 | }
58 |
59 | private void TestExpectedValues()
60 | {
61 | foreach (var (e, values) in _expectedComponentValues)
62 | {
63 | foreach (var (type, expectedValue) in values)
64 | {
65 | var component = World.Get(e, type) as IIntComponent;
66 | Assert.That(component, Is.Not.Null);
67 | Assert.That(component.Value, Is.EqualTo(expectedValue));
68 | }
69 | }
70 | }
71 |
72 | public override void Update(in int t)
73 | {
74 | TestExpectedValues();
75 |
76 | IncrementAQuery(World);
77 | _expectedComponentValues[0].ComponentValues[typeof(IntComponentA)]++;
78 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;
79 | _expectedComponentValues[3].ComponentValues[typeof(IntComponentA)]++;
80 | TestExpectedValues();
81 |
82 | IncrementOnlyAWithBQuery(World);
83 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;
84 | _expectedComponentValues[3].ComponentValues[typeof(IntComponentA)]++;
85 | TestExpectedValues();
86 |
87 | IncrementANotCQuery(World);
88 | _expectedComponentValues[0].ComponentValues[typeof(IntComponentA)]++;
89 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;
90 | TestExpectedValues();
91 |
92 | IncrementAAndBQuery(World);
93 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentA)]++;
94 | _expectedComponentValues[2].ComponentValues[typeof(IntComponentB)]++;
95 | _expectedComponentValues[3].ComponentValues[typeof(IntComponentA)]++;
96 | _expectedComponentValues[3].ComponentValues[typeof(IntComponentB)]++;
97 | TestExpectedValues();
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/Shared/BaseTestSystem.cs:
--------------------------------------------------------------------------------
1 | using Arch.Core;
2 |
3 | namespace Arch.System.SourceGenerator.Tests;
4 |
5 | ///
6 | /// Provides a base class for test systems. This must be included in the compilation to ensure that the system is generated correctly.
7 | ///
8 | /// The world instance to which the system will be attached.
9 | internal abstract class BaseTestSystem : BaseSystem
10 | {
11 | protected BaseTestSystem(World world) : base(world) { }
12 |
13 | ///
14 | /// Sets up the system for testing. Create entities, components, and any other necessary state.
15 | ///
16 | public abstract void Setup();
17 |
18 | ///
19 | /// Runs the test logic for the system. By default, it simply calls the update pipeline.
20 | ///
21 | public virtual void Test()
22 | {
23 | BeforeUpdate(0);
24 | Update(0);
25 | AfterUpdate(0);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/Shared/IntComponents.cs:
--------------------------------------------------------------------------------
1 | namespace Arch.System.SourceGenerator.Tests;
2 |
3 | #pragma warning disable CS0649 // Allow fields to be unassigned for testing purposes
4 | internal interface IIntComponent
5 | {
6 | int Value { get; }
7 | }
8 |
9 | internal struct IntComponentA : IIntComponent
10 | {
11 | public int Value;
12 |
13 | readonly int IIntComponent.Value
14 | {
15 | get => Value;
16 | }
17 | }
18 |
19 | internal struct IntComponentB : IIntComponent
20 | {
21 | public int Value;
22 |
23 | readonly int IIntComponent.Value
24 | {
25 | get => Value;
26 | }
27 | }
28 |
29 | internal struct IntComponentC : IIntComponent
30 | {
31 | public int Value;
32 |
33 | readonly int IIntComponent.Value
34 | {
35 | get => Value;
36 | }
37 | }
38 |
39 | internal struct IntComponentD : IIntComponent
40 | {
41 | public int Value;
42 |
43 | readonly int IIntComponent.Value
44 | {
45 | get => Value;
46 | }
47 | }
48 |
49 | #pragma warning restore CS0649
50 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator.Tests/SystemsTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Arch.Core;
3 | using NUnit.Framework;
4 |
5 | namespace Arch.System.SourceGenerator.Tests;
6 |
7 | ///
8 | /// Runs tests for systems in each compilation.
9 | /// Note that the compilation is shared across all tests, so the systems are not isolated.
10 | /// As a result, the tests may not be completely independent. However, they are easier to debug.
11 | /// Separately, the same tests are run in isolation in the Arch.System.SourceGenerator.Tests project.
12 | ///
13 | [TestFixture]
14 | internal sealed class SystemsTest
15 | {
16 | ///
17 | /// Tests a system by creating it and running its update method.
18 | ///
19 | ///
20 | /// The type of the system to test, which must inherit from BaseSystem and must have a constructor that takes a World parameter.
21 | ///
22 | private static void TestSystem() where T : BaseTestSystem
23 | {
24 | using var world = World.Create();
25 | var system = Activator.CreateInstance(typeof(T), world) as T;
26 | Assert.That(system, Is.Not.Null,
27 | $"System instance {typeof(T).Name} should not be null. Ensure it has a constructor that takes a single World param.");
28 | system.Setup();
29 | system.Test();
30 | }
31 |
32 | [Test]
33 | public void BasicCompilation()
34 | {
35 | TestSystem();
36 | }
37 |
38 | [Test]
39 | public void AttributeQueryCompilation()
40 | {
41 | TestSystem();
42 | }
43 |
44 | [Test]
45 | public void ParamQueryCompilation()
46 | {
47 | TestSystem();
48 | }
49 |
50 | [Test]
51 | public void DataParamCompilation()
52 | {
53 | TestSystem();
54 | }
55 |
56 | [Test]
57 | public void GeneratedUpdateCompilation()
58 | {
59 | TestSystem();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator/Arch.System.SourceGenerator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | enable
6 | enable
7 | latest
8 |
9 | true
10 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
11 | true
12 | snupkg
13 |
14 | Arch.System.SourceGenerator
15 | Arch.System.SourceGenerator
16 | 2.1.0
17 | genaray
18 | Apache-2.0
19 | A source generator for arch.system.
20 | Updated to fit Arch 2.1.0-beta and upwards.
21 | c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;
22 |
23 | https://github.com/genaray/Arch.Extended
24 | https://github.com/genaray/Arch.Extended.git
25 | git
26 | true
27 |
28 | 12
29 | true
30 | Apache2.0
31 |
32 | en-US
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator/Extensions/IMethodSymbolExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 |
3 | namespace Arch.System.SourceGenerator;
4 |
5 | public static class IMethodSymbolExtensions
6 | {
7 |
8 | ///
9 | /// Searches attributes of a and returns the first one found.
10 | ///
11 | /// The instance.
12 | /// The attributes name.
13 | /// The attribute wrapped in an .
14 | public static AttributeData GetAttributeData(this IMethodSymbol ms, string name)
15 | {
16 | foreach (var attribute in ms.GetAttributes())
17 | {
18 | var classSymbol = attribute.AttributeClass;
19 | if(!classSymbol.Name.Contains(name)) continue;
20 |
21 | return attribute;
22 | }
23 |
24 | return default;
25 | }
26 |
27 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator/Extensions/StringBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 | using System.Text;
3 | using Microsoft.CodeAnalysis;
4 |
5 | namespace Arch.System.SourceGenerator;
6 |
7 | public static class CommonUtils
8 | {
9 |
10 | ///
11 | /// Convert a to its code string equivalent.
12 | ///
13 | /// The .
14 | /// The code string equivalent.
15 | public static string RefKindToString(RefKind refKind)
16 | {
17 | switch (refKind)
18 | {
19 | case RefKind.None:
20 | return "";
21 | case RefKind.Ref:
22 | return "ref";
23 | case RefKind.In:
24 | return "in";
25 | case RefKind.Out:
26 | return "out";
27 | }
28 | return null;
29 | }
30 |
31 | ///
32 | /// Creates a list of generic type parameters separated by a simple comma.
33 | /// T0,T1,..TN
34 | ///
35 | /// The instance.
36 | /// The amount of generic type parameters.
37 | ///
38 | public static StringBuilder GenericsWithoutBrackets(this StringBuilder sb, int amount)
39 | {
40 | for (var i = 0; i < amount; i++)
41 | sb.Append($"T{i},");
42 | if (sb.Length > 0) sb.Length -= 1;
43 |
44 | return sb;
45 | }
46 |
47 | ///
48 | /// Creates a list of generic type parameters types separated by a simple comma.
49 | /// typeof(T0),typeof(T1),..typeof(TN)
50 | ///
51 | /// The instance.
52 | /// The amount of generic type parameters.
53 | ///
54 | public static StringBuilder GenericsToTypeArray(this StringBuilder sb, int amount)
55 | {
56 | for (var i = 0; i < amount; i++)
57 | sb.Append($"typeof(T{i}),");
58 | if (sb.Length > 0) sb.Length -= 1;
59 |
60 | return sb;
61 | }
62 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator/Model.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 |
3 | namespace Arch.System.SourceGenerator;
4 |
5 | ///
6 | /// Represents the BaseSystem that is generated and calls its generated query methods.
7 | ///
8 | public struct BaseSystem
9 | {
10 | ///
11 | /// The namespace its generic is in.
12 | ///
13 | public string GenericTypeNamespace { get; set; }
14 |
15 | ///
16 | /// The namespace this system is in.
17 | ///
18 | public string Namespace { get; set; }
19 |
20 | ///
21 | /// Its name.
22 | ///
23 | public string Name { get; set; }
24 |
25 | ///
26 | /// The generic type.
27 | ///
28 | public ITypeSymbol GenericType { get; set; }
29 |
30 | ///
31 | /// The Query methods this base system calls one after another.
32 | ///
33 | public IList QueryMethods { get; set; }
34 | }
35 |
36 | ///
37 | /// Represents the Query method that is generated.
38 | ///
39 | public struct QueryMethod
40 | {
41 | ///
42 | /// If the class containing this Query method is within the global namespace.
43 | ///
44 | public bool IsGlobalNamespace { get; set; }
45 |
46 | ///
47 | /// The namespace of the method.
48 | ///
49 | public string Namespace { get; set; }
50 |
51 | ///
52 | /// If this method is static.
53 | ///
54 | public bool IsStatic { get; set; }
55 |
56 | ///
57 | /// If this Query method contains an Entity as a param and acesses it.
58 | ///
59 | public bool IsEntityQuery { get; set; }
60 |
61 | ///
62 | /// The name of the class containing this Query method.
63 | ///
64 | public string ClassName { get; set; }
65 |
66 | ///
67 | /// The name of the Query method.
68 | ///
69 | public string MethodName { get; set; }
70 |
71 | ///
72 | /// The entity parameter, if its an entity query.
73 | ///
74 | public IParameterSymbol EntityParameter { get; set; }
75 |
76 | ///
77 | /// All parameters within the query method, not only the components. Also Entity and Data annotated ones.
78 | /// public void Query([Data] float time, in Entity entity, ...);
79 | ///
80 | public IList Parameters { get; set; }
81 |
82 | ///
83 | /// The Components acessed within the query method.
84 | /// public void Query(ref Position pos, in Velocity vel){}
85 | ///
86 | public IList Components { get; set; }
87 |
88 | ///
89 | /// All s mentioned in the All annotation query filter.
90 | /// [All(typeof(Position), typeof(Velocity)] or its generic variant
91 | ///
92 | public IList AllFilteredTypes { get; set; }
93 |
94 | ///
95 | /// All s mentioned in the Any annotation query filter.
96 | /// [Any(typeof(Position), typeof(Velocity)] or its generic variant
97 | ///
98 | public IList AnyFilteredTypes { get; set; }
99 |
100 | ///
101 | /// All s mentioned in the None annotation query filter.
102 | /// [None(typeof(Position), typeof(Velocity)] or its generic variant
103 | ///
104 | public IList NoneFilteredTypes { get; set; }
105 |
106 | ///
107 | /// All s mentioned in the Exclusive annotation query filter.
108 | /// [Exclusive(typeof(Position), typeof(Velocity)] or its generic variant
109 | ///
110 | public IList ExclusiveFilteredTypes { get; set; }
111 | }
--------------------------------------------------------------------------------
/Arch.System.SourceGenerator/SourceGenerator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 | using System.Diagnostics;
3 | using System.Text;
4 | using Microsoft.CodeAnalysis;
5 | using Microsoft.CodeAnalysis.CSharp;
6 | using Microsoft.CodeAnalysis.CSharp.Syntax;
7 | using Microsoft.CodeAnalysis.Text;
8 |
9 | namespace Arch.System.SourceGenerator;
10 |
11 | [Generator]
12 | public class QueryGenerator : IIncrementalGenerator
13 | {
14 | private static Dictionary> _classToMethods { get; set; }
15 |
16 | public void Initialize(IncrementalGeneratorInitializationContext context)
17 | {
18 | //if (!Debugger.IsAttached) Debugger.Launch();
19 |
20 | // Do a simple filter for methods marked with update
21 | IncrementalValuesProvider methodDeclarations = context.SyntaxProvider.CreateSyntaxProvider(
22 | static (s, _) => s is MethodDeclarationSyntax { AttributeLists.Count: > 0 },
23 | static (ctx, _) => GetMethodSymbolIfAttributeof(ctx, "Arch.System.QueryAttribute")
24 | ).Where(static m => m is not null)!; // filter out attributed methods that we don't care about
25 |
26 | // Combine the selected enums with the `Compilation`
27 | IncrementalValueProvider<(Compilation, ImmutableArray)> compilationAndMethods = context.CompilationProvider.Combine(methodDeclarations.WithComparer(Comparer.Instance).Collect());
28 | context.RegisterSourceOutput(compilationAndMethods, static (spc, source) => Generate(source.Item1, source.Item2, spc));
29 | }
30 |
31 | ///
32 | /// Adds a to its class.
33 | /// Stores them in .
34 | ///
35 | /// The which will be added/mapped to its class.
36 | private static void AddMethodToClass(IMethodSymbol methodSymbol)
37 | {
38 | if (!_classToMethods.TryGetValue(methodSymbol.ContainingSymbol, out var list))
39 | {
40 | list = new List();
41 | _classToMethods[methodSymbol.ContainingSymbol] = list;
42 | }
43 | list.Add(methodSymbol);
44 | }
45 |
46 | ///
47 | /// Returns a if its annocated with a attribute of .
48 | ///
49 | /// Its .
50 | /// The attributes name.
51 | ///
52 | private static MethodDeclarationSyntax? GetMethodSymbolIfAttributeof(GeneratorSyntaxContext context, string name)
53 | {
54 | // we know the node is a EnumDeclarationSyntax thanks to IsSyntaxTargetForGeneration
55 | var enumDeclarationSyntax = (MethodDeclarationSyntax)context.Node;
56 |
57 | // loop through all the attributes on the method
58 | foreach (var attributeListSyntax in enumDeclarationSyntax.AttributeLists)
59 | {
60 | foreach (var attributeSyntax in attributeListSyntax.Attributes)
61 | {
62 | if (ModelExtensions.GetSymbolInfo(context.SemanticModel, attributeSyntax).Symbol is not IMethodSymbol attributeSymbol) continue;
63 |
64 | var attributeContainingTypeSymbol = attributeSymbol.ContainingType;
65 | var fullName = attributeContainingTypeSymbol.ToDisplayString();
66 |
67 | // Is the attribute the [EnumExtensions] attribute?
68 | if (fullName != name) continue;
69 | return enumDeclarationSyntax;
70 | }
71 | }
72 |
73 | // we didn't find the attribute we were looking for
74 | return null;
75 | }
76 |
77 | ///
78 | /// Generates queries and partial classes for the found marked methods.
79 | ///
80 | /// The .
81 | /// The array, the methods which we will generate queries and classes for.
82 | /// The .
83 | private static void Generate(Compilation compilation, ImmutableArray methods, SourceProductionContext context)
84 | {
85 | if (methods.IsDefaultOrEmpty) return;
86 |
87 | // Generate Query methods and map them to their classes
88 | _classToMethods = new(512);
89 | foreach (var methodSyntax in methods)
90 | {
91 | IMethodSymbol? methodSymbol = null;
92 | try
93 | {
94 | var semanticModel = compilation.GetSemanticModel(methodSyntax.SyntaxTree);
95 | methodSymbol = ModelExtensions.GetDeclaredSymbol(semanticModel, methodSyntax) as IMethodSymbol;
96 | }
97 | catch
98 | {
99 | //not update,skip
100 | continue;
101 | }
102 |
103 | AddMethodToClass(methodSymbol);
104 |
105 | var sb = new StringBuilder();
106 | var method = sb.AppendQueryMethod(methodSymbol);
107 | var fileName = methodSymbol.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat).Replace('<', '{').Replace('>', '}');
108 | context.AddSource($"{fileName}.g.cs",CSharpSyntaxTree.ParseText(method.ToString()).GetRoot().NormalizeWhitespace().ToFullString());
109 | }
110 |
111 | // Creating class that calls the created methods after another.
112 | foreach (var classToMethod in _classToMethods)
113 | {
114 | var template = new StringBuilder().AppendBaseSystem(classToMethod).ToString();
115 | if (string.IsNullOrEmpty(template)) continue;
116 |
117 | var fileName = (classToMethod.Key as INamedTypeSymbol).ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat).Replace('<', '{').Replace('>', '}');
118 | context.AddSource($"{fileName}.g.cs",
119 | CSharpSyntaxTree.ParseText(template).GetRoot().NormalizeWhitespace().ToFullString());
120 | }
121 | }
122 |
123 | ///
124 | /// Compares s to remove duplicates.
125 | ///
126 | class Comparer : IEqualityComparer
127 | {
128 | public static readonly Comparer Instance = new();
129 |
130 | public bool Equals(MethodDeclarationSyntax x, MethodDeclarationSyntax y)
131 | {
132 | return x.Equals(y);
133 | }
134 |
135 | public int GetHashCode(MethodDeclarationSyntax obj)
136 | {
137 | return obj.GetHashCode();
138 | }
139 | }
140 | }
--------------------------------------------------------------------------------
/Arch.System/Arch.System.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0; net6.0; netstandard2.1
5 | enable
6 |
7 | true
8 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
9 | true
10 | snupkg
11 |
12 | Arch.System
13 | Arch.System
14 | 1.1.0
15 | genaray
16 | Apache-2.0
17 | A systems framework for arch.
18 | Made group extendible.
19 | c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system; arch;
20 |
21 | https://github.com/genaray/Arch.Extended
22 | https://github.com/genaray/Arch.Extended.git
23 | git
24 | true
25 |
26 | 11
27 | true
28 | Apache2.0
29 |
30 | en-US
31 |
32 | true
33 |
34 |
35 |
36 |
37 | TextTemplatingFileGenerator
38 | GenericAttributes.cs
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | True
49 | True
50 | GenericAttributes.tt
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Arch.System/Attributes.cs:
--------------------------------------------------------------------------------
1 | namespace Arch.System;
2 |
3 | ///
4 | /// Marks a method to generate a high performance query for it.
5 | ///
6 | [global::System.AttributeUsage(global::System.AttributeTargets.Method)]
7 | public class QueryAttribute : global::System.Attribute
8 | {
9 | ///
10 | /// If set to true, Query will be run in parallel.
11 | ///
12 | public bool Parallel { get; set; }
13 | }
14 |
15 | ///
16 | /// Marks a parameter as "data". This will be taken into account during source generation and will still be passed as a parameter in the query method.
17 | /// Is not treated as an entity component.
18 | ///
19 | [global::System.AttributeUsage(global::System.AttributeTargets.Parameter)]
20 | public class DataAttribute : global::System.Attribute
21 | {
22 | }
23 |
24 | ///
25 | /// Defines a set of components each entity requires.
26 | ///
27 | [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
28 | public class AllAttribute : global::System.Attribute
29 | {
30 | ///
31 | /// The types of the component.
32 | ///
33 | public Type[] ComponentTypes { get; }
34 |
35 | ///
36 | /// Constructs an All attribute with the specified component types.
37 | ///
38 | /// The types of the components that should be present.
39 | public AllAttribute(params Type[] componentTypes)
40 | {
41 | ComponentTypes = componentTypes;
42 | }
43 | }
44 |
45 | ///
46 | /// Defines a set of components each entity requires any from.
47 | ///
48 | [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
49 | public class AnyAttribute : global::System.Attribute
50 | {
51 | ///
52 | /// The types of the component.
53 | ///
54 | public Type[] ComponentTypes { get; }
55 |
56 | ///
57 | /// Constructs an Any attribute with the specified component types.
58 | ///
59 | /// The types of the components that can be present.
60 | public AnyAttribute(params Type[] componentTypes)
61 | {
62 | ComponentTypes = componentTypes;
63 | }
64 | }
65 |
66 | ///
67 | /// Defines a set of components none of the entities should have.
68 | ///
69 | [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
70 | public class NoneAttribute : global::System.Attribute
71 | {
72 |
73 | ///
74 | /// The types of the component.
75 | ///
76 | public Type[] ComponentTypes { get; }
77 |
78 | ///
79 | /// Constructs a None attribute with the specified component types.
80 | ///
81 | /// The types of the components that should not be present.
82 | public NoneAttribute(params Type[] componentTypes)
83 | {
84 | ComponentTypes = componentTypes;
85 | }
86 | }
87 |
88 | ///
89 | /// Defines an exclusive set of components an entity should have.
90 | ///
91 | [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
92 | public class ExclusiveAttribute : global::System.Attribute
93 | {
94 | ///
95 | /// The types of the component.
96 | ///
97 | public Type[] ComponentTypes { get; }
98 |
99 | ///
100 | /// Constructs an exclusive attribute with the specified component types.
101 | ///
102 | /// The types of the components that should be present exclusively.
103 | public ExclusiveAttribute(params Type[] componentTypes)
104 | {
105 | ComponentTypes = componentTypes;
106 | }
107 | }
--------------------------------------------------------------------------------
/Arch.System/Templates/GenericAttributes.tt:
--------------------------------------------------------------------------------
1 | namespace Arch.System;
2 | <#@ template language="C#" #>
3 | <#@ output extension=".cs" #>
4 | <#@ import namespace="System.Text" #>
5 | <#@ include file="Helpers.ttinclude" #>
6 | #if NET7_0_OR_GREATER
7 |
8 | <#
9 | var names = new string[] { "All", "Any", "None", "Exclusive" };
10 | foreach (var name in names)
11 | {
12 | for (var index = 1; index <= Amount; index++)
13 | {
14 | var generics = AppendGenerics(index);
15 | var parameters = AppendGenericTypeParameters(index);
16 | #>
17 | ///
18 | public class <#= name #>Attribute<<#= generics #>> : <#= name #>Attribute
19 | {
20 | ///
21 | public <#= name #>Attribute() : base(<#= parameters #>) { }
22 | }
23 |
24 | <#
25 | }
26 | }
27 | #>
28 | #endif
29 |
--------------------------------------------------------------------------------
/Arch.System/Templates/Helpers.ttinclude:
--------------------------------------------------------------------------------
1 | <#@ import namespace="System.Text" #>
2 | <#@ import namespace="System.Collections.Generic" #>
3 | <#+
4 | public int Amount = 25;
5 |
6 | public string Indent(StringBuilder sb, int spaces)
7 | {
8 | var indent = new string(' ', spaces);
9 | return sb.ToString().Replace("\n", "\n" + indent);
10 | }
11 |
12 | string AppendGenerics(int amount)
13 | {
14 | var sb = new StringBuilder();
15 | for (var i = 0; i < amount; i++)
16 | {
17 | if (i > 0) sb.Append(", ");
18 | sb.Append($"T{i}");
19 | }
20 | return sb.ToString();
21 | }
22 |
23 | ///
24 | /// Lists generic types in a row as parameters.
25 | ///
26 | ///
27 | /// typeof(T0), typeof(T1), ...
28 | ///
29 | ///
30 | ///
31 | ///
32 | ///
33 | ///
34 | public StringBuilder AppendGenericTypeParameters(int amount)
35 | {
36 | var sb = new StringBuilder();
37 | for (var localIndex = 0; localIndex < amount; localIndex++)
38 | {
39 | sb.Append($"typeof(T{localIndex}), ");
40 | }
41 |
42 | sb.Length -= 2;
43 | return sb;
44 | }
45 | #>
--------------------------------------------------------------------------------
/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | Release
7 | false
8 | en
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Arch.Extended
2 | [](https://GitHub.com/Naereen/StrapDown.js/graphs/commit-activity)
3 | [](https://www.nuget.org/packages/Arch.System/)
4 | [](https://opensource.org/licenses/Apache-2.0)
5 | 
6 |
7 | Extensions for [Arch](https://github.com/genaray/Arch) with some useful features like Systems, Source Generator and Utils.
8 |
9 | - 🛠️ **_Productive_** > Adds some useful tools and features to the main repository!
10 | - ☕️ **_SIMPLE_** > Works easily, reliably and understandably!
11 | - 💪 _**MAINTAINED**_ > It's actively being worked on, maintained, and supported!
12 | - 🚢 _**SUPPORT**_ > Supports .NetStandard 2.1, .Net Core 6 and 7 and therefore you may use it with Unity or Godot!
13 |
14 | Download the packages and get started today!
15 | ```console
16 | dotnet add package Arch.System --version 1.1.0
17 | dotnet add package Arch.System.SourceGenerator --version 2.1.0
18 | dotnet add package Arch.EventBus --version 1.0.2
19 | dotnet add package Arch.LowLevel --version 1.1.5
20 | dotnet add package Arch.Relationships --version 1.0.0
21 | dotnet add package Arch.Persistence --version 2.0.0
22 | dotnet add package Arch.AOT.SourceGenerator --version 1.0.1
23 | ```
24 |
25 | # Features & Tools
26 | - ⚙️ **_[Systems](https://github.com/genaray/Arch.Extended/wiki/Systems-API)_** > By means of systems, it is now easy to organize, reuse and arrange queries.
27 | - ✍️ **_[Source Generator](https://github.com/genaray/Arch.Extended/wiki/Source-Generator)_** > Declarative syntax using attributes and source generator, let your queries write themselves!
28 | - ✉️ **_[EventBus](https://github.com/genaray/Arch.Extended/wiki/EventBus)_** > A source generated EventBus, send Events with high-performance!
29 | - 👾 **_[LowLevel](https://github.com/genaray/Arch.Extended/wiki/Lowlevel-&-Resource-Management)_** > Low-level utils and data structures to get rid of GC pressure!
30 | - 💑 **_[Relationships](https://github.com/genaray/Arch.Extended/wiki/Relationships)_** > Adds simple relationships between entities to arch!
31 | - 💾 **_[Persistence](https://github.com/genaray/Arch.Extended/wiki/Persistence)_** > JSON and Binary (de)serialization to persist your Worlds!
32 | - ⌛ **_[AOT Source Generator](https://github.com/genaray/Arch.Extended/wiki/AOT-Source-Generator)_** > Helps with AOT compatibility and reduces boilerplate code!
33 | > Check the links and the [Wiki](https://github.com/genaray/Arch.Extended/wiki)!
34 |
35 | # Full code sample
36 |
37 | With this package you are able to write and group queries and systems for Arch automatically.
38 | And all this with the best possible performance.
39 |
40 | The tools can be used independently of each other.
41 |
42 | ```cs
43 | // Components ( ignore the formatting, this saves space )
44 | public struct Position{ float X, Y };
45 | public struct Velocity{ float Dx, Dy };
46 |
47 | // BaseSystem provides several useful methods for interacting and structuring systems
48 | public class MovementSystem : BaseSystem
49 | {
50 | public MovementSystem(World world) : base(world) {}
51 |
52 | // Generates a query and calls that one automatically on BaseSystem.Update
53 | [Query]
54 | public void Move([Data] in float time, ref Position pos, ref Velocity vel)
55 | {
56 | pos.X += time * vel.X;
57 | pos.Y += time * vel.Y;
58 | }
59 |
60 | // Generates and filters a query and calls that one automatically on BaseSystem.Update in order
61 | [Query]
62 | [All, Any, None] // Attributes also accept non generics :)
63 | public void ResetVelocity(ref Velocity vel)
64 | {
65 | vel = new Velocity{ X = 0, Y = 0 };
66 | }
67 | }
68 |
69 | public class Game
70 | {
71 | public static void Main(string[] args)
72 | {
73 | var deltaTime = 0.05f; // This is mostly given by engines, frameworks
74 |
75 | // Create a world and a group of systems which will be controlled
76 | var world = World.Create();
77 | var _systems = new Group(
78 | "Systems",
79 | new MovementSystem(world), // Run in order
80 | new MyOtherSystem(...),
81 | ...
82 | );
83 |
84 | _systems.Initialize(); // Inits all registered systems
85 | _systems.BeforeUpdate(in deltaTime); // Calls .BeforeUpdate on all systems ( can be overriden )
86 | _systems.Update(in deltaTime); // Calls .Update on all systems ( can be overriden )
87 | _systems.AfterUpdate(in deltaTime); // Calls .AfterUpdate on all System ( can be overriden )
88 | _systems.Dispose(); // Calls .Dispose on all systems ( can be overriden )
89 | }
90 | }
91 | ```
92 |
--------------------------------------------------------------------------------
/scripts/UnityPublish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Publishes Unity release to dist/Assemblies using only netstandard2.0 and netstandard2.1
4 | #########################################################################################
5 |
6 | dotnet restore
7 |
8 | assemblyDir="`pwd`/dist/Assemblies"
9 |
10 | rm -rf "${assemblyDir}"
11 |
12 | mkdir -p "${assemblyDir}"
13 |
14 | dotnet msbuild /t:Unity \
15 | -p:PublishDir="${assemblyDir}" \
16 | -p:TargetFramework=netstandard2.1 \
17 | -p:TargetFrameworks=netstandard2.1 \
18 | -p:TargetFrameworkVersion=v2.1
19 |
--------------------------------------------------------------------------------