refactor: simplify component iteration and singleton handling
Update the ECS engine to support automatic mutation tracking for singletons during iteration, removing the need for manual `MarkModified` calls. - Update `ComponentDiscoveryGenerator` to detect singleton components. - Refactor `PlaceMarkCommand` and `WinCheckSystem` to leverage automatic mutation marking. - Replace `ForEach` usage with `Select` and `ItemN` access in tests and systems to align with the updated iterator API.
This commit is contained in:
@@ -44,6 +44,15 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
||||
"GetSources",
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> _singletonMethods = new()
|
||||
{
|
||||
"SetSingleton",
|
||||
"GetSingleton",
|
||||
"ReadSingleton",
|
||||
"HasSingleton",
|
||||
"RemoveSingleton",
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> _forEachNames = new()
|
||||
{
|
||||
"ForEach",
|
||||
@@ -57,7 +66,7 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
||||
predicate: IsCandidateInvocation,
|
||||
transform: ExtractComponentType)
|
||||
.Where(t => t.FullyQualifiedName != null)
|
||||
.Select((t, _) => (t.FullyQualifiedName!, t.AssemblyQualifiedName!, t.IsRelationship));
|
||||
.Select((t, _) => (t.FullyQualifiedName!, t.AssemblyQualifiedName!, t.IsRelationship, t.IsSingleton));
|
||||
|
||||
// Also collect ForEach type arguments from the World class.
|
||||
var forEachCalls = context.SyntaxProvider
|
||||
@@ -104,7 +113,7 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
||||
return false;
|
||||
}
|
||||
|
||||
private static (string? FullyQualifiedName, string? AssemblyQualifiedName, bool IsRelationship) ExtractComponentType(
|
||||
private static (string? FullyQualifiedName, string? AssemblyQualifiedName, bool IsRelationship, bool IsSingleton) ExtractComponentType(
|
||||
GeneratorSyntaxContext ctx, CancellationToken _)
|
||||
{
|
||||
if (ctx.Node is not InvocationExpressionSyntax invocation)
|
||||
@@ -140,7 +149,9 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
||||
bool isRelationship = typeSymbol.AllInterfaces.Any(i =>
|
||||
i.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global::OECS.IRelationship");
|
||||
|
||||
return (fqn, aqn, isRelationship);
|
||||
bool isSingleton = _singletonMethods.Contains(genericName.Identifier.Text);
|
||||
|
||||
return (fqn, aqn, isRelationship, isSingleton);
|
||||
}
|
||||
|
||||
private static ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship)> ExtractForEachTypes(
|
||||
@@ -177,21 +188,29 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
||||
}
|
||||
|
||||
private static void GenerateRegistry(SourceProductionContext context,
|
||||
(ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship)> Left,
|
||||
(ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship, bool IsSingleton)> Left,
|
||||
ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship)> Right) data)
|
||||
{
|
||||
var (invocations, forEachTypes) = data;
|
||||
|
||||
// Collect unique types by fully-qualified name, deduplicating.
|
||||
var typeMap = new Dictionary<string, (string Fqn, string Aqn, bool IsRel)>();
|
||||
var typeMap = new Dictionary<string, (string Fqn, string Aqn, bool IsRel, bool IsSingleton)>();
|
||||
foreach (var t in invocations)
|
||||
typeMap[t.FullyQualifiedName] = (t.FullyQualifiedName, t.AssemblyQualifiedName, t.IsRelationship);
|
||||
{
|
||||
if (typeMap.TryGetValue(t.FullyQualifiedName, out var existing))
|
||||
typeMap[t.FullyQualifiedName] = (existing.Fqn, existing.Aqn, existing.IsRel || t.IsRelationship, existing.IsSingleton || t.IsSingleton);
|
||||
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);
|
||||
typeMap[t.FullyQualifiedName] = (t.FullyQualifiedName, t.AssemblyQualifiedName, t.IsRelationship, false);
|
||||
else if (t.IsRelationship)
|
||||
typeMap[t.FullyQualifiedName] = (t.FullyQualifiedName, t.AssemblyQualifiedName, true);
|
||||
{
|
||||
var existing = typeMap[t.FullyQualifiedName];
|
||||
typeMap[t.FullyQualifiedName] = (existing.Fqn, existing.Aqn, true, existing.IsSingleton);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeMap.Count == 0)
|
||||
@@ -213,7 +232,7 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
||||
sb.AppendLine(" {");
|
||||
|
||||
bool first = true;
|
||||
foreach (var (fqn, aqn, isRel) in typeMap.Values.OrderBy(t => t.Fqn))
|
||||
foreach (var (fqn, aqn, isRel, isSingleton) in typeMap.Values.OrderBy(t => t.Fqn))
|
||||
{
|
||||
if (!first)
|
||||
sb.AppendLine(",");
|
||||
@@ -225,7 +244,8 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
||||
sb.AppendLine($" serialize: obj => MessagePackSerializer.Serialize(({fqn})obj),");
|
||||
sb.AppendLine($" deserializeAndAdd: (world, entity, data) =>");
|
||||
sb.AppendLine($" world.AddComponent(entity, MessagePackSerializer.Deserialize<{fqn}>(data)),");
|
||||
sb.AppendLine($" deserialize: data => MessagePackSerializer.Deserialize<{fqn}>(data)");
|
||||
sb.AppendLine($" deserialize: data => MessagePackSerializer.Deserialize<{fqn}>(data),");
|
||||
sb.AppendLine($" isSingleton: {(isSingleton ? "true" : "false")}");
|
||||
|
||||
sb.Append(" )");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user