From 148b0a0f48204650f15ce2e0902559f0c55a1d96 Mon Sep 17 00:00:00 2001 From: hzhang Date: Wed, 5 Feb 2025 12:38:51 +0000 Subject: [PATCH] add: Registry --- AssetInfo.cs | 26 ++++++++++++ AssetProcessGenerator.cs | 80 +++++++++++++++++++++++++++++++++++ ClassSyntaxReceiver.cs | 18 ++++++++ GlobalRegistryGenerator.cs | 37 ++++++++++++++++ Hangman.SDK.Generators.csproj | 19 --------- 5 files changed, 161 insertions(+), 19 deletions(-) create mode 100644 AssetInfo.cs create mode 100644 AssetProcessGenerator.cs create mode 100644 ClassSyntaxReceiver.cs create mode 100644 GlobalRegistryGenerator.cs diff --git a/AssetInfo.cs b/AssetInfo.cs new file mode 100644 index 0000000..a2a21c7 --- /dev/null +++ b/AssetInfo.cs @@ -0,0 +1,26 @@ +namespace Hangman.SDK.Generators; + + +using System; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + + +public struct AssetInfo +{ + public INamedTypeSymbol Symbol; + public string Path; + public ClassDeclarationSyntax DeclarationSyntax; + public string ClassName; + public string ClassFullName; + public string GodotPath { + get + { + string rs = Path.Replace("\\", "/").Replace(" ", "%20"); + rs = rs.Substring(rs.IndexOf("Assets", StringComparison.Ordinal)); + return "res://" + rs; + } + } + + public string ScenePath => GodotPath.Replace(".cs", ".tscn"); +} \ No newline at end of file diff --git a/AssetProcessGenerator.cs b/AssetProcessGenerator.cs new file mode 100644 index 0000000..edd1237 --- /dev/null +++ b/AssetProcessGenerator.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.IO; +using Microsoft.CodeAnalysis; + +namespace Hangman.SDK.Generators; + +public abstract class AssetProcessGenerator : ISourceGenerator +{ + public void Initialize(GeneratorInitializationContext context) + { + context.RegisterForSyntaxNotifications(() => new ClassSyntaxReceiver()); + } + + public abstract void Execute(GeneratorExecutionContext context); + + protected IEnumerable GetAssetsOfType(GeneratorExecutionContext context, INamedTypeSymbol? t) + { + if (!(context.SyntaxReceiver is ClassSyntaxReceiver receiver)) + yield break; + Compilation compilation = context.Compilation; + foreach (var derivedClassDeclaration in receiver.Classes) + { + SemanticModel model = compilation.GetSemanticModel(derivedClassDeclaration.SyntaxTree); + INamedTypeSymbol? derivedClassSymbol = model.GetDeclaredSymbol(derivedClassDeclaration) as INamedTypeSymbol; + string filePath = derivedClassDeclaration.SyntaxTree.FilePath; + string className = Path.GetFileNameWithoutExtension(filePath); + if(derivedClassSymbol == null || !filePath.Contains("Assets")) + continue; + AssetInfo res = new AssetInfo + { + DeclarationSyntax = derivedClassDeclaration, + ClassName = className, + ClassFullName = derivedClassSymbol.ToDisplayString(), + Path = filePath, + Symbol = derivedClassSymbol + }; + if (IsDerivedFrom(derivedClassSymbol, t)) + { + yield return res; + continue; + } + foreach (INamedTypeSymbol interfaceSymbol in derivedClassSymbol.AllInterfaces) + { + if (SymbolEqualityComparer.Default.Equals(interfaceSymbol, t)) + { + yield return res; + break; + } + } + + } + } + + protected IEnumerable GetAssetsOfType(GeneratorExecutionContext context, string t) + { + + Compilation compilation = context.Compilation; + INamedTypeSymbol? specificType = compilation.GetTypeByMetadataName(t); + return GetAssetsOfType(context, specificType); + } + protected static bool IsDerivedFrom(INamedTypeSymbol? symbol, INamedTypeSymbol? baseType) + { + if (symbol == null) + return false; + if (baseType == null) + return true; + INamedTypeSymbol? current = symbol.BaseType; + + while (current != null) + { + if (SymbolEqualityComparer.Default.Equals(current, baseType)) + return true; + current = current.BaseType; + } + + return false; + } + + +} diff --git a/ClassSyntaxReceiver.cs b/ClassSyntaxReceiver.cs new file mode 100644 index 0000000..da7824f --- /dev/null +++ b/ClassSyntaxReceiver.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Hangman.SDK.Generators; + +public class ClassSyntaxReceiver : ISyntaxReceiver +{ + public List Classes { get; set; } = new (); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is ClassDeclarationSyntax classDeclaration) + { + Classes.Add(classDeclaration); + } + } +} \ No newline at end of file diff --git a/GlobalRegistryGenerator.cs b/GlobalRegistryGenerator.cs new file mode 100644 index 0000000..7417bc6 --- /dev/null +++ b/GlobalRegistryGenerator.cs @@ -0,0 +1,37 @@ +using System.Text; +using Microsoft.CodeAnalysis; + +namespace Hangman.SDK.Generators; +[Generator] +public class GlobalRegistryGenerator : ISourceGenerator +{ + public void Initialize(GeneratorInitializationContext context) + { + } + + public void Execute(GeneratorExecutionContext context) + { + StringBuilder sb = new(); + sb.AppendLine("using System;"); + sb.AppendLine("using System.Collections.Generic;"); + sb.AppendLine("using System.Linq;"); + sb.AppendLine("using System.Reflection;"); + sb.AppendLine("using Hangman.SDK.Attributes;"); + sb.AppendLine("public static partial class GlobalRegistry"); + sb.AppendLine("{"); + sb.AppendLine(" public static void Register()"); + sb.AppendLine(" {"); + sb.AppendLine(" Assembly assembly = Assembly.GetEntryAssembly();"); + sb.AppendLine(" IEnumerable registerTypes = assembly.GetTypes()"); + sb.AppendLine(" .Where(t => t.IsClass && t.GetCustomAttributes(typeof(AutoRegister), false).Any());"); + sb.AppendLine(" foreach(Type t in registerTypes)"); + sb.AppendLine(" {"); + sb.AppendLine(" MethodInfo registerMethod = t.GetMethod(\"Register\", BindingFlags.Static | BindingFlags.Public);"); + sb.AppendLine(" if (registerMethod != null)"); + sb.AppendLine(" registerMethod.Invoke(null, null);"); + sb.AppendLine(" }"); + sb.AppendLine(" }"); + sb.AppendLine("}"); + context.AddSource("GlobalRegistry.g.cs", sb.ToString()); + } +} \ No newline at end of file diff --git a/Hangman.SDK.Generators.csproj b/Hangman.SDK.Generators.csproj index 141cf49..adec8f8 100644 --- a/Hangman.SDK.Generators.csproj +++ b/Hangman.SDK.Generators.csproj @@ -22,23 +22,4 @@ - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - - - True - True - Resources.resx - - - - - - -