Refactor project structure and enhance functionality

Changed the project namespace from `Ghost.Editor` to `Ghost.App` across multiple files.
Changed the `InternalsVisibleTo` attribute in `AssemblyInfo.cs` to include `Ghost.App`.
Changed the `ProjectRepository` class to add new asynchronous methods for retrieving projects by ID, name, and metadata path.
Changed the `ProjectService` class to utilize the new asynchronous project loading methods.
Changed the `SceneGraph` classes to improve node management and serialization.
Changed the `EntityManager` class to enhance entity management with new component handling methods.
Added new test classes, `EntityTest` and `SerializationTest`, to ensure reliability in entity and serialization systems.
Added the `Ghost.App` project file to establish a modular project structure.
Added the `Ghost.Generator` project for automated component serialization code generation.
Updated UI components to reflect the new namespace for proper functionality.
This commit is contained in:
2025-06-07 20:54:07 +09:00
parent bab3be2508
commit 40d333b004
123 changed files with 1441 additions and 740 deletions

View File

@@ -0,0 +1,114 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
namespace Ghost.Generator
{
[Generator]
public class ComponentSerializationGenerator : IIncrementalGenerator
{
private void GenerateJsonContext(SourceProductionContext context, ImmutableArray<INamedTypeSymbol> symbols)
{
if (symbols.IsDefaultOrEmpty)
{
return;
}
var sb = new StringBuilder();
sb.Append(@"
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
namespace Ghost.Engine.Components.Serialization
{
[JsonSourceGenerationOptions(WriteIndented = true, IncludeFields = true)]");
foreach (var symbol in symbols.Distinct(SymbolEqualityComparer.Default))
{
if (symbol is null)
{
continue;
}
var fqtn = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
sb.Append($@"
[JsonSerializable(typeof({fqtn}))]");
}
sb.Append(@"
public partial class ComponentJsonContext : JsonSerializerContext
{
private static readonly Dictionary<Type, JsonTypeInfo> _typeLookup = new()
{");
foreach (var symbol in symbols.Distinct(SymbolEqualityComparer.Default))
{
if (symbol is null)
{
continue;
}
var fqtn = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
sb.Append($@"
{{ typeof({fqtn}), ComponentJsonContext.{symbol.Name} }},");
}
sb.Append(@"
};
/// <summary>
/// Tries to retrieve the generated JsonTypeInfo for a given component type.
/// </summary>
public static bool TryGetTypeInfo(Type componentType, out JsonTypeInfo jsonTypeInfo) =>
_typeLookup.TryGetValue(componentType, out jsonTypeInfo);
}
}");
context.AddSource("ComponentJsonContext.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
}
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var componentCandidates = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: (syntaxNode, _) => syntaxNode is StructDeclarationSyntax,
transform: (ctx, _) =>
{
var structSyntax = (StructDeclarationSyntax)ctx.Node;
if (!(ctx.SemanticModel.GetDeclaredSymbol(structSyntax) is INamedTypeSymbol symbol))
{
return null;
}
var compilation = ctx.SemanticModel.Compilation;
var iComponentDataSymbol = compilation.GetTypeByMetadataName("Ghost.Entities.Components.IComponentData");
if (iComponentDataSymbol == null)
{
return null;
}
foreach (var iface in symbol.AllInterfaces)
{
if (SymbolEqualityComparer.Default.Equals(iface, iComponentDataSymbol))
{
return symbol;
}
}
return null;
})
.Where(symbol => symbol != null)
.Collect();
context.RegisterSourceOutput(componentCandidates, GenerateJsonContext);
}
}
}