using Godot; using Rokojori; using System.Collections.Generic; using System; using System.Reflection; using System.Text.RegularExpressions; using System.Linq; using System.IO; namespace Rokojori.GDLibraryGeneration { [Tool][GlobalClass] public partial class GDLibraryGenerator:Node { [Export] public string path = "rokojori_action_library_gd"; [Export] public bool scanForGDExport = true; [Export] public string[] files = []; [ExportToolButton( "Generate" )] public Callable generateButton => Callable.From( ()=> { GenerateGDLibrary(); } ); HashSet defines = new HashSet(); void GenerateGDLibrary() { defines = new HashSet(); defines.Add( GDScriptGenerator.GD_SCRIPT_TRANSPILING ); var codeFilePaths = GetCodeFilePaths(); var rokojoriProPath = FilePath.Absolute( ProjectSettings.GlobalizePath( RokojoriPlugin.path ) ); var rokojoriGDPath = FilePath.Absolute( ProjectSettings.GlobalizePath( "res://addons/" + path ) ); codeFilePaths.ForEach( ( c )=> { var parser = new CSParser( c.absolutePath, defines ); var root = parser.root as CSFileRoot; var originalPath = FilePath.Absolute( root.GetFilePath() ); var relativePath = rokojoriProPath.MakeAbsolutePathRelative( originalPath.parentAbsolutePath ); var gdPath = rokojoriGDPath.MakeRelative( relativePath.path ); var converter = new GDScriptFromCSAST(); converter.Convert( root ); var gdclass = converter.gdClass; var gdgenerator = new GDScriptGenerator(); gdgenerator.gdClasses = [ gdclass ]; FilesSync.EnsureDirectoryExists( gdPath.absolutePath ); gdgenerator.Generate( gdPath.absolutePath ); } ); } List GetCodeFilePaths() { var codeFilePaths = new List(); var map = new HashSet(); var combinedFiles = new List(); combinedFiles.AddRange( files ); if ( scanForGDExport ) { var absPath = ProjectSettings.GlobalizePath( RokojoriPlugin.path ); var scannedExportfiles = FilesSync.GetFilesRecursive( absPath, f => f.HasFileExtension( ".cs" ) ); scannedExportfiles = scannedExportfiles.Filter( ( f, i ) => { var text = f.LoadUTF8(); if ( ! text.Contains( "GDExport" ) ) { return false; } var parser = new CSParser( f.absolutePath, defines ); var csRoot = parser.root as CSFileRoot; var cd = csRoot.GetObjectDeclarations().Find( c => c.objectName.match == f.fileName ); return cd?.GetMemberAttributes().Contains( "GDExport" ) ?? false; } ); var scannedPaths = scannedExportfiles.Map( f => f.absolutePath ); RJLog.Log( "Found paths:", scannedPaths ); combinedFiles.AddRange( scannedPaths ); } combinedFiles.ForEach( ( fileString )=> { FilePath filePath; if ( fileString.StartsWith( "res://" ) ) { filePath = FilePath.Absolute( ProjectSettings.GlobalizePath( fileString ) ); } else if ( ! fileString.EndsWith( ".cs" ) ) { filePath = FindFilePathOf( fileString ); } else { filePath = FilePath.Absolute( fileString ); } if ( filePath == null || ! filePath.Exists() ) { return; } var absolutePath = filePath.absolutePath; if ( map.Contains( absolutePath ) ) { return; } codeFilePaths.Add( filePath ); map.Add( absolutePath ); } ); return codeFilePaths; } List filePaths; FilePath FindFilePathOf( string type ) { if ( filePaths == null ) { var rokojoriPath = ProjectSettings.GlobalizePath( RokojoriPlugin.path ); filePaths = FilesSync.GetFilesRecursive( rokojoriPath, fp => fp.HasFileExtension( ".cs" ) ); } return filePaths.Find( fp => fp.fileName == type ); } } }