diff --git a/OECS.SourceGen/ComponentDiscoveryGenerator.cs b/OECS.SourceGen/ComponentDiscoveryGenerator.cs index 21a5b45..39235d9 100644 --- a/OECS.SourceGen/ComponentDiscoveryGenerator.cs +++ b/OECS.SourceGen/ComponentDiscoveryGenerator.cs @@ -53,10 +53,7 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator "RemoveSingleton", }; - private static readonly HashSet _forEachNames = new() - { - "ForEach", - }; + public void Initialize(IncrementalGeneratorInitializationContext context) { @@ -68,15 +65,7 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator .Where(t => t.FullyQualifiedName != null) .Select((t, _) => (t.FullyQualifiedName!, t.AssemblyQualifiedName!, t.IsRelationship, t.IsSingleton)); - // Also collect ForEach type arguments from the World class. - var forEachCalls = context.SyntaxProvider - .CreateSyntaxProvider( - predicate: IsForEachCandidate, - transform: ExtractForEachTypes) - .Where(list => list.Length > 0) - .SelectMany((list, _) => list); - - var allTypes = invocations.Collect().Combine(forEachCalls.Collect()); + var allTypes = invocations.Collect(); context.RegisterSourceOutput(allTypes, GenerateRegistry); } @@ -97,21 +86,7 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator return false; } - private static bool IsForEachCandidate(SyntaxNode node, CancellationToken _) - { - if (node is not InvocationExpressionSyntax invocation) - return false; - if (invocation.Expression is MemberAccessExpressionSyntax memberAccess) - { - var name = memberAccess.Name is GenericNameSyntax gn - ? gn.Identifier.Text - : memberAccess.Name.Identifier.Text; - return _forEachNames.Contains(name); - } - - return false; - } private static (string? FullyQualifiedName, string? AssemblyQualifiedName, bool IsRelationship, bool IsSingleton) ExtractComponentType( GeneratorSyntaxContext ctx, CancellationToken _) @@ -154,44 +129,11 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator return (fqn, aqn, isRelationship, isSingleton); } - private static ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship)> ExtractForEachTypes( - GeneratorSyntaxContext ctx, CancellationToken _) - { - if (ctx.Node is not InvocationExpressionSyntax invocation) - return ImmutableArray<(string, string, bool)>.Empty; - if (invocation.Expression is not MemberAccessExpressionSyntax memberAccess) - return ImmutableArray<(string, string, bool)>.Empty; - - if (memberAccess.Name is not GenericNameSyntax genericName) - return ImmutableArray<(string, string, bool)>.Empty; - - var types = ImmutableArray.CreateBuilder<(string, string, bool)>(); - foreach (var typeArg in genericName.TypeArgumentList.Arguments) - { - var symbolInfo = ctx.SemanticModel.GetSymbolInfo(typeArg); - if (symbolInfo.Symbol is INamedTypeSymbol typeSymbol && - typeSymbol.IsValueType && !typeSymbol.IsAbstract && - typeSymbol.DeclaredAccessibility == Accessibility.Public) - { - var fqn = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - var aqn = typeSymbol.ContainingAssembly != null - ? $"{typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted))}, {typeSymbol.ContainingAssembly.Name}" - : fqn; - bool isRelationship = typeSymbol.AllInterfaces.Any(i => - i.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global::OECS.IRelationship"); - types.Add((fqn, aqn, isRelationship)); - } - } - - return types.ToImmutable(); - } private static void GenerateRegistry(SourceProductionContext context, - (ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship, bool IsSingleton)> Left, - ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship)> Right) data) + ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship, bool IsSingleton)> invocations) { - var (invocations, forEachTypes) = data; // Collect unique types by fully-qualified name, deduplicating. var typeMap = new Dictionary(); @@ -202,16 +144,6 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator else typeMap[t.FullyQualifiedName] = (t.FullyQualifiedName, t.AssemblyQualifiedName, t.IsRelationship, t.IsSingleton); } - foreach (var t in forEachTypes) - { - if (!typeMap.ContainsKey(t.FullyQualifiedName)) - typeMap[t.FullyQualifiedName] = (t.FullyQualifiedName, t.AssemblyQualifiedName, t.IsRelationship, false); - else if (t.IsRelationship) - { - var existing = typeMap[t.FullyQualifiedName]; - typeMap[t.FullyQualifiedName] = (existing.Fqn, existing.Aqn, true, existing.IsSingleton); - } - } if (typeMap.Count == 0) return; diff --git a/OECS/World.cs b/OECS/World.cs index 8c0c7fd..403ef28 100644 --- a/OECS/World.cs +++ b/OECS/World.cs @@ -194,6 +194,11 @@ public class World : IDisposable nameof(AddComponentImpl), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!; + private static readonly System.Reflection.MethodInfo s_removeComponentImpl = + typeof(World).GetMethod( + nameof(RemoveComponentImpl), + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!; + private void AddComponentImpl(Entity entity, T component) where T : struct { ThrowIfNotAlive(entity); @@ -589,20 +594,13 @@ public class World : IDisposable switch (m.Kind) { case PendingMutationKind.AddComponent: - // Use reflection to call AddComponentImpl. - var addMethod = typeof(World).GetMethod( - nameof(AddComponentImpl), - System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!; - var genericAdd = addMethod.MakeGenericMethod(m.ComponentType); - genericAdd.Invoke(this, [m.Entity, m.Component]); + s_addComponentImpl.MakeGenericMethod(m.ComponentType) + .Invoke(this, [m.Entity, m.Component]); break; case PendingMutationKind.RemoveComponent: - var removeMethod = typeof(World).GetMethod( - nameof(RemoveComponentImpl), - System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!; - var genericRemove = removeMethod.MakeGenericMethod(m.ComponentType); - genericRemove.Invoke(this, [m.Entity]); + s_removeComponentImpl.MakeGenericMethod(m.ComponentType) + .Invoke(this, [m.Entity]); break; case PendingMutationKind.DestroyEntity: diff --git a/docs/api-surface.md b/docs/api-surface.md index 242598a..4b45551 100644 --- a/docs/api-surface.md +++ b/docs/api-surface.md @@ -379,7 +379,6 @@ namespace OECS; public interface IRelationship { - Entity Source { get; } Entity Target { get; } } ``` @@ -399,8 +398,7 @@ namespace OECS; public struct Relationship : IRelationship where TSelf : struct where TTarget : struct { - [Key(0)] public Entity Source { get; set; } - [Key(1)] public Entity Target { get; set; } + [Key(0)] public Entity Target { get; set; } } ``` @@ -424,7 +422,8 @@ public enum ChangeKind EntityRemoved, ComponentAdded, ComponentRemoved, - ComponentModified + ComponentModified, + RelationshipReordered } ```