Refactor component registration, update deps, improve JSON
- Updated Misaki.HighPerformance package versions in Core and Graphics projects. - Added IsTrimmable to Ghost.Engine.csproj for trimming support. - Renamed GetOrRegisterComponent to GetOrRegisterComponentID and updated all usages. - Component registration codegen now uses a static class with [ModuleInitializer], no longer requires [EngineEntry]. - Improved JSON serialization: added string support, introduced Utf8JsonObjectScope/ArrayScope, and new extension methods for cleaner JSON writing. - Removed [SkipLocalsInit] from Hierarchy and LocalToWorld. - Fixed Entity.Invalid to use INVALID_ID for both fields. - Minor cleanup: clarified comments, reorganized Ghost.Generator in solution, and disabled component serialization generator.
This commit is contained in:
@@ -8,6 +8,7 @@ using System.Threading;
|
||||
|
||||
namespace Ghost.Generator
|
||||
{
|
||||
// TODO: this should be per assembly, not global
|
||||
[Generator]
|
||||
public class ComponentRegistrationGenerator : IIncrementalGenerator
|
||||
{
|
||||
@@ -21,20 +22,8 @@ namespace Ghost.Generator
|
||||
.Where(symbol => symbol != null)
|
||||
.Collect();
|
||||
|
||||
// 2. Pipeline: Find the ONE class with [EngineEntry]
|
||||
var engineEntryClass = context.SyntaxProvider
|
||||
.CreateSyntaxProvider(
|
||||
predicate: (s, _) => s is ClassDeclarationSyntax,
|
||||
transform: GetEngineEntrySymbol)
|
||||
.Where(symbol => symbol != null)
|
||||
.Collect(); // Returns ImmutableArray<INamedTypeSymbol>
|
||||
|
||||
// 3. COMBINE: Pair the list of components with the list of entry classes
|
||||
// The result 'source' in the callback will be a tuple: (ImmutableArray<Info>, ImmutableArray<Entry>)
|
||||
var combinedProvider = componentCandidates.Combine(engineEntryClass);
|
||||
|
||||
// 4. Output: Generate the source using both pieces of data at once
|
||||
context.RegisterSourceOutput(combinedProvider, GenerateRegistrationCode);
|
||||
context.RegisterSourceOutput(componentCandidates, GenerateRegistrationCode);
|
||||
}
|
||||
|
||||
// Extraction Logic for Components
|
||||
@@ -63,76 +52,38 @@ namespace Ghost.Generator
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extraction Logic for Engine Entry
|
||||
private static INamedTypeSymbol GetEngineEntrySymbol(GeneratorSyntaxContext ctx, CancellationToken _)
|
||||
{
|
||||
var classSyntax = (ClassDeclarationSyntax)ctx.Node;
|
||||
if (!(ctx.SemanticModel.GetDeclaredSymbol(classSyntax) is INamedTypeSymbol symbol))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check attributes
|
||||
foreach (var attribute in symbol.GetAttributes())
|
||||
{
|
||||
if (attribute.AttributeClass?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global::Ghost.Engine.EngineEntryAttribute")
|
||||
{
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// The Generation Logic (Stateless)
|
||||
private static void GenerateRegistrationCode(
|
||||
SourceProductionContext context,
|
||||
(ImmutableArray<INamedTypeSymbol> Components, ImmutableArray<INamedTypeSymbol> Entries) source)
|
||||
private static void GenerateRegistrationCode(SourceProductionContext context, ImmutableArray<INamedTypeSymbol> components)
|
||||
{
|
||||
var components = source.Components;
|
||||
var entries = source.Entries;
|
||||
|
||||
// 1. Validation: Ensure we found exactly one [EngineEntry] class
|
||||
if (entries.IsDefaultOrEmpty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Pick the first one (if multiple exist, you might want to report a diagnostic error)
|
||||
var targetClass = entries[0];
|
||||
|
||||
if (components.IsDefaultOrEmpty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Extract Namespace and Class Name directly from the symbol found in the pipeline
|
||||
var targetNamespace = targetClass.ContainingNamespace.ToDisplayString();
|
||||
var targetClassName = targetClass.Name;
|
||||
var name = $"g_component_registration";
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append($@"
|
||||
namespace {targetNamespace}
|
||||
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
|
||||
internal static class {name}
|
||||
{{
|
||||
public partial class {targetClassName}
|
||||
{{
|
||||
private static void RegisterIComponentTypes()
|
||||
{{");
|
||||
[global::System.Runtime.CompilerServices.ModuleInitializer]
|
||||
public static void RegisterIComponentTypes()
|
||||
{{");
|
||||
|
||||
foreach (var symbol in components.Distinct(SymbolEqualityComparer.Default))
|
||||
{
|
||||
if (symbol is null) continue;
|
||||
foreach (var symbol in components.Distinct(SymbolEqualityComparer.Default))
|
||||
{
|
||||
if (symbol is null) continue;
|
||||
|
||||
sb.Append($@"
|
||||
global::Ghost.Entities.ComponentRegistry.GetOrRegisterComponent<{symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>();");
|
||||
}
|
||||
|
||||
sb.Append(@"
|
||||
sb.Append($@"
|
||||
global::Ghost.Entities.ComponentRegistry.GetOrRegisterComponentID<{symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>();");
|
||||
}
|
||||
|
||||
sb.Append(@"
|
||||
}
|
||||
}");
|
||||
|
||||
context.AddSource($"{targetClassName}.ComponentReg.gen.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
|
||||
context.AddSource($"{name}.gen.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user