using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Polonium.Tasks; public class GenerateProxyNodesTask : Task { [Required] public string SourceDirectory { get; set; } [Required] public string OutputDirectory { get; set; } [Required] public string TemplateDirectory { get; set; } [Required] public string AttributeName { get; set; } public override bool Execute() { try { if(Directory.Exists(OutputDirectory)) Directory.Delete(OutputDirectory, true); Directory.CreateDirectory(OutputDirectory); string[] csFiles = Directory.GetFiles(SourceDirectory, "*.cs", SearchOption.AllDirectories); foreach (string csFile in csFiles) { string code = File.ReadAllText(csFile); SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code); CompilationUnitSyntax root = syntaxTree.GetCompilationUnitRoot(); IEnumerable classes = root.DescendantNodes().OfType() .Where(cls => cls.AttributeLists .SelectMany(attrList => attrList.Attributes) .Any(attr => attr.Name.ToString().Contains(AttributeName))); foreach (ClassDeclarationSyntax cls in classes) { string className = cls.Identifier.Text; StringBuilder sb = new StringBuilder(); sb .AppendLine("using Godot;") .AppendLine("namespace GlobalClasses;") .AppendLine("[GlobalClass]") .AppendLine("[Tool]") .AppendLine($"public partial class {className} : {GetDisplayName(cls)}") .AppendLine("{") .AppendLine("}"); string outputFile = Path.Combine(OutputDirectory, $"{className}.cs"); File.WriteAllText(outputFile, sb.ToString()); Log.LogMessage(MessageImportance.High, $"Generated proxy file: {outputFile}"); StringBuilder sbx = new StringBuilder(); sbx .AppendLine("// meta-default: true") .AppendLine("using _BINDINGS_NAMESPACE_;") .AppendLine("using System;") .AppendLine("public partial class _CLASS_ : GlobalClasses._CLASS_") .AppendLine("{") .AppendLine("}"); if(!Directory.Exists($"{TemplateDirectory}/{className}")) Directory.CreateDirectory($"{TemplateDirectory}/{className}"); string templateFile = $"{TemplateDirectory}/{className}/Polonium_{className}.cs"; File.WriteAllText(templateFile, sbx.ToString()); } } return true; } catch (Exception ex) { Log.LogErrorFromException(ex); return false; } } private string GetDisplayName(ClassDeclarationSyntax cls) { string name = cls.Identifier.Text; SyntaxNode node = cls.Parent; while (node is not null) { if(node is NamespaceDeclarationSyntax ns) name = ns.Name.ToString() + "." + name; else if (node is FileScopedNamespaceDeclarationSyntax fs) name = fs.Name.ToString() + "." + name; node = node.Parent; } return name; } }