using System.Collections.Generic; using System.IO; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Text; namespace Godot.Sharp.Extended.Generators; [Generator] public class SceneGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { var scenes = context.AdditionalTextsProvider .Where(text => text.Path.EndsWith(".tscn")); context.RegisterSourceOutput( context.CompilationProvider.Combine(scenes.Collect()).Combine(context.AnalyzerConfigOptionsProvider), (ctx, t) => GenerateCode(ctx, t.Left.Left, t.Left.Right, t.Right)); } private void GenerateCode( SourceProductionContext context, Compilation compilation, IEnumerable scenes, AnalyzerConfigOptionsProvider optionsProvider) { optionsProvider.GlobalOptions.TryGetValue("build_property.projectdir", out var projectDirectory); var allMethods = new StringBuilder(); foreach (var scene in scenes) { var directory = Path.GetDirectoryName(scene.Path); var name = Path.GetFileNameWithoutExtension(scene.Path); var relativePath = scene.Path.Replace(projectDirectory ?? "", "").Replace("\\", "/"); allMethods.AppendLine( $$""" public static T New{{name.ToPascalCase()}}() where T : Node { var packedScene = GD.Load("res://{{relativePath}}"); return packedScene.Instance(); } """); var code = $$""" // using System; using Godot; namespace Godot.Sharp.Extended; public class Scenes { {{allMethods}} } """; context.AddSource("Godot.Sharp.Extended.Scenes.g.cs", SourceText.From(code, Encoding.UTF8)); } } }