summaryrefslogtreecommitdiff
path: root/modules/mono/editor
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/editor')
-rw-r--r--modules/mono/editor/GodotSharpTools/.gitignore2
-rw-r--r--modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs425
-rw-r--r--modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs75
-rw-r--r--modules/mono/editor/GodotSharpTools/GodotSharpTools.sln17
-rw-r--r--modules/mono/editor/GodotSharpTools/Utils/OS.cs62
-rw-r--r--modules/mono/editor/GodotTools/.gitignore356
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs186
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj59
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.BuildLogger/Properties/AssemblyInfo.cs35
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj38
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Core/ProcessExtensions.cs38
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Core/Properties/AssemblyInfo.cs26
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs (renamed from modules/mono/editor/GodotSharpTools/StringExtensions.cs)33
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ApiAssembliesInfo.cs15
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ApiSolutionGenerator.cs52
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs122
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj (renamed from modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj)41
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/IdentifierUtils.cs (renamed from modules/mono/editor/GodotSharpTools/Project/IdentifierUtils.cs)14
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectExtensions.cs (renamed from modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs)3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs (renamed from modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs)38
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs (renamed from modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs)5
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/Properties/AssemblyInfo.cs (renamed from modules/mono/editor/GodotSharpTools/Properties/AssemblyInfo.cs)4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/packages.config (renamed from modules/mono/editor/GodotSharpTools/packages.config)2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs172
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs210
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/CSharpProject.cs115
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs396
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs538
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpExport.cs197
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj81
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs47
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/BindingsGenerator.cs87
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs50
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs91
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs127
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/ScriptClassParser.cs52
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/MonoBottomPanel.cs342
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/MonoBuildInfo.cs47
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/MonoBuildTab.cs260
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/MonoDevelopInstance.cs (renamed from modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs)55
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Properties/AssemblyInfo.cs26
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/CollectionExtensions.cs20
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/Directory.cs40
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/File.cs43
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs127
-rw-r--r--modules/mono/editor/bindings_generator.cpp162
-rw-r--r--modules/mono/editor/bindings_generator.h8
-rw-r--r--modules/mono/editor/csharp_project.cpp206
-rw-r--r--modules/mono/editor/csharp_project.h7
-rw-r--r--modules/mono/editor/dotnet_solution.cpp140
-rw-r--r--modules/mono/editor/dotnet_solution.h63
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp429
-rw-r--r--modules/mono/editor/editor_internal_calls.h (renamed from modules/mono/editor/mono_build_info.h)29
-rw-r--r--modules/mono/editor/godotsharp_builds.cpp632
-rw-r--r--modules/mono/editor/godotsharp_builds.h103
-rw-r--r--modules/mono/editor/godotsharp_editor.cpp582
-rw-r--r--modules/mono/editor/godotsharp_editor.h134
-rw-r--r--modules/mono/editor/godotsharp_export.cpp204
-rw-r--r--modules/mono/editor/godotsharp_export.h28
-rw-r--r--modules/mono/editor/mono_bottom_panel.cpp528
-rw-r--r--modules/mono/editor/mono_bottom_panel.h150
-rw-r--r--modules/mono/editor/mono_build_info.cpp62
-rw-r--r--modules/mono/editor/monodevelop_instance.cpp85
-rw-r--r--modules/mono/editor/monodevelop_instance.h56
64 files changed, 4704 insertions, 3675 deletions
diff --git a/modules/mono/editor/GodotSharpTools/.gitignore b/modules/mono/editor/GodotSharpTools/.gitignore
deleted file mode 100644
index 296ad48834..0000000000
--- a/modules/mono/editor/GodotSharpTools/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# nuget packages
-packages \ No newline at end of file
diff --git a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
deleted file mode 100644
index e5044feb75..0000000000
--- a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
+++ /dev/null
@@ -1,425 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Diagnostics;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Security;
-using Microsoft.Build.Framework;
-
-namespace GodotSharpTools.Build
-{
- public class BuildInstance : IDisposable
- {
- [MethodImpl(MethodImplOptions.InternalCall)]
- private extern static void godot_icall_BuildInstance_ExitCallback(string solution, string config, int exitCode);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private extern static string godot_icall_BuildInstance_get_MSBuildPath();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private extern static string godot_icall_BuildInstance_get_MonoWindowsBinDir();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private extern static bool godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private extern static bool godot_icall_BuildInstance_get_PrintBuildOutput();
-
- private static string GetMSBuildPath()
- {
- string msbuildPath = godot_icall_BuildInstance_get_MSBuildPath();
-
- if (msbuildPath == null)
- throw new FileNotFoundException("Cannot find the MSBuild executable.");
-
- return msbuildPath;
- }
-
- private static string MonoWindowsBinDir
- {
- get
- {
- string monoWinBinDir = godot_icall_BuildInstance_get_MonoWindowsBinDir();
-
- if (monoWinBinDir == null)
- throw new FileNotFoundException("Cannot find the Windows Mono binaries directory.");
-
- return monoWinBinDir;
- }
- }
-
- private static bool UsingMonoMSBuildOnWindows
- {
- get
- {
- return godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows();
- }
- }
-
- private static bool PrintBuildOutput
- {
- get
- {
- return godot_icall_BuildInstance_get_PrintBuildOutput();
- }
- }
-
- private string solution;
- private string config;
-
- private Process process;
-
- private int exitCode;
- public int ExitCode { get { return exitCode; } }
-
- public bool IsRunning { get { return process != null && !process.HasExited; } }
-
- public BuildInstance(string solution, string config)
- {
- this.solution = solution;
- this.config = config;
- }
-
- public bool Build(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null)
- {
- List<string> customPropertiesList = new List<string>();
-
- if (customProperties != null)
- customPropertiesList.AddRange(customProperties);
-
- string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customPropertiesList);
-
- ProcessStartInfo startInfo = new ProcessStartInfo(GetMSBuildPath(), compilerArgs);
-
- bool redirectOutput = !IsDebugMSBuildRequested() && !PrintBuildOutput;
-
- if (!redirectOutput) // TODO: or if stdout verbose
- Console.WriteLine($"Running: \"{startInfo.FileName}\" {startInfo.Arguments}");
-
- startInfo.RedirectStandardOutput = redirectOutput;
- startInfo.RedirectStandardError = redirectOutput;
- startInfo.UseShellExecute = false;
-
- if (UsingMonoMSBuildOnWindows)
- {
- // These environment variables are required for Mono's MSBuild to find the compilers.
- // We use the batch files in Mono's bin directory to make sure the compilers are executed with mono.
- string monoWinBinDir = MonoWindowsBinDir;
- startInfo.EnvironmentVariables.Add("CscToolExe", Path.Combine(monoWinBinDir, "csc.bat"));
- startInfo.EnvironmentVariables.Add("VbcToolExe", Path.Combine(monoWinBinDir, "vbc.bat"));
- startInfo.EnvironmentVariables.Add("FscToolExe", Path.Combine(monoWinBinDir, "fsharpc.bat"));
- }
-
- // Needed when running from Developer Command Prompt for VS
- RemovePlatformVariable(startInfo.EnvironmentVariables);
-
- using (Process process = new Process())
- {
- process.StartInfo = startInfo;
-
- process.Start();
-
- if (redirectOutput)
- {
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
- }
-
- process.WaitForExit();
-
- exitCode = process.ExitCode;
- }
-
- return true;
- }
-
- public bool BuildAsync(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null)
- {
- if (process != null)
- throw new InvalidOperationException("Already in use");
-
- List<string> customPropertiesList = new List<string>();
-
- if (customProperties != null)
- customPropertiesList.AddRange(customProperties);
-
- string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customPropertiesList);
-
- ProcessStartInfo startInfo = new ProcessStartInfo(GetMSBuildPath(), compilerArgs);
-
- bool redirectOutput = !IsDebugMSBuildRequested() && !PrintBuildOutput;
-
- if (!redirectOutput) // TODO: or if stdout verbose
- Console.WriteLine($"Running: \"{startInfo.FileName}\" {startInfo.Arguments}");
-
- startInfo.RedirectStandardOutput = redirectOutput;
- startInfo.RedirectStandardError = redirectOutput;
- startInfo.UseShellExecute = false;
-
- if (UsingMonoMSBuildOnWindows)
- {
- // These environment variables are required for Mono's MSBuild to find the compilers.
- // We use the batch files in Mono's bin directory to make sure the compilers are executed with mono.
- string monoWinBinDir = MonoWindowsBinDir;
- startInfo.EnvironmentVariables.Add("CscToolExe", Path.Combine(monoWinBinDir, "csc.bat"));
- startInfo.EnvironmentVariables.Add("VbcToolExe", Path.Combine(monoWinBinDir, "vbc.bat"));
- startInfo.EnvironmentVariables.Add("FscToolExe", Path.Combine(monoWinBinDir, "fsharpc.bat"));
- }
-
- // Needed when running from Developer Command Prompt for VS
- RemovePlatformVariable(startInfo.EnvironmentVariables);
-
- process = new Process();
- process.StartInfo = startInfo;
- process.EnableRaisingEvents = true;
- process.Exited += new EventHandler(BuildProcess_Exited);
-
- process.Start();
-
- if (redirectOutput)
- {
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
- }
-
- return true;
- }
-
- private string BuildArguments(string loggerAssemblyPath, string loggerOutputDir, List<string> customProperties)
- {
- string arguments = string.Format(@"""{0}"" /v:normal /t:Rebuild ""/p:{1}"" ""/l:{2},{3};{4}""",
- solution,
- "Configuration=" + config,
- typeof(GodotBuildLogger).FullName,
- loggerAssemblyPath,
- loggerOutputDir
- );
-
- foreach (string customProperty in customProperties)
- {
- arguments += " /p:" + customProperty;
- }
-
- return arguments;
- }
-
- private void RemovePlatformVariable(StringDictionary environmentVariables)
- {
- // EnvironmentVariables is case sensitive? Seriously?
-
- List<string> platformEnvironmentVariables = new List<string>();
-
- foreach (string env in environmentVariables.Keys)
- {
- if (env.ToUpper() == "PLATFORM")
- platformEnvironmentVariables.Add(env);
- }
-
- foreach (string env in platformEnvironmentVariables)
- environmentVariables.Remove(env);
- }
-
- private void BuildProcess_Exited(object sender, System.EventArgs e)
- {
- exitCode = process.ExitCode;
-
- godot_icall_BuildInstance_ExitCallback(solution, config, exitCode);
-
- Dispose();
- }
-
- private static bool IsDebugMSBuildRequested()
- {
- return Environment.GetEnvironmentVariable("GODOT_DEBUG_MSBUILD")?.Trim() == "1";
- }
-
- public void Dispose()
- {
- if (process != null)
- {
- process.Dispose();
- process = null;
- }
- }
- }
-
- public class GodotBuildLogger : ILogger
- {
- public string Parameters { get; set; }
- public LoggerVerbosity Verbosity { get; set; }
-
- public void Initialize(IEventSource eventSource)
- {
- if (null == Parameters)
- throw new LoggerException("Log directory was not set.");
-
- string[] parameters = Parameters.Split(new[] { ';' });
-
- string logDir = parameters[0];
-
- if (String.IsNullOrEmpty(logDir))
- throw new LoggerException("Log directory was not set.");
-
- if (parameters.Length > 1)
- throw new LoggerException("Too many parameters passed.");
-
- string logFile = Path.Combine(logDir, "msbuild_log.txt");
- string issuesFile = Path.Combine(logDir, "msbuild_issues.csv");
-
- try
- {
- if (!Directory.Exists(logDir))
- Directory.CreateDirectory(logDir);
-
- this.logStreamWriter = new StreamWriter(logFile);
- this.issuesStreamWriter = new StreamWriter(issuesFile);
- }
- catch (Exception ex)
- {
- if
- (
- ex is UnauthorizedAccessException
- || ex is ArgumentNullException
- || ex is PathTooLongException
- || ex is DirectoryNotFoundException
- || ex is NotSupportedException
- || ex is ArgumentException
- || ex is SecurityException
- || ex is IOException
- )
- {
- throw new LoggerException("Failed to create log file: " + ex.Message);
- }
- else
- {
- // Unexpected failure
- throw;
- }
- }
-
- eventSource.ProjectStarted += new ProjectStartedEventHandler(eventSource_ProjectStarted);
- eventSource.TaskStarted += new TaskStartedEventHandler(eventSource_TaskStarted);
- eventSource.MessageRaised += new BuildMessageEventHandler(eventSource_MessageRaised);
- eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised);
- eventSource.ErrorRaised += new BuildErrorEventHandler(eventSource_ErrorRaised);
- eventSource.ProjectFinished += new ProjectFinishedEventHandler(eventSource_ProjectFinished);
- }
-
- void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e)
- {
- string line = String.Format("{0}({1},{2}): error {3}: {4}", e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message);
-
- if (e.ProjectFile.Length > 0)
- line += string.Format(" [{0}]", e.ProjectFile);
-
- WriteLine(line);
-
- string errorLine = String.Format(@"error,{0},{1},{2},{3},{4},{5}",
- e.File.CsvEscape(), e.LineNumber, e.ColumnNumber,
- e.Code.CsvEscape(), e.Message.CsvEscape(), e.ProjectFile.CsvEscape());
- issuesStreamWriter.WriteLine(errorLine);
- }
-
- void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
- {
- string line = String.Format("{0}({1},{2}): warning {3}: {4}", e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message, e.ProjectFile);
-
- if (e.ProjectFile != null && e.ProjectFile.Length > 0)
- line += string.Format(" [{0}]", e.ProjectFile);
-
- WriteLine(line);
-
- string warningLine = String.Format(@"warning,{0},{1},{2},{3},{4},{5}",
- e.File.CsvEscape(), e.LineNumber, e.ColumnNumber,
- e.Code.CsvEscape(), e.Message.CsvEscape(), e.ProjectFile != null ? e.ProjectFile.CsvEscape() : string.Empty);
- issuesStreamWriter.WriteLine(warningLine);
- }
-
- void eventSource_MessageRaised(object sender, BuildMessageEventArgs e)
- {
- // BuildMessageEventArgs adds Importance to BuildEventArgs
- // Let's take account of the verbosity setting we've been passed in deciding whether to log the message
- if ((e.Importance == MessageImportance.High && IsVerbosityAtLeast(LoggerVerbosity.Minimal))
- || (e.Importance == MessageImportance.Normal && IsVerbosityAtLeast(LoggerVerbosity.Normal))
- || (e.Importance == MessageImportance.Low && IsVerbosityAtLeast(LoggerVerbosity.Detailed))
- )
- {
- WriteLineWithSenderAndMessage(String.Empty, e);
- }
- }
-
- void eventSource_TaskStarted(object sender, TaskStartedEventArgs e)
- {
- // TaskStartedEventArgs adds ProjectFile, TaskFile, TaskName
- // To keep this log clean, this logger will ignore these events.
- }
-
- void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
- {
- WriteLine(e.Message);
- indent++;
- }
-
- void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e)
- {
- indent--;
- WriteLine(e.Message);
- }
-
- /// <summary>
- /// Write a line to the log, adding the SenderName
- /// </summary>
- private void WriteLineWithSender(string line, BuildEventArgs e)
- {
- if (0 == String.Compare(e.SenderName, "MSBuild", true /*ignore case*/))
- {
- // Well, if the sender name is MSBuild, let's leave it out for prettiness
- WriteLine(line);
- }
- else
- {
- WriteLine(e.SenderName + ": " + line);
- }
- }
-
- /// <summary>
- /// Write a line to the log, adding the SenderName and Message
- /// (these parameters are on all MSBuild event argument objects)
- /// </summary>
- private void WriteLineWithSenderAndMessage(string line, BuildEventArgs e)
- {
- if (0 == String.Compare(e.SenderName, "MSBuild", true /*ignore case*/))
- {
- // Well, if the sender name is MSBuild, let's leave it out for prettiness
- WriteLine(line + e.Message);
- }
- else
- {
- WriteLine(e.SenderName + ": " + line + e.Message);
- }
- }
-
- private void WriteLine(string line)
- {
- for (int i = indent; i > 0; i--)
- {
- logStreamWriter.Write("\t");
- }
- logStreamWriter.WriteLine(line);
- }
-
- public void Shutdown()
- {
- logStreamWriter.Close();
- issuesStreamWriter.Close();
- }
-
- public bool IsVerbosityAtLeast(LoggerVerbosity checkVerbosity)
- {
- return this.Verbosity >= checkVerbosity;
- }
-
- private StreamWriter logStreamWriter;
- private StreamWriter issuesStreamWriter;
- private int indent;
- }
-}
diff --git a/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs b/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs
deleted file mode 100644
index 44a43f0ddd..0000000000
--- a/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.CompilerServices;
-
-namespace GodotSharpTools.Editor
-{
- public static class GodotSharpExport
- {
- public static void _ExportBegin(string[] features, bool debug, string path, int flags)
- {
- var featureSet = new HashSet<string>(features);
-
- if (PlatformHasTemplateDir(featureSet))
- {
- string templateDirName = "data.mono";
-
- if (featureSet.Contains("Windows"))
- {
- templateDirName += ".windows";
- templateDirName += featureSet.Contains("64") ? ".64" : ".32";
- }
- else if (featureSet.Contains("X11"))
- {
- templateDirName += ".x11";
- templateDirName += featureSet.Contains("64") ? ".64" : ".32";
- }
- else
- {
- throw new NotSupportedException("Target platform not supported");
- }
-
- templateDirName += debug ? ".release_debug" : ".release";
-
- string templateDirPath = Path.Combine(GetTemplatesDir(), templateDirName);
-
- if (!Directory.Exists(templateDirPath))
- throw new FileNotFoundException("Data template directory not found");
-
- string outputDir = new FileInfo(path).Directory.FullName;
-
- string outputDataDir = Path.Combine(outputDir, GetDataDirName());
-
- if (Directory.Exists(outputDataDir))
- Directory.Delete(outputDataDir, recursive: true); // Clean first
-
- Directory.CreateDirectory(outputDataDir);
-
- foreach (string dir in Directory.GetDirectories(templateDirPath, "*", SearchOption.AllDirectories))
- {
- Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(templateDirPath.Length + 1)));
- }
-
- foreach (string file in Directory.GetFiles(templateDirPath, "*", SearchOption.AllDirectories))
- {
- File.Copy(file, Path.Combine(outputDataDir, file.Substring(templateDirPath.Length + 1)));
- }
- }
- }
-
- public static bool PlatformHasTemplateDir(HashSet<string> featureSet)
- {
- // OSX export templates are contained in a zip, so we place
- // our custom template inside it and let Godot do the rest.
- return !featureSet.Any(f => new[] {"OSX", "Android"}.Contains(f));
- }
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- extern static string GetTemplatesDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- extern static string GetDataDirName();
- }
-}
diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.sln b/modules/mono/editor/GodotSharpTools/GodotSharpTools.sln
deleted file mode 100644
index 5f7d0e8a39..0000000000
--- a/modules/mono/editor/GodotSharpTools/GodotSharpTools.sln
+++ /dev/null
@@ -1,17 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharpTools", "GodotSharpTools.csproj", "{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
-EndGlobal
diff --git a/modules/mono/editor/GodotSharpTools/Utils/OS.cs b/modules/mono/editor/GodotSharpTools/Utils/OS.cs
deleted file mode 100644
index 148e954e77..0000000000
--- a/modules/mono/editor/GodotSharpTools/Utils/OS.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using System;
-using System.Linq;
-using System.Runtime.CompilerServices;
-
-namespace GodotSharpTools.Utils
-{
- public static class OS
- {
- [MethodImpl(MethodImplOptions.InternalCall)]
- extern static string GetPlatformName();
-
- const string HaikuName = "Haiku";
- const string OSXName = "OSX";
- const string ServerName = "Server";
- const string UWPName = "UWP";
- const string WindowsName = "Windows";
- const string X11Name = "X11";
-
- public static bool IsHaiku()
- {
- return HaikuName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
- }
-
- public static bool IsOSX()
- {
- return OSXName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
- }
-
- public static bool IsServer()
- {
- return ServerName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
- }
-
- public static bool IsUWP()
- {
- return UWPName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
- }
-
- public static bool IsWindows()
- {
- return WindowsName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
- }
-
- public static bool IsX11()
- {
- return X11Name.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
- }
-
- static bool? IsUnixCache = null;
- static readonly string[] UnixPlatforms = new string[] { HaikuName, OSXName, ServerName, X11Name };
-
- public static bool IsUnix()
- {
- if (IsUnixCache.HasValue)
- return IsUnixCache.Value;
-
- string osName = GetPlatformName();
- IsUnixCache = UnixPlatforms.Any(p => p.Equals(osName, StringComparison.OrdinalIgnoreCase));
- return IsUnixCache.Value;
- }
- }
-}
diff --git a/modules/mono/editor/GodotTools/.gitignore b/modules/mono/editor/GodotTools/.gitignore
new file mode 100644
index 0000000000..48e2f914d8
--- /dev/null
+++ b/modules/mono/editor/GodotTools/.gitignore
@@ -0,0 +1,356 @@
+# Rider
+.idea/
+
+# Visual Studio Code
+.vscode/
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
new file mode 100644
index 0000000000..a0f6f1ff32
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
@@ -0,0 +1,186 @@
+using System;
+using System.IO;
+using System.Security;
+using Microsoft.Build.Framework;
+using GodotTools.Core;
+
+namespace GodotTools.BuildLogger
+{
+ public class GodotBuildLogger : ILogger
+ {
+ public static readonly string AssemblyPath = Path.GetFullPath(typeof(GodotBuildLogger).Assembly.Location);
+
+ public string Parameters { get; set; }
+ public LoggerVerbosity Verbosity { get; set; }
+
+ public void Initialize(IEventSource eventSource)
+ {
+ if (null == Parameters)
+ throw new LoggerException("Log directory was not set.");
+
+ var parameters = Parameters.Split(new[] {';'});
+
+ string logDir = parameters[0];
+
+ if (string.IsNullOrEmpty(logDir))
+ throw new LoggerException("Log directory was not set.");
+
+ if (parameters.Length > 1)
+ throw new LoggerException("Too many parameters passed.");
+
+ string logFile = Path.Combine(logDir, "msbuild_log.txt");
+ string issuesFile = Path.Combine(logDir, "msbuild_issues.csv");
+
+ try
+ {
+ if (!Directory.Exists(logDir))
+ Directory.CreateDirectory(logDir);
+
+ logStreamWriter = new StreamWriter(logFile);
+ issuesStreamWriter = new StreamWriter(issuesFile);
+ }
+ catch (Exception ex)
+ {
+ if (ex is UnauthorizedAccessException
+ || ex is ArgumentNullException
+ || ex is PathTooLongException
+ || ex is DirectoryNotFoundException
+ || ex is NotSupportedException
+ || ex is ArgumentException
+ || ex is SecurityException
+ || ex is IOException)
+ {
+ throw new LoggerException("Failed to create log file: " + ex.Message);
+ }
+ else
+ {
+ // Unexpected failure
+ throw;
+ }
+ }
+
+ eventSource.ProjectStarted += eventSource_ProjectStarted;
+ eventSource.TaskStarted += eventSource_TaskStarted;
+ eventSource.MessageRaised += eventSource_MessageRaised;
+ eventSource.WarningRaised += eventSource_WarningRaised;
+ eventSource.ErrorRaised += eventSource_ErrorRaised;
+ eventSource.ProjectFinished += eventSource_ProjectFinished;
+ }
+
+ void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e)
+ {
+ string line = $"{e.File}({e.LineNumber},{e.ColumnNumber}): error {e.Code}: {e.Message}";
+
+ if (e.ProjectFile.Length > 0)
+ line += $" [{e.ProjectFile}]";
+
+ WriteLine(line);
+
+ string errorLine = $@"error,{e.File.CsvEscape()},{e.LineNumber},{e.ColumnNumber}," +
+ $@"{e.Code.CsvEscape()},{e.Message.CsvEscape()},{e.ProjectFile.CsvEscape()}";
+ issuesStreamWriter.WriteLine(errorLine);
+ }
+
+ void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
+ {
+ string line = $"{e.File}({e.LineNumber},{e.ColumnNumber}): warning {e.Code}: {e.Message}";
+
+ if (!string.IsNullOrEmpty(e.ProjectFile))
+ line += $" [{e.ProjectFile}]";
+
+ WriteLine(line);
+
+ string warningLine = $@"warning,{e.File.CsvEscape()},{e.LineNumber},{e.ColumnNumber},{e.Code.CsvEscape()}," +
+ $@"{e.Message.CsvEscape()},{(e.ProjectFile != null ? e.ProjectFile.CsvEscape() : string.Empty)}";
+ issuesStreamWriter.WriteLine(warningLine);
+ }
+
+ private void eventSource_MessageRaised(object sender, BuildMessageEventArgs e)
+ {
+ // BuildMessageEventArgs adds Importance to BuildEventArgs
+ // Let's take account of the verbosity setting we've been passed in deciding whether to log the message
+ if (e.Importance == MessageImportance.High && IsVerbosityAtLeast(LoggerVerbosity.Minimal)
+ || e.Importance == MessageImportance.Normal && IsVerbosityAtLeast(LoggerVerbosity.Normal)
+ || e.Importance == MessageImportance.Low && IsVerbosityAtLeast(LoggerVerbosity.Detailed))
+ {
+ WriteLineWithSenderAndMessage(string.Empty, e);
+ }
+ }
+
+ private void eventSource_TaskStarted(object sender, TaskStartedEventArgs e)
+ {
+ // TaskStartedEventArgs adds ProjectFile, TaskFile, TaskName
+ // To keep this log clean, this logger will ignore these events.
+ }
+
+ private void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
+ {
+ WriteLine(e.Message);
+ indent++;
+ }
+
+ private void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e)
+ {
+ indent--;
+ WriteLine(e.Message);
+ }
+
+ /// <summary>
+ /// Write a line to the log, adding the SenderName
+ /// </summary>
+ private void WriteLineWithSender(string line, BuildEventArgs e)
+ {
+ if (0 == string.Compare(e.SenderName, "MSBuild", StringComparison.OrdinalIgnoreCase))
+ {
+ // Well, if the sender name is MSBuild, let's leave it out for prettiness
+ WriteLine(line);
+ }
+ else
+ {
+ WriteLine(e.SenderName + ": " + line);
+ }
+ }
+
+ /// <summary>
+ /// Write a line to the log, adding the SenderName and Message
+ /// (these parameters are on all MSBuild event argument objects)
+ /// </summary>
+ private void WriteLineWithSenderAndMessage(string line, BuildEventArgs e)
+ {
+ if (0 == string.Compare(e.SenderName, "MSBuild", StringComparison.OrdinalIgnoreCase))
+ {
+ // Well, if the sender name is MSBuild, let's leave it out for prettiness
+ WriteLine(line + e.Message);
+ }
+ else
+ {
+ WriteLine(e.SenderName + ": " + line + e.Message);
+ }
+ }
+
+ private void WriteLine(string line)
+ {
+ for (int i = indent; i > 0; i--)
+ {
+ logStreamWriter.Write("\t");
+ }
+
+ logStreamWriter.WriteLine(line);
+ }
+
+ public void Shutdown()
+ {
+ logStreamWriter.Close();
+ issuesStreamWriter.Close();
+ }
+
+ private bool IsVerbosityAtLeast(LoggerVerbosity checkVerbosity)
+ {
+ return Verbosity >= checkVerbosity;
+ }
+
+ private StreamWriter logStreamWriter;
+ private StreamWriter issuesStreamWriter;
+ private int indent;
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj
new file mode 100644
index 0000000000..f3ac353c0f
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{6CE9A984-37B1-4F8A-8FE9-609F05F071B3}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>GodotTools.BuildLogger</RootNamespace>
+ <AssemblyName>GodotTools.BuildLogger</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>portable</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugType>portable</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.Build.Framework" />
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="GodotBuildLogger.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj">
+ <Project>{639e48bd-44e5-4091-8edd-22d36dc0768d}</Project>
+ <Name>GodotTools.Core</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/Properties/AssemblyInfo.cs b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..8717c4901e
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("GodotTools.BuildLogger")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Godot Engine contributors")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("6CE9A984-37B1-4F8A-8FE9-609F05F071B3")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj
new file mode 100644
index 0000000000..f36b40f87c
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{639E48BD-44E5-4091-8EDD-22D36DC0768D}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <RootNamespace>GodotTools.Core</RootNamespace>
+ <AssemblyName>GodotTools.Core</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="ProcessExtensions.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="StringExtensions.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/ProcessExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.Core/ProcessExtensions.cs
new file mode 100644
index 0000000000..43d40f2ad9
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools.Core/ProcessExtensions.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace GodotTools.Core
+{
+ public static class ProcessExtensions
+ {
+ public static async Task WaitForExitAsync(this Process process, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var tcs = new TaskCompletionSource<bool>();
+
+ void ProcessExited(object sender, EventArgs e)
+ {
+ tcs.TrySetResult(true);
+ }
+
+ process.EnableRaisingEvents = true;
+ process.Exited += ProcessExited;
+
+ try
+ {
+ if (process.HasExited)
+ return;
+
+ using (cancellationToken.Register(() => tcs.TrySetCanceled()))
+ {
+ await tcs.Task;
+ }
+ }
+ finally
+ {
+ process.Exited -= ProcessExited;
+ }
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/Properties/AssemblyInfo.cs b/modules/mono/editor/GodotTools/GodotTools.Core/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..699ae6e741
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools.Core/Properties/AssemblyInfo.cs
@@ -0,0 +1,26 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("GodotTools.Core")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Godot Engine contributors")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
diff --git a/modules/mono/editor/GodotSharpTools/StringExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
index b0436d2f18..8cd7e76303 100644
--- a/modules/mono/editor/GodotSharpTools/StringExtensions.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
@@ -1,7 +1,8 @@
using System;
+using System.Collections.Generic;
using System.IO;
-namespace GodotSharpTools
+namespace GodotTools.Core
{
public static class StringExtensions
{
@@ -25,7 +26,7 @@ namespace GodotSharpTools
path = path.Replace('\\', '/');
- string[] parts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
+ string[] parts = path.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
path = string.Join(Path.DirectorySeparatorChar.ToString(), parts).Trim();
@@ -37,18 +38,40 @@ namespace GodotSharpTools
public static bool IsAbsolutePath(this string path)
{
return path.StartsWith("/", StringComparison.Ordinal) ||
- path.StartsWith("\\", StringComparison.Ordinal) ||
- path.StartsWith(driveRoot, StringComparison.Ordinal);
+ path.StartsWith("\\", StringComparison.Ordinal) ||
+ path.StartsWith(driveRoot, StringComparison.Ordinal);
}
public static string CsvEscape(this string value, char delimiter = ',')
{
- bool hasSpecialChar = value.IndexOfAny(new char[] { '\"', '\n', '\r', delimiter }) != -1;
+ bool hasSpecialChar = value.IndexOfAny(new char[] {'\"', '\n', '\r', delimiter}) != -1;
if (hasSpecialChar)
return "\"" + value.Replace("\"", "\"\"") + "\"";
return value;
}
+
+ public static string ToSafeDirName(this string dirName, bool allowDirSeparator)
+ {
+ var invalidChars = new List<string> {":", "*", "?", "\"", "<", ">", "|"};
+
+ if (allowDirSeparator)
+ {
+ // Directory separators are allowed, but disallow ".." to avoid going up the filesystem
+ invalidChars.Add("..");
+ }
+ else
+ {
+ invalidChars.Add("/");
+ }
+
+ string safeDirName = dirName.Replace("\\", "/").Trim();
+
+ foreach (string invalidChar in invalidChars)
+ safeDirName = safeDirName.Replace(invalidChar, "-");
+
+ return safeDirName;
+ }
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ApiAssembliesInfo.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ApiAssembliesInfo.cs
new file mode 100644
index 0000000000..345a472185
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ApiAssembliesInfo.cs
@@ -0,0 +1,15 @@
+namespace GodotTools
+{
+ public static class ApiAssemblyNames
+ {
+ public const string SolutionName = "GodotSharp";
+ public const string Core = "GodotSharp";
+ public const string Editor = "GodotSharpEditor";
+ }
+
+ public enum ApiAssemblyType
+ {
+ Core,
+ Editor
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ApiSolutionGenerator.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ApiSolutionGenerator.cs
new file mode 100644
index 0000000000..bfae2afc13
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ApiSolutionGenerator.cs
@@ -0,0 +1,52 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace GodotTools.ProjectEditor
+{
+ public static class ApiSolutionGenerator
+ {
+ public static void GenerateApiSolution(string solutionDir,
+ string coreProjDir, IEnumerable<string> coreCompileItems,
+ string editorProjDir, IEnumerable<string> editorCompileItems)
+ {
+ var solution = new DotNetSolution(ApiAssemblyNames.SolutionName);
+
+ solution.DirectoryPath = solutionDir;
+
+ // GodotSharp project
+
+ const string coreApiAssemblyName = ApiAssemblyNames.Core;
+
+ string coreGuid = ProjectGenerator.GenCoreApiProject(coreProjDir, coreCompileItems);
+
+ var coreProjInfo = new DotNetSolution.ProjectInfo
+ {
+ Guid = coreGuid,
+ PathRelativeToSolution = Path.Combine(coreApiAssemblyName, $"{coreApiAssemblyName}.csproj")
+ };
+ coreProjInfo.Configs.Add("Debug");
+ coreProjInfo.Configs.Add("Release");
+
+ solution.AddNewProject(coreApiAssemblyName, coreProjInfo);
+
+ // GodotSharpEditor project
+
+ const string editorApiAssemblyName = ApiAssemblyNames.Editor;
+
+ string editorGuid = ProjectGenerator.GenEditorApiProject(editorProjDir,
+ $"../{coreApiAssemblyName}/{coreApiAssemblyName}.csproj", editorCompileItems);
+
+ var editorProjInfo = new DotNetSolution.ProjectInfo();
+ editorProjInfo.Guid = editorGuid;
+ editorProjInfo.PathRelativeToSolution = Path.Combine(editorApiAssemblyName, $"{editorApiAssemblyName}.csproj");
+ editorProjInfo.Configs.Add("Debug");
+ editorProjInfo.Configs.Add("Release");
+
+ solution.AddNewProject(editorApiAssemblyName, editorProjInfo);
+
+ // Save solution
+
+ solution.Save();
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs
new file mode 100644
index 0000000000..76cb249acf
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs
@@ -0,0 +1,122 @@
+using GodotTools.Core;
+using System.Collections.Generic;
+using System.IO;
+
+namespace GodotTools.ProjectEditor
+{
+ public class DotNetSolution
+ {
+ private string directoryPath;
+ private readonly Dictionary<string, ProjectInfo> projects = new Dictionary<string, ProjectInfo>();
+
+ public string Name { get; }
+
+ public string DirectoryPath
+ {
+ get => directoryPath;
+ set => directoryPath = value.IsAbsolutePath() ? value : Path.GetFullPath(value);
+ }
+
+ public class ProjectInfo
+ {
+ public string Guid;
+ public string PathRelativeToSolution;
+ public List<string> Configs = new List<string>();
+ }
+
+ public void AddNewProject(string name, ProjectInfo projectInfo)
+ {
+ projects[name] = projectInfo;
+ }
+
+ public bool HasProject(string name)
+ {
+ return projects.ContainsKey(name);
+ }
+
+ public ProjectInfo GetProjectInfo(string name)
+ {
+ return projects[name];
+ }
+
+ public bool RemoveProject(string name)
+ {
+ return projects.Remove(name);
+ }
+
+ public void Save()
+ {
+ if (!Directory.Exists(DirectoryPath))
+ throw new FileNotFoundException("The solution directory does not exist.");
+
+ string projectsDecl = string.Empty;
+ string slnPlatformsCfg = string.Empty;
+ string projPlatformsCfg = string.Empty;
+
+ bool isFirstProject = true;
+
+ foreach (var pair in projects)
+ {
+ string name = pair.Key;
+ ProjectInfo projectInfo = pair.Value;
+
+ if (!isFirstProject)
+ projectsDecl += "\n";
+
+ projectsDecl += string.Format(ProjectDeclaration,
+ name, projectInfo.PathRelativeToSolution.Replace("/", "\\"), projectInfo.Guid);
+
+ for (int i = 0; i < projectInfo.Configs.Count; i++)
+ {
+ string config = projectInfo.Configs[i];
+
+ if (i != 0 || !isFirstProject)
+ {
+ slnPlatformsCfg += "\n";
+ projPlatformsCfg += "\n";
+ }
+
+ slnPlatformsCfg += string.Format(SolutionPlatformsConfig, config);
+ projPlatformsCfg += string.Format(ProjectPlatformsConfig, projectInfo.Guid, config);
+ }
+
+ isFirstProject = false;
+ }
+
+ string solutionPath = Path.Combine(DirectoryPath, Name + ".sln");
+ string content = string.Format(SolutionTemplate, projectsDecl, slnPlatformsCfg, projPlatformsCfg);
+
+ File.WriteAllText(solutionPath, content);
+ }
+
+ public DotNetSolution(string name)
+ {
+ Name = name;
+ }
+
+ const string SolutionTemplate =
+@"Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+{0}
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+{1}
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+{2}
+ EndGlobalSection
+EndGlobal
+";
+
+ const string ProjectDeclaration =
+@"Project(""{{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}}"") = ""{0}"", ""{1}"", ""{{{2}}}""
+EndProject";
+
+ const string SolutionPlatformsConfig =
+@" {0}|Any CPU = {0}|Any CPU";
+
+ const string ProjectPlatformsConfig =
+@" {{{0}}}.{1}|Any CPU.ActiveCfg = {1}|Any CPU
+ {{{0}}}.{1}|Any CPU.Build.0 = {1}|Any CPU";
+ }
+}
diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
index 2871c041f5..08b8ba3946 100644
--- a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
@@ -1,12 +1,12 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}</ProjectGuid>
<OutputType>Library</OutputType>
- <RootNamespace>GodotSharpTools</RootNamespace>
- <AssemblyName>GodotSharpTools</AssemblyName>
+ <RootNamespace>GodotTools.ProjectEditor</RootNamespace>
+ <AssemblyName>GodotTools.ProjectEditor</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<BaseIntermediateOutputPath>obj</BaseIntermediateOutputPath>
</PropertyGroup>
@@ -21,7 +21,6 @@
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>portable</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
@@ -31,25 +30,35 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="Microsoft.Build" />
- <Reference Include="Microsoft.Build.Framework" />
<Reference Include="DotNet.Glob, Version=2.1.1.0, Culture=neutral, PublicKeyToken=b68cc888b4f632d1, processorArchitecture=MSIL">
- <HintPath>packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath>
+ <!--
+ When building Godot with 'mono_glue=no' SCons will build this project alone instead of the
+ entire solution. $(SolutionDir) is not defined in that case, so we need to workaround that.
+ We make SCons restore the NuGet packages in the project directory instead in this case.
+ -->
+ <HintPath Condition=" '$(SolutionDir)' != '' ">$(SolutionDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath>
+ <HintPath>$(ProjectDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath>
+ <HintPath>packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath> <!-- Are you happy CI? -->
</Reference>
</ItemGroup>
<ItemGroup>
- <Compile Include="StringExtensions.cs" />
- <Compile Include="Build\BuildSystem.cs" />
- <Compile Include="Editor\MonoDevelopInstance.cs" />
- <Compile Include="Project\ProjectExtensions.cs" />
- <Compile Include="Project\IdentifierUtils.cs" />
- <Compile Include="Project\ProjectGenerator.cs" />
- <Compile Include="Project\ProjectUtils.cs" />
+ <Compile Include="ApiAssembliesInfo.cs" />
+ <Compile Include="ApiSolutionGenerator.cs" />
+ <Compile Include="DotNetSolution.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Utils\OS.cs" />
- <Compile Include="Editor\GodotSharpExport.cs" />
+ <Compile Include="IdentifierUtils.cs" />
+ <Compile Include="ProjectExtensions.cs" />
+ <Compile Include="ProjectGenerator.cs" />
+ <Compile Include="ProjectUtils.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj">
+ <Project>{639E48BD-44E5-4091-8EDD-22D36DC0768D}</Project>
+ <Name>GodotTools.Core</Name>
+ </ProjectReference>
+ </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/modules/mono/editor/GodotSharpTools/Project/IdentifierUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/IdentifierUtils.cs
index 83e2d2cf8d..f93eb9a1fa 100644
--- a/modules/mono/editor/GodotSharpTools/Project/IdentifierUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/IdentifierUtils.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Text;
-namespace GodotSharpTools.Project
+namespace GodotTools.ProjectEditor
{
public static class IdentifierUtils
{
@@ -12,7 +12,7 @@ namespace GodotSharpTools.Project
if (string.IsNullOrEmpty(qualifiedIdentifier))
throw new ArgumentException($"{nameof(qualifiedIdentifier)} cannot be empty", nameof(qualifiedIdentifier));
- string[] identifiers = qualifiedIdentifier.Split(new[] { '.' });
+ string[] identifiers = qualifiedIdentifier.Split('.');
for (int i = 0; i < identifiers.Length; i++)
{
@@ -66,8 +66,6 @@ namespace GodotSharpTools.Project
if (identifierBuilder.Length > startIndex || @char == '_')
identifierBuilder.Append(@char);
break;
- default:
- break;
}
}
@@ -97,14 +95,14 @@ namespace GodotSharpTools.Project
}
else
{
- if (_doubleUnderscoreKeywords.Contains(value))
+ if (DoubleUnderscoreKeywords.Contains(value))
return true;
}
- return _keywords.Contains(value);
+ return Keywords.Contains(value);
}
- static HashSet<string> _doubleUnderscoreKeywords = new HashSet<string>
+ private static readonly HashSet<string> DoubleUnderscoreKeywords = new HashSet<string>
{
"__arglist",
"__makeref",
@@ -112,7 +110,7 @@ namespace GodotSharpTools.Project
"__refvalue",
};
- static HashSet<string> _keywords = new HashSet<string>
+ private static readonly HashSet<string> Keywords = new HashSet<string>
{
"as",
"do",
diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectExtensions.cs
index 647d9ac81d..36961eb45e 100644
--- a/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectExtensions.cs
@@ -1,8 +1,9 @@
+using GodotTools.Core;
using System;
using DotNet.Globbing;
using Microsoft.Build.Construction;
-namespace GodotSharpTools.Project
+namespace GodotTools.ProjectEditor
{
public static class ProjectExtensions
{
diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
index f4ab11a222..7cf58b6755 100644
--- a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
@@ -1,17 +1,19 @@
+using GodotTools.Core;
using System;
+using System.Collections.Generic;
using System.IO;
using Microsoft.Build.Construction;
-namespace GodotSharpTools.Project
+namespace GodotTools.ProjectEditor
{
public static class ProjectGenerator
{
- public const string CoreApiProjectName = "GodotSharp";
- public const string EditorApiProjectName = "GodotSharpEditor";
- const string CoreApiProjectGuid = "{AEBF0036-DA76-4341-B651-A3F2856AB2FA}";
- const string EditorApiProjectGuid = "{8FBEC238-D944-4074-8548-B3B524305905}";
+ private const string CoreApiProjectName = "GodotSharp";
+ private const string EditorApiProjectName = "GodotSharpEditor";
+ private const string CoreApiProjectGuid = "{AEBF0036-DA76-4341-B651-A3F2856AB2FA}";
+ private const string EditorApiProjectGuid = "{8FBEC238-D944-4074-8548-B3B524305905}";
- public static string GenCoreApiProject(string dir, string[] compileItems)
+ public static string GenCoreApiProject(string dir, IEnumerable<string> compileItems)
{
string path = Path.Combine(dir, CoreApiProjectName + ".csproj");
@@ -24,8 +26,8 @@ namespace GodotSharpTools.Project
mainGroup.SetProperty("BaseIntermediateOutputPath", "obj");
GenAssemblyInfoFile(root, dir, CoreApiProjectName,
- new string[] { "[assembly: InternalsVisibleTo(\"" + EditorApiProjectName + "\")]" },
- new string[] { "System.Runtime.CompilerServices" });
+ new[] {"[assembly: InternalsVisibleTo(\"" + EditorApiProjectName + "\")]"},
+ new[] {"System.Runtime.CompilerServices"});
foreach (var item in compileItems)
{
@@ -37,7 +39,7 @@ namespace GodotSharpTools.Project
return CoreApiProjectGuid;
}
- public static string GenEditorApiProject(string dir, string coreApiProjPath, string[] compileItems)
+ public static string GenEditorApiProject(string dir, string coreApiProjPath, IEnumerable<string> compileItems)
{
string path = Path.Combine(dir, EditorApiProjectName + ".csproj");
@@ -64,7 +66,7 @@ namespace GodotSharpTools.Project
return EditorApiProjectGuid;
}
- public static string GenGameProject(string dir, string name, string[] compileItems)
+ public static string GenGameProject(string dir, string name, IEnumerable<string> compileItems)
{
string path = Path.Combine(dir, name + ".csproj");
@@ -74,6 +76,8 @@ namespace GodotSharpTools.Project
mainGroup.SetProperty("OutputPath", Path.Combine(".mono", "temp", "bin", "$(Configuration)"));
mainGroup.SetProperty("BaseIntermediateOutputPath", Path.Combine(".mono", "temp", "obj"));
mainGroup.SetProperty("IntermediateOutputPath", Path.Combine("$(BaseIntermediateOutputPath)", "$(Configuration)"));
+ mainGroup.SetProperty("ApiConfiguration", "Debug").Condition = " '$(Configuration)' != 'Release' ";
+ mainGroup.SetProperty("ApiConfiguration", "Release").Condition = " '$(Configuration)' == 'Release' ";
var toolsGroup = root.AddPropertyGroup();
toolsGroup.Condition = " '$(Configuration)|$(Platform)' == 'Tools|AnyCPU' ";
@@ -86,11 +90,13 @@ namespace GodotSharpTools.Project
toolsGroup.AddProperty("ConsolePause", "false");
var coreApiRef = root.AddItem("Reference", CoreApiProjectName);
+ coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", "$(ApiConfiguration)", CoreApiProjectName + ".dll"));
coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", CoreApiProjectName + ".dll"));
coreApiRef.AddMetadata("Private", "False");
var editorApiRef = root.AddItem("Reference", EditorApiProjectName);
editorApiRef.Condition = " '$(Configuration)' == 'Tools' ";
+ editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", "$(ApiConfiguration)", EditorApiProjectName + ".dll"));
editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", EditorApiProjectName + ".dll"));
editorApiRef.AddMetadata("Private", "False");
@@ -108,7 +114,6 @@ namespace GodotSharpTools.Project
public static void GenAssemblyInfoFile(ProjectRootElement root, string dir, string name, string[] assemblyLines = null, string[] usingDirectives = null)
{
-
string propertiesDir = Path.Combine(dir, "Properties");
if (!Directory.Exists(propertiesDir))
Directory.CreateDirectory(propertiesDir);
@@ -124,12 +129,9 @@ namespace GodotSharpTools.Project
string assemblyLinesText = string.Empty;
if (assemblyLines != null)
- {
- foreach (var assemblyLine in assemblyLines)
- assemblyLinesText += string.Join("\n", assemblyLines) + "\n";
- }
+ assemblyLinesText += string.Join("\n", assemblyLines) + "\n";
- string content = string.Format(assemblyInfoTemplate, usingDirectivesText, name, assemblyLinesText);
+ string content = string.Format(AssemblyInfoTemplate, usingDirectivesText, name, assemblyLinesText);
string assemblyInfoFile = Path.Combine(propertiesDir, "AssemblyInfo.cs");
@@ -194,8 +196,8 @@ namespace GodotSharpTools.Project
}
}
- private const string assemblyInfoTemplate =
-@"using System.Reflection;{0}
+ private const string AssemblyInfoTemplate =
+ @"using System.Reflection;{0}
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
index a13f4fd6ef..22cf89695d 100644
--- a/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
@@ -1,9 +1,10 @@
+using GodotTools.Core;
using System.Collections.Generic;
using System.IO;
using DotNet.Globbing;
using Microsoft.Build.Construction;
-namespace GodotSharpTools.Project
+namespace GodotTools.ProjectEditor
{
public static class ProjectUtils
{
@@ -53,7 +54,7 @@ namespace GodotSharpTools.Project
var glob = Glob.Parse(normalizedInclude, globOptions);
- // TODO Check somehow if path has no blog to avoid the following loop...
+ // TODO Check somehow if path has no blob to avoid the following loop...
foreach (var existingFile in existingFiles)
{
diff --git a/modules/mono/editor/GodotSharpTools/Properties/AssemblyInfo.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/Properties/AssemblyInfo.cs
index 7115d8fc71..09333850fc 100644
--- a/modules/mono/editor/GodotSharpTools/Properties/AssemblyInfo.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/Properties/AssemblyInfo.cs
@@ -4,12 +4,12 @@ using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
-[assembly: AssemblyTitle("GodotSharpTools")]
+[assembly: AssemblyTitle("GodotTools.ProjectEditor")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
-[assembly: AssemblyCopyright("ignacio")]
+[assembly: AssemblyCopyright("Godot Engine contributors")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/modules/mono/editor/GodotSharpTools/packages.config b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/packages.config
index 2c7cb0bd4b..13915000e4 100644
--- a/modules/mono/editor/GodotSharpTools/packages.config
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/packages.config
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="DotNet.Glob" version="2.1.1" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
new file mode 100644
index 0000000000..f849356919
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
@@ -0,0 +1,172 @@
+using GodotTools.Core;
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.IO;
+using System.Threading.Tasks;
+using GodotTools.BuildLogger;
+using GodotTools.Internals;
+using GodotTools.Utils;
+using Directory = System.IO.Directory;
+
+namespace GodotTools.Build
+{
+ public static class BuildSystem
+ {
+ private static string GetMsBuildPath()
+ {
+ string msbuildPath = MsBuildFinder.FindMsBuild();
+
+ if (msbuildPath == null)
+ throw new FileNotFoundException("Cannot find the MSBuild executable.");
+
+ return msbuildPath;
+ }
+
+ private static string MonoWindowsBinDir
+ {
+ get
+ {
+ string monoWinBinDir = Path.Combine(Internal.MonoWindowsInstallRoot, "bin");
+
+ if (!Directory.Exists(monoWinBinDir))
+ throw new FileNotFoundException("Cannot find the Windows Mono install bin directory.");
+
+ return monoWinBinDir;
+ }
+ }
+
+ private static Godot.EditorSettings EditorSettings =>
+ GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
+
+ private static bool UsingMonoMsBuildOnWindows
+ {
+ get
+ {
+ if (OS.IsWindows())
+ {
+ return (GodotSharpBuilds.BuildTool) EditorSettings.GetSetting("mono/builds/build_tool")
+ == GodotSharpBuilds.BuildTool.MsBuildMono;
+ }
+
+ return false;
+ }
+ }
+
+ private static bool PrintBuildOutput =>
+ (bool) EditorSettings.GetSetting("mono/builds/print_build_output");
+
+ private static Process LaunchBuild(string solution, string config, string loggerOutputDir, IEnumerable<string> customProperties = null)
+ {
+ var customPropertiesList = new List<string>();
+
+ if (customProperties != null)
+ customPropertiesList.AddRange(customProperties);
+
+ string compilerArgs = BuildArguments(solution, config, loggerOutputDir, customPropertiesList);
+
+ var startInfo = new ProcessStartInfo(GetMsBuildPath(), compilerArgs);
+
+ bool redirectOutput = !IsDebugMsBuildRequested() && !PrintBuildOutput;
+
+ if (!redirectOutput || Godot.OS.IsStdoutVerbose())
+ Console.WriteLine($"Running: \"{startInfo.FileName}\" {startInfo.Arguments}");
+
+ startInfo.RedirectStandardOutput = redirectOutput;
+ startInfo.RedirectStandardError = redirectOutput;
+ startInfo.UseShellExecute = false;
+
+ if (UsingMonoMsBuildOnWindows)
+ {
+ // These environment variables are required for Mono's MSBuild to find the compilers.
+ // We use the batch files in Mono's bin directory to make sure the compilers are executed with mono.
+ string monoWinBinDir = MonoWindowsBinDir;
+ startInfo.EnvironmentVariables.Add("CscToolExe", Path.Combine(monoWinBinDir, "csc.bat"));
+ startInfo.EnvironmentVariables.Add("VbcToolExe", Path.Combine(monoWinBinDir, "vbc.bat"));
+ startInfo.EnvironmentVariables.Add("FscToolExe", Path.Combine(monoWinBinDir, "fsharpc.bat"));
+ }
+
+ // Needed when running from Developer Command Prompt for VS
+ RemovePlatformVariable(startInfo.EnvironmentVariables);
+
+ var process = new Process {StartInfo = startInfo};
+
+ process.Start();
+
+ if (redirectOutput)
+ {
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+ }
+
+ return process;
+ }
+
+ public static int Build(MonoBuildInfo monoBuildInfo)
+ {
+ return Build(monoBuildInfo.Solution, monoBuildInfo.Configuration,
+ monoBuildInfo.LogsDirPath, monoBuildInfo.CustomProperties);
+ }
+
+ public static async Task<int> BuildAsync(MonoBuildInfo monoBuildInfo)
+ {
+ return await BuildAsync(monoBuildInfo.Solution, monoBuildInfo.Configuration,
+ monoBuildInfo.LogsDirPath, monoBuildInfo.CustomProperties);
+ }
+
+ public static int Build(string solution, string config, string loggerOutputDir, IEnumerable<string> customProperties = null)
+ {
+ using (var process = LaunchBuild(solution, config, loggerOutputDir, customProperties))
+ {
+ process.WaitForExit();
+
+ return process.ExitCode;
+ }
+ }
+
+ public static async Task<int> BuildAsync(string solution, string config, string loggerOutputDir, IEnumerable<string> customProperties = null)
+ {
+ using (var process = LaunchBuild(solution, config, loggerOutputDir, customProperties))
+ {
+ await process.WaitForExitAsync();
+
+ return process.ExitCode;
+ }
+ }
+
+ private static string BuildArguments(string solution, string config, string loggerOutputDir, List<string> customProperties)
+ {
+ string arguments = $@"""{solution}"" /v:normal /t:Rebuild ""/p:{"Configuration=" + config}"" " +
+ $@"""/l:{typeof(GodotBuildLogger).FullName},{GodotBuildLogger.AssemblyPath};{loggerOutputDir}""";
+
+ foreach (string customProperty in customProperties)
+ {
+ arguments += " /p:" + customProperty;
+ }
+
+ return arguments;
+ }
+
+ private static void RemovePlatformVariable(StringDictionary environmentVariables)
+ {
+ // EnvironmentVariables is case sensitive? Seriously?
+
+ var platformEnvironmentVariables = new List<string>();
+
+ foreach (string env in environmentVariables.Keys)
+ {
+ if (env.ToUpper() == "PLATFORM")
+ platformEnvironmentVariables.Add(env);
+ }
+
+ foreach (string env in platformEnvironmentVariables)
+ environmentVariables.Remove(env);
+ }
+
+ private static bool IsDebugMsBuildRequested()
+ {
+ return Environment.GetEnvironmentVariable("GODOT_DEBUG_MSBUILD")?.Trim() == "1";
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
new file mode 100644
index 0000000000..a0d14c43c9
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
@@ -0,0 +1,210 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Godot;
+using GodotTools.Internals;
+using Directory = System.IO.Directory;
+using Environment = System.Environment;
+using File = System.IO.File;
+using Path = System.IO.Path;
+using OS = GodotTools.Utils.OS;
+
+namespace GodotTools.Build
+{
+ public static class MsBuildFinder
+ {
+ private static string _msbuildToolsPath = string.Empty;
+ private static string _msbuildUnixPath = string.Empty;
+ private static string _xbuildUnixPath = string.Empty;
+
+ public static string FindMsBuild()
+ {
+ var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
+ var buildTool = (GodotSharpBuilds.BuildTool) editorSettings.GetSetting("mono/builds/build_tool");
+
+ if (OS.IsWindows())
+ {
+ switch (buildTool)
+ {
+ case GodotSharpBuilds.BuildTool.MsBuildVs:
+ {
+ if (_msbuildToolsPath.Empty() || !File.Exists(_msbuildToolsPath))
+ {
+ // Try to search it again if it wasn't found last time or if it was removed from its location
+ _msbuildToolsPath = FindMsBuildToolsPathOnWindows();
+
+ if (_msbuildToolsPath.Empty())
+ {
+ throw new FileNotFoundException($"Cannot find executable for '{GodotSharpBuilds.PropNameMsbuildVs}'. Tried with path: {_msbuildToolsPath}");
+ }
+ }
+
+ if (!_msbuildToolsPath.EndsWith("\\"))
+ _msbuildToolsPath += "\\";
+
+ return Path.Combine(_msbuildToolsPath, "MSBuild.exe");
+ }
+
+ case GodotSharpBuilds.BuildTool.MsBuildMono:
+ {
+ string msbuildPath = Path.Combine(Internal.MonoWindowsInstallRoot, "bin", "msbuild.bat");
+
+ if (!File.Exists(msbuildPath))
+ {
+ throw new FileNotFoundException($"Cannot find executable for '{GodotSharpBuilds.PropNameMsbuildMono}'. Tried with path: {msbuildPath}");
+ }
+
+ return msbuildPath;
+ }
+
+ case GodotSharpBuilds.BuildTool.XBuild:
+ {
+ string xbuildPath = Path.Combine(Internal.MonoWindowsInstallRoot, "bin", "xbuild.bat");
+
+ if (!File.Exists(xbuildPath))
+ {
+ throw new FileNotFoundException($"Cannot find executable for '{GodotSharpBuilds.PropNameXbuild}'. Tried with path: {xbuildPath}");
+ }
+
+ return xbuildPath;
+ }
+
+ default:
+ throw new IndexOutOfRangeException("Invalid build tool in editor settings");
+ }
+ }
+
+ if (OS.IsUnix())
+ {
+ if (buildTool == GodotSharpBuilds.BuildTool.XBuild)
+ {
+ if (_xbuildUnixPath.Empty() || !File.Exists(_xbuildUnixPath))
+ {
+ // Try to search it again if it wasn't found last time or if it was removed from its location
+ _xbuildUnixPath = FindBuildEngineOnUnix("msbuild");
+ }
+
+ if (_xbuildUnixPath.Empty())
+ {
+ throw new FileNotFoundException($"Cannot find binary for '{GodotSharpBuilds.PropNameXbuild}'");
+ }
+ }
+ else
+ {
+ if (_msbuildUnixPath.Empty() || !File.Exists(_msbuildUnixPath))
+ {
+ // Try to search it again if it wasn't found last time or if it was removed from its location
+ _msbuildUnixPath = FindBuildEngineOnUnix("msbuild");
+ }
+
+ if (_msbuildUnixPath.Empty())
+ {
+ throw new FileNotFoundException($"Cannot find binary for '{GodotSharpBuilds.PropNameMsbuildMono}'");
+ }
+ }
+
+ return buildTool != GodotSharpBuilds.BuildTool.XBuild ? _msbuildUnixPath : _xbuildUnixPath;
+ }
+
+ throw new PlatformNotSupportedException();
+ }
+
+ private static IEnumerable<string> MsBuildHintDirs
+ {
+ get
+ {
+ var result = new List<string>();
+
+ if (OS.IsOSX())
+ {
+ result.Add("/Library/Frameworks/Mono.framework/Versions/Current/bin/");
+ result.Add("/usr/local/var/homebrew/linked/mono/bin/");
+ }
+
+ result.Add("/opt/novell/mono/bin/");
+
+ return result;
+ }
+ }
+
+ private static string FindBuildEngineOnUnix(string name)
+ {
+ string ret = OS.PathWhich(name);
+
+ if (!ret.Empty())
+ return ret;
+
+ string retFallback = OS.PathWhich($"{name}.exe");
+
+ if (!retFallback.Empty())
+ return retFallback;
+
+ foreach (string hintDir in MsBuildHintDirs)
+ {
+ string hintPath = Path.Combine(hintDir, name);
+
+ if (File.Exists(hintPath))
+ return hintPath;
+ }
+
+ return string.Empty;
+ }
+
+ private static string FindMsBuildToolsPathOnWindows()
+ {
+ if (!OS.IsWindows())
+ throw new PlatformNotSupportedException();
+
+ // Try to find 15.0 with vswhere
+
+ string vsWherePath = Environment.GetEnvironmentVariable(Internal.GodotIs32Bits() ? "ProgramFiles" : "ProgramFiles(x86)");
+ vsWherePath += "\\Microsoft Visual Studio\\Installer\\vswhere.exe";
+
+ var vsWhereArgs = new[] {"-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild"};
+
+ var outputArray = new Godot.Collections.Array<string>();
+ int exitCode = Godot.OS.Execute(vsWherePath, vsWhereArgs,
+ blocking: true, output: (Godot.Collections.Array) outputArray);
+
+ if (exitCode == 0)
+ return string.Empty;
+
+ if (outputArray.Count == 0)
+ return string.Empty;
+
+ var lines = outputArray[1].Split('\n');
+
+ foreach (string line in lines)
+ {
+ int sepIdx = line.IndexOf(':');
+
+ if (sepIdx <= 0)
+ continue;
+
+ string key = line.Substring(0, sepIdx); // No need to trim
+
+ if (key != "installationPath")
+ continue;
+
+ string value = line.Substring(sepIdx + 1).StripEdges();
+
+ if (value.Empty())
+ throw new FormatException("installationPath value is empty");
+
+ if (!value.EndsWith("\\"))
+ value += "\\";
+
+ // Since VS2019, the directory is simply named "Current"
+ string msbuildDir = Path.Combine(value, "MSBuild\\Current\\Bin");
+
+ if (Directory.Exists(msbuildDir))
+ return msbuildDir;
+
+ // Directory name "15.0" is used in VS 2017
+ return Path.Combine(value, "MSBuild\\15.0\\Bin");
+ }
+
+ return string.Empty;
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/CSharpProject.cs b/modules/mono/editor/GodotTools/GodotTools/CSharpProject.cs
new file mode 100644
index 0000000000..0426f0ac5a
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/CSharpProject.cs
@@ -0,0 +1,115 @@
+using Godot;
+using System;
+using System.Collections.Generic;
+using Godot.Collections;
+using GodotTools.Internals;
+using GodotTools.ProjectEditor;
+using File = GodotTools.Utils.File;
+using Directory = GodotTools.Utils.Directory;
+
+namespace GodotTools
+{
+ public static class CSharpProject
+ {
+ public static string GenerateGameProject(string dir, string name, IEnumerable<string> files = null)
+ {
+ try
+ {
+ return ProjectGenerator.GenGameProject(dir, name, files);
+ }
+ catch (Exception e)
+ {
+ GD.PushError(e.ToString());
+ return string.Empty;
+ }
+ }
+
+ public static void AddItem(string projectPath, string itemType, string include)
+ {
+ if (!(bool) Internal.GlobalDef("mono/project/auto_update_project", true))
+ return;
+
+ ProjectUtils.AddItemToProjectChecked(projectPath, itemType, include);
+ }
+
+ private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+ private static ulong ConvertToTimestamp(this DateTime value)
+ {
+ TimeSpan elapsedTime = value - Epoch;
+ return (ulong) elapsedTime.TotalSeconds;
+ }
+
+ public static void GenerateScriptsMetadata(string projectPath, string outputPath)
+ {
+ if (File.Exists(outputPath))
+ File.Delete(outputPath);
+
+ var oldDict = Internal.GetScriptsMetadataOrNothing();
+ var newDict = new Godot.Collections.Dictionary<string, object>();
+
+ foreach (var includeFile in ProjectUtils.GetIncludeFiles(projectPath, "Compile"))
+ {
+ string projectIncludeFile = ("res://" + includeFile).SimplifyGodotPath();
+
+ ulong modifiedTime = File.GetLastWriteTime(projectIncludeFile).ConvertToTimestamp();
+
+ if (oldDict.TryGetValue(projectIncludeFile, out var oldFileVar))
+ {
+ var oldFileDict = (Dictionary) oldFileVar;
+
+ if (ulong.TryParse((string) oldFileDict["modified_time"], out ulong storedModifiedTime))
+ {
+ if (storedModifiedTime == modifiedTime)
+ {
+ // No changes so no need to parse again
+ newDict[projectIncludeFile] = oldFileDict;
+ continue;
+ }
+ }
+ }
+
+ ScriptClassParser.ParseFileOrThrow(projectIncludeFile, out var classes);
+
+ string searchName = System.IO.Path.GetFileNameWithoutExtension(projectIncludeFile);
+
+ var classDict = new Dictionary();
+
+ foreach (var classDecl in classes)
+ {
+ if (classDecl.BaseCount == 0)
+ continue; // Does not inherit nor implement anything, so it can't be a script class
+
+ string classCmp = classDecl.Nested ?
+ classDecl.Name.Substring(classDecl.Name.LastIndexOf(".", StringComparison.Ordinal) + 1) :
+ classDecl.Name;
+
+ if (classCmp != searchName)
+ continue;
+
+ classDict["namespace"] = classDecl.Namespace;
+ classDict["class_name"] = classDecl.Name;
+ classDict["nested"] = classDecl.Nested;
+ break;
+ }
+
+ if (classDict.Count == 0)
+ continue; // Not found
+
+ newDict[projectIncludeFile] = new Dictionary {["modified_time"] = $"{modifiedTime}", ["class"] = classDict};
+ }
+
+ if (newDict.Count > 0)
+ {
+ string json = JSON.Print(newDict);
+
+ string baseDir = outputPath.GetBaseDir();
+
+ if (!Directory.Exists(baseDir))
+ Directory.CreateDirectory(baseDir);
+
+ File.WriteAllText(outputPath, json);
+ }
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs
new file mode 100644
index 0000000000..433a931941
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs
@@ -0,0 +1,396 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using GodotTools.Build;
+using GodotTools.Internals;
+using GodotTools.Utils;
+using Error = Godot.Error;
+using File = GodotTools.Utils.File;
+using Directory = GodotTools.Utils.Directory;
+
+namespace GodotTools
+{
+ public static class GodotSharpBuilds
+ {
+ private static readonly List<MonoBuildInfo> BuildsInProgress = new List<MonoBuildInfo>();
+
+ public const string PropNameMsbuildMono = "MSBuild (Mono)";
+ public const string PropNameMsbuildVs = "MSBuild (VS Build Tools)";
+ public const string PropNameXbuild = "xbuild (Deprecated)";
+
+ public const string MsBuildIssuesFileName = "msbuild_issues.csv";
+ public const string MsBuildLogFileName = "msbuild_log.txt";
+
+ public enum BuildTool
+ {
+ MsBuildMono,
+ MsBuildVs,
+ XBuild // Deprecated
+ }
+
+ private static void RemoveOldIssuesFile(MonoBuildInfo buildInfo)
+ {
+ var issuesFile = GetIssuesFilePath(buildInfo);
+
+ if (!File.Exists(issuesFile))
+ return;
+
+ File.Delete(issuesFile);
+ }
+
+ private static string _ApiFolderName(ApiAssemblyType apiType)
+ {
+ ulong apiHash = apiType == ApiAssemblyType.Core ?
+ Internal.GetCoreApiHash() :
+ Internal.GetEditorApiHash();
+ return $"{apiHash}_{BindingsGenerator.Version}_{BindingsGenerator.CsGlueVersion}";
+ }
+
+ private static void ShowBuildErrorDialog(string message)
+ {
+ GodotSharpEditor.Instance.ShowErrorDialog(message, "Build error");
+ GodotSharpEditor.Instance.MonoBottomPanel.ShowBuildTab();
+ }
+
+ public static void RestartBuild(MonoBuildTab buildTab) => throw new NotImplementedException();
+ public static void StopBuild(MonoBuildTab buildTab) => throw new NotImplementedException();
+
+ private static string GetLogFilePath(MonoBuildInfo buildInfo)
+ {
+ return Path.Combine(buildInfo.LogsDirPath, MsBuildLogFileName);
+ }
+
+ private static string GetIssuesFilePath(MonoBuildInfo buildInfo)
+ {
+ return Path.Combine(Godot.ProjectSettings.LocalizePath(buildInfo.LogsDirPath), MsBuildIssuesFileName);
+ }
+
+ private static void PrintVerbose(string text)
+ {
+ if (Godot.OS.IsStdoutVerbose())
+ Godot.GD.Print(text);
+ }
+
+ public static bool Build(MonoBuildInfo buildInfo)
+ {
+ if (BuildsInProgress.Contains(buildInfo))
+ throw new InvalidOperationException("A build is already in progress");
+
+ BuildsInProgress.Add(buildInfo);
+
+ try
+ {
+ MonoBuildTab buildTab = GodotSharpEditor.Instance.MonoBottomPanel.GetBuildTabFor(buildInfo);
+ buildTab.OnBuildStart();
+
+ // Required in order to update the build tasks list
+ Internal.GodotMainIteration();
+
+ try
+ {
+ RemoveOldIssuesFile(buildInfo);
+ }
+ catch (IOException e)
+ {
+ buildTab.OnBuildExecFailed($"Cannot remove issues file: {GetIssuesFilePath(buildInfo)}");
+ Console.Error.WriteLine(e);
+ }
+
+ try
+ {
+ int exitCode = BuildSystem.Build(buildInfo);
+
+ if (exitCode != 0)
+ PrintVerbose($"MSBuild exited with code: {exitCode}. Log file: {GetLogFilePath(buildInfo)}");
+
+ buildTab.OnBuildExit(exitCode == 0 ? MonoBuildTab.BuildResults.Success : MonoBuildTab.BuildResults.Error);
+
+ return exitCode == 0;
+ }
+ catch (Exception e)
+ {
+ buildTab.OnBuildExecFailed($"The build method threw an exception.\n{e.GetType().FullName}: {e.Message}");
+ Console.Error.WriteLine(e);
+ return false;
+ }
+ }
+ finally
+ {
+ BuildsInProgress.Remove(buildInfo);
+ }
+ }
+
+ public static async Task<bool> BuildAsync(MonoBuildInfo buildInfo)
+ {
+ if (BuildsInProgress.Contains(buildInfo))
+ throw new InvalidOperationException("A build is already in progress");
+
+ BuildsInProgress.Add(buildInfo);
+
+ try
+ {
+ MonoBuildTab buildTab = GodotSharpEditor.Instance.MonoBottomPanel.GetBuildTabFor(buildInfo);
+
+ try
+ {
+ RemoveOldIssuesFile(buildInfo);
+ }
+ catch (IOException e)
+ {
+ buildTab.OnBuildExecFailed($"Cannot remove issues file: {GetIssuesFilePath(buildInfo)}");
+ Console.Error.WriteLine(e);
+ }
+
+ try
+ {
+ int exitCode = await BuildSystem.BuildAsync(buildInfo);
+
+ if (exitCode != 0)
+ PrintVerbose($"MSBuild exited with code: {exitCode}. Log file: {GetLogFilePath(buildInfo)}");
+
+ buildTab.OnBuildExit(exitCode == 0 ? MonoBuildTab.BuildResults.Success : MonoBuildTab.BuildResults.Error);
+
+ return exitCode == 0;
+ }
+ catch (Exception e)
+ {
+ buildTab.OnBuildExecFailed($"The build method threw an exception.\n{e.GetType().FullName}: {e.Message}");
+ Console.Error.WriteLine(e);
+ return false;
+ }
+ }
+ finally
+ {
+ BuildsInProgress.Remove(buildInfo);
+ }
+ }
+
+ public static bool BuildApiSolution(string apiSlnDir, string config)
+ {
+ string apiSlnFile = Path.Combine(apiSlnDir, $"{ApiAssemblyNames.SolutionName}.sln");
+
+ string coreApiAssemblyDir = Path.Combine(apiSlnDir, ApiAssemblyNames.Core, "bin", config);
+ string coreApiAssemblyFile = Path.Combine(coreApiAssemblyDir, $"{ApiAssemblyNames.Core}.dll");
+
+ string editorApiAssemblyDir = Path.Combine(apiSlnDir, ApiAssemblyNames.Editor, "bin", config);
+ string editorApiAssemblyFile = Path.Combine(editorApiAssemblyDir, $"{ApiAssemblyNames.Editor}.dll");
+
+ if (File.Exists(coreApiAssemblyFile) && File.Exists(editorApiAssemblyFile))
+ return true; // The assemblies are in the output folder; assume the solution is already built
+
+ var apiBuildInfo = new MonoBuildInfo(apiSlnFile, config);
+
+ // TODO Replace this global NoWarn with '#pragma warning' directives on generated files,
+ // once we start to actively document manually maintained C# classes
+ apiBuildInfo.CustomProperties.Add("NoWarn=1591"); // Ignore missing documentation warnings
+
+ if (Build(apiBuildInfo))
+ return true;
+
+ ShowBuildErrorDialog($"Failed to build {ApiAssemblyNames.SolutionName} solution.");
+ return false;
+ }
+
+ private static bool CopyApiAssembly(string srcDir, string dstDir, string assemblyName, ApiAssemblyType apiType)
+ {
+ // Create destination directory if needed
+ if (!Directory.Exists(dstDir))
+ {
+ try
+ {
+ Directory.CreateDirectory(dstDir);
+ }
+ catch (IOException e)
+ {
+ ShowBuildErrorDialog($"Failed to create destination directory for the API assemblies. Exception message: {e.Message}");
+ return false;
+ }
+ }
+
+ string assemblyFile = assemblyName + ".dll";
+ string assemblySrc = Path.Combine(srcDir, assemblyFile);
+ string assemblyDst = Path.Combine(dstDir, assemblyFile);
+
+ if (!File.Exists(assemblyDst) || File.GetLastWriteTime(assemblySrc) > File.GetLastWriteTime(assemblyDst) ||
+ Internal.MetadataIsApiAssemblyInvalidated(apiType))
+ {
+ string xmlFile = $"{assemblyName}.xml";
+ string pdbFile = $"{assemblyName}.pdb";
+
+ try
+ {
+ File.Copy(Path.Combine(srcDir, xmlFile), Path.Combine(dstDir, xmlFile));
+ }
+ catch (IOException e)
+ {
+ Godot.GD.PushWarning(e.ToString());
+ }
+
+ try
+ {
+ File.Copy(Path.Combine(srcDir, pdbFile), Path.Combine(dstDir, pdbFile));
+ }
+ catch (IOException e)
+ {
+ Godot.GD.PushWarning(e.ToString());
+ }
+
+ try
+ {
+ File.Copy(assemblySrc, assemblyDst);
+ }
+ catch (IOException e)
+ {
+ ShowBuildErrorDialog($"Failed to copy {assemblyFile}. Exception message: {e.Message}");
+ return false;
+ }
+
+ Internal.MetadataSetApiAssemblyInvalidated(apiType, false);
+ }
+
+ return true;
+ }
+
+ public static bool MakeApiAssembly(ApiAssemblyType apiType, string config)
+ {
+ string apiName = apiType == ApiAssemblyType.Core ? ApiAssemblyNames.Core : ApiAssemblyNames.Editor;
+
+ string editorPrebuiltApiDir = Path.Combine(GodotSharpDirs.DataEditorPrebuiltApiDir, config);
+ string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, config);
+
+ if (File.Exists(Path.Combine(editorPrebuiltApiDir, $"{apiName}.dll")))
+ {
+ using (var copyProgress = new EditorProgress("mono_copy_prebuilt_api_assembly", $"Copying prebuilt {apiName} assembly...", 1))
+ {
+ copyProgress.Step($"Copying {apiName} assembly", 0);
+ return CopyApiAssembly(editorPrebuiltApiDir, resAssembliesDir, apiName, apiType);
+ }
+ }
+
+ const string apiSolutionName = ApiAssemblyNames.SolutionName;
+
+ using (var pr = new EditorProgress($"mono_build_release_{apiSolutionName}", $"Building {apiSolutionName} solution...", 3))
+ {
+ pr.Step($"Generating {apiSolutionName} solution", 0);
+
+ string apiSlnDir = Path.Combine(GodotSharpDirs.MonoSolutionsDir, _ApiFolderName(ApiAssemblyType.Core));
+ string apiSlnFile = Path.Combine(apiSlnDir, $"{apiSolutionName}.sln");
+
+ if (!Directory.Exists(apiSlnDir) || !File.Exists(apiSlnFile))
+ {
+ var bindingsGenerator = new BindingsGenerator();
+
+ if (!Godot.OS.IsStdoutVerbose())
+ bindingsGenerator.LogPrintEnabled = false;
+
+ Error err = bindingsGenerator.GenerateCsApi(apiSlnDir);
+ if (err != Error.Ok)
+ {
+ ShowBuildErrorDialog($"Failed to generate {apiSolutionName} solution. Error: {err}");
+ return false;
+ }
+ }
+
+ pr.Step($"Building {apiSolutionName} solution", 1);
+
+ if (!BuildApiSolution(apiSlnDir, config))
+ return false;
+
+ pr.Step($"Copying {apiName} assembly", 2);
+
+ // Copy the built assembly to the assemblies directory
+ string apiAssemblyDir = Path.Combine(apiSlnDir, apiName, "bin", config);
+ if (!CopyApiAssembly(apiAssemblyDir, resAssembliesDir, apiName, apiType))
+ return false;
+ }
+
+ return true;
+ }
+
+ public static bool BuildProjectBlocking(string config, IEnumerable<string> godotDefines)
+ {
+ if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
+ return true; // No solution to build
+
+ string apiConfig = config == "Release" ? "Release" : "Debug";
+
+ if (!MakeApiAssembly(ApiAssemblyType.Core, apiConfig))
+ return false;
+
+ if (!MakeApiAssembly(ApiAssemblyType.Editor, apiConfig))
+ return false;
+
+ using (var pr = new EditorProgress("mono_project_debug_build", "Building project solution...", 1))
+ {
+ pr.Step("Building project solution", 0);
+
+ var buildInfo = new MonoBuildInfo(GodotSharpDirs.ProjectSlnPath, config);
+
+ // Add Godot defines
+ string constants = OS.IsWindows() ? "GodotDefineConstants=\"" : "GodotDefineConstants=\\\"";
+
+ foreach (var godotDefine in godotDefines)
+ constants += $"GODOT_{godotDefine.ToUpper().Replace("-", "_").Replace(" ", "_").Replace(";", "_")};";
+
+ if (Internal.GodotIsRealTDouble())
+ constants += "GODOT_REAL_T_IS_DOUBLE;";
+
+ constants += OS.IsWindows() ? "\"" : "\\\"";
+
+ buildInfo.CustomProperties.Add(constants);
+
+ if (!Build(buildInfo))
+ {
+ ShowBuildErrorDialog("Failed to build project solution");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static bool EditorBuildCallback()
+ {
+ if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
+ return true; // No solution to build
+
+ string editorScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor");
+ string playerScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor_player");
+
+ CSharpProject.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, editorScriptsMetadataPath);
+
+ if (File.Exists(editorScriptsMetadataPath))
+ File.Copy(editorScriptsMetadataPath, playerScriptsMetadataPath);
+
+ var godotDefines = new[]
+ {
+ Godot.OS.GetName(),
+ Internal.GodotIs32Bits() ? "32" : "64"
+ };
+
+ return BuildProjectBlocking("Tools", godotDefines);
+ }
+
+ public static void Initialize()
+ {
+ // Build tool settings
+
+ Internal.EditorDef("mono/builds/build_tool", OS.IsWindows() ? BuildTool.MsBuildVs : BuildTool.MsBuildMono);
+
+ var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
+
+ editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
+ {
+ ["type"] = Godot.Variant.Type.Int,
+ ["name"] = "mono/builds/build_tool",
+ ["hint"] = Godot.PropertyHint.Enum,
+ ["hint_string"] = OS.IsWindows() ?
+ $"{PropNameMsbuildMono},{PropNameMsbuildVs},{PropNameXbuild}" :
+ $"{PropNameMsbuildMono},{PropNameXbuild}"
+ });
+
+ Internal.EditorDef("mono/builds/print_build_output", false);
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
new file mode 100644
index 0000000000..955574d5fe
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -0,0 +1,538 @@
+using Godot;
+using GodotTools.Utils;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using GodotTools.Internals;
+using GodotTools.ProjectEditor;
+using File = GodotTools.Utils.File;
+using Path = System.IO.Path;
+using OS = GodotTools.Utils.OS;
+
+namespace GodotTools
+{
+ public class GodotSharpEditor : EditorPlugin, ISerializationListener
+ {
+ private EditorSettings editorSettings;
+
+ private PopupMenu menuPopup;
+
+ private AcceptDialog errorDialog;
+ private AcceptDialog aboutDialog;
+ private CheckBox aboutDialogCheckBox;
+
+ private ToolButton bottomPanelBtn;
+
+ private MonoDevelopInstance monoDevelopInstance;
+ private MonoDevelopInstance visualStudioForMacInstance;
+
+ public MonoBottomPanel MonoBottomPanel { get; private set; }
+
+ private bool CreateProjectSolution()
+ {
+ using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...", 2)) // TTR("Generating solution...")
+ {
+ pr.Step("Generating C# project..."); // TTR("Generating C# project...")
+
+ string resourceDir = ProjectSettings.GlobalizePath("res://");
+
+ string path = resourceDir;
+ string name = (string) ProjectSettings.GetSetting("application/config/name");
+ if (name.Empty())
+ name = "UnnamedProject";
+
+ string guid = CSharpProject.GenerateGameProject(path, name);
+
+ if (guid.Length > 0)
+ {
+ var solution = new DotNetSolution(name)
+ {
+ DirectoryPath = path
+ };
+
+ var projectInfo = new DotNetSolution.ProjectInfo
+ {
+ Guid = guid,
+ PathRelativeToSolution = name + ".csproj",
+ Configs = new List<string> {"Debug", "Release", "Tools"}
+ };
+
+ solution.AddNewProject(name, projectInfo);
+
+ try
+ {
+ solution.Save();
+ }
+ catch (IOException e)
+ {
+ ShowErrorDialog($"Failed to save solution. Exception message: {e.Message}"); // TTR
+ return false;
+ }
+
+ string apiConfig = "Debug";
+
+ if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Core, apiConfig))
+ return false;
+
+ if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Editor, apiConfig))
+ return false;
+
+ pr.Step("Done"); // TTR("Done")
+
+ // Here, after all calls to progress_task_step
+ CallDeferred(nameof(_RemoveCreateSlnMenuOption));
+ }
+ else
+ {
+ ShowErrorDialog("Failed to create C# project."); // TTR
+ }
+
+ return true;
+ }
+ }
+
+ private static int _makeApiSolutionsAttempts = 100;
+ private static bool _makeApiSolutionsRecursionGuard = false;
+
+ private void _MakeApiSolutionsIfNeeded()
+ {
+ // I'm sick entirely of ProgressDialog
+
+ if (Internal.IsMessageQueueFlushing() || Engine.GetMainLoop() == null)
+ {
+ if (_makeApiSolutionsAttempts == 0) // This better never happen or I swear...
+ throw new TimeoutException();
+
+ if (Engine.GetMainLoop() != null)
+ {
+ if (!Engine.GetMainLoop().IsConnected("idle_frame", this, nameof(_MakeApiSolutionsIfNeeded)))
+ Engine.GetMainLoop().Connect("idle_frame", this, nameof(_MakeApiSolutionsIfNeeded));
+ }
+ else
+ {
+ CallDeferred(nameof(_MakeApiSolutionsIfNeededImpl));
+ }
+
+ _makeApiSolutionsAttempts--;
+ return;
+ }
+
+ // Recursion guard needed because signals don't play well with ProgressDialog either, but unlike
+ // the message queue, with signals the collateral damage should be minimal in the worst case.
+ if (!_makeApiSolutionsRecursionGuard)
+ {
+ _makeApiSolutionsRecursionGuard = true;
+
+ // Oneshot signals don't play well with ProgressDialog either, so we do it this way instead
+ if (Engine.GetMainLoop().IsConnected("idle_frame", this, nameof(_MakeApiSolutionsIfNeeded)))
+ Engine.GetMainLoop().Disconnect("idle_frame", this, nameof(_MakeApiSolutionsIfNeeded));
+
+ _MakeApiSolutionsIfNeededImpl();
+
+ _makeApiSolutionsRecursionGuard = false;
+ }
+ }
+
+ private void _MakeApiSolutionsIfNeededImpl()
+ {
+ // If the project has a solution and C# project make sure the API assemblies are present and up to date
+
+ string api_config = "Debug";
+ string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, api_config);
+
+ if (!File.Exists(Path.Combine(resAssembliesDir, $"{ApiAssemblyNames.Core}.dll")) ||
+ Internal.MetadataIsApiAssemblyInvalidated(ApiAssemblyType.Core))
+ {
+ if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Core, api_config))
+ return;
+ }
+
+ if (!File.Exists(Path.Combine(resAssembliesDir, $"{ApiAssemblyNames.Editor}.dll")) ||
+ Internal.MetadataIsApiAssemblyInvalidated(ApiAssemblyType.Editor))
+ {
+ if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Editor, api_config))
+ return; // Redundant? I don't think so!
+ }
+ }
+
+ private void _RemoveCreateSlnMenuOption()
+ {
+ menuPopup.RemoveItem(menuPopup.GetItemIndex((int) MenuOptions.CreateSln));
+ bottomPanelBtn.Show();
+ }
+
+ private void _ShowAboutDialog()
+ {
+ bool showOnStart = (bool) editorSettings.GetSetting("mono/editor/show_info_on_start");
+ aboutDialogCheckBox.Pressed = showOnStart;
+ aboutDialog.PopupCenteredMinsize();
+ }
+
+ private void _ToggleAboutDialogOnStart(bool enabled)
+ {
+ bool showOnStart = (bool) editorSettings.GetSetting("mono/editor/show_info_on_start");
+ if (showOnStart != enabled)
+ editorSettings.SetSetting("mono/editor/show_info_on_start", enabled);
+ }
+
+ private void _MenuOptionPressed(MenuOptions id)
+ {
+ switch (id)
+ {
+ case MenuOptions.CreateSln:
+ CreateProjectSolution();
+ break;
+ case MenuOptions.AboutCSharp:
+ _ShowAboutDialog();
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(id), id, "Invalid menu option");
+ }
+ }
+
+ private void _BuildSolutionPressed()
+ {
+ if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
+ {
+ if (!CreateProjectSolution())
+ return; // Failed to create solution
+ }
+
+ Instance.MonoBottomPanel.BuildProjectPressed();
+ }
+
+ public override void _Notification(int what)
+ {
+ base._Notification(what);
+
+ if (what == NotificationReady)
+ {
+ bool showInfoDialog = (bool) editorSettings.GetSetting("mono/editor/show_info_on_start");
+ if (showInfoDialog)
+ {
+ aboutDialog.PopupExclusive = true;
+ _ShowAboutDialog();
+ // Once shown a first time, it can be seen again via the Mono menu - it doesn't have to be exclusive from that time on.
+ aboutDialog.PopupExclusive = false;
+ }
+ }
+ }
+
+ public enum MenuOptions
+ {
+ CreateSln,
+ AboutCSharp,
+ }
+
+ public enum ExternalEditor
+ {
+ None,
+ VisualStudio, // TODO (Windows-only)
+ VisualStudioForMac, // Mac-only
+ MonoDevelop,
+ VsCode
+ }
+
+ public void ShowErrorDialog(string message, string title = "Error")
+ {
+ errorDialog.WindowTitle = title;
+ errorDialog.DialogText = message;
+ errorDialog.PopupCenteredMinsize();
+ }
+
+ private static string _vsCodePath = string.Empty;
+
+ private static readonly string[] VsCodeNames =
+ {
+ "code", "code-oss", "vscode", "vscode-oss", "visual-studio-code", "visual-studio-code-oss"
+ };
+
+ public Error OpenInExternalEditor(Script script, int line, int col)
+ {
+ var editor = (ExternalEditor) editorSettings.GetSetting("mono/editor/external_editor");
+
+ switch (editor)
+ {
+ case ExternalEditor.VsCode:
+ {
+ if (_vsCodePath.Empty() || !File.Exists(_vsCodePath))
+ {
+ // Try to search it again if it wasn't found last time or if it was removed from its location
+ _vsCodePath = VsCodeNames.SelectFirstNotNull(OS.PathWhich, orElse: string.Empty);
+ }
+
+ var args = new List<string>();
+
+ bool osxAppBundleInstalled = false;
+
+ if (OS.IsOSX())
+ {
+ // The package path is '/Applications/Visual Studio Code.app'
+ const string vscodeBundleId = "com.microsoft.VSCode";
+
+ osxAppBundleInstalled = Internal.IsOsxAppBundleInstalled(vscodeBundleId);
+
+ if (osxAppBundleInstalled)
+ {
+ args.Add("-b");
+ args.Add(vscodeBundleId);
+
+ // The reusing of existing windows made by the 'open' command might not choose a wubdiw that is
+ // editing our folder. It's better to ask for a new window and let VSCode do the window management.
+ args.Add("-n");
+
+ // The open process must wait until the application finishes (which is instant in VSCode's case)
+ args.Add("--wait-apps");
+
+ args.Add("--args");
+ }
+ }
+
+ var resourcePath = ProjectSettings.GlobalizePath("res://");
+ args.Add(resourcePath);
+
+ string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);
+
+ if (line >= 0)
+ {
+ args.Add("-g");
+ args.Add($"{scriptPath}:{line + 1}:{col}");
+ }
+ else
+ {
+ args.Add(scriptPath);
+ }
+
+ string command;
+
+ if (OS.IsOSX())
+ {
+ if (!osxAppBundleInstalled && _vsCodePath.Empty())
+ {
+ GD.PushError("Cannot find code editor: VSCode");
+ return Error.FileNotFound;
+ }
+
+ command = osxAppBundleInstalled ? "/usr/bin/open" : _vsCodePath;
+ }
+ else
+ {
+ if (_vsCodePath.Empty())
+ {
+ GD.PushError("Cannot find code editor: VSCode");
+ return Error.FileNotFound;
+ }
+
+ command = _vsCodePath;
+ }
+
+ try
+ {
+ OS.RunProcess(command, args);
+ }
+ catch (Exception e)
+ {
+ GD.PushError($"Error when trying to run code editor: VSCode. Exception message: '{e.Message}'");
+ }
+
+ break;
+ }
+
+ case ExternalEditor.VisualStudioForMac:
+ goto case ExternalEditor.MonoDevelop;
+ case ExternalEditor.MonoDevelop:
+ {
+ MonoDevelopInstance GetMonoDevelopInstance(string solutionPath)
+ {
+ if (OS.IsOSX() && editor == ExternalEditor.VisualStudioForMac)
+ {
+ if (visualStudioForMacInstance == null)
+ visualStudioForMacInstance = new MonoDevelopInstance(solutionPath, MonoDevelopInstance.EditorId.VisualStudioForMac);
+
+ return visualStudioForMacInstance;
+ }
+
+ if (monoDevelopInstance == null)
+ monoDevelopInstance = new MonoDevelopInstance(solutionPath, MonoDevelopInstance.EditorId.MonoDevelop);
+
+ return monoDevelopInstance;
+ }
+
+ string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);
+
+ if (line >= 0)
+ scriptPath += $";{line + 1};{col}";
+
+ GetMonoDevelopInstance(GodotSharpDirs.ProjectSlnPath).Execute(scriptPath);
+
+ break;
+ }
+
+ case ExternalEditor.None:
+ return Error.Unavailable;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ return Error.Ok;
+ }
+
+ public bool OverridesExternalEditor()
+ {
+ return (ExternalEditor) editorSettings.GetSetting("mono/editor/external_editor") != ExternalEditor.None;
+ }
+
+ public override bool Build()
+ {
+ return GodotSharpBuilds.EditorBuildCallback();
+ }
+
+ public override void EnablePlugin()
+ {
+ base.EnablePlugin();
+
+ if (Instance != null)
+ throw new InvalidOperationException();
+ Instance = this;
+
+ var editorInterface = GetEditorInterface();
+ var editorBaseControl = editorInterface.GetBaseControl();
+
+ editorSettings = editorInterface.GetEditorSettings();
+
+ errorDialog = new AcceptDialog();
+ editorBaseControl.AddChild(errorDialog);
+
+ MonoBottomPanel = new MonoBottomPanel();
+
+ bottomPanelBtn = AddControlToBottomPanel(MonoBottomPanel, "Mono"); // TTR("Mono")
+
+ AddChild(new HotReloadAssemblyWatcher {Name = "HotReloadAssemblyWatcher"});
+
+ menuPopup = new PopupMenu();
+ menuPopup.Hide();
+ menuPopup.SetAsToplevel(true);
+
+ AddToolSubmenuItem("Mono", menuPopup);
+
+ // TODO: Remove or edit this info dialog once Mono support is no longer in alpha
+ {
+ menuPopup.AddItem("About C# support", (int) MenuOptions.AboutCSharp); // TTR("About C# support")
+ aboutDialog = new AcceptDialog();
+ editorBaseControl.AddChild(aboutDialog);
+ aboutDialog.WindowTitle = "Important: C# support is not feature-complete";
+
+ // We don't use DialogText as the default AcceptDialog Label doesn't play well with the TextureRect and CheckBox
+ // we'll add. Instead we add containers and a new autowrapped Label inside.
+
+ // Main VBoxContainer (icon + label on top, checkbox at bottom)
+ var aboutVBox = new VBoxContainer();
+ aboutDialog.AddChild(aboutVBox);
+
+ // HBoxContainer for icon + label
+ var aboutHBox = new HBoxContainer();
+ aboutVBox.AddChild(aboutHBox);
+
+ var aboutIcon = new TextureRect();
+ aboutIcon.Texture = aboutIcon.GetIcon("NodeWarning", "EditorIcons");
+ aboutHBox.AddChild(aboutIcon);
+
+ var aboutLabel = new Label();
+ aboutHBox.AddChild(aboutLabel);
+ aboutLabel.RectMinSize = new Vector2(600, 150) * Internal.EditorScale;
+ aboutLabel.SizeFlagsVertical = (int) Control.SizeFlags.ExpandFill;
+ aboutLabel.Autowrap = true;
+ aboutLabel.Text =
+ "C# support in Godot Engine is in late alpha stage and, while already usable, " +
+ "it is not meant for use in production.\n\n" +
+ "Projects can be exported to Linux, macOS and Windows, but not yet to mobile or web platforms. " +
+ "Bugs and usability issues will be addressed gradually over future releases, " +
+ "potentially including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" +
+ "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, MSBuild version, IDE, etc.:\n\n" +
+ " https://github.com/godotengine/godot/issues\n\n" +
+ "Your critical feedback at this stage will play a great role in shaping the C# support in future releases, so thank you!";
+
+ Internal.EditorDef("mono/editor/show_info_on_start", true);
+
+ // CheckBox in main container
+ aboutDialogCheckBox = new CheckBox {Text = "Show this warning when starting the editor"};
+ aboutDialogCheckBox.Connect("toggled", this, nameof(_ToggleAboutDialogOnStart));
+ aboutVBox.AddChild(aboutDialogCheckBox);
+ }
+
+ if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath))
+ {
+ // Defer this task because EditorProgress calls Main::iterarion() and the main loop is not yet initialized.
+ CallDeferred(nameof(_MakeApiSolutionsIfNeeded));
+ }
+ else
+ {
+ bottomPanelBtn.Hide();
+ menuPopup.AddItem("Create C# solution", (int) MenuOptions.CreateSln); // TTR("Create C# solution")
+ }
+
+ menuPopup.Connect("id_pressed", this, nameof(_MenuOptionPressed));
+
+ var buildButton = new ToolButton
+ {
+ Text = "Build",
+ HintTooltip = "Build solution",
+ FocusMode = Control.FocusModeEnum.None
+ };
+ buildButton.Connect("pressed", this, nameof(_BuildSolutionPressed));
+ AddControlToContainer(CustomControlContainer.Toolbar, buildButton);
+
+ // External editor settings
+ Internal.EditorDef("mono/editor/external_editor", ExternalEditor.None);
+
+ string settingsHintStr = "Disabled";
+
+ if (OS.IsWindows())
+ {
+ settingsHintStr += $",MonoDevelop:{(int) ExternalEditor.MonoDevelop}" +
+ $",Visual Studio Code:{(int) ExternalEditor.VsCode}";
+ }
+ else if (OS.IsOSX())
+ {
+ settingsHintStr += $",Visual Studio:{(int) ExternalEditor.VisualStudioForMac}" +
+ $",MonoDevelop:{(int) ExternalEditor.MonoDevelop}" +
+ $",Visual Studio Code:{(int) ExternalEditor.VsCode}";
+ }
+ else if (OS.IsUnix())
+ {
+ settingsHintStr += $",MonoDevelop:{(int) ExternalEditor.MonoDevelop}" +
+ $",Visual Studio Code:{(int) ExternalEditor.VsCode}";
+ }
+
+ editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
+ {
+ ["type"] = Variant.Type.Int,
+ ["name"] = "mono/editor/external_editor",
+ ["hint"] = PropertyHint.Enum,
+ ["hint_string"] = settingsHintStr
+ });
+
+ // Export plugin
+ AddExportPlugin(new GodotSharpExport());
+
+ GodotSharpBuilds.Initialize();
+ }
+
+ public void OnBeforeSerialize()
+ {
+ }
+
+ public void OnAfterDeserialize()
+ {
+ Instance = this;
+ }
+
+ // Singleton
+
+ public static GodotSharpEditor Instance { get; private set; }
+
+ private GodotSharpEditor()
+ {
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpExport.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpExport.cs
new file mode 100644
index 0000000000..b80fe1fab7
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpExport.cs
@@ -0,0 +1,197 @@
+using Godot;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using GodotTools.Core;
+using GodotTools.Internals;
+using Directory = GodotTools.Utils.Directory;
+using File = GodotTools.Utils.File;
+using Path = System.IO.Path;
+
+namespace GodotTools
+{
+ public class GodotSharpExport : EditorExportPlugin
+ {
+ private void AddFile(string srcPath, string dstPath, bool remap = false)
+ {
+ AddFile(dstPath, File.ReadAllBytes(srcPath), remap);
+ }
+
+ public override void _ExportFile(string path, string type, string[] features)
+ {
+ base._ExportFile(path, type, features);
+
+ if (type != Internal.CSharpLanguageType)
+ return;
+
+ if (Path.GetExtension(path) != $".{Internal.CSharpLanguageExtension}")
+ throw new ArgumentException($"Resource of type {Internal.CSharpLanguageType} has an invalid file extension: {path}", nameof(path));
+
+ // TODO What if the source file is not part of the game's C# project
+
+ bool includeScriptsContent = (bool) ProjectSettings.GetSetting("mono/export/include_scripts_content");
+
+ if (!includeScriptsContent)
+ {
+ // We don't want to include the source code on exported games
+ AddFile(path, new byte[] { }, remap: false);
+ Skip();
+ }
+ }
+
+ public override void _ExportBegin(string[] features, bool isDebug, string path, int flags)
+ {
+ base._ExportBegin(features, isDebug, path, flags);
+
+ try
+ {
+ _ExportBeginImpl(features, isDebug, path, flags);
+ }
+ catch (Exception e)
+ {
+ GD.PushError($"Failed to export project. Exception message: {e.Message}");
+ Console.Error.WriteLine(e);
+ }
+ }
+
+ public void _ExportBeginImpl(string[] features, bool isDebug, string path, int flags)
+ {
+ // TODO Right now there is no way to stop the export process with an error
+
+ if (File.Exists(GodotSharpDirs.ProjectSlnPath))
+ {
+ string buildConfig = isDebug ? "Debug" : "Release";
+
+ string scriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, $"scripts_metadata.{(isDebug ? "debug" : "release")}");
+ CSharpProject.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, scriptsMetadataPath);
+
+ AddFile(scriptsMetadataPath, scriptsMetadataPath);
+
+ // Turn export features into defines
+ var godotDefines = features;
+
+ if (!GodotSharpBuilds.BuildProjectBlocking(buildConfig, godotDefines))
+ {
+ GD.PushError("Failed to build project");
+ return;
+ }
+
+ // Add dependency assemblies
+
+ var dependencies = new Godot.Collections.Dictionary<string, string>();
+
+ var projectDllName = (string) ProjectSettings.GetSetting("application/config/name");
+ if (projectDllName.Empty())
+ {
+ projectDllName = "UnnamedProject";
+ }
+
+ string projectDllSrcDir = Path.Combine(GodotSharpDirs.ResTempAssembliesBaseDir, buildConfig);
+ string projectDllSrcPath = Path.Combine(projectDllSrcDir, $"{projectDllName}.dll");
+
+ dependencies[projectDllName] = projectDllSrcPath;
+
+ {
+ string templatesDir = Internal.FullTemplatesDir;
+ string androidBclDir = Path.Combine(templatesDir, "android-bcl");
+
+ string customLibDir = features.Contains("Android") && Directory.Exists(androidBclDir) ? androidBclDir : string.Empty;
+
+ GetExportedAssemblyDependencies(projectDllName, projectDllSrcPath, buildConfig, customLibDir, dependencies);
+ }
+
+ string apiConfig = isDebug ? "Debug" : "Release";
+ string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, apiConfig);
+
+ foreach (var dependency in dependencies)
+ {
+ string dependSrcPath = dependency.Value;
+ string dependDstPath = Path.Combine(resAssembliesDir, dependSrcPath.GetFile());
+ AddFile(dependSrcPath, dependDstPath);
+ }
+ }
+
+ // Mono specific export template extras (data dir)
+ ExportDataDirectory(features, isDebug, path);
+ }
+
+ private static void ExportDataDirectory(IEnumerable<string> features, bool debug, string path)
+ {
+ var featureSet = new HashSet<string>(features);
+
+ if (!PlatformHasTemplateDir(featureSet))
+ return;
+
+ string templateDirName = "data.mono";
+
+ if (featureSet.Contains("Windows"))
+ {
+ templateDirName += ".windows";
+ templateDirName += featureSet.Contains("64") ? ".64" : ".32";
+ }
+ else if (featureSet.Contains("X11"))
+ {
+ templateDirName += ".x11";
+ templateDirName += featureSet.Contains("64") ? ".64" : ".32";
+ }
+ else
+ {
+ throw new NotSupportedException("Target platform not supported");
+ }
+
+ templateDirName += debug ? ".release_debug" : ".release";
+
+ string templateDirPath = Path.Combine(Internal.FullTemplatesDir, templateDirName);
+
+ if (!Directory.Exists(templateDirPath))
+ throw new FileNotFoundException("Data template directory not found");
+
+ string outputDir = new FileInfo(path).Directory?.FullName ??
+ throw new FileNotFoundException("Base directory not found");
+
+ string outputDataDir = Path.Combine(outputDir, DataDirName);
+
+ if (Directory.Exists(outputDataDir))
+ Directory.Delete(outputDataDir, recursive: true); // Clean first
+
+ Directory.CreateDirectory(outputDataDir);
+
+ foreach (string dir in Directory.GetDirectories(templateDirPath, "*", SearchOption.AllDirectories))
+ {
+ Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(templateDirPath.Length + 1)));
+ }
+
+ foreach (string file in Directory.GetFiles(templateDirPath, "*", SearchOption.AllDirectories))
+ {
+ File.Copy(file, Path.Combine(outputDataDir, file.Substring(templateDirPath.Length + 1)));
+ }
+ }
+
+ private static bool PlatformHasTemplateDir(IEnumerable<string> featureSet)
+ {
+ // OSX export templates are contained in a zip, so we place
+ // our custom template inside it and let Godot do the rest.
+ return !featureSet.Any(f => new[] {"OSX", "Android"}.Contains(f));
+ }
+
+ private static string DataDirName
+ {
+ get
+ {
+ var appName = (string) ProjectSettings.GetSetting("application/config/name");
+ string appNameSafe = appName.ToSafeDirName(allowDirSeparator: false);
+ return $"data_{appNameSafe}";
+ }
+ }
+
+ private static void GetExportedAssemblyDependencies(string projectDllName, string projectDllSrcPath,
+ string buildConfig, string customLibDir, Godot.Collections.Dictionary<string, string> dependencies) =>
+ internal_GetExportedAssemblyDependencies(projectDllName, projectDllSrcPath, buildConfig, customLibDir, dependencies);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_GetExportedAssemblyDependencies(string projectDllName, string projectDllSrcPath,
+ string buildConfig, string customLibDir, Godot.Collections.Dictionary<string, string> dependencies);
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
new file mode 100644
index 0000000000..a0ff8a0df1
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{27B00618-A6F2-4828-B922-05CAEB08C286}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <RootNamespace>GodotTools</RootNamespace>
+ <AssemblyName>GodotTools</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <GodotSourceRootPath>$(SolutionDir)/../../../../</GodotSourceRootPath>
+ <GodotApiConfiguration>Debug</GodotApiConfiguration>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>portable</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="GodotSharp">
+ <HintPath>$(GodotSourceRootPath)/bin/GodotSharp/Api/$(GodotApiConfiguration)/GodotSharp.dll</HintPath>
+ </Reference>
+ <Reference Include="GodotSharpEditor">
+ <HintPath>$(GodotSourceRootPath)/bin/GodotSharp/Api/$(GodotApiConfiguration)/GodotSharpEditor.dll</HintPath>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Build\MsBuildFinder.cs" />
+ <Compile Include="Internals\BindingsGenerator.cs" />
+ <Compile Include="Internals\EditorProgress.cs" />
+ <Compile Include="Internals\GodotSharpDirs.cs" />
+ <Compile Include="Internals\Internal.cs" />
+ <Compile Include="Internals\ScriptClassParser.cs" />
+ <Compile Include="MonoDevelopInstance.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Build\BuildSystem.cs" />
+ <Compile Include="Utils\Directory.cs" />
+ <Compile Include="Utils\File.cs" />
+ <Compile Include="Utils\OS.cs" />
+ <Compile Include="GodotSharpEditor.cs" />
+ <Compile Include="GodotSharpBuilds.cs" />
+ <Compile Include="HotReloadAssemblyWatcher.cs" />
+ <Compile Include="MonoBuildInfo.cs" />
+ <Compile Include="MonoBuildTab.cs" />
+ <Compile Include="MonoBottomPanel.cs" />
+ <Compile Include="GodotSharpExport.cs" />
+ <Compile Include="CSharpProject.cs" />
+ <Compile Include="Utils\CollectionExtensions.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\GodotTools.BuildLogger\GodotTools.BuildLogger.csproj">
+ <Project>{6ce9a984-37b1-4f8a-8fe9-609f05f071b3}</Project>
+ <Name>GodotTools.BuildLogger</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\GodotTools.ProjectEditor\GodotTools.ProjectEditor.csproj">
+ <Project>{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}</Project>
+ <Name>GodotTools.ProjectEditor</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj">
+ <Project>{639E48BD-44E5-4091-8EDD-22D36DC0768D}</Project>
+ <Name>GodotTools.Core</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="Editor" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
new file mode 100644
index 0000000000..aa52079cf4
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
@@ -0,0 +1,47 @@
+using Godot;
+using GodotTools.Internals;
+
+namespace GodotTools
+{
+ public class HotReloadAssemblyWatcher : Node
+ {
+ private Timer watchTimer;
+
+ public override void _Notification(int what)
+ {
+ if (what == MainLoop.NotificationWmFocusIn)
+ {
+ RestartTimer();
+
+ if (Internal.IsAssembliesReloadingNeeded())
+ Internal.ReloadAssemblies(softReload: false);
+ }
+ }
+
+ private void TimerTimeout()
+ {
+ if (Internal.IsAssembliesReloadingNeeded())
+ Internal.ReloadAssemblies(softReload: false);
+ }
+
+ public void RestartTimer()
+ {
+ watchTimer.Stop();
+ watchTimer.Start();
+ }
+
+ public override void _Ready()
+ {
+ base._Ready();
+
+ watchTimer = new Timer
+ {
+ OneShot = false,
+ WaitTime = (float) Internal.EditorDef("mono/assembly_watch_interval_sec", 0.5)
+ };
+ watchTimer.Connect("timeout", this, nameof(TimerTimeout));
+ AddChild(watchTimer);
+ watchTimer.Start();
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/BindingsGenerator.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/BindingsGenerator.cs
new file mode 100644
index 0000000000..1daa5e138e
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/BindingsGenerator.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace GodotTools.Internals
+{
+ public class BindingsGenerator : IDisposable
+ {
+ class BindingsGeneratorSafeHandle : SafeHandle
+ {
+ public BindingsGeneratorSafeHandle(IntPtr handle) : base(IntPtr.Zero, true)
+ {
+ this.handle = handle;
+ }
+
+ public override bool IsInvalid => handle == IntPtr.Zero;
+
+ protected override bool ReleaseHandle()
+ {
+ internal_Dtor(handle);
+ return true;
+ }
+ }
+
+ private BindingsGeneratorSafeHandle safeHandle;
+ private bool disposed = false;
+
+ public bool LogPrintEnabled
+ {
+ get => internal_LogPrintEnabled(GetPtr());
+ set => internal_SetLogPrintEnabled(GetPtr(), value);
+ }
+
+ public static uint Version => internal_Version();
+ public static uint CsGlueVersion => internal_CsGlueVersion();
+
+ public Godot.Error GenerateCsApi(string outputDir) => internal_GenerateCsApi(GetPtr(), outputDir);
+
+ internal IntPtr GetPtr()
+ {
+ if (disposed)
+ throw new ObjectDisposedException(GetType().FullName);
+
+ return safeHandle.DangerousGetHandle();
+ }
+
+ public void Dispose()
+ {
+ if (disposed)
+ return;
+
+ if (safeHandle != null && !safeHandle.IsInvalid)
+ {
+ safeHandle.Dispose();
+ safeHandle = null;
+ }
+
+ disposed = true;
+ }
+
+ public BindingsGenerator()
+ {
+ safeHandle = new BindingsGeneratorSafeHandle(internal_Ctor());
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern IntPtr internal_Ctor();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_Dtor(IntPtr handle);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern bool internal_LogPrintEnabled(IntPtr handle);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_SetLogPrintEnabled(IntPtr handle, bool enabled);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern Godot.Error internal_GenerateCsApi(IntPtr handle, string outputDir);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern uint internal_Version();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern uint internal_CsGlueVersion();
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs
new file mode 100644
index 0000000000..70ba7c733a
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Runtime.CompilerServices;
+using Godot;
+
+namespace GodotTools.Internals
+{
+ public class EditorProgress : IDisposable
+ {
+ public string Task { get; }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_Create(string task, string label, int amount, bool canCancel);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_Dispose(string task);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern bool internal_Step(string task, string state, int step, bool forceRefresh);
+
+ public EditorProgress(string task, string label, int amount, bool canCancel = false)
+ {
+ Task = task;
+ internal_Create(task, label, amount, canCancel);
+ }
+
+ ~EditorProgress()
+ {
+ // Should never rely on the GC to dispose EditorProgress.
+ // It should be disposed immediately when the task finishes.
+ GD.PushError("EditorProgress disposed by the Garbage Collector");
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ internal_Dispose(Task);
+ GC.SuppressFinalize(this);
+ }
+
+ public void Step(string state, int step = -1, bool forceRefresh = true)
+ {
+ internal_Step(Task, state, step, forceRefresh);
+ }
+
+ public bool TryStep(string state, int step = -1, bool forceRefresh = true)
+ {
+ return internal_Step(Task, state, step, forceRefresh);
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
new file mode 100644
index 0000000000..ddf3b829b5
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
@@ -0,0 +1,91 @@
+using System.Runtime.CompilerServices;
+
+namespace GodotTools.Internals
+{
+ public static class GodotSharpDirs
+ {
+ public static string ResDataDir => internal_ResDataDir();
+ public static string ResMetadataDir => internal_ResMetadataDir();
+ public static string ResAssembliesBaseDir => internal_ResAssembliesBaseDir();
+ public static string ResAssembliesDir => internal_ResAssembliesDir();
+ public static string ResConfigDir => internal_ResConfigDir();
+ public static string ResTempDir => internal_ResTempDir();
+ public static string ResTempAssembliesBaseDir => internal_ResTempAssembliesBaseDir();
+ public static string ResTempAssembliesDir => internal_ResTempAssembliesDir();
+
+ public static string MonoUserDir => internal_MonoUserDir();
+ public static string MonoLogsDir => internal_MonoLogsDir();
+
+ #region Tools-only
+ public static string MonoSolutionsDir => internal_MonoSolutionsDir();
+ public static string BuildLogsDirs => internal_BuildLogsDirs();
+
+ public static string ProjectSlnPath => internal_ProjectSlnPath();
+ public static string ProjectCsProjPath => internal_ProjectCsProjPath();
+
+ public static string DataEditorToolsDir => internal_DataEditorToolsDir();
+ public static string DataEditorPrebuiltApiDir => internal_DataEditorPrebuiltApiDir();
+ #endregion
+
+ public static string DataMonoEtcDir => internal_DataMonoEtcDir();
+ public static string DataMonoLibDir => internal_DataMonoLibDir();
+
+ #region Windows-only
+ public static string DataMonoBinDir => internal_DataMonoBinDir();
+ #endregion
+
+
+ #region Internal
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_ResDataDir();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_ResMetadataDir();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_ResAssembliesBaseDir();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_ResAssembliesDir();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_ResConfigDir();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_ResTempDir();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_ResTempAssembliesBaseDir();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_ResTempAssembliesDir();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_MonoUserDir();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_MonoLogsDir();
+
+ #region Tools-only
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_MonoSolutionsDir();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_BuildLogsDirs();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_ProjectSlnPath();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_ProjectCsProjPath();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_DataEditorToolsDir();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_DataEditorPrebuiltApiDir();
+ #endregion
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_DataMonoEtcDir();
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_DataMonoLibDir();
+
+ #region Windows-only
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_DataMonoBinDir();
+ #endregion
+
+ #endregion
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
new file mode 100644
index 0000000000..5c7ce832cd
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
@@ -0,0 +1,127 @@
+using System;
+using System.Runtime.CompilerServices;
+using Godot;
+using Godot.Collections;
+
+namespace GodotTools.Internals
+{
+ public static class Internal
+ {
+ public const string CSharpLanguageType = "CSharpScript";
+ public const string CSharpLanguageExtension = "cs";
+
+ public static float EditorScale => internal_EditorScale();
+
+ public static object GlobalDef(string setting, object defaultValue, bool restartIfChanged = false) =>
+ internal_GlobalDef(setting, defaultValue, restartIfChanged);
+
+ public static object EditorDef(string setting, object defaultValue, bool restartIfChanged = false) =>
+ internal_EditorDef(setting, defaultValue, restartIfChanged);
+
+ public static string FullTemplatesDir =>
+ internal_FullTemplatesDir();
+
+ public static string SimplifyGodotPath(this string path) => internal_SimplifyGodotPath(path);
+
+ public static bool IsOsxAppBundleInstalled(string bundleId) => internal_IsOsxAppBundleInstalled(bundleId);
+
+ public static bool MetadataIsApiAssemblyInvalidated(ApiAssemblyType apiType) =>
+ internal_MetadataIsApiAssemblyInvalidated(apiType);
+
+ public static void MetadataSetApiAssemblyInvalidated(ApiAssemblyType apiType, bool invalidated) =>
+ internal_MetadataSetApiAssemblyInvalidated(apiType, invalidated);
+
+ public static bool IsMessageQueueFlushing() => internal_IsMessageQueueFlushing();
+
+ public static bool GodotIs32Bits() => internal_GodotIs32Bits();
+
+ public static bool GodotIsRealTDouble() => internal_GodotIsRealTDouble();
+
+ public static void GodotMainIteration() => internal_GodotMainIteration();
+
+ public static ulong GetCoreApiHash() => internal_GetCoreApiHash();
+
+ public static ulong GetEditorApiHash() => internal_GetEditorApiHash();
+
+ public static bool IsAssembliesReloadingNeeded() => internal_IsAssembliesReloadingNeeded();
+
+ public static void ReloadAssemblies(bool softReload) => internal_ReloadAssemblies(softReload);
+
+ public static void ScriptEditorDebuggerReloadScripts() => internal_ScriptEditorDebuggerReloadScripts();
+
+ public static bool ScriptEditorEdit(Resource resource, int line, int col, bool grabFocus = true) =>
+ internal_ScriptEditorEdit(resource, line, col, grabFocus);
+
+ public static void EditorNodeShowScriptScreen() => internal_EditorNodeShowScriptScreen();
+
+ public static Dictionary<string, object> GetScriptsMetadataOrNothing() =>
+ internal_GetScriptsMetadataOrNothing(typeof(Dictionary<string, object>));
+
+ public static string MonoWindowsInstallRoot => internal_MonoWindowsInstallRoot();
+
+ // Internal Calls
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern float internal_EditorScale();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern object internal_GlobalDef(string setting, object defaultValue, bool restartIfChanged);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern object internal_EditorDef(string setting, object defaultValue, bool restartIfChanged);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_FullTemplatesDir();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_SimplifyGodotPath(this string path);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern bool internal_IsOsxAppBundleInstalled(string bundleId);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern bool internal_MetadataIsApiAssemblyInvalidated(ApiAssemblyType apiType);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_MetadataSetApiAssemblyInvalidated(ApiAssemblyType apiType, bool invalidated);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern bool internal_IsMessageQueueFlushing();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern bool internal_GodotIs32Bits();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern bool internal_GodotIsRealTDouble();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_GodotMainIteration();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern ulong internal_GetCoreApiHash();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern ulong internal_GetEditorApiHash();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern bool internal_IsAssembliesReloadingNeeded();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_ReloadAssemblies(bool softReload);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_ScriptEditorDebuggerReloadScripts();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern bool internal_ScriptEditorEdit(Resource resource, int line, int col, bool grabFocus);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_EditorNodeShowScriptScreen();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern Dictionary<string, object> internal_GetScriptsMetadataOrNothing(Type dictType);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string internal_MonoWindowsInstallRoot();
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/ScriptClassParser.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/ScriptClassParser.cs
new file mode 100644
index 0000000000..2497d276a9
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/ScriptClassParser.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using Godot;
+using Godot.Collections;
+
+namespace GodotTools.Internals
+{
+ public static class ScriptClassParser
+ {
+ public class ClassDecl
+ {
+ public string Name { get; }
+ public string Namespace { get; }
+ public bool Nested { get; }
+ public int BaseCount { get; }
+
+ public ClassDecl(string name, string @namespace, bool nested, int baseCount)
+ {
+ Name = name;
+ Namespace = @namespace;
+ Nested = nested;
+ BaseCount = baseCount;
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern Error internal_ParseFile(string filePath, Array<Dictionary> classes);
+
+ public static void ParseFileOrThrow(string filePath, out IEnumerable<ClassDecl> classes)
+ {
+ var classesArray = new Array<Dictionary>();
+ var error = internal_ParseFile(filePath, classesArray);
+ if (error != Error.Ok)
+ throw new Exception($"Failed to determine namespace and class for script: {filePath}. Parse error: {error}");
+
+ var classesList = new List<ClassDecl>();
+
+ foreach (var classDeclDict in classesArray)
+ {
+ classesList.Add(new ClassDecl(
+ (string) classDeclDict["name"],
+ (string) classDeclDict["namespace"],
+ (bool) classDeclDict["nested"],
+ (int) classDeclDict["base_count"]
+ ));
+ }
+
+ classes = classesList;
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/MonoBottomPanel.cs b/modules/mono/editor/GodotTools/GodotTools/MonoBottomPanel.cs
new file mode 100644
index 0000000000..300cf7fcb9
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/MonoBottomPanel.cs
@@ -0,0 +1,342 @@
+using Godot;
+using System;
+using System.IO;
+using Godot.Collections;
+using GodotTools.Internals;
+using File = GodotTools.Utils.File;
+using Path = System.IO.Path;
+
+namespace GodotTools
+{
+ public class MonoBottomPanel : VBoxContainer
+ {
+ private EditorInterface editorInterface;
+
+ private TabContainer panelTabs;
+
+ private VBoxContainer panelBuildsTab;
+
+ private ItemList buildTabsList;
+ private TabContainer buildTabs;
+
+ private ToolButton warningsBtn;
+ private ToolButton errorsBtn;
+ private Button viewLogBtn;
+
+ private void _UpdateBuildTabsList()
+ {
+ buildTabsList.Clear();
+
+ int currentTab = buildTabs.CurrentTab;
+
+ bool noCurrentTab = currentTab < 0 || currentTab >= buildTabs.GetTabCount();
+
+ for (int i = 0; i < buildTabs.GetChildCount(); i++)
+ {
+ var tab = (MonoBuildTab) buildTabs.GetChild(i);
+
+ if (tab == null)
+ continue;
+
+ string itemName = Path.GetFileNameWithoutExtension(tab.BuildInfo.Solution);
+ itemName += " [" + tab.BuildInfo.Configuration + "]";
+
+ buildTabsList.AddItem(itemName, tab.IconTexture);
+
+ string itemTooltip = "Solution: " + tab.BuildInfo.Solution;
+ itemTooltip += "\nConfiguration: " + tab.BuildInfo.Configuration;
+ itemTooltip += "\nStatus: ";
+
+ if (tab.BuildExited)
+ itemTooltip += tab.BuildResult == MonoBuildTab.BuildResults.Success ? "Succeeded" : "Errored";
+ else
+ itemTooltip += "Running";
+
+ if (!tab.BuildExited || tab.BuildResult == MonoBuildTab.BuildResults.Error)
+ itemTooltip += $"\nErrors: {tab.ErrorCount}";
+
+ itemTooltip += $"\nWarnings: {tab.WarningCount}";
+
+ buildTabsList.SetItemTooltip(i, itemTooltip);
+
+ if (noCurrentTab || currentTab == i)
+ {
+ buildTabsList.Select(i);
+ _BuildTabsItemSelected(i);
+ }
+ }
+ }
+
+ public MonoBuildTab GetBuildTabFor(MonoBuildInfo buildInfo)
+ {
+ foreach (var buildTab in new Array<MonoBuildTab>(buildTabs.GetChildren()))
+ {
+ if (buildTab.BuildInfo.Equals(buildInfo))
+ return buildTab;
+ }
+
+ var newBuildTab = new MonoBuildTab(buildInfo);
+ AddBuildTab(newBuildTab);
+
+ return newBuildTab;
+ }
+
+ private void _BuildTabsItemSelected(int idx)
+ {
+ if (idx < 0 || idx >= buildTabs.GetTabCount())
+ throw new IndexOutOfRangeException();
+
+ buildTabs.CurrentTab = idx;
+ if (!buildTabs.Visible)
+ buildTabs.Visible = true;
+
+ warningsBtn.Visible = true;
+ errorsBtn.Visible = true;
+ viewLogBtn.Visible = true;
+ }
+
+ private void _BuildTabsNothingSelected()
+ {
+ if (buildTabs.GetTabCount() != 0)
+ {
+ // just in case
+ buildTabs.Visible = false;
+
+ // This callback is called when clicking on the empty space of the list.
+ // ItemList won't deselect the items automatically, so we must do it ourselves.
+ buildTabsList.UnselectAll();
+ }
+
+ warningsBtn.Visible = false;
+ errorsBtn.Visible = false;
+ viewLogBtn.Visible = false;
+ }
+
+ private void _WarningsToggled(bool pressed)
+ {
+ int currentTab = buildTabs.CurrentTab;
+
+ if (currentTab < 0 || currentTab >= buildTabs.GetTabCount())
+ throw new InvalidOperationException("No tab selected");
+
+ var buildTab = (MonoBuildTab) buildTabs.GetChild(currentTab);
+ buildTab.WarningsVisible = pressed;
+ buildTab.UpdateIssuesList();
+ }
+
+ private void _ErrorsToggled(bool pressed)
+ {
+ int currentTab = buildTabs.CurrentTab;
+
+ if (currentTab < 0 || currentTab >= buildTabs.GetTabCount())
+ throw new InvalidOperationException("No tab selected");
+
+ var buildTab = (MonoBuildTab) buildTabs.GetChild(currentTab);
+ buildTab.ErrorsVisible = pressed;
+ buildTab.UpdateIssuesList();
+ }
+
+ public void BuildProjectPressed()
+ {
+ if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
+ return; // No solution to build
+
+ string editorScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor");
+ string playerScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor_player");
+
+ CSharpProject.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, editorScriptsMetadataPath);
+
+ if (File.Exists(editorScriptsMetadataPath))
+ {
+ try
+ {
+ File.Copy(editorScriptsMetadataPath, playerScriptsMetadataPath);
+ }
+ catch (IOException e)
+ {
+ GD.PushError($"Failed to copy scripts metadata file. Exception message: {e.Message}");
+ return;
+ }
+ }
+
+ var godotDefines = new[]
+ {
+ OS.GetName(),
+ Internal.GodotIs32Bits() ? "32" : "64"
+ };
+
+ bool buildSuccess = GodotSharpBuilds.BuildProjectBlocking("Tools", godotDefines);
+
+ if (!buildSuccess)
+ return;
+
+ // Notify running game for hot-reload
+ Internal.ScriptEditorDebuggerReloadScripts();
+
+ // Hot-reload in the editor
+ GodotSharpEditor.Instance.GetNode<HotReloadAssemblyWatcher>("HotReloadAssemblyWatcher").RestartTimer();
+
+ if (Internal.IsAssembliesReloadingNeeded())
+ Internal.ReloadAssemblies(softReload: false);
+ }
+
+ private void _ViewLogPressed()
+ {
+ if (!buildTabsList.IsAnythingSelected())
+ return;
+
+ var selectedItems = buildTabsList.GetSelectedItems();
+
+ if (selectedItems.Length != 1)
+ throw new InvalidOperationException($"Expected 1 selected item, got {selectedItems.Length}");
+
+ int selectedItem = selectedItems[0];
+
+ var buildTab = (MonoBuildTab) buildTabs.GetTabControl(selectedItem);
+
+ OS.ShellOpen(Path.Combine(buildTab.BuildInfo.LogsDirPath, GodotSharpBuilds.MsBuildLogFileName));
+ }
+
+ public override void _Notification(int what)
+ {
+ base._Notification(what);
+
+ if (what == EditorSettings.NotificationEditorSettingsChanged)
+ {
+ var editorBaseControl = editorInterface.GetBaseControl();
+ panelTabs.AddStyleboxOverride("panel", editorBaseControl.GetStylebox("DebuggerPanel", "EditorStyles"));
+ panelTabs.AddStyleboxOverride("tab_fg", editorBaseControl.GetStylebox("DebuggerTabFG", "EditorStyles"));
+ panelTabs.AddStyleboxOverride("tab_bg", editorBaseControl.GetStylebox("DebuggerTabBG", "EditorStyles"));
+ }
+ }
+
+ public void AddBuildTab(MonoBuildTab buildTab)
+ {
+ buildTabs.AddChild(buildTab);
+ RaiseBuildTab(buildTab);
+ }
+
+ public void RaiseBuildTab(MonoBuildTab buildTab)
+ {
+ if (buildTab.GetParent() != buildTabs)
+ throw new InvalidOperationException("Build tab is not in the tabs list");
+
+ buildTabs.MoveChild(buildTab, 0);
+ _UpdateBuildTabsList();
+ }
+
+ public void ShowBuildTab()
+ {
+ for (int i = 0; i < panelTabs.GetTabCount(); i++)
+ {
+ if (panelTabs.GetTabControl(i) == panelBuildsTab)
+ {
+ panelTabs.CurrentTab = i;
+ GodotSharpEditor.Instance.MakeBottomPanelItemVisible(this);
+ return;
+ }
+ }
+
+ GD.PushError("Builds tab not found");
+ }
+
+ public override void _Ready()
+ {
+ base._Ready();
+
+ editorInterface = GodotSharpEditor.Instance.GetEditorInterface();
+
+ var editorBaseControl = editorInterface.GetBaseControl();
+
+ SizeFlagsVertical = (int) SizeFlags.ExpandFill;
+ SetAnchorsAndMarginsPreset(LayoutPreset.Wide);
+
+ panelTabs = new TabContainer
+ {
+ TabAlign = TabContainer.TabAlignEnum.Left,
+ RectMinSize = new Vector2(0, 228) * Internal.EditorScale,
+ SizeFlagsVertical = (int) SizeFlags.ExpandFill
+ };
+ panelTabs.AddStyleboxOverride("panel", editorBaseControl.GetStylebox("DebuggerPanel", "EditorStyles"));
+ panelTabs.AddStyleboxOverride("tab_fg", editorBaseControl.GetStylebox("DebuggerTabFG", "EditorStyles"));
+ panelTabs.AddStyleboxOverride("tab_bg", editorBaseControl.GetStylebox("DebuggerTabBG", "EditorStyles"));
+ AddChild(panelTabs);
+
+ {
+ // Builds tab
+ panelBuildsTab = new VBoxContainer
+ {
+ Name = "Builds", // TTR
+ SizeFlagsHorizontal = (int) SizeFlags.ExpandFill
+ };
+ panelTabs.AddChild(panelBuildsTab);
+
+ var toolBarHBox = new HBoxContainer {SizeFlagsHorizontal = (int) SizeFlags.ExpandFill};
+ panelBuildsTab.AddChild(toolBarHBox);
+
+ var buildProjectBtn = new Button
+ {
+ Text = "Build Project", // TTR
+ FocusMode = FocusModeEnum.None
+ };
+ buildProjectBtn.Connect("pressed", this, nameof(BuildProjectPressed));
+ toolBarHBox.AddChild(buildProjectBtn);
+
+ toolBarHBox.AddSpacer(begin: false);
+
+ warningsBtn = new ToolButton
+ {
+ Text = "Warnings", // TTR
+ ToggleMode = true,
+ Pressed = true,
+ Visible = false,
+ FocusMode = FocusModeEnum.None
+ };
+ warningsBtn.Connect("toggled", this, nameof(_WarningsToggled));
+ toolBarHBox.AddChild(warningsBtn);
+
+ errorsBtn = new ToolButton
+ {
+ Text = "Errors", // TTR
+ ToggleMode = true,
+ Pressed = true,
+ Visible = false,
+ FocusMode = FocusModeEnum.None
+ };
+ errorsBtn.Connect("toggled", this, nameof(_ErrorsToggled));
+ toolBarHBox.AddChild(errorsBtn);
+
+ toolBarHBox.AddSpacer(begin: false);
+
+ viewLogBtn = new Button
+ {
+ Text = "View log", // TTR
+ FocusMode = FocusModeEnum.None,
+ Visible = false
+ };
+ viewLogBtn.Connect("pressed", this, nameof(_ViewLogPressed));
+ toolBarHBox.AddChild(viewLogBtn);
+
+ var hsc = new HSplitContainer
+ {
+ SizeFlagsHorizontal = (int) SizeFlags.ExpandFill,
+ SizeFlagsVertical = (int) SizeFlags.ExpandFill
+ };
+ panelBuildsTab.AddChild(hsc);
+
+ buildTabsList = new ItemList {SizeFlagsHorizontal = (int) SizeFlags.ExpandFill};
+ buildTabsList.Connect("item_selected", this, nameof(_BuildTabsItemSelected));
+ buildTabsList.Connect("nothing_selected", this, nameof(_BuildTabsNothingSelected));
+ hsc.AddChild(buildTabsList);
+
+ buildTabs = new TabContainer
+ {
+ TabAlign = TabContainer.TabAlignEnum.Left,
+ SizeFlagsHorizontal = (int) SizeFlags.ExpandFill,
+ TabsVisible = false
+ };
+ hsc.AddChild(buildTabs);
+ }
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/MonoBuildInfo.cs b/modules/mono/editor/GodotTools/GodotTools/MonoBuildInfo.cs
new file mode 100644
index 0000000000..858e852392
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/MonoBuildInfo.cs
@@ -0,0 +1,47 @@
+using System;
+using Godot;
+using Godot.Collections;
+using GodotTools.Internals;
+using Path = System.IO.Path;
+
+namespace GodotTools
+{
+ [Serializable]
+ public sealed class MonoBuildInfo : Reference // TODO Remove Reference once we have proper serialization
+ {
+ public string Solution { get; }
+ public string Configuration { get; }
+ public Array<string> CustomProperties { get; } = new Array<string>(); // TODO Use List once we have proper serialization
+
+ public string LogsDirPath => Path.Combine(GodotSharpDirs.BuildLogsDirs, $"{Solution.MD5Text()}_{Configuration}");
+
+ public override bool Equals(object obj)
+ {
+ if (obj is MonoBuildInfo other)
+ return other.Solution == Solution && other.Configuration == Configuration;
+
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ int hash = 17;
+ hash = hash * 29 + Solution.GetHashCode();
+ hash = hash * 29 + Configuration.GetHashCode();
+ return hash;
+ }
+ }
+
+ private MonoBuildInfo()
+ {
+ }
+
+ public MonoBuildInfo(string solution, string configuration)
+ {
+ Solution = solution;
+ Configuration = configuration;
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/MonoBuildTab.cs b/modules/mono/editor/GodotTools/GodotTools/MonoBuildTab.cs
new file mode 100644
index 0000000000..75fdacc0da
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/MonoBuildTab.cs
@@ -0,0 +1,260 @@
+using Godot;
+using System;
+using Godot.Collections;
+using GodotTools.Internals;
+using File = GodotTools.Utils.File;
+using Path = System.IO.Path;
+
+namespace GodotTools
+{
+ public class MonoBuildTab : VBoxContainer
+ {
+ public enum BuildResults
+ {
+ Error,
+ Success
+ }
+
+ [Serializable]
+ private class BuildIssue : Reference // TODO Remove Reference once we have proper serialization
+ {
+ public bool Warning { get; set; }
+ public string File { get; set; }
+ public int Line { get; set; }
+ public int Column { get; set; }
+ public string Code { get; set; }
+ public string Message { get; set; }
+ public string ProjectFile { get; set; }
+ }
+
+ private readonly Array<BuildIssue> issues = new Array<BuildIssue>(); // TODO Use List once we have proper serialization
+ private ItemList issuesList;
+
+ public bool BuildExited { get; private set; } = false;
+
+ public BuildResults? BuildResult { get; private set; } = null;
+
+ public int ErrorCount { get; private set; } = 0;
+
+ public int WarningCount { get; private set; } = 0;
+
+ public bool ErrorsVisible { get; set; } = true;
+ public bool WarningsVisible { get; set; } = true;
+
+ public Texture IconTexture
+ {
+ get
+ {
+ if (!BuildExited)
+ return GetIcon("Stop", "EditorIcons");
+
+ if (BuildResult == BuildResults.Error)
+ return GetIcon("StatusError", "EditorIcons");
+
+ return GetIcon("StatusSuccess", "EditorIcons");
+ }
+ }
+
+ public MonoBuildInfo BuildInfo { get; private set; }
+
+ private void _LoadIssuesFromFile(string csvFile)
+ {
+ using (var file = new Godot.File())
+ {
+ Error openError = file.Open(csvFile, Godot.File.ModeFlags.Read);
+
+ if (openError != Error.Ok)
+ return;
+
+ while (!file.EofReached())
+ {
+ string[] csvColumns = file.GetCsvLine();
+
+ if (csvColumns.Length == 1 && csvColumns[0].Empty())
+ return;
+
+ if (csvColumns.Length != 7)
+ {
+ GD.PushError($"Expected 7 columns, got {csvColumns.Length}");
+ continue;
+ }
+
+ var issue = new BuildIssue
+ {
+ Warning = csvColumns[0] == "warning",
+ File = csvColumns[1],
+ Line = int.Parse(csvColumns[2]),
+ Column = int.Parse(csvColumns[3]),
+ Code = csvColumns[4],
+ Message = csvColumns[5],
+ ProjectFile = csvColumns[6]
+ };
+
+ if (issue.Warning)
+ WarningCount += 1;
+ else
+ ErrorCount += 1;
+
+ issues.Add(issue);
+ }
+ }
+ }
+
+ private void _IssueActivated(int idx)
+ {
+ if (idx < 0 || idx >= issuesList.GetItemCount())
+ throw new IndexOutOfRangeException("Item list index out of range");
+
+ // Get correct issue idx from issue list
+ int issueIndex = (int) issuesList.GetItemMetadata(idx);
+
+ if (idx < 0 || idx >= issues.Count)
+ throw new IndexOutOfRangeException("Issue index out of range");
+
+ BuildIssue issue = issues[issueIndex];
+
+ if (issue.ProjectFile.Empty() && issue.File.Empty())
+ return;
+
+ string projectDir = issue.ProjectFile.Length > 0 ? issue.ProjectFile.GetBaseDir() : BuildInfo.Solution.GetBaseDir();
+
+ string file = Path.Combine(projectDir.SimplifyGodotPath(), issue.File.SimplifyGodotPath());
+
+ if (!File.Exists(file))
+ return;
+
+ file = ProjectSettings.LocalizePath(file);
+
+ if (file.StartsWith("res://"))
+ {
+ var script = (Script) ResourceLoader.Load(file, typeHint: Internal.CSharpLanguageType);
+
+ if (script != null && Internal.ScriptEditorEdit(script, issue.Line, issue.Column))
+ Internal.EditorNodeShowScriptScreen();
+ }
+ }
+
+ public void UpdateIssuesList()
+ {
+ issuesList.Clear();
+
+ using (var warningIcon = GetIcon("Warning", "EditorIcons"))
+ using (var errorIcon = GetIcon("Error", "EditorIcons"))
+ {
+ for (int i = 0; i < issues.Count; i++)
+ {
+ BuildIssue issue = issues[i];
+
+ if (!(issue.Warning ? WarningsVisible : ErrorsVisible))
+ continue;
+
+ string tooltip = string.Empty;
+ tooltip += $"Message: {issue.Message}";
+
+ if (!issue.Code.Empty())
+ tooltip += $"\nCode: {issue.Code}";
+
+ tooltip += $"\nType: {(issue.Warning ? "warning" : "error")}";
+
+ string text = string.Empty;
+
+ if (!issue.File.Empty())
+ {
+ text += $"{issue.File}({issue.Line},{issue.Column}): ";
+
+ tooltip += $"\nFile: {issue.File}";
+ tooltip += $"\nLine: {issue.Line}";
+ tooltip += $"\nColumn: {issue.Column}";
+ }
+
+ if (!issue.ProjectFile.Empty())
+ tooltip += $"\nProject: {issue.ProjectFile}";
+
+ text += issue.Message;
+
+ int lineBreakIdx = text.IndexOf("\n", StringComparison.Ordinal);
+ string itemText = lineBreakIdx == -1 ? text : text.Substring(0, lineBreakIdx);
+ issuesList.AddItem(itemText, issue.Warning ? warningIcon : errorIcon);
+
+ int index = issuesList.GetItemCount() - 1;
+ issuesList.SetItemTooltip(index, tooltip);
+ issuesList.SetItemMetadata(index, i);
+ }
+ }
+ }
+
+ public void OnBuildStart()
+ {
+ BuildExited = false;
+
+ issues.Clear();
+ WarningCount = 0;
+ ErrorCount = 0;
+ UpdateIssuesList();
+
+ GodotSharpEditor.Instance.MonoBottomPanel.RaiseBuildTab(this);
+ }
+
+ public void OnBuildExit(BuildResults result)
+ {
+ BuildExited = true;
+ BuildResult = result;
+
+ _LoadIssuesFromFile(Path.Combine(BuildInfo.LogsDirPath, GodotSharpBuilds.MsBuildIssuesFileName));
+ UpdateIssuesList();
+
+ GodotSharpEditor.Instance.MonoBottomPanel.RaiseBuildTab(this);
+ }
+
+ public void OnBuildExecFailed(string cause)
+ {
+ BuildExited = true;
+ BuildResult = BuildResults.Error;
+
+ issuesList.Clear();
+
+ var issue = new BuildIssue {Message = cause, Warning = false};
+
+ ErrorCount += 1;
+ issues.Add(issue);
+
+ UpdateIssuesList();
+
+ GodotSharpEditor.Instance.MonoBottomPanel.RaiseBuildTab(this);
+ }
+
+ public void RestartBuild()
+ {
+ if (!BuildExited)
+ throw new InvalidOperationException("Build already started");
+
+ GodotSharpBuilds.RestartBuild(this);
+ }
+
+ public void StopBuild()
+ {
+ if (!BuildExited)
+ throw new InvalidOperationException("Build is not in progress");
+
+ GodotSharpBuilds.StopBuild(this);
+ }
+
+ public override void _Ready()
+ {
+ base._Ready();
+
+ issuesList = new ItemList {SizeFlagsVertical = (int) SizeFlags.ExpandFill};
+ issuesList.Connect("item_activated", this, nameof(_IssueActivated));
+ AddChild(issuesList);
+ }
+
+ private MonoBuildTab()
+ {
+ }
+
+ public MonoBuildTab(MonoBuildInfo buildInfo)
+ {
+ BuildInfo = buildInfo;
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs b/modules/mono/editor/GodotTools/GodotTools/MonoDevelopInstance.cs
index fba4a8f65c..0c8d86e799 100644
--- a/modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/MonoDevelopInstance.cs
@@ -1,11 +1,11 @@
+using GodotTools.Core;
using System;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Runtime.CompilerServices;
+using GodotTools.Internals;
-namespace GodotSharpTools.Editor
+namespace GodotTools
{
public class MonoDevelopInstance
{
@@ -15,24 +15,24 @@ namespace GodotSharpTools.Editor
VisualStudioForMac = 1
}
- readonly string solutionFile;
- readonly EditorId editorId;
+ private readonly string solutionFile;
+ private readonly EditorId editorId;
- Process process;
+ private Process process;
- public void Execute(string[] files)
+ public void Execute(params string[] files)
{
bool newWindow = process == null || process.HasExited;
- List<string> args = new List<string>();
+ var args = new List<string>();
string command;
if (Utils.OS.IsOSX())
{
- string bundleId = codeEditorBundleIds[editorId];
+ string bundleId = CodeEditorBundleIds[editorId];
- if (IsApplicationBundleInstalled(bundleId))
+ if (Internal.IsOsxAppBundleInstalled(bundleId))
{
command = "open";
@@ -47,12 +47,12 @@ namespace GodotSharpTools.Editor
}
else
{
- command = codeEditorPaths[editorId];
+ command = CodeEditorPaths[editorId];
}
}
else
{
- command = codeEditorPaths[editorId];
+ command = CodeEditorPaths[editorId];
}
args.Add("--ipc-tcp");
@@ -72,7 +72,7 @@ namespace GodotSharpTools.Editor
if (newWindow)
{
- process = Process.Start(new ProcessStartInfo()
+ process = Process.Start(new ProcessStartInfo
{
FileName = command,
Arguments = string.Join(" ", args),
@@ -81,12 +81,12 @@ namespace GodotSharpTools.Editor
}
else
{
- Process.Start(new ProcessStartInfo()
+ Process.Start(new ProcessStartInfo
{
FileName = command,
Arguments = string.Join(" ", args),
UseShellExecute = false
- });
+ })?.Dispose();
}
}
@@ -99,45 +99,42 @@ namespace GodotSharpTools.Editor
this.editorId = editorId;
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- private extern static bool IsApplicationBundleInstalled(string bundleId);
-
- static readonly IReadOnlyDictionary<EditorId, string> codeEditorPaths;
- static readonly IReadOnlyDictionary<EditorId, string> codeEditorBundleIds;
+ private static readonly IReadOnlyDictionary<EditorId, string> CodeEditorPaths;
+ private static readonly IReadOnlyDictionary<EditorId, string> CodeEditorBundleIds;
static MonoDevelopInstance()
{
if (Utils.OS.IsOSX())
{
- codeEditorPaths = new Dictionary<EditorId, string>
+ CodeEditorPaths = new Dictionary<EditorId, string>
{
// Rely on PATH
- { EditorId.MonoDevelop, "monodevelop" },
- { EditorId.VisualStudioForMac, "VisualStudio" }
+ {EditorId.MonoDevelop, "monodevelop"},
+ {EditorId.VisualStudioForMac, "VisualStudio"}
};
- codeEditorBundleIds = new Dictionary<EditorId, string>
+ CodeEditorBundleIds = new Dictionary<EditorId, string>
{
// TODO EditorId.MonoDevelop
- { EditorId.VisualStudioForMac, "com.microsoft.visual-studio" }
+ {EditorId.VisualStudioForMac, "com.microsoft.visual-studio"}
};
}
else if (Utils.OS.IsWindows())
{
- codeEditorPaths = new Dictionary<EditorId, string>
+ CodeEditorPaths = new Dictionary<EditorId, string>
{
// XamarinStudio is no longer a thing, and the latest version is quite old
// MonoDevelop is available from source only on Windows. The recommendation
// is to use Visual Studio instead. Since there are no official builds, we
// will rely on custom MonoDevelop builds being added to PATH.
- { EditorId.MonoDevelop, "MonoDevelop.exe" }
+ {EditorId.MonoDevelop, "MonoDevelop.exe"}
};
}
else if (Utils.OS.IsUnix())
{
- codeEditorPaths = new Dictionary<EditorId, string>
+ CodeEditorPaths = new Dictionary<EditorId, string>
{
// Rely on PATH
- { EditorId.MonoDevelop, "monodevelop" }
+ {EditorId.MonoDevelop, "monodevelop"}
};
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Properties/AssemblyInfo.cs b/modules/mono/editor/GodotTools/GodotTools/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..f5fe85c722
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Properties/AssemblyInfo.cs
@@ -0,0 +1,26 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("GodotTools")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Godot Engine contributors")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/CollectionExtensions.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/CollectionExtensions.cs
new file mode 100644
index 0000000000..3ae6c10bbf
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/CollectionExtensions.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+
+namespace GodotTools.Utils
+{
+ public static class CollectionExtensions
+ {
+ public static T SelectFirstNotNull<T>(this IEnumerable<T> enumerable, Func<T, T> predicate, T orElse = null)
+ where T : class
+ {
+ foreach (T elem in enumerable)
+ {
+ if (predicate(elem) != null)
+ return elem;
+ }
+
+ return orElse;
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/Directory.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/Directory.cs
new file mode 100644
index 0000000000..c67d48b92a
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/Directory.cs
@@ -0,0 +1,40 @@
+using System.IO;
+using Godot;
+
+namespace GodotTools.Utils
+{
+ public static class Directory
+ {
+ private static string GlobalizePath(this string path)
+ {
+ return ProjectSettings.GlobalizePath(path);
+ }
+
+ public static bool Exists(string path)
+ {
+ return System.IO.Directory.Exists(path.GlobalizePath());
+ }
+
+ /// Create directory recursively
+ public static DirectoryInfo CreateDirectory(string path)
+ {
+ return System.IO.Directory.CreateDirectory(path.GlobalizePath());
+ }
+
+ public static void Delete(string path, bool recursive)
+ {
+ System.IO.Directory.Delete(path.GlobalizePath(), recursive);
+ }
+
+
+ public static string[] GetDirectories(string path, string searchPattern, SearchOption searchOption)
+ {
+ return System.IO.Directory.GetDirectories(path.GlobalizePath(), searchPattern, searchOption);
+ }
+
+ public static string[] GetFiles(string path, string searchPattern, SearchOption searchOption)
+ {
+ return System.IO.Directory.GetFiles(path.GlobalizePath(), searchPattern, searchOption);
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/File.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/File.cs
new file mode 100644
index 0000000000..e1e2188edb
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/File.cs
@@ -0,0 +1,43 @@
+using System;
+using Godot;
+
+namespace GodotTools.Utils
+{
+ public static class File
+ {
+ private static string GlobalizePath(this string path)
+ {
+ return ProjectSettings.GlobalizePath(path);
+ }
+
+ public static void WriteAllText(string path, string contents)
+ {
+ System.IO.File.WriteAllText(path.GlobalizePath(), contents);
+ }
+
+ public static bool Exists(string path)
+ {
+ return System.IO.File.Exists(path.GlobalizePath());
+ }
+
+ public static DateTime GetLastWriteTime(string path)
+ {
+ return System.IO.File.GetLastWriteTime(path.GlobalizePath());
+ }
+
+ public static void Delete(string path)
+ {
+ System.IO.File.Delete(path.GlobalizePath());
+ }
+
+ public static void Copy(string sourceFileName, string destFileName)
+ {
+ System.IO.File.Copy(sourceFileName.GlobalizePath(), destFileName.GlobalizePath(), overwrite: true);
+ }
+
+ public static byte[] ReadAllBytes(string path)
+ {
+ return System.IO.File.ReadAllBytes(path.GlobalizePath());
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
new file mode 100644
index 0000000000..e48b1115db
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
@@ -0,0 +1,127 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+
+namespace GodotTools.Utils
+{
+ public static class OS
+ {
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ extern static string GetPlatformName();
+
+ const string HaikuName = "Haiku";
+ const string OSXName = "OSX";
+ const string ServerName = "Server";
+ const string UWPName = "UWP";
+ const string WindowsName = "Windows";
+ const string X11Name = "X11";
+
+ public static bool IsHaiku()
+ {
+ return HaikuName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
+ }
+
+ public static bool IsOSX()
+ {
+ return OSXName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
+ }
+
+ public static bool IsServer()
+ {
+ return ServerName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
+ }
+
+ public static bool IsUWP()
+ {
+ return UWPName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
+ }
+
+ public static bool IsWindows()
+ {
+ return WindowsName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
+ }
+
+ public static bool IsX11()
+ {
+ return X11Name.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
+ }
+
+ private static bool? _isUnixCache;
+ private static readonly string[] UnixPlatforms = {HaikuName, OSXName, ServerName, X11Name};
+
+ public static bool IsUnix()
+ {
+ if (_isUnixCache.HasValue)
+ return _isUnixCache.Value;
+
+ string osName = GetPlatformName();
+ _isUnixCache = UnixPlatforms.Any(p => p.Equals(osName, StringComparison.OrdinalIgnoreCase));
+ return _isUnixCache.Value;
+ }
+
+ public static char PathSep => IsWindows() ? ';' : ':';
+
+ public static string PathWhich(string name)
+ {
+ string[] windowsExts = IsWindows() ? Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) : null;
+ string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep);
+
+ var searchDirs = new List<string>();
+
+ if (pathDirs != null)
+ searchDirs.AddRange(pathDirs);
+
+ searchDirs.Add(System.IO.Directory.GetCurrentDirectory()); // last in the list
+
+ foreach (var dir in searchDirs)
+ {
+ string path = Path.Combine(dir, name);
+
+ if (IsWindows() && windowsExts != null)
+ {
+ foreach (var extension in windowsExts)
+ {
+ string pathWithExtension = path + extension;
+
+ if (File.Exists(pathWithExtension))
+ return pathWithExtension;
+ }
+ }
+ else
+ {
+ if (File.Exists(path))
+ return path;
+ }
+ }
+
+ return null;
+ }
+
+ public static void RunProcess(string command, IEnumerable<string> arguments)
+ {
+ string CmdLineArgsToString(IEnumerable<string> args)
+ {
+ return string.Join(" ", args.Select(arg => arg.Contains(" ") ? $@"""{arg}""" : arg));
+ }
+
+ ProcessStartInfo startInfo = new ProcessStartInfo(command, CmdLineArgsToString(arguments))
+ {
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false
+ };
+
+ using (Process process = Process.Start(startInfo))
+ {
+ if (process == null)
+ throw new Exception("No process was started");
+
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+ }
+ }
+ }
+}
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 5e0ce3554a..ebf317f08b 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -861,26 +861,22 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
p_output.append("\n#pragma warning restore CS1591\n");
}
-Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution) {
-
- String proj_dir = p_solution_dir.plus_file(CORE_API_ASSEMBLY_NAME);
+Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vector<String> &r_compile_items) {
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
- if (!DirAccess::exists(proj_dir)) {
- Error err = da->make_dir_recursive(proj_dir);
+ if (!DirAccess::exists(p_proj_dir)) {
+ Error err = da->make_dir_recursive(p_proj_dir);
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
}
- da->change_dir(proj_dir);
+ da->change_dir(p_proj_dir);
da->make_dir("Core");
da->make_dir("ObjectType");
- String core_dir = path_join(proj_dir, "Core");
- String obj_type_dir = path_join(proj_dir, "ObjectType");
-
- Vector<String> compile_items;
+ String core_dir = path_join(p_proj_dir, "Core");
+ String obj_type_dir = path_join(p_proj_dir, "ObjectType");
// Generate source file for global scope constants and enums
{
@@ -891,7 +887,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir,
if (save_err != OK)
return save_err;
- compile_items.push_back(output_file);
+ r_compile_items.push_back(output_file);
}
for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
@@ -909,7 +905,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir,
if (err != OK)
return err;
- compile_items.push_back(output_file);
+ r_compile_items.push_back(output_file);
}
// Generate sources from compressed files
@@ -939,7 +935,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir,
file->store_buffer(data.ptr(), data.size());
file->close();
- compile_items.push_back(output_file);
+ r_compile_items.push_back(output_file);
}
StringBuilder cs_icalls_content;
@@ -981,43 +977,27 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir,
if (err != OK)
return err;
- compile_items.push_back(internal_methods_file);
-
- String guid = CSharpProject::generate_core_api_project(proj_dir, compile_items);
-
- DotNetSolution::ProjectInfo proj_info;
- proj_info.guid = guid;
- proj_info.relpath = String(CORE_API_ASSEMBLY_NAME).plus_file(CORE_API_ASSEMBLY_NAME ".csproj");
- proj_info.configs.push_back("Debug");
- proj_info.configs.push_back("Release");
-
- r_solution.add_new_project(CORE_API_ASSEMBLY_NAME, proj_info);
-
- _log("The solution and C# project for the Core API was generated successfully\n");
+ r_compile_items.push_back(internal_methods_file);
return OK;
}
-Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution) {
-
- String proj_dir = p_solution_dir.plus_file(EDITOR_API_ASSEMBLY_NAME);
+Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Vector<String> &r_compile_items) {
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
- if (!DirAccess::exists(proj_dir)) {
- Error err = da->make_dir_recursive(proj_dir);
+ if (!DirAccess::exists(p_proj_dir)) {
+ Error err = da->make_dir_recursive(p_proj_dir);
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
}
- da->change_dir(proj_dir);
+ da->change_dir(p_proj_dir);
da->make_dir("Core");
da->make_dir("ObjectType");
- String core_dir = path_join(proj_dir, "Core");
- String obj_type_dir = path_join(proj_dir, "ObjectType");
-
- Vector<String> compile_items;
+ String core_dir = path_join(p_proj_dir, "Core");
+ String obj_type_dir = path_join(p_proj_dir, "ObjectType");
for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
const TypeInterface &itype = E.get();
@@ -1034,7 +1014,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir
if (err != OK)
return err;
- compile_items.push_back(output_file);
+ r_compile_items.push_back(output_file);
}
StringBuilder cs_icalls_content;
@@ -1077,58 +1057,56 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir
if (err != OK)
return err;
- compile_items.push_back(internal_methods_file);
-
- String guid = CSharpProject::generate_editor_api_project(proj_dir, "../" CORE_API_ASSEMBLY_NAME "/" CORE_API_ASSEMBLY_NAME ".csproj", compile_items);
-
- DotNetSolution::ProjectInfo proj_info;
- proj_info.guid = guid;
- proj_info.relpath = String(EDITOR_API_ASSEMBLY_NAME).plus_file(EDITOR_API_ASSEMBLY_NAME ".csproj");
- proj_info.configs.push_back("Debug");
- proj_info.configs.push_back("Release");
-
- r_solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, proj_info);
-
- _log("The solution and C# project for the Editor API was generated successfully\n");
+ r_compile_items.push_back(internal_methods_file);
return OK;
}
Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
+ String output_dir = DirAccess::get_full_path(p_output_dir, DirAccess::ACCESS_FILESYSTEM);
+
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
- if (!DirAccess::exists(p_output_dir)) {
- Error err = da->make_dir_recursive(p_output_dir);
+ if (!DirAccess::exists(output_dir)) {
+ Error err = da->make_dir_recursive(output_dir);
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
}
- DotNetSolution solution(API_SOLUTION_NAME);
+ Error proj_err;
- if (!solution.set_path(p_output_dir))
- return ERR_FILE_NOT_FOUND;
+ // Generate GodotSharp source files
- Error proj_err;
+ String core_proj_dir = output_dir.plus_file(CORE_API_ASSEMBLY_NAME);
+ Vector<String> core_compile_items;
- proj_err = generate_cs_core_project(p_output_dir, solution);
+ proj_err = generate_cs_core_project(core_proj_dir, core_compile_items);
if (proj_err != OK) {
ERR_PRINT("Generation of the Core API C# project failed");
return proj_err;
}
- proj_err = generate_cs_editor_project(p_output_dir, solution);
+ // Generate GodotSharpEditor source files
+
+ String editor_proj_dir = output_dir.plus_file(EDITOR_API_ASSEMBLY_NAME);
+ Vector<String> editor_compile_items;
+
+ proj_err = generate_cs_editor_project(editor_proj_dir, editor_compile_items);
if (proj_err != OK) {
ERR_PRINT("Generation of the Editor API C# project failed");
return proj_err;
}
- Error sln_error = solution.save();
- if (sln_error != OK) {
- ERR_PRINT("Failed to save API solution");
- return sln_error;
+ // Generate solution
+
+ if (!CSharpProject::generate_api_solution(output_dir,
+ core_proj_dir, core_compile_items, editor_proj_dir, editor_compile_items)) {
+ return ERR_CANT_CREATE;
}
+ _log("The solution for the Godot API was generated successfully\n");
+
return OK;
}
@@ -1311,8 +1289,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.append(MEMBER_BEGIN "private static Godot.Object singleton;\n");
output.append(MEMBER_BEGIN "public static Godot.Object Singleton\n" INDENT2 "{\n" INDENT3
"get\n" INDENT3 "{\n" INDENT4 "if (singleton == null)\n" INDENT5
- "singleton = Engine.GetSingleton(" BINDINGS_NATIVE_NAME_FIELD ");\n" INDENT4
- "return singleton;\n" INDENT3 "}\n" INDENT2 "}\n");
+ "singleton = Engine.GetSingleton(typeof(");
+ output.append(itype.proxy_name);
+ output.append(").Name);\n" INDENT4 "return singleton;\n" INDENT3 "}\n" INDENT2 "}\n");
output.append(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
output.append(itype.name);
@@ -3018,36 +2997,49 @@ void BindingsGenerator::_initialize() {
void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
const int NUM_OPTIONS = 2;
- String mono_glue_option = "--generate-mono-glue";
- String cs_api_option = "--generate-cs-api";
+ String generate_all_glue_option = "--generate-mono-glue";
+ String generate_cs_glue_option = "--generate-mono-cs-glue";
+ String generate_cpp_glue_option = "--generate-mono-cpp-glue";
- String mono_glue_path;
- String cs_api_path;
+ String glue_dir_path;
+ String cs_dir_path;
+ String cpp_dir_path;
int options_left = NUM_OPTIONS;
const List<String>::Element *elem = p_cmdline_args.front();
while (elem && options_left) {
- if (elem->get() == mono_glue_option) {
+ if (elem->get() == generate_all_glue_option) {
const List<String>::Element *path_elem = elem->next();
if (path_elem) {
- mono_glue_path = path_elem->get();
+ glue_dir_path = path_elem->get();
elem = elem->next();
} else {
- ERR_PRINTS(mono_glue_option + ": No output directory specified");
+ ERR_PRINTS(generate_all_glue_option + ": No output directory specified (expected path to {GODOT_ROOT}/modules/mono/glue)");
}
--options_left;
- } else if (elem->get() == cs_api_option) {
+ } else if (elem->get() == generate_cs_glue_option) {
const List<String>::Element *path_elem = elem->next();
if (path_elem) {
- cs_api_path = path_elem->get();
+ cs_dir_path = path_elem->get();
elem = elem->next();
} else {
- ERR_PRINTS(cs_api_option + ": No output directory specified");
+ ERR_PRINTS(generate_cs_glue_option + ": No output directory specified");
+ }
+
+ --options_left;
+ } else if (elem->get() == generate_cpp_glue_option) {
+ const List<String>::Element *path_elem = elem->next();
+
+ if (path_elem) {
+ cpp_dir_path = path_elem->get();
+ elem = elem->next();
+ } else {
+ ERR_PRINTS(generate_cpp_glue_option + ": No output directory specified");
}
--options_left;
@@ -3056,18 +3048,26 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
elem = elem->next();
}
- if (mono_glue_path.length() || cs_api_path.length()) {
+ if (glue_dir_path.length() || cs_dir_path.length() || cpp_dir_path.length()) {
BindingsGenerator bindings_generator;
bindings_generator.set_log_print_enabled(true);
- if (mono_glue_path.length()) {
- if (bindings_generator.generate_glue(mono_glue_path) != OK)
- ERR_PRINTS(mono_glue_option + ": Failed to generate mono glue");
+ if (glue_dir_path.length()) {
+ if (bindings_generator.generate_glue(glue_dir_path) != OK)
+ ERR_PRINTS(generate_all_glue_option + ": Failed to generate the C++ glue");
+
+ if (bindings_generator.generate_cs_api(glue_dir_path.plus_file("Managed/Generated")) != OK)
+ ERR_PRINTS(generate_all_glue_option + ": Failed to generate the C# API");
+ }
+
+ if (cs_dir_path.length()) {
+ if (bindings_generator.generate_cs_api(cs_dir_path) != OK)
+ ERR_PRINTS(generate_cs_glue_option + ": Failed to generate the C# API");
}
- if (cs_api_path.length()) {
- if (bindings_generator.generate_cs_api(cs_api_path) != OK)
- ERR_PRINTS(cs_api_option + ": Failed to generate the C# API");
+ if (cpp_dir_path.length()) {
+ if (bindings_generator.generate_glue(cpp_dir_path) != OK)
+ ERR_PRINTS(generate_cpp_glue_option + ": Failed to generate the C++ glue");
}
// Exit once done
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index ffc73a7e3e..8be51a6c55 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -33,7 +33,6 @@
#include "core/class_db.h"
#include "core/string_builder.h"
-#include "dotnet_solution.h"
#include "editor/doc/doc_data.h"
#include "editor/editor_help.h"
@@ -614,12 +613,13 @@ class BindingsGenerator {
void _initialize();
public:
- Error generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution);
- Error generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution);
+ Error generate_cs_core_project(const String &p_proj_dir, Vector<String> &r_compile_files);
+ Error generate_cs_editor_project(const String &p_proj_dir, Vector<String> &r_compile_items);
Error generate_cs_api(const String &p_output_dir);
Error generate_glue(const String &p_output_dir);
- void set_log_print_enabled(bool p_enabled) { log_print_enabled = p_enabled; }
+ _FORCE_INLINE_ bool is_log_print_enabled() { return log_print_enabled; }
+ _FORCE_INLINE_ void set_log_print_enabled(bool p_enabled) { log_print_enabled = p_enabled; }
static uint32_t get_version();
diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp
index fe79286556..d88b08c646 100644
--- a/modules/mono/editor/csharp_project.cpp
+++ b/modules/mono/editor/csharp_project.cpp
@@ -44,66 +44,54 @@
namespace CSharpProject {
-String generate_core_api_project(const String &p_dir, const Vector<String> &p_files) {
-
- _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
-
- GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator");
-
- Variant dir = p_dir;
- Variant compile_items = p_files;
- const Variant *args[2] = { &dir, &compile_items };
+bool generate_api_solution_impl(const String &p_solution_dir, const String &p_core_proj_dir, const Vector<String> &p_core_compile_items,
+ const String &p_editor_proj_dir, const Vector<String> &p_editor_compile_items,
+ GDMonoAssembly *p_tools_project_editor_assembly) {
+
+ GDMonoClass *klass = p_tools_project_editor_assembly->get_class("GodotTools.ProjectEditor", "ApiSolutionGenerator");
+
+ Variant solution_dir = p_solution_dir;
+ Variant core_proj_dir = p_core_proj_dir;
+ Variant core_compile_items = p_core_compile_items;
+ Variant editor_proj_dir = p_editor_proj_dir;
+ Variant editor_compile_items = p_editor_compile_items;
+ const Variant *args[5] = { &solution_dir, &core_proj_dir, &core_compile_items, &editor_proj_dir, &editor_compile_items };
MonoException *exc = NULL;
- MonoObject *ret = klass->get_method("GenCoreApiProject", 2)->invoke(NULL, args, &exc);
+ klass->get_method("GenerateApiSolution", 5)->invoke(NULL, args, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
- ERR_FAIL_V(String());
+ ERR_FAIL_V(false);
}
- return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String();
+ return true;
}
-String generate_editor_api_project(const String &p_dir, const String &p_core_proj_path, const Vector<String> &p_files) {
-
- _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
-
- GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator");
-
- Variant dir = p_dir;
- Variant core_proj_path = p_core_proj_path;
- Variant compile_items = p_files;
- const Variant *args[3] = { &dir, &core_proj_path, &compile_items };
- MonoException *exc = NULL;
- MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- ERR_FAIL_V(String());
- }
-
- return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String();
-}
+bool generate_api_solution(const String &p_solution_dir, const String &p_core_proj_dir, const Vector<String> &p_core_compile_items,
+ const String &p_editor_proj_dir, const Vector<String> &p_editor_compile_items) {
-String generate_game_project(const String &p_dir, const String &p_name, const Vector<String> &p_files) {
+ if (GDMono::get_singleton()->get_tools_project_editor_assembly()) {
+ return generate_api_solution_impl(p_solution_dir, p_core_proj_dir, p_core_compile_items,
+ p_editor_proj_dir, p_editor_compile_items,
+ GDMono::get_singleton()->get_tools_project_editor_assembly());
+ } else {
+ MonoDomain *temp_domain = GDMonoUtils::create_domain("GodotEngine.ApiSolutionGenerationDomain");
+ CRASH_COND(temp_domain == NULL);
+ _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(temp_domain);
- _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
+ _GDMONO_SCOPE_DOMAIN_(temp_domain);
- GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator");
+ GDMonoAssembly *tools_project_editor_assembly = NULL;
- Variant dir = p_dir;
- Variant name = p_name;
- Variant compile_items = p_files;
- const Variant *args[3] = { &dir, &name, &compile_items };
- MonoException *exc = NULL;
- MonoObject *ret = klass->get_method("GenGameProject", 3)->invoke(NULL, args, &exc);
+ if (!GDMono::get_singleton()->load_assembly("GodotTools.ProjectEditor", &tools_project_editor_assembly)) {
+ ERR_EXPLAIN("Failed to load assembly: 'GodotTools.ProjectEditor'");
+ ERR_FAIL_V(false);
+ }
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- ERR_FAIL_V(String());
+ return generate_api_solution_impl(p_solution_dir, p_core_proj_dir, p_core_compile_items,
+ p_editor_proj_dir, p_editor_compile_items,
+ tools_project_editor_assembly);
}
-
- return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String();
}
void add_item(const String &p_project_path, const String &p_item_type, const String &p_include) {
@@ -111,9 +99,9 @@ void add_item(const String &p_project_path, const String &p_item_type, const Str
if (!GLOBAL_DEF("mono/project/auto_update_project", true))
return;
- _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
+ GDMonoAssembly *tools_project_editor_assembly = GDMono::get_singleton()->get_tools_project_editor_assembly();
- GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils");
+ GDMonoClass *klass = tools_project_editor_assembly->get_class("GodotTools.ProjectEditor", "ProjectUtils");
Variant project_path = p_project_path;
Variant item_type = p_item_type;
@@ -128,126 +116,4 @@ void add_item(const String &p_project_path, const String &p_item_type, const Str
}
}
-Error generate_scripts_metadata(const String &p_project_path, const String &p_output_path) {
-
- _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
-
- if (FileAccess::exists(p_output_path)) {
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- Error rm_err = da->remove(p_output_path);
-
- ERR_EXPLAIN("Failed to remove old scripts metadata file");
- ERR_FAIL_COND_V(rm_err != OK, rm_err);
- }
-
- GDMonoClass *project_utils = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils");
-
- void *args[2] = {
- GDMonoMarshal::mono_string_from_godot(p_project_path),
- GDMonoMarshal::mono_string_from_godot("Compile")
- };
-
- MonoException *exc = NULL;
- MonoArray *ret = (MonoArray *)project_utils->get_method("GetIncludeFiles", 2)->invoke_raw(NULL, args, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- ERR_FAIL_V(FAILED);
- }
-
- PoolStringArray project_files = GDMonoMarshal::mono_array_to_PoolStringArray(ret);
- PoolStringArray::Read r = project_files.read();
-
- Dictionary old_dict = CSharpLanguage::get_singleton()->get_scripts_metadata_or_nothing();
- Dictionary new_dict;
-
- for (int i = 0; i < project_files.size(); i++) {
- const String &project_file = ("res://" + r[i]).simplify_path();
-
- uint64_t modified_time = FileAccess::get_modified_time(project_file);
-
- const Variant *old_file_var = old_dict.getptr(project_file);
- if (old_file_var) {
- Dictionary old_file_dict = old_file_var->operator Dictionary();
-
- if (old_file_dict["modified_time"].operator uint64_t() == modified_time) {
- // No changes so no need to parse again
- new_dict[project_file] = old_file_dict;
- continue;
- }
- }
-
- ScriptClassParser scp;
- Error err = scp.parse_file(project_file);
- if (err != OK) {
- ERR_PRINTS("Parse error: " + scp.get_error());
- ERR_EXPLAIN("Failed to determine namespace and class for script: " + project_file);
- ERR_FAIL_V(err);
- }
-
- Vector<ScriptClassParser::ClassDecl> classes = scp.get_classes();
-
- bool found = false;
- Dictionary class_dict;
-
- String search_name = project_file.get_file().get_basename();
-
- for (int j = 0; j < classes.size(); j++) {
- const ScriptClassParser::ClassDecl &class_decl = classes[j];
-
- if (class_decl.base.size() == 0)
- continue; // Does not inherit nor implement anything, so it can't be a script class
-
- String class_cmp;
-
- if (class_decl.nested) {
- class_cmp = class_decl.name.get_slice(".", class_decl.name.get_slice_count(".") - 1);
- } else {
- class_cmp = class_decl.name;
- }
-
- if (class_cmp != search_name)
- continue;
-
- class_dict["namespace"] = class_decl.namespace_;
- class_dict["class_name"] = class_decl.name;
- class_dict["nested"] = class_decl.nested;
-
- found = true;
- break;
- }
-
- if (found) {
- Dictionary file_dict;
- file_dict["modified_time"] = modified_time;
- file_dict["class"] = class_dict;
- new_dict[project_file] = file_dict;
- }
- }
-
- if (new_dict.size()) {
- String json = JSON::print(new_dict, "", false);
-
- String base_dir = p_output_path.get_base_dir();
-
- if (!DirAccess::exists(base_dir)) {
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
-
- Error err = da->make_dir_recursive(base_dir);
- ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
- }
-
- Error ferr;
- FileAccess *f = FileAccess::open(p_output_path, FileAccess::WRITE, &ferr);
- ERR_EXPLAIN("Cannot open file for writing: " + p_output_path);
- ERR_FAIL_COND_V(ferr != OK, ferr);
- f->store_string(json);
- f->flush();
- f->close();
- memdelete(f);
- }
-
- return OK;
-}
-
} // namespace CSharpProject
diff --git a/modules/mono/editor/csharp_project.h b/modules/mono/editor/csharp_project.h
index b08c9090c7..b42762cea2 100644
--- a/modules/mono/editor/csharp_project.h
+++ b/modules/mono/editor/csharp_project.h
@@ -35,14 +35,11 @@
namespace CSharpProject {
-String generate_core_api_project(const String &p_dir, const Vector<String> &p_files = Vector<String>());
-String generate_editor_api_project(const String &p_dir, const String &p_core_proj_path, const Vector<String> &p_files = Vector<String>());
-String generate_game_project(const String &p_dir, const String &p_name, const Vector<String> &p_files = Vector<String>());
+bool generate_api_solution(const String &p_solution_dir, const String &p_core_proj_dir, const Vector<String> &p_core_compile_items,
+ const String &p_editor_proj_dir, const Vector<String> &p_editor_compile_items);
void add_item(const String &p_project_path, const String &p_item_type, const String &p_include);
-Error generate_scripts_metadata(const String &p_project_path, const String &p_output_path);
-
} // namespace CSharpProject
#endif // CSHARP_PROJECT_H
diff --git a/modules/mono/editor/dotnet_solution.cpp b/modules/mono/editor/dotnet_solution.cpp
deleted file mode 100644
index 324752cafc..0000000000
--- a/modules/mono/editor/dotnet_solution.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-/*************************************************************************/
-/* dotnet_solution.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "dotnet_solution.h"
-
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
-
-#include "../utils/path_utils.h"
-#include "../utils/string_utils.h"
-#include "csharp_project.h"
-
-#define SOLUTION_TEMPLATE \
- "Microsoft Visual Studio Solution File, Format Version 12.00\n" \
- "# Visual Studio 2012\n" \
- "%0\n" \
- "Global\n" \
- "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n" \
- "%1\n" \
- "\tEndGlobalSection\n" \
- "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n" \
- "%2\n" \
- "\tEndGlobalSection\n" \
- "EndGlobal\n"
-
-#define PROJECT_DECLARATION "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"%0\", \"%1\", \"{%2}\"\nEndProject"
-
-#define SOLUTION_PLATFORMS_CONFIG "\t%0|Any CPU = %0|Any CPU"
-
-#define PROJECT_PLATFORMS_CONFIG \
- "\t\t{%0}.%1|Any CPU.ActiveCfg = %1|Any CPU\n" \
- "\t\t{%0}.%1|Any CPU.Build.0 = %1|Any CPU"
-
-void DotNetSolution::add_new_project(const String &p_name, const ProjectInfo &p_project_info) {
- projects[p_name] = p_project_info;
-}
-
-bool DotNetSolution::has_project(const String &p_name) const {
- return projects.find(p_name) != NULL;
-}
-
-const DotNetSolution::ProjectInfo &DotNetSolution::get_project_info(const String &p_name) const {
- return projects[p_name];
-}
-
-bool DotNetSolution::remove_project(const String &p_name) {
- return projects.erase(p_name);
-}
-
-Error DotNetSolution::save() {
- bool dir_exists = DirAccess::exists(path);
- ERR_EXPLAIN("The directory does not exist.");
- ERR_FAIL_COND_V(!dir_exists, ERR_FILE_NOT_FOUND);
-
- String projs_decl;
- String sln_platform_cfg;
- String proj_platform_cfg;
-
- for (Map<String, ProjectInfo>::Element *E = projects.front(); E; E = E->next()) {
- const String &name = E->key();
- const ProjectInfo &proj_info = E->value();
-
- bool is_front = E == projects.front();
-
- if (!is_front)
- projs_decl += "\n";
-
- projs_decl += sformat(PROJECT_DECLARATION, name, proj_info.relpath.replace("/", "\\"), proj_info.guid);
-
- for (int i = 0; i < proj_info.configs.size(); i++) {
- const String &config = proj_info.configs[i];
-
- if (i != 0 || !is_front) {
- sln_platform_cfg += "\n";
- proj_platform_cfg += "\n";
- }
-
- sln_platform_cfg += sformat(SOLUTION_PLATFORMS_CONFIG, config);
- proj_platform_cfg += sformat(PROJECT_PLATFORMS_CONFIG, proj_info.guid, config);
- }
- }
-
- String content = sformat(SOLUTION_TEMPLATE, projs_decl, sln_platform_cfg, proj_platform_cfg);
-
- FileAccess *file = FileAccess::open(path_join(path, name + ".sln"), FileAccess::WRITE);
- ERR_FAIL_NULL_V(file, ERR_FILE_CANT_WRITE);
- file->store_string(content);
- file->close();
- memdelete(file);
-
- return OK;
-}
-
-bool DotNetSolution::set_path(const String &p_existing_path) {
- if (p_existing_path.is_abs_path()) {
- path = p_existing_path;
- } else {
- String abspath;
- if (!rel_path_to_abs(p_existing_path, abspath))
- return false;
- path = abspath;
- }
-
- return true;
-}
-
-String DotNetSolution::get_path() {
- return path;
-}
-
-DotNetSolution::DotNetSolution(const String &p_name) {
- name = p_name;
-}
diff --git a/modules/mono/editor/dotnet_solution.h b/modules/mono/editor/dotnet_solution.h
deleted file mode 100644
index 18933364fa..0000000000
--- a/modules/mono/editor/dotnet_solution.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*************************************************************************/
-/* dotnet_solution.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef NET_SOLUTION_H
-#define NET_SOLUTION_H
-
-#include "core/map.h"
-#include "core/ustring.h"
-
-struct DotNetSolution {
- String name;
-
- struct ProjectInfo {
- String guid;
- String relpath; // Must be relative to the solution directory
- Vector<String> configs;
- };
-
- void add_new_project(const String &p_name, const ProjectInfo &p_project_info);
- bool has_project(const String &p_name) const;
- const ProjectInfo &get_project_info(const String &p_name) const;
- bool remove_project(const String &p_name);
-
- Error save();
-
- bool set_path(const String &p_existing_path);
- String get_path();
-
- DotNetSolution(const String &p_name);
-
-private:
- String path;
- Map<String, ProjectInfo> projects;
-};
-
-#endif // NET_SOLUTION_H
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
new file mode 100644
index 0000000000..a3b5b450ef
--- /dev/null
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -0,0 +1,429 @@
+/*************************************************************************/
+/* editor_internal_calls.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_internal_calls.h"
+
+#include "core/message_queue.h"
+#include "core/os/os.h"
+#include "core/version.h"
+#include "editor/editor_node.h"
+#include "editor/plugins/script_editor_plugin.h"
+#include "editor/script_editor_debugger.h"
+#include "main/main.h"
+
+#include "../csharp_script.h"
+#include "../glue/cs_glue_version.gen.h"
+#include "../godotsharp_dirs.h"
+#include "../mono_gd/gd_mono_marshal.h"
+#include "../utils/osx_utils.h"
+#include "bindings_generator.h"
+#include "godotsharp_export.h"
+#include "script_class_parser.h"
+
+MonoString *godot_icall_GodotSharpDirs_ResDataDir() {
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_data_dir());
+}
+
+MonoString *godot_icall_GodotSharpDirs_ResMetadataDir() {
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_metadata_dir());
+}
+
+MonoString *godot_icall_GodotSharpDirs_ResAssembliesBaseDir() {
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_assemblies_base_dir());
+}
+
+MonoString *godot_icall_GodotSharpDirs_ResAssembliesDir() {
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_assemblies_dir());
+}
+
+MonoString *godot_icall_GodotSharpDirs_ResConfigDir() {
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_config_dir());
+}
+
+MonoString *godot_icall_GodotSharpDirs_ResTempDir() {
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_temp_dir());
+}
+
+MonoString *godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir() {
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_temp_assemblies_base_dir());
+}
+
+MonoString *godot_icall_GodotSharpDirs_ResTempAssembliesDir() {
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_temp_assemblies_dir());
+}
+
+MonoString *godot_icall_GodotSharpDirs_MonoUserDir() {
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_mono_user_dir());
+}
+
+MonoString *godot_icall_GodotSharpDirs_MonoLogsDir() {
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_mono_logs_dir());
+}
+
+MonoString *godot_icall_GodotSharpDirs_MonoSolutionsDir() {
+#ifdef TOOLS_ENABLED
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_mono_solutions_dir());
+#else
+ return NULL;
+#endif
+}
+
+MonoString *godot_icall_GodotSharpDirs_BuildLogsDirs() {
+#ifdef TOOLS_ENABLED
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_build_logs_dir());
+#else
+ return NULL;
+#endif
+}
+
+MonoString *godot_icall_GodotSharpDirs_ProjectSlnPath() {
+#ifdef TOOLS_ENABLED
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_project_sln_path());
+#else
+ return NULL;
+#endif
+}
+
+MonoString *godot_icall_GodotSharpDirs_ProjectCsProjPath() {
+#ifdef TOOLS_ENABLED
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_project_csproj_path());
+#else
+ return NULL;
+#endif
+}
+
+MonoString *godot_icall_GodotSharpDirs_DataEditorToolsDir() {
+#ifdef TOOLS_ENABLED
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_editor_tools_dir());
+#else
+ return NULL;
+#endif
+}
+
+MonoString *godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir() {
+#ifdef TOOLS_ENABLED
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_editor_prebuilt_api_dir());
+#else
+ return NULL;
+#endif
+}
+
+MonoString *godot_icall_GodotSharpDirs_DataMonoEtcDir() {
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_mono_etc_dir());
+}
+
+MonoString *godot_icall_GodotSharpDirs_DataMonoLibDir() {
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_mono_lib_dir());
+}
+
+MonoString *godot_icall_GodotSharpDirs_DataMonoBinDir() {
+#ifdef WINDOWS_ENABLED
+ return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_mono_bin_dir());
+#else
+ return NULL;
+#endif
+}
+
+void godot_icall_EditorProgress_Create(MonoString *p_task, MonoString *p_label, int32_t p_amount, MonoBoolean p_can_cancel) {
+ String task = GDMonoMarshal::mono_string_to_godot(p_task);
+ String label = GDMonoMarshal::mono_string_to_godot(p_label);
+ EditorNode::progress_add_task(task, label, p_amount, (bool)p_can_cancel);
+}
+
+void godot_icall_EditorProgress_Dispose(MonoString *p_task) {
+ String task = GDMonoMarshal::mono_string_to_godot(p_task);
+ EditorNode::progress_end_task(task);
+}
+
+MonoBoolean godot_icall_EditorProgress_Step(MonoString *p_task, MonoString *p_state, int32_t p_step, MonoBoolean p_force_refresh) {
+ String task = GDMonoMarshal::mono_string_to_godot(p_task);
+ String state = GDMonoMarshal::mono_string_to_godot(p_state);
+ return EditorNode::progress_task_step(task, state, p_step, (bool)p_force_refresh);
+}
+
+BindingsGenerator *godot_icall_BindingsGenerator_Ctor() {
+ return memnew(BindingsGenerator);
+}
+
+void godot_icall_BindingsGenerator_Dtor(BindingsGenerator *p_handle) {
+ memdelete(p_handle);
+}
+
+MonoBoolean godot_icall_BindingsGenerator_LogPrintEnabled(BindingsGenerator *p_handle) {
+ return p_handle->is_log_print_enabled();
+}
+
+void godot_icall_BindingsGenerator_SetLogPrintEnabled(BindingsGenerator p_handle, MonoBoolean p_enabled) {
+ p_handle.set_log_print_enabled(p_enabled);
+}
+
+int32_t godot_icall_BindingsGenerator_GenerateCsApi(BindingsGenerator *p_handle, MonoString *p_output_dir) {
+ String output_dir = GDMonoMarshal::mono_string_to_godot(p_output_dir);
+ return p_handle->generate_cs_api(output_dir);
+}
+
+uint32_t godot_icall_BindingsGenerator_Version() {
+ return BindingsGenerator::get_version();
+}
+
+uint32_t godot_icall_BindingsGenerator_CsGlueVersion() {
+ return CS_GLUE_VERSION;
+}
+
+int32_t godot_icall_ScriptClassParser_ParseFile(MonoString *p_filepath, MonoObject *p_classes) {
+ String filepath = GDMonoMarshal::mono_string_to_godot(p_filepath);
+
+ ScriptClassParser scp;
+ Error err = scp.parse_file(filepath);
+ if (err == OK) {
+ Array classes = GDMonoMarshal::mono_object_to_variant(p_classes);
+ const Vector<ScriptClassParser::ClassDecl> &class_decls = scp.get_classes();
+
+ for (int i = 0; i < class_decls.size(); i++) {
+ const ScriptClassParser::ClassDecl &classDecl = class_decls[i];
+
+ Dictionary classDeclDict;
+ classDeclDict["name"] = classDecl.name;
+ classDeclDict["namespace"] = classDecl.namespace_;
+ classDeclDict["nested"] = classDecl.nested;
+ classDeclDict["base_count"] = classDecl.base.size();
+ classes.push_back(classDeclDict);
+ }
+ }
+ return err;
+}
+
+uint32_t godot_icall_GodotSharpExport_GetExportedAssemblyDependencies(MonoString *p_project_dll_name, MonoString *p_project_dll_src_path,
+ MonoString *p_build_config, MonoString *p_custom_lib_dir, MonoObject *r_dependencies) {
+ String project_dll_name = GDMonoMarshal::mono_string_to_godot(p_project_dll_name);
+ String project_dll_src_path = GDMonoMarshal::mono_string_to_godot(p_project_dll_src_path);
+ String build_config = GDMonoMarshal::mono_string_to_godot(p_build_config);
+ String custom_lib_dir = GDMonoMarshal::mono_string_to_godot(p_custom_lib_dir);
+ Dictionary dependencies = GDMonoMarshal::mono_object_to_variant(r_dependencies);
+
+ return GodotSharpExport::get_exported_assembly_dependencies(project_dll_name, project_dll_src_path, build_config, custom_lib_dir, dependencies);
+}
+
+float godot_icall_Internal_EditorScale() {
+ return EDSCALE;
+}
+
+MonoObject *godot_icall_Internal_GlobalDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) {
+ String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
+ Variant default_value = GDMonoMarshal::mono_object_to_variant(p_default_value);
+ Variant result = _GLOBAL_DEF(setting, default_value, (bool)p_restart_if_changed);
+ return GDMonoMarshal::variant_to_mono_object(result);
+}
+
+MonoObject *godot_icall_Internal_EditorDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) {
+ String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
+ Variant default_value = GDMonoMarshal::mono_object_to_variant(p_default_value);
+ Variant result = _GLOBAL_DEF(setting, default_value, (bool)p_restart_if_changed);
+ return GDMonoMarshal::variant_to_mono_object(result);
+}
+
+MonoString *godot_icall_Internal_FullTemplatesDir() {
+ String full_templates_dir = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG);
+ return GDMonoMarshal::mono_string_from_godot(full_templates_dir);
+}
+
+MonoString *godot_icall_Internal_SimplifyGodotPath(MonoString *p_path) {
+ String path = GDMonoMarshal::mono_string_to_godot(p_path);
+ return GDMonoMarshal::mono_string_from_godot(path.simplify_path());
+}
+
+MonoBoolean godot_icall_Internal_IsOsxAppBundleInstalled(MonoString *p_bundle_id) {
+#ifdef OSX_ENABLED
+ String bundle_id = GDMonoMarshal::mono_string_to_godot(p_bundle_id);
+ return (MonoBoolean)osx_is_app_bundle_installed;
+#else
+ (void)p_bundle_id; // UNUSED
+ return (MonoBoolean) false;
+#endif
+}
+
+MonoBoolean godot_icall_Internal_MetadataIsApiAssemblyInvalidated(int32_t p_api_type) {
+ return GDMono::get_singleton()->metadata_is_api_assembly_invalidated((APIAssembly::Type)p_api_type);
+}
+
+void godot_icall_Internal_MetadataSetApiAssemblyInvalidated(int32_t p_api_type, MonoBoolean p_invalidated) {
+ GDMono::get_singleton()->metadata_set_api_assembly_invalidated((APIAssembly::Type)p_api_type, (bool)p_invalidated);
+}
+
+MonoBoolean godot_icall_Internal_IsMessageQueueFlushing() {
+ return (MonoBoolean)MessageQueue::get_singleton()->is_flushing();
+}
+
+MonoBoolean godot_icall_Internal_GodotIs32Bits() {
+ return sizeof(void *) == 4;
+}
+
+MonoBoolean godot_icall_Internal_GodotIsRealTDouble() {
+#ifdef REAL_T_IS_DOUBLE
+ return (MonoBoolean) true;
+#else
+ return (MonoBoolean) false;
+#endif
+}
+
+void godot_icall_Internal_GodotMainIteration() {
+ Main::iteration();
+}
+
+uint64_t godot_icall_Internal_GetCoreApiHash() {
+ return ClassDB::get_api_hash(ClassDB::API_CORE);
+}
+
+uint64_t godot_icall_Internal_GetEditorApiHash() {
+ return ClassDB::get_api_hash(ClassDB::API_EDITOR);
+}
+
+MonoBoolean godot_icall_Internal_IsAssembliesReloadingNeeded() {
+#ifdef GD_MONO_HOT_RELOAD
+ return (MonoBoolean)CSharpLanguage::get_singleton()->is_assembly_reloading_needed();
+#else
+ return (MonoBoolean) false;
+#endif
+}
+
+void godot_icall_Internal_ReloadAssemblies(MonoBoolean p_soft_reload) {
+#ifdef GD_MONO_HOT_RELOAD
+ _GodotSharp::get_singleton()->call_deferred("_reload_assemblies", (bool)p_soft_reload);
+#endif
+}
+
+void godot_icall_Internal_ScriptEditorDebuggerReloadScripts() {
+ ScriptEditor::get_singleton()->get_debugger()->reload_scripts();
+}
+
+MonoBoolean godot_icall_Internal_ScriptEditorEdit(MonoObject *p_resource, int32_t p_line, int32_t p_col, MonoBoolean p_grab_focus) {
+ Ref<Resource> resource = GDMonoMarshal::mono_object_to_variant(p_resource);
+ return (MonoBoolean)ScriptEditor::get_singleton()->edit(resource, p_line, p_col, (bool)p_grab_focus);
+}
+
+void godot_icall_Internal_EditorNodeShowScriptScreen() {
+ EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
+}
+
+MonoObject *godot_icall_Internal_GetScriptsMetadataOrNothing(MonoReflectionType *p_dict_reftype) {
+ Dictionary maybe_metadata = CSharpLanguage::get_singleton()->get_scripts_metadata_or_nothing();
+
+ MonoType *dict_type = mono_reflection_type_get_type(p_dict_reftype);
+
+ uint32_t type_encoding = mono_type_get_type(dict_type);
+ MonoClass *type_class_raw = mono_class_from_mono_type(dict_type);
+ GDMonoClass *type_class = GDMono::get_singleton()->get_class(type_class_raw);
+
+ return GDMonoMarshal::variant_to_mono_object(maybe_metadata, ManagedType(type_encoding, type_class));
+}
+
+MonoString *godot_icall_Internal_MonoWindowsInstallRoot() {
+#ifdef WINDOWS_ENABLED
+ String install_root_dir = GDMono::get_singleton()->get_mono_reg_info().install_root_dir;
+ return GDMonoMarshal::mono_string_from_godot(install_root_dir);
+#else
+ return NULL;
+#endif
+}
+
+MonoString *godot_icall_Utils_OS_GetPlatformName() {
+ String os_name = OS::get_singleton()->get_name();
+ return GDMonoMarshal::mono_string_from_godot(os_name);
+}
+
+void register_editor_internal_calls() {
+
+ // GodotSharpDirs
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResDataDir", (void *)godot_icall_GodotSharpDirs_ResDataDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResMetadataDir", (void *)godot_icall_GodotSharpDirs_ResMetadataDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesBaseDir", (void *)godot_icall_GodotSharpDirs_ResAssembliesBaseDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesDir", (void *)godot_icall_GodotSharpDirs_ResAssembliesDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResConfigDir", (void *)godot_icall_GodotSharpDirs_ResConfigDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempDir", (void *)godot_icall_GodotSharpDirs_ResTempDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesBaseDir", (void *)godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesDir", (void *)godot_icall_GodotSharpDirs_ResTempAssembliesDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoUserDir", (void *)godot_icall_GodotSharpDirs_MonoUserDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoLogsDir", (void *)godot_icall_GodotSharpDirs_MonoLogsDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoSolutionsDir", (void *)godot_icall_GodotSharpDirs_MonoSolutionsDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_BuildLogsDirs", (void *)godot_icall_GodotSharpDirs_BuildLogsDirs);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectSlnPath", (void *)godot_icall_GodotSharpDirs_ProjectSlnPath);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectCsProjPath", (void *)godot_icall_GodotSharpDirs_ProjectCsProjPath);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorToolsDir", (void *)godot_icall_GodotSharpDirs_DataEditorToolsDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorPrebuiltApiDir", (void *)godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoEtcDir", (void *)godot_icall_GodotSharpDirs_DataMonoEtcDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoLibDir", (void *)godot_icall_GodotSharpDirs_DataMonoLibDir);
+ mono_add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoBinDir", (void *)godot_icall_GodotSharpDirs_DataMonoBinDir);
+
+ // EditorProgress
+ mono_add_internal_call("GodotTools.Internals.EditorProgress::internal_Create", (void *)godot_icall_EditorProgress_Create);
+ mono_add_internal_call("GodotTools.Internals.EditorProgress::internal_Dispose", (void *)godot_icall_EditorProgress_Dispose);
+ mono_add_internal_call("GodotTools.Internals.EditorProgress::internal_Step", (void *)godot_icall_EditorProgress_Step);
+
+ // BiningsGenerator
+ mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_Ctor", (void *)godot_icall_BindingsGenerator_Ctor);
+ mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_Dtor", (void *)godot_icall_BindingsGenerator_Dtor);
+ mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_LogPrintEnabled", (void *)godot_icall_BindingsGenerator_LogPrintEnabled);
+ mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_SetLogPrintEnabled", (void *)godot_icall_BindingsGenerator_SetLogPrintEnabled);
+ mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_GenerateCsApi", (void *)godot_icall_BindingsGenerator_GenerateCsApi);
+ mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_Version", (void *)godot_icall_BindingsGenerator_Version);
+ mono_add_internal_call("GodotTools.Internals.BindingsGenerator::internal_CsGlueVersion", (void *)godot_icall_BindingsGenerator_CsGlueVersion);
+
+ // ScriptClassParser
+ mono_add_internal_call("GodotTools.Internals.ScriptClassParser::internal_ParseFile", (void *)godot_icall_ScriptClassParser_ParseFile);
+
+ // GodotSharpExport
+ mono_add_internal_call("GodotTools.GodotSharpExport::internal_GetExportedAssemblyDependencies", (void *)godot_icall_GodotSharpExport_GetExportedAssemblyDependencies);
+
+ // Internals
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorScale", (void *)godot_icall_Internal_EditorScale);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_GlobalDef", (void *)godot_icall_Internal_GlobalDef);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorDef", (void *)godot_icall_Internal_EditorDef);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_FullTemplatesDir", (void *)godot_icall_Internal_FullTemplatesDir);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_SimplifyGodotPath", (void *)godot_icall_Internal_SimplifyGodotPath);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_IsOsxAppBundleInstalled", (void *)godot_icall_Internal_IsOsxAppBundleInstalled);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_MetadataIsApiAssemblyInvalidated", (void *)godot_icall_Internal_MetadataIsApiAssemblyInvalidated);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_MetadataSetApiAssemblyInvalidated", (void *)godot_icall_Internal_MetadataSetApiAssemblyInvalidated);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_IsMessageQueueFlushing", (void *)godot_icall_Internal_IsMessageQueueFlushing);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotIs32Bits", (void *)godot_icall_Internal_GodotIs32Bits);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotIsRealTDouble", (void *)godot_icall_Internal_GodotIsRealTDouble);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotMainIteration", (void *)godot_icall_Internal_GodotMainIteration);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_GetCoreApiHash", (void *)godot_icall_Internal_GetCoreApiHash);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_GetEditorApiHash", (void *)godot_icall_Internal_GetEditorApiHash);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_IsAssembliesReloadingNeeded", (void *)godot_icall_Internal_IsAssembliesReloadingNeeded);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_ReloadAssemblies", (void *)godot_icall_Internal_ReloadAssemblies);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorDebuggerReloadScripts", (void *)godot_icall_Internal_ScriptEditorDebuggerReloadScripts);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorEdit", (void *)godot_icall_Internal_ScriptEditorEdit);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorNodeShowScriptScreen", (void *)godot_icall_Internal_EditorNodeShowScriptScreen);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_GetScriptsMetadataOrNothing", (void *)godot_icall_Internal_GetScriptsMetadataOrNothing);
+ mono_add_internal_call("GodotTools.Internals.Internal::internal_MonoWindowsInstallRoot", (void *)godot_icall_Internal_MonoWindowsInstallRoot);
+
+ // Utils.OS
+ mono_add_internal_call("GodotTools.Utils.OS::GetPlatformName", (void *)godot_icall_Utils_OS_GetPlatformName);
+}
diff --git a/modules/mono/editor/mono_build_info.h b/modules/mono/editor/editor_internal_calls.h
index b0ae2ed52e..1682da66e5 100644
--- a/modules/mono/editor/mono_build_info.h
+++ b/modules/mono/editor/editor_internal_calls.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* mono_build_info.h */
+/* editor_internal_calls.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,28 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef MONO_BUILD_INFO_H
-#define MONO_BUILD_INFO_H
+#ifndef EDITOR_INTERNAL_CALL_H
+#define EDITOR_INTERNAL_CALL_H
-#include "core/ustring.h"
-#include "core/vector.h"
+void register_editor_internal_calls();
-struct MonoBuildInfo {
-
- struct Hasher {
- static uint32_t hash(const MonoBuildInfo &p_key);
- };
-
- String solution;
- String configuration;
- Vector<String> custom_props;
-
- bool operator==(const MonoBuildInfo &p_b) const;
-
- String get_log_dirpath();
-
- MonoBuildInfo();
- MonoBuildInfo(const String &p_solution, const String &p_config);
-};
-
-#endif // MONO_BUILD_INFO_H
+#endif // EDITOR_INTERNAL_CALL_H
diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp
deleted file mode 100644
index a962d6df27..0000000000
--- a/modules/mono/editor/godotsharp_builds.cpp
+++ /dev/null
@@ -1,632 +0,0 @@
-/*************************************************************************/
-/* godotsharp_builds.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "godotsharp_builds.h"
-
-#include "core/os/os.h"
-#include "core/vector.h"
-#include "main/main.h"
-
-#include "../glue/cs_glue_version.gen.h"
-#include "../godotsharp_dirs.h"
-#include "../mono_gd/gd_mono_class.h"
-#include "../mono_gd/gd_mono_marshal.h"
-#include "../utils/path_utils.h"
-#include "bindings_generator.h"
-#include "csharp_project.h"
-#include "godotsharp_editor.h"
-
-#define PROP_NAME_MSBUILD_MONO "MSBuild (Mono)"
-#define PROP_NAME_MSBUILD_VS "MSBuild (VS Build Tools)"
-#define PROP_NAME_XBUILD "xbuild (Deprecated)"
-
-void godot_icall_BuildInstance_ExitCallback(MonoString *p_solution, MonoString *p_config, int p_exit_code) {
-
- String solution = GDMonoMarshal::mono_string_to_godot(p_solution);
- String config = GDMonoMarshal::mono_string_to_godot(p_config);
- GodotSharpBuilds::get_singleton()->build_exit_callback(MonoBuildInfo(solution, config), p_exit_code);
-}
-
-static Vector<const char *> _get_msbuild_hint_dirs() {
- Vector<const char *> ret;
-#ifdef OSX_ENABLED
- ret.push_back("/Library/Frameworks/Mono.framework/Versions/Current/bin/");
- ret.push_back("/usr/local/var/homebrew/linked/mono/bin/");
-#endif
- ret.push_back("/opt/novell/mono/bin/");
- return ret;
-}
-
-#ifdef UNIX_ENABLED
-String _find_build_engine_on_unix(const String &p_name) {
- String ret = path_which(p_name);
-
- if (ret.length())
- return ret;
-
- String ret_fallback = path_which(p_name + ".exe");
- if (ret_fallback.length())
- return ret_fallback;
-
- static Vector<const char *> locations = _get_msbuild_hint_dirs();
-
- for (int i = 0; i < locations.size(); i++) {
- String hint_path = locations[i] + p_name;
-
- if (FileAccess::exists(hint_path)) {
- return hint_path;
- }
- }
-
- return String();
-}
-#endif
-
-MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
-
- GodotSharpBuilds::BuildTool build_tool = GodotSharpBuilds::BuildTool(int(EditorSettings::get_singleton()->get("mono/builds/build_tool")));
-
-#if defined(WINDOWS_ENABLED)
- switch (build_tool) {
- case GodotSharpBuilds::MSBUILD_VS: {
- static String msbuild_tools_path;
-
- if (msbuild_tools_path.empty() || !FileAccess::exists(msbuild_tools_path)) {
- // Try to search it again if it wasn't found last time or if it was removed from its location
- msbuild_tools_path = MonoRegUtils::find_msbuild_tools_path();
-
- if (msbuild_tools_path.empty()) {
- ERR_PRINTS("Cannot find executable for '" PROP_NAME_MSBUILD_VS "'. Tried with path: " + msbuild_tools_path);
- return NULL;
- }
- }
-
- if (!msbuild_tools_path.ends_with("\\"))
- msbuild_tools_path += "\\";
-
- return GDMonoMarshal::mono_string_from_godot(msbuild_tools_path + "MSBuild.exe");
- } break;
- case GodotSharpBuilds::MSBUILD_MONO: {
- String msbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("msbuild.bat");
-
- if (!FileAccess::exists(msbuild_path)) {
- ERR_PRINTS("Cannot find executable for '" PROP_NAME_MSBUILD_MONO "'. Tried with path: " + msbuild_path);
- return NULL;
- }
-
- return GDMonoMarshal::mono_string_from_godot(msbuild_path);
- } break;
- case GodotSharpBuilds::XBUILD: {
- String xbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("xbuild.bat");
-
- if (!FileAccess::exists(xbuild_path)) {
- ERR_PRINTS("Cannot find executable for '" PROP_NAME_XBUILD "'. Tried with path: " + xbuild_path);
- return NULL;
- }
-
- return GDMonoMarshal::mono_string_from_godot(xbuild_path);
- } break;
- default:
- ERR_EXPLAIN("You don't deserve to live");
- CRASH_NOW();
- }
-#elif defined(UNIX_ENABLED)
- static String msbuild_path;
- static String xbuild_path;
-
- if (build_tool == GodotSharpBuilds::XBUILD) {
- if (xbuild_path.empty() || !FileAccess::exists(xbuild_path)) {
- // Try to search it again if it wasn't found last time or if it was removed from its location
- xbuild_path = _find_build_engine_on_unix("msbuild");
- }
-
- if (xbuild_path.empty()) {
- ERR_PRINT("Cannot find binary for '" PROP_NAME_XBUILD "'");
- return NULL;
- }
- } else {
- if (msbuild_path.empty() || !FileAccess::exists(msbuild_path)) {
- // Try to search it again if it wasn't found last time or if it was removed from its location
- msbuild_path = _find_build_engine_on_unix("msbuild");
- }
-
- if (msbuild_path.empty()) {
- ERR_PRINT("Cannot find binary for '" PROP_NAME_MSBUILD_MONO "'");
- return NULL;
- }
- }
-
- return GDMonoMarshal::mono_string_from_godot(build_tool != GodotSharpBuilds::XBUILD ? msbuild_path : xbuild_path);
-#else
- (void)build_tool; // UNUSED
-
- ERR_EXPLAIN("Not implemented on this platform");
- ERR_FAIL_V(NULL);
-#endif
-}
-
-MonoString *godot_icall_BuildInstance_get_MonoWindowsBinDir() {
-
-#if defined(WINDOWS_ENABLED)
- const MonoRegInfo &mono_reg_info = GDMono::get_singleton()->get_mono_reg_info();
- if (mono_reg_info.bin_dir.length()) {
- return GDMonoMarshal::mono_string_from_godot(mono_reg_info.bin_dir);
- }
-
- ERR_EXPLAIN("Cannot find Mono's binaries directory in the registry");
- ERR_FAIL_V(NULL);
-#else
- return NULL;
-#endif
-}
-
-MonoBoolean godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows() {
-
-#if defined(WINDOWS_ENABLED)
- return GodotSharpBuilds::BuildTool(int(EditorSettings::get_singleton()->get("mono/builds/build_tool"))) == GodotSharpBuilds::MSBUILD_MONO;
-#else
- return false;
-#endif
-}
-
-MonoBoolean godot_icall_BuildInstance_get_PrintBuildOutput() {
-
- return (bool)EDITOR_GET("mono/builds/print_build_output");
-}
-
-void GodotSharpBuilds::register_internal_calls() {
-
- static bool registered = false;
- ERR_FAIL_COND(registered);
- registered = true;
-
- mono_add_internal_call("GodotSharpTools.Build.BuildSystem::godot_icall_BuildInstance_ExitCallback", (void *)godot_icall_BuildInstance_ExitCallback);
- mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_MSBuildPath", (void *)godot_icall_BuildInstance_get_MSBuildPath);
- mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_MonoWindowsBinDir", (void *)godot_icall_BuildInstance_get_MonoWindowsBinDir);
- mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows", (void *)godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows);
- mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_PrintBuildOutput", (void *)godot_icall_BuildInstance_get_PrintBuildOutput);
-}
-
-void GodotSharpBuilds::show_build_error_dialog(const String &p_message) {
-
- GodotSharpEditor::get_singleton()->show_error_dialog(p_message, "Build error");
- MonoBottomPanel::get_singleton()->show_build_tab();
-}
-
-bool GodotSharpBuilds::build_api_sln(const String &p_api_sln_dir, const String &p_config) {
-
- String api_sln_file = p_api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
-
- String core_api_assembly_dir = p_api_sln_dir.plus_file(CORE_API_ASSEMBLY_NAME).plus_file("bin").plus_file(p_config);
- String core_api_assembly_file = core_api_assembly_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
-
- String editor_api_assembly_dir = p_api_sln_dir.plus_file(EDITOR_API_ASSEMBLY_NAME).plus_file("bin").plus_file(p_config);
- String editor_api_assembly_file = editor_api_assembly_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
-
- if (!FileAccess::exists(core_api_assembly_file) || !FileAccess::exists(editor_api_assembly_file)) {
- MonoBuildInfo api_build_info(api_sln_file, p_config);
- // TODO Replace this global NoWarn with '#pragma warning' directives on generated files,
- // once we start to actively document manually maintained C# classes
- api_build_info.custom_props.push_back("NoWarn=1591"); // Ignore missing documentation warnings
-
- if (!GodotSharpBuilds::get_singleton()->build(api_build_info)) {
- show_build_error_dialog("Failed to build " API_SOLUTION_NAME " solution.");
- return false;
- }
- }
-
- return true;
-}
-
-bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type) {
-
- // Create destination directory if needed
- if (!DirAccess::exists(p_dst_dir)) {
- DirAccess *da = DirAccess::create_for_path(p_dst_dir);
- Error err = da->make_dir_recursive(p_dst_dir);
- memdelete(da);
-
- if (err != OK) {
- show_build_error_dialog("Failed to create destination directory for the API assemblies. Error: " + itos(err));
- return false;
- }
- }
-
- String assembly_file = p_assembly_name + ".dll";
- String assembly_src = p_src_dir.plus_file(assembly_file);
- String assembly_dst = p_dst_dir.plus_file(assembly_file);
-
- if (!FileAccess::exists(assembly_dst) ||
- FileAccess::get_modified_time(assembly_src) > FileAccess::get_modified_time(assembly_dst) ||
- GDMono::get_singleton()->metadata_is_api_assembly_invalidated(p_api_type)) {
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
-
- String xml_file = p_assembly_name + ".xml";
- if (da->copy(p_src_dir.plus_file(xml_file), p_dst_dir.plus_file(xml_file)) != OK)
- WARN_PRINTS("Failed to copy " + xml_file);
-
- String pdb_file = p_assembly_name + ".pdb";
- if (da->copy(p_src_dir.plus_file(pdb_file), p_dst_dir.plus_file(pdb_file)) != OK)
- WARN_PRINTS("Failed to copy " + pdb_file);
-
- Error err = da->copy(assembly_src, assembly_dst);
-
- if (err != OK) {
- show_build_error_dialog("Failed to copy " + assembly_file);
- return false;
- }
-
- GDMono::get_singleton()->metadata_set_api_assembly_invalidated(p_api_type, false);
- }
-
- return true;
-}
-
-String GodotSharpBuilds::_api_folder_name(APIAssembly::Type p_api_type) {
-
- uint64_t api_hash = p_api_type == APIAssembly::API_CORE ?
- GDMono::get_singleton()->get_api_core_hash() :
- GDMono::get_singleton()->get_api_editor_hash();
- return String::num_uint64(api_hash) +
- "_" + String::num_uint64(BindingsGenerator::get_version()) +
- "_" + String::num_uint64(CS_GLUE_VERSION);
-}
-
-bool GodotSharpBuilds::make_api_assembly(APIAssembly::Type p_api_type) {
-
- String api_name = p_api_type == APIAssembly::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
-
- String editor_prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir();
- String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
-
- if (FileAccess::exists(editor_prebuilt_api_dir.plus_file(api_name + ".dll"))) {
- EditorProgress pr("mono_copy_prebuilt_api_assembly", "Copying prebuilt " + api_name + " assembly...", 1);
- pr.step("Copying " + api_name + " assembly", 0);
- return GodotSharpBuilds::copy_api_assembly(editor_prebuilt_api_dir, res_assemblies_dir, api_name, p_api_type);
- }
-
- String api_build_config = "Release";
-
- EditorProgress pr("mono_build_release_" API_SOLUTION_NAME, "Building " API_SOLUTION_NAME " solution...", 3);
-
- pr.step("Generating " API_SOLUTION_NAME " solution", 0);
-
- String api_sln_dir = GodotSharpDirs::get_mono_solutions_dir()
- .plus_file(_api_folder_name(APIAssembly::API_CORE));
-
- String api_sln_file = api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
-
- if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) {
- BindingsGenerator bindings_generator;
-
- if (!OS::get_singleton()->is_stdout_verbose()) {
- bindings_generator.set_log_print_enabled(false);
- }
-
- Error err = bindings_generator.generate_cs_api(api_sln_dir);
- if (err != OK) {
- show_build_error_dialog("Failed to generate " API_SOLUTION_NAME " solution. Error: " + itos(err));
- return false;
- }
- }
-
- pr.step("Building " API_SOLUTION_NAME " solution", 1);
-
- if (!GodotSharpBuilds::build_api_sln(api_sln_dir, api_build_config))
- return false;
-
- pr.step("Copying " + api_name + " assembly", 2);
-
- // Copy the built assembly to the assemblies directory
- String api_assembly_dir = api_sln_dir.plus_file(api_name).plus_file("bin").plus_file(api_build_config);
- if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name, p_api_type))
- return false;
-
- return true;
-}
-
-bool GodotSharpBuilds::build_project_blocking(const String &p_config, const Vector<String> &p_godot_defines) {
-
- if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
- return true; // No solution to build
-
- if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
- return false;
-
- if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR))
- return false;
-
- EditorProgress pr("mono_project_debug_build", "Building project solution...", 1);
- pr.step("Building project solution", 0);
-
- MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), p_config);
-
- // Add Godot defines
-#ifdef WINDOWS_ENABLED
- String constants = "GodotDefineConstants=\"";
-#else
- String constants = "GodotDefineConstants=\\\"";
-#endif
-
- for (int i = 0; i < p_godot_defines.size(); i++) {
- constants += "GODOT_" + p_godot_defines[i].to_upper().replace("-", "_").replace(" ", "_").replace(";", "_") + ";";
- }
-
-#ifdef REAL_T_IS_DOUBLE
- constants += "GODOT_REAL_T_IS_DOUBLE;";
-#endif
-
-#ifdef WINDOWS_ENABLED
- constants += "\"";
-#else
- constants += "\\\"";
-#endif
- build_info.custom_props.push_back(constants);
-
- if (!GodotSharpBuilds::get_singleton()->build(build_info)) {
- GodotSharpBuilds::show_build_error_dialog("Failed to build project solution");
- return false;
- }
-
- return true;
-}
-
-bool GodotSharpBuilds::editor_build_callback() {
-
- if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
- return true; // No solution to build
-
- String scripts_metadata_path_editor = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor");
- String scripts_metadata_path_player = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor_player");
-
- Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path_editor);
- ERR_FAIL_COND_V(metadata_err != OK, false);
-
- if (FileAccess::exists(scripts_metadata_path_editor)) {
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- Error copy_err = da->copy(scripts_metadata_path_editor, scripts_metadata_path_player);
-
- ERR_EXPLAIN("Failed to copy scripts metadata file");
- ERR_FAIL_COND_V(copy_err != OK, false);
- }
-
- Vector<String> godot_defines;
- godot_defines.push_back(OS::get_singleton()->get_name());
- godot_defines.push_back(sizeof(void *) == 4 ? "32" : "64");
- return build_project_blocking("Tools", godot_defines);
-}
-
-GodotSharpBuilds *GodotSharpBuilds::singleton = NULL;
-
-void GodotSharpBuilds::build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code) {
-
- BuildProcess *match = builds.getptr(p_build_info);
- ERR_FAIL_NULL(match);
-
- BuildProcess &bp = *match;
- bp.on_exit(p_exit_code);
-}
-
-void GodotSharpBuilds::restart_build(MonoBuildTab *p_build_tab) {
-}
-
-void GodotSharpBuilds::stop_build(MonoBuildTab *p_build_tab) {
-}
-
-bool GodotSharpBuilds::build(const MonoBuildInfo &p_build_info) {
-
- BuildProcess *match = builds.getptr(p_build_info);
-
- if (match) {
- BuildProcess &bp = *match;
- bp.start(true);
- return bp.exit_code == 0;
- } else {
- BuildProcess bp = BuildProcess(p_build_info);
- bp.start(true);
- builds.set(p_build_info, bp);
- return bp.exit_code == 0;
- }
-}
-
-bool GodotSharpBuilds::build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback) {
-
- BuildProcess *match = builds.getptr(p_build_info);
-
- if (match) {
- BuildProcess &bp = *match;
- bp.start();
- return !bp.exited; // failed to start
- } else {
- BuildProcess bp = BuildProcess(p_build_info, p_callback);
- bp.start();
- builds.set(p_build_info, bp);
- return !bp.exited; // failed to start
- }
-}
-
-GodotSharpBuilds::GodotSharpBuilds() {
-
- singleton = this;
-
- EditorNode::get_singleton()->add_build_callback(&GodotSharpBuilds::editor_build_callback);
-
- // Build tool settings
- EditorSettings *ed_settings = EditorSettings::get_singleton();
-
-#ifdef WINDOWS_ENABLED
- EDITOR_DEF("mono/builds/build_tool", MSBUILD_VS);
-#else
- EDITOR_DEF("mono/builds/build_tool", MSBUILD_MONO);
-#endif
-
- ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/builds/build_tool", PROPERTY_HINT_ENUM,
- PROP_NAME_MSBUILD_MONO
-#ifdef WINDOWS_ENABLED
- "," PROP_NAME_MSBUILD_VS
-#endif
- "," PROP_NAME_XBUILD));
-
- EDITOR_DEF("mono/builds/print_build_output", false);
-}
-
-GodotSharpBuilds::~GodotSharpBuilds() {
-
- singleton = NULL;
-}
-
-void GodotSharpBuilds::BuildProcess::on_exit(int p_exit_code) {
-
- exited = true;
- exit_code = p_exit_code;
- build_tab->on_build_exit(p_exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR);
- build_instance.unref();
-
- if (exit_callback)
- exit_callback(exit_code);
-}
-
-void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
-
- _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
-
- exit_code = -1;
-
- String log_dirpath = build_info.get_log_dirpath();
-
- if (build_tab) {
- build_tab->on_build_start();
- } else {
- build_tab = memnew(MonoBuildTab(build_info, log_dirpath));
- MonoBottomPanel::get_singleton()->add_build_tab(build_tab);
- }
-
- if (p_blocking) {
- // Required in order to update the build tasks list
- Main::iteration();
- }
-
- if (!exited) {
- exited = true;
- String message = "Tried to start build process, but it is already running";
- build_tab->on_build_exec_failed(message);
- ERR_EXPLAIN(message);
- ERR_FAIL();
- }
-
- exited = false;
-
- // Remove old issues file
-
- String issues_file = get_msbuild_issues_filename();
- DirAccessRef d = DirAccess::create_for_path(log_dirpath);
- if (d->file_exists(issues_file)) {
- Error err = d->remove(issues_file);
- if (err != OK) {
- exited = true;
- String file_path = ProjectSettings::get_singleton()->localize_path(log_dirpath).plus_file(issues_file);
- String message = "Cannot remove issues file: " + file_path;
- build_tab->on_build_exec_failed(message);
- ERR_EXPLAIN(message);
- ERR_FAIL();
- }
- }
-
- GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Build", "BuildInstance");
-
- MonoObject *mono_object = mono_object_new(mono_domain_get(), klass->get_mono_ptr());
-
- // Construct
-
- Variant solution = build_info.solution;
- Variant config = build_info.configuration;
-
- const Variant *ctor_args[2] = { &solution, &config };
-
- MonoException *exc = NULL;
- GDMonoMethod *ctor = klass->get_method(".ctor", 2);
- ctor->invoke(mono_object, ctor_args, &exc);
-
- if (exc) {
- exited = true;
- GDMonoUtils::debug_unhandled_exception(exc);
- String message = "The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(exc);
- build_tab->on_build_exec_failed(message);
- ERR_EXPLAIN(message);
- ERR_FAIL();
- }
-
- // Call Build
-
- String logger_assembly_path = GDMono::get_singleton()->get_editor_tools_assembly()->get_path();
- Variant logger_assembly = ProjectSettings::get_singleton()->globalize_path(logger_assembly_path);
- Variant logger_output_dir = log_dirpath;
- Variant custom_props = build_info.custom_props;
-
- const Variant *args[3] = { &logger_assembly, &logger_output_dir, &custom_props };
-
- exc = NULL;
- GDMonoMethod *build_method = klass->get_method(p_blocking ? "Build" : "BuildAsync", 3);
- build_method->invoke(mono_object, args, &exc);
-
- if (exc) {
- exited = true;
- GDMonoUtils::debug_unhandled_exception(exc);
- String message = "The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(exc);
- build_tab->on_build_exec_failed(message);
- ERR_EXPLAIN(message);
- ERR_FAIL();
- }
-
- // Build returned
-
- if (p_blocking) {
- exited = true;
- exit_code = klass->get_field("exitCode")->get_int_value(mono_object);
-
- if (exit_code != 0) {
- String log_filepath = build_info.get_log_dirpath().plus_file(get_msbuild_log_filename());
- print_verbose("MSBuild exited with code: " + itos(exit_code) + ". Log file: " + log_filepath);
- }
-
- build_tab->on_build_exit(exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR);
- } else {
- build_instance = MonoGCHandle::create_strong(mono_object);
- exited = false;
- }
-}
-
-GodotSharpBuilds::BuildProcess::BuildProcess(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback) :
- build_info(p_build_info),
- build_tab(NULL),
- exit_callback(p_callback),
- exited(true),
- exit_code(-1) {
-}
diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h
deleted file mode 100644
index 2e9050e12e..0000000000
--- a/modules/mono/editor/godotsharp_builds.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*************************************************************************/
-/* godotsharp_builds.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GODOTSHARP_BUILDS_H
-#define GODOTSHARP_BUILDS_H
-
-#include "../mono_gd/gd_mono.h"
-#include "mono_bottom_panel.h"
-#include "mono_build_info.h"
-
-typedef void (*GodotSharpBuild_ExitCallback)(int);
-
-class GodotSharpBuilds {
-
-private:
- struct BuildProcess {
- Ref<MonoGCHandle> build_instance;
- MonoBuildInfo build_info;
- MonoBuildTab *build_tab;
- GodotSharpBuild_ExitCallback exit_callback;
- bool exited;
- int exit_code;
-
- void on_exit(int p_exit_code);
- void start(bool p_blocking = false);
-
- BuildProcess() {}
- BuildProcess(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback = NULL);
- };
-
- HashMap<MonoBuildInfo, BuildProcess, MonoBuildInfo::Hasher> builds;
-
- static String _api_folder_name(APIAssembly::Type p_api_type);
-
- static GodotSharpBuilds *singleton;
-
-public:
- enum BuildTool {
- MSBUILD_MONO,
-#ifdef WINDOWS_ENABLED
- MSBUILD_VS,
-#endif
- XBUILD // Deprecated
- };
-
- _FORCE_INLINE_ static GodotSharpBuilds *get_singleton() { return singleton; }
-
- static void register_internal_calls();
-
- static void show_build_error_dialog(const String &p_message);
-
- static const char *get_msbuild_issues_filename() { return "msbuild_issues.csv"; }
- static const char *get_msbuild_log_filename() { return "msbuild_log.txt"; }
-
- void build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code);
-
- void restart_build(MonoBuildTab *p_build_tab);
- void stop_build(MonoBuildTab *p_build_tab);
-
- bool build(const MonoBuildInfo &p_build_info);
- bool build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback = NULL);
-
- static bool build_api_sln(const String &p_api_sln_dir, const String &p_config);
- static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type);
-
- static bool make_api_assembly(APIAssembly::Type p_api_type);
-
- static bool build_project_blocking(const String &p_config, const Vector<String> &p_godot_defines);
-
- static bool editor_build_callback();
-
- GodotSharpBuilds();
- ~GodotSharpBuilds();
-};
-
-#endif // GODOTSHARP_BUILDS_H
diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp
deleted file mode 100644
index 8dc5ced29f..0000000000
--- a/modules/mono/editor/godotsharp_editor.cpp
+++ /dev/null
@@ -1,582 +0,0 @@
-/*************************************************************************/
-/* godotsharp_editor.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "godotsharp_editor.h"
-
-#include "core/message_queue.h"
-#include "core/os/os.h"
-#include "core/project_settings.h"
-#include "scene/gui/control.h"
-#include "scene/main/node.h"
-
-#include "../csharp_script.h"
-#include "../godotsharp_dirs.h"
-#include "../mono_gd/gd_mono.h"
-#include "../mono_gd/gd_mono_marshal.h"
-#include "../utils/path_utils.h"
-#include "bindings_generator.h"
-#include "csharp_project.h"
-#include "dotnet_solution.h"
-#include "godotsharp_export.h"
-
-#ifdef OSX_ENABLED
-#include "../utils/osx_utils.h"
-#endif
-
-#ifdef WINDOWS_ENABLED
-#include "../utils/mono_reg_utils.h"
-#endif
-
-GodotSharpEditor *GodotSharpEditor::singleton = NULL;
-
-bool GodotSharpEditor::_create_project_solution() {
-
- EditorProgress pr("create_csharp_solution", TTR("Generating solution..."), 2);
-
- pr.step(TTR("Generating C# project..."));
-
- String path = OS::get_singleton()->get_resource_dir();
- String appname = ProjectSettings::get_singleton()->get("application/config/name");
- String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
- if (appname_safe.empty()) {
- appname_safe = "UnnamedProject";
- }
-
- String guid = CSharpProject::generate_game_project(path, appname_safe);
-
- if (guid.length()) {
-
- DotNetSolution solution(appname_safe);
-
- if (!solution.set_path(path)) {
- show_error_dialog(TTR("Failed to create solution."));
- return false;
- }
-
- DotNetSolution::ProjectInfo proj_info;
- proj_info.guid = guid;
- proj_info.relpath = appname_safe + ".csproj";
- proj_info.configs.push_back("Debug");
- proj_info.configs.push_back("Release");
- proj_info.configs.push_back("Tools");
-
- solution.add_new_project(appname_safe, proj_info);
-
- Error sln_error = solution.save();
-
- if (sln_error != OK) {
- show_error_dialog(TTR("Failed to save solution."));
- return false;
- }
-
- if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
- return false;
-
- if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR))
- return false;
-
- pr.step(TTR("Done"));
-
- // Here, after all calls to progress_task_step
- call_deferred("_remove_create_sln_menu_option");
-
- } else {
- show_error_dialog(TTR("Failed to create C# project."));
- }
-
- return true;
-}
-
-void GodotSharpEditor::_make_api_solutions_if_needed() {
- // I'm sick entirely of ProgressDialog
-
- static int attempts_left = 100;
-
- if (MessageQueue::get_singleton()->is_flushing() || !SceneTree::get_singleton()) {
- ERR_FAIL_COND(attempts_left == 0); // You've got to be kidding
-
- if (SceneTree::get_singleton()) {
- SceneTree::get_singleton()->connect("idle_frame", this, "_make_api_solutions_if_needed", Vector<Variant>());
- } else {
- call_deferred("_make_api_solutions_if_needed");
- }
-
- attempts_left--;
- return;
- }
-
- // Recursion guard needed because signals don't play well with ProgressDialog either, but unlike
- // the message queue, with signals the collateral damage should be minimal in the worst case.
- static bool recursion_guard = false;
- if (!recursion_guard) {
- recursion_guard = true;
-
- // Oneshot signals don't play well with ProgressDialog either, so we do it this way instead
- SceneTree::get_singleton()->disconnect("idle_frame", this, "_make_api_solutions_if_needed");
-
- _make_api_solutions_if_needed_impl();
-
- recursion_guard = false;
- }
-}
-
-void GodotSharpEditor::_make_api_solutions_if_needed_impl() {
- // If the project has a solution and C# project make sure the API assemblies are present and up to date
- String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
-
- if (!FileAccess::exists(res_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll")) ||
- GDMono::get_singleton()->metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) {
- if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
- return;
- }
-
- if (!FileAccess::exists(res_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll")) ||
- GDMono::get_singleton()->metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) {
- if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR))
- return; // Redundant? I don't think so
- }
-}
-
-void GodotSharpEditor::_remove_create_sln_menu_option() {
-
- menu_popup->remove_item(menu_popup->get_item_index(MENU_CREATE_SLN));
-
- bottom_panel_btn->show();
-}
-
-void GodotSharpEditor::_show_about_dialog() {
-
- bool show_on_start = EDITOR_GET("mono/editor/show_info_on_start");
- about_dialog_checkbox->set_pressed(show_on_start);
- about_dialog->popup_centered_minsize();
-}
-
-void GodotSharpEditor::_toggle_about_dialog_on_start(bool p_enabled) {
-
- bool show_on_start = EDITOR_GET("mono/editor/show_info_on_start");
- if (show_on_start != p_enabled) {
- EditorSettings::get_singleton()->set_setting("mono/editor/show_info_on_start", p_enabled);
- }
-}
-
-void GodotSharpEditor::_build_solution_pressed() {
-
- if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path())) {
- if (!_create_project_solution())
- return; // Failed to create solution
- }
-
- MonoBottomPanel::get_singleton()->call("_build_project_pressed");
-}
-
-void GodotSharpEditor::_menu_option_pressed(int p_id) {
-
- switch (p_id) {
- case MENU_CREATE_SLN: {
-
- _create_project_solution();
- } break;
- case MENU_ABOUT_CSHARP: {
-
- _show_about_dialog();
- } break;
- default:
- ERR_FAIL();
- }
-}
-
-void GodotSharpEditor::_notification(int p_notification) {
-
- switch (p_notification) {
-
- case NOTIFICATION_READY: {
-
- bool show_info_dialog = EDITOR_GET("mono/editor/show_info_on_start");
- if (show_info_dialog) {
- about_dialog->set_exclusive(true);
- _show_about_dialog();
- // Once shown a first time, it can be seen again via the Mono menu - it doesn't have to be exclusive then.
- about_dialog->set_exclusive(false);
- }
- }
- }
-}
-
-void GodotSharpEditor::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_build_solution_pressed"), &GodotSharpEditor::_build_solution_pressed);
- ClassDB::bind_method(D_METHOD("_create_project_solution"), &GodotSharpEditor::_create_project_solution);
- ClassDB::bind_method(D_METHOD("_make_api_solutions_if_needed"), &GodotSharpEditor::_make_api_solutions_if_needed);
- ClassDB::bind_method(D_METHOD("_remove_create_sln_menu_option"), &GodotSharpEditor::_remove_create_sln_menu_option);
- ClassDB::bind_method(D_METHOD("_toggle_about_dialog_on_start"), &GodotSharpEditor::_toggle_about_dialog_on_start);
- ClassDB::bind_method(D_METHOD("_menu_option_pressed", "id"), &GodotSharpEditor::_menu_option_pressed);
-}
-
-MonoBoolean godot_icall_MonoDevelopInstance_IsApplicationBundleInstalled(MonoString *p_bundle_id) {
-#ifdef OSX_ENABLED
- return (MonoBoolean)osx_is_app_bundle_installed(GDMonoMarshal::mono_string_to_godot(p_bundle_id));
-#else
- (void)p_bundle_id; // UNUSED
- ERR_FAIL_V(false);
-#endif
-}
-
-MonoString *godot_icall_Utils_OS_GetPlatformName() {
- return GDMonoMarshal::mono_string_from_godot(OS::get_singleton()->get_name());
-}
-
-void GodotSharpEditor::register_internal_calls() {
-
- static bool registered = false;
- ERR_FAIL_COND(registered);
- registered = true;
-
- mono_add_internal_call("GodotSharpTools.Editor.MonoDevelopInstance::IsApplicationBundleInstalled", (void *)godot_icall_MonoDevelopInstance_IsApplicationBundleInstalled);
- mono_add_internal_call("GodotSharpTools.Utils.OS::GetPlatformName", (void *)godot_icall_Utils_OS_GetPlatformName);
-
- GodotSharpBuilds::register_internal_calls();
- GodotSharpExport::register_internal_calls();
-}
-
-void GodotSharpEditor::show_error_dialog(const String &p_message, const String &p_title) {
-
- error_dialog->set_title(p_title);
- error_dialog->set_text(p_message);
- error_dialog->popup_centered_minsize();
-}
-
-Error GodotSharpEditor::open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) {
-
- ExternalEditor editor = ExternalEditor(int(EditorSettings::get_singleton()->get("mono/editor/external_editor")));
-
- switch (editor) {
- case EDITOR_VSCODE: {
- static String vscode_path;
-
- if (vscode_path.empty() || !FileAccess::exists(vscode_path)) {
- // Try to search it again if it wasn't found last time or if it was removed from its location
- bool found = false;
-
- // TODO: Use initializer lists once C++11 is allowed
-
- static Vector<String> vscode_names;
- if (vscode_names.empty()) {
- vscode_names.push_back("code");
- vscode_names.push_back("code-oss");
- vscode_names.push_back("vscode");
- vscode_names.push_back("vscode-oss");
- vscode_names.push_back("visual-studio-code");
- vscode_names.push_back("visual-studio-code-oss");
- }
- for (int i = 0; i < vscode_names.size(); i++) {
- vscode_path = path_which(vscode_names[i]);
- if (!vscode_path.empty()) {
- found = true;
- break;
- }
- }
-
- if (!found)
- vscode_path.clear(); // Not found, clear so next time the empty() check is enough
- }
-
- List<String> args;
-
-#ifdef OSX_ENABLED
- // The package path is '/Applications/Visual Studio Code.app'
- static const String vscode_bundle_id = "com.microsoft.VSCode";
- static bool osx_app_bundle_installed = osx_is_app_bundle_installed(vscode_bundle_id);
-
- if (osx_app_bundle_installed) {
- args.push_back("-b");
- args.push_back(vscode_bundle_id);
-
- // The reusing of existing windows made by the 'open' command might not choose a wubdiw that is
- // editing our folder. It's better to ask for a new window and let VSCode do the window management.
- args.push_back("-n");
-
- // The open process must wait until the application finishes (which is instant in VSCode's case)
- args.push_back("--wait-apps");
-
- args.push_back("--args");
- }
-#endif
-
- args.push_back(ProjectSettings::get_singleton()->get_resource_path());
-
- String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path());
-
- if (p_line >= 0) {
- args.push_back("-g");
- args.push_back(script_path + ":" + itos(p_line + 1) + ":" + itos(p_col));
- } else {
- args.push_back(script_path);
- }
-
-#ifdef OSX_ENABLED
- ERR_EXPLAIN("Cannot find code editor: VSCode");
- ERR_FAIL_COND_V(!osx_app_bundle_installed && vscode_path.empty(), ERR_FILE_NOT_FOUND);
-
- String command = osx_app_bundle_installed ? "/usr/bin/open" : vscode_path;
-#else
- ERR_EXPLAIN("Cannot find code editor: VSCode");
- ERR_FAIL_COND_V(vscode_path.empty(), ERR_FILE_NOT_FOUND);
-
- String command = vscode_path;
-#endif
-
- Error err = OS::get_singleton()->execute(command, args, false);
-
- if (err != OK) {
- ERR_PRINT("Error when trying to execute code editor: VSCode");
- return err;
- }
- } break;
-#ifdef OSX_ENABLED
- case EDITOR_VISUALSTUDIO_MAC:
- // [[fallthrough]];
-#endif
- case EDITOR_MONODEVELOP: {
-#ifdef OSX_ENABLED
- bool is_visualstudio = editor == EDITOR_VISUALSTUDIO_MAC;
-
- MonoDevelopInstance **instance = is_visualstudio ?
- &visualstudio_mac_instance :
- &monodevelop_instance;
-
- MonoDevelopInstance::EditorId editor_id = is_visualstudio ?
- MonoDevelopInstance::VISUALSTUDIO_FOR_MAC :
- MonoDevelopInstance::MONODEVELOP;
-#else
- MonoDevelopInstance **instance = &monodevelop_instance;
- MonoDevelopInstance::EditorId editor_id = MonoDevelopInstance::MONODEVELOP;
-#endif
-
- if (!*instance)
- *instance = memnew(MonoDevelopInstance(GodotSharpDirs::get_project_sln_path(), editor_id));
-
- String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path());
-
- if (p_line >= 0) {
- script_path += ";" + itos(p_line + 1) + ";" + itos(p_col);
- }
-
- (*instance)->execute(script_path);
- } break;
- default:
- return ERR_UNAVAILABLE;
- }
-
- return OK;
-}
-
-bool GodotSharpEditor::overrides_external_editor() {
-
- return ExternalEditor(int(EditorSettings::get_singleton()->get("mono/editor/external_editor"))) != EDITOR_NONE;
-}
-
-GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
-
- singleton = this;
-
- monodevelop_instance = NULL;
-#ifdef OSX_ENABLED
- visualstudio_mac_instance = NULL;
-#endif
-
- editor = p_editor;
-
- error_dialog = memnew(AcceptDialog);
- editor->get_gui_base()->add_child(error_dialog);
-
- bottom_panel_btn = editor->add_bottom_panel_item(TTR("Mono"), memnew(MonoBottomPanel(editor)));
-
- godotsharp_builds = memnew(GodotSharpBuilds);
-
- editor->add_child(memnew(MonoReloadNode));
-
- menu_popup = memnew(PopupMenu);
- menu_popup->hide();
- menu_popup->set_as_toplevel(true);
- menu_popup->set_pass_on_modal_close_click(false);
-
- editor->add_tool_submenu_item("Mono", menu_popup);
-
- // TODO: Remove or edit this info dialog once Mono support is no longer in alpha
- {
- menu_popup->add_item(TTR("About C# support"), MENU_ABOUT_CSHARP);
- about_dialog = memnew(AcceptDialog);
- editor->get_gui_base()->add_child(about_dialog);
- about_dialog->set_title("Important: C# support is not feature-complete");
-
- // We don't use set_text() as the default AcceptDialog Label doesn't play well with the TextureRect and CheckBox
- // we'll add. Instead we add containers and a new autowrapped Label inside.
-
- // Main VBoxContainer (icon + label on top, checkbox at bottom)
- VBoxContainer *about_vbc = memnew(VBoxContainer);
- about_dialog->add_child(about_vbc);
-
- // HBoxContainer for icon + label
- HBoxContainer *about_hbc = memnew(HBoxContainer);
- about_vbc->add_child(about_hbc);
-
- TextureRect *about_icon = memnew(TextureRect);
- about_hbc->add_child(about_icon);
- Ref<Texture> about_icon_tex = about_icon->get_icon("NodeWarning", "EditorIcons");
- about_icon->set_texture(about_icon_tex);
-
- Label *about_label = memnew(Label);
- about_hbc->add_child(about_label);
- about_label->set_custom_minimum_size(Size2(600, 150) * EDSCALE);
- about_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- about_label->set_autowrap(true);
- String about_text =
- String("C# support in Godot Engine is in late alpha stage and, while already usable, ") +
- "it is not meant for use in production.\n\n" +
- "Projects can be exported to Linux, macOS and Windows, but not yet to mobile or web platforms. " +
- "Bugs and usability issues will be addressed gradually over future releases, " +
- "potentially including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" +
- "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, MSBuild version, IDE, etc.:\n\n" +
- " https://github.com/godotengine/godot/issues\n\n" +
- "Your critical feedback at this stage will play a great role in shaping the C# support in future releases, so thank you!";
- about_label->set_text(about_text);
-
- EDITOR_DEF("mono/editor/show_info_on_start", true);
-
- // CheckBox in main container
- about_dialog_checkbox = memnew(CheckBox);
- about_vbc->add_child(about_dialog_checkbox);
- about_dialog_checkbox->set_text("Show this warning when starting the editor");
- about_dialog_checkbox->connect("toggled", this, "_toggle_about_dialog_on_start");
- }
-
- String sln_path = GodotSharpDirs::get_project_sln_path();
- String csproj_path = GodotSharpDirs::get_project_csproj_path();
-
- if (FileAccess::exists(sln_path) && FileAccess::exists(csproj_path)) {
- // Defer this task because EditorProgress calls Main::iterarion() and the main loop is not yet initialized.
- call_deferred("_make_api_solutions_if_needed");
- } else {
- bottom_panel_btn->hide();
- menu_popup->add_item(TTR("Create C# solution"), MENU_CREATE_SLN);
- }
-
- menu_popup->connect("id_pressed", this, "_menu_option_pressed");
-
- ToolButton *build_button = memnew(ToolButton);
- build_button->set_text("Build");
- build_button->set_tooltip("Build solution");
- build_button->set_focus_mode(Control::FOCUS_NONE);
- build_button->connect("pressed", this, "_build_solution_pressed");
- editor->get_menu_hb()->add_child(build_button);
-
- // External editor settings
- EditorSettings *ed_settings = EditorSettings::get_singleton();
- EDITOR_DEF("mono/editor/external_editor", EDITOR_NONE);
-
- String settings_hint_str = "Disabled";
-
-#if defined(WINDOWS_ENABLED)
- settings_hint_str += ",MonoDevelop,Visual Studio Code";
-#elif defined(OSX_ENABLED)
- settings_hint_str += ",Visual Studio,MonoDevelop,Visual Studio Code";
-#elif defined(UNIX_ENABLED)
- settings_hint_str += ",MonoDevelop,Visual Studio Code";
-#endif
-
- ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/editor/external_editor", PROPERTY_HINT_ENUM, settings_hint_str));
-
- // Export plugin
- Ref<GodotSharpExport> godotsharp_export;
- godotsharp_export.instance();
- EditorExport::get_singleton()->add_export_plugin(godotsharp_export);
-}
-
-GodotSharpEditor::~GodotSharpEditor() {
-
- singleton = NULL;
-
- memdelete(godotsharp_builds);
-
- if (monodevelop_instance) {
- memdelete(monodevelop_instance);
- monodevelop_instance = NULL;
- }
-}
-
-MonoReloadNode *MonoReloadNode::singleton = NULL;
-
-void MonoReloadNode::_reload_timer_timeout() {
-
- if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) {
- CSharpLanguage::get_singleton()->reload_assemblies(false);
- }
-}
-
-void MonoReloadNode::restart_reload_timer() {
-
- reload_timer->stop();
- reload_timer->start();
-}
-
-void MonoReloadNode::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_reload_timer_timeout"), &MonoReloadNode::_reload_timer_timeout);
-}
-
-void MonoReloadNode::_notification(int p_what) {
- switch (p_what) {
- case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
- restart_reload_timer();
- if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) {
- CSharpLanguage::get_singleton()->reload_assemblies(false);
- }
- } break;
- default: {
- } break;
- };
-}
-
-MonoReloadNode::MonoReloadNode() {
-
- singleton = this;
-
- reload_timer = memnew(Timer);
- add_child(reload_timer);
- reload_timer->set_one_shot(false);
- reload_timer->set_wait_time(EDITOR_DEF("mono/assembly_watch_interval_sec", 0.5));
- reload_timer->connect("timeout", this, "_reload_timer_timeout");
- reload_timer->start();
-}
-
-MonoReloadNode::~MonoReloadNode() {
-
- singleton = NULL;
-}
diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h
deleted file mode 100644
index d5bd8ba126..0000000000
--- a/modules/mono/editor/godotsharp_editor.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*************************************************************************/
-/* godotsharp_editor.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GODOTSHARP_EDITOR_H
-#define GODOTSHARP_EDITOR_H
-
-#include "godotsharp_builds.h"
-#include "monodevelop_instance.h"
-
-class GodotSharpEditor : public Node {
- GDCLASS(GodotSharpEditor, Node);
-
- EditorNode *editor;
-
- MenuButton *menu_button;
- PopupMenu *menu_popup;
-
- AcceptDialog *error_dialog;
- AcceptDialog *about_dialog;
- CheckBox *about_dialog_checkbox;
-
- ToolButton *bottom_panel_btn;
-
- GodotSharpBuilds *godotsharp_builds;
-
- MonoDevelopInstance *monodevelop_instance;
-#ifdef OSX_ENABLED
- MonoDevelopInstance *visualstudio_mac_instance;
-#endif
-
- bool _create_project_solution();
- void _make_api_solutions_if_needed();
- void _make_api_solutions_if_needed_impl();
-
- void _remove_create_sln_menu_option();
- void _show_about_dialog();
- void _toggle_about_dialog_on_start(bool p_enabled);
-
- void _menu_option_pressed(int p_id);
-
- void _build_solution_pressed();
-
- static GodotSharpEditor *singleton;
-
-protected:
- void _notification(int p_notification);
- static void _bind_methods();
-
-public:
- enum MenuOptions {
- MENU_CREATE_SLN,
- MENU_ABOUT_CSHARP,
- };
-
- enum ExternalEditor {
- EDITOR_NONE,
-#if defined(WINDOWS_ENABLED)
- //EDITOR_VISUALSTUDIO, // TODO
- EDITOR_MONODEVELOP,
- EDITOR_VSCODE
-#elif defined(OSX_ENABLED)
- EDITOR_VISUALSTUDIO_MAC,
- EDITOR_MONODEVELOP,
- EDITOR_VSCODE
-#elif defined(UNIX_ENABLED)
- EDITOR_MONODEVELOP,
- EDITOR_VSCODE
-#endif
- };
-
- _FORCE_INLINE_ static GodotSharpEditor *get_singleton() { return singleton; }
-
- static void register_internal_calls();
-
- void show_error_dialog(const String &p_message, const String &p_title = "Error");
-
- Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col);
- bool overrides_external_editor();
-
- GodotSharpEditor(EditorNode *p_editor);
- ~GodotSharpEditor();
-};
-
-class MonoReloadNode : public Node {
- GDCLASS(MonoReloadNode, Node);
-
- Timer *reload_timer;
-
- void _reload_timer_timeout();
-
- static MonoReloadNode *singleton;
-
-protected:
- static void _bind_methods();
-
- void _notification(int p_what);
-
-public:
- _FORCE_INLINE_ static MonoReloadNode *get_singleton() { return singleton; }
-
- void restart_reload_timer();
-
- MonoReloadNode();
- ~MonoReloadNode();
-};
-
-#endif // GODOTSHARP_EDITOR_H
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index 590ec007ad..020bb70a08 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -30,180 +30,28 @@
#include "godotsharp_export.h"
-#include "core/version.h"
+#include <mono/metadata/image.h>
-#include "../csharp_script.h"
-#include "../godotsharp_defs.h"
-#include "../godotsharp_dirs.h"
-#include "../mono_gd/gd_mono_class.h"
-#include "../mono_gd/gd_mono_marshal.h"
-#include "csharp_project.h"
-#include "godotsharp_builds.h"
+#include "../mono_gd/gd_mono.h"
+#include "../mono_gd/gd_mono_assembly.h"
-static MonoString *godot_icall_GodotSharpExport_GetTemplatesDir() {
- String current_version = VERSION_FULL_CONFIG;
- String templates_dir = EditorSettings::get_singleton()->get_templates_dir().plus_file(current_version);
- return GDMonoMarshal::mono_string_from_godot(ProjectSettings::get_singleton()->globalize_path(templates_dir));
-}
-
-static MonoString *godot_icall_GodotSharpExport_GetDataDirName() {
- String appname = ProjectSettings::get_singleton()->get("application/config/name");
- String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
- return GDMonoMarshal::mono_string_from_godot("data_" + appname_safe);
-}
-
-void GodotSharpExport::register_internal_calls() {
- static bool registered = false;
- ERR_FAIL_COND(registered);
- registered = true;
-
- mono_add_internal_call("GodotSharpTools.Editor.GodotSharpExport::GetTemplatesDir", (void *)godot_icall_GodotSharpExport_GetTemplatesDir);
- mono_add_internal_call("GodotSharpTools.Editor.GodotSharpExport::GetDataDirName", (void *)godot_icall_GodotSharpExport_GetDataDirName);
-}
-
-void GodotSharpExport::_export_file(const String &p_path, const String &p_type, const Set<String> &) {
-
- if (p_type != CSharpLanguage::get_singleton()->get_type())
- return;
-
- ERR_FAIL_COND(p_path.get_extension() != CSharpLanguage::get_singleton()->get_extension());
-
- // TODO what if the source file is not part of the game's C# project
-
- if (!GLOBAL_GET("mono/export/include_scripts_content")) {
- // We don't want to include the source code on exported games
- add_file(p_path, Vector<uint8_t>(), false);
- skip();
- }
-}
-
-void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug, const String &p_path, int p_flags) {
-
- // TODO right now there is no way to stop the export process with an error
-
- ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
- ERR_FAIL_NULL(TOOLS_DOMAIN);
- ERR_FAIL_NULL(GDMono::get_singleton()->get_editor_tools_assembly());
-
- if (FileAccess::exists(GodotSharpDirs::get_project_sln_path())) {
- String build_config = p_debug ? "Debug" : "Release";
-
- String scripts_metadata_path = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata." + String(p_debug ? "debug" : "release"));
- Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path);
- ERR_FAIL_COND(metadata_err != OK);
-
- ERR_FAIL_COND(!_add_file(scripts_metadata_path, scripts_metadata_path));
-
- // Turn export features into defines
- Vector<String> godot_defines;
- for (Set<String>::Element *E = p_features.front(); E; E = E->next()) {
- godot_defines.push_back(E->get());
- }
- ERR_FAIL_COND(!GodotSharpBuilds::build_project_blocking(build_config, godot_defines));
-
- // Add dependency assemblies
-
- Map<String, String> dependencies;
-
- String project_dll_name = ProjectSettings::get_singleton()->get("application/config/name");
- String project_dll_name_safe = OS::get_singleton()->get_safe_dir_name(project_dll_name);
- if (project_dll_name_safe.empty()) {
- project_dll_name_safe = "UnnamedProject";
- }
-
- String project_dll_src_dir = GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(build_config);
- String project_dll_src_path = project_dll_src_dir.plus_file(project_dll_name_safe + ".dll");
- dependencies.insert(project_dll_name_safe, project_dll_src_path);
-
- {
- MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain");
- ERR_FAIL_NULL(export_domain);
- _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain);
-
- _GDMONO_SCOPE_DOMAIN_(export_domain);
+String get_assemblyref_name(MonoImage *p_image, int index) {
+ const MonoTableInfo *table_info = mono_image_get_table_info(p_image, MONO_TABLE_ASSEMBLYREF);
- GDMonoAssembly *scripts_assembly = NULL;
- bool load_success = GDMono::get_singleton()->load_assembly_from(project_dll_name_safe,
- project_dll_src_path, &scripts_assembly, /* refonly: */ true);
+ uint32_t cols[MONO_ASSEMBLYREF_SIZE];
- ERR_EXPLAIN("Cannot load assembly (refonly): " + project_dll_name_safe);
- ERR_FAIL_COND(!load_success);
+ mono_metadata_decode_row(table_info, index, cols, MONO_ASSEMBLYREF_SIZE);
- Vector<String> search_dirs;
- String templates_dir = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG);
- String android_bcl_dir = templates_dir.plus_file("android-bcl");
-
- String custom_lib_dir;
-
- if (p_features.find("Android") && DirAccess::exists(android_bcl_dir)) {
- custom_lib_dir = android_bcl_dir;
- }
-
- GDMonoAssembly::fill_search_dirs(search_dirs, build_config, custom_lib_dir);
-
- Error depend_error = _get_assembly_dependencies(scripts_assembly, search_dirs, dependencies);
- ERR_FAIL_COND(depend_error != OK);
- }
-
- for (Map<String, String>::Element *E = dependencies.front(); E; E = E->next()) {
- String depend_src_path = E->value();
- String depend_dst_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(depend_src_path.get_file());
- ERR_FAIL_COND(!_add_file(depend_src_path, depend_dst_path));
- }
- }
-
- // Mono specific export template extras (data dir)
-
- GDMonoClass *export_class = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Editor", "GodotSharpExport");
- ERR_FAIL_NULL(export_class);
- GDMonoMethod *export_begin_method = export_class->get_method("_ExportBegin", 4);
- ERR_FAIL_NULL(export_begin_method);
-
- MonoArray *features = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), p_features.size());
- int i = 0;
- for (const Set<String>::Element *E = p_features.front(); E; E = E->next()) {
- MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E->get());
- mono_array_setref(features, i, boxed);
- i++;
- }
-
- MonoBoolean debug = p_debug;
- MonoString *path = GDMonoMarshal::mono_string_from_godot(p_path);
- uint32_t flags = p_flags;
- void *args[4] = { features, &debug, path, &flags };
- MonoException *exc = NULL;
- export_begin_method->invoke_raw(NULL, args, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- ERR_FAIL();
- }
-}
-
-bool GodotSharpExport::_add_file(const String &p_src_path, const String &p_dst_path, bool p_remap) {
-
- FileAccessRef f = FileAccess::open(p_src_path, FileAccess::READ);
- ERR_FAIL_COND_V(!f, false);
-
- Vector<uint8_t> data;
- data.resize(f->get_len());
- f->get_buffer(data.ptrw(), data.size());
-
- add_file(p_dst_path, data, p_remap);
-
- return true;
+ return String::utf8(mono_metadata_string_heap(p_image, cols[MONO_ASSEMBLYREF_NAME]));
}
-Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Map<String, String> &r_dependencies) {
-
+Error GodotSharpExport::get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_dependencies) {
MonoImage *image = p_assembly->get_image();
for (int i = 0; i < mono_image_get_table_rows(image, MONO_TABLE_ASSEMBLYREF); i++) {
- MonoAssemblyName *ref_aname = aname_prealloc;
- mono_assembly_get_assemblyref(image, i, ref_aname);
- String ref_name = mono_assembly_name_get_name(ref_aname);
+ String ref_name = get_assemblyref_name(image, i);
- if (r_dependencies.find(ref_name))
+ if (r_dependencies.has(ref_name))
continue;
GDMonoAssembly *ref_assembly = NULL;
@@ -242,9 +90,9 @@ Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, c
ERR_FAIL_V(ERR_CANT_RESOLVE);
}
- r_dependencies.insert(ref_name, ref_assembly->get_path());
+ r_dependencies[ref_name] = ref_assembly->get_path();
- Error err = _get_assembly_dependencies(ref_assembly, p_search_dirs, r_dependencies);
+ Error err = get_assembly_dependencies(ref_assembly, p_search_dirs, r_dependencies);
if (err != OK) {
ERR_EXPLAIN("Cannot load one of the dependencies for the assembly: " + ref_name);
ERR_FAIL_V(err);
@@ -254,14 +102,22 @@ Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, c
return OK;
}
-GodotSharpExport::GodotSharpExport() {
- // MonoAssemblyName is an incomplete type (internal to mono), so we can't allocate it ourselves.
- // There isn't any api to allocate an empty one either, so we need to do it this way.
- aname_prealloc = mono_assembly_name_new("whatever");
- mono_assembly_name_free(aname_prealloc); // "it does not frees the object itself, only the name members" (typo included)
-}
+Error GodotSharpExport::get_exported_assembly_dependencies(const String &p_project_dll_name, const String &p_project_dll_src_path, const String &p_build_config, const String &p_custom_lib_dir, Dictionary &r_dependencies) {
+ MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain");
+ ERR_FAIL_NULL_V(export_domain, FAILED);
+ _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain);
+
+ _GDMONO_SCOPE_DOMAIN_(export_domain);
+
+ GDMonoAssembly *scripts_assembly = NULL;
+ bool load_success = GDMono::get_singleton()->load_assembly_from(p_project_dll_name,
+ p_project_dll_src_path, &scripts_assembly, /* refonly: */ true);
+
+ ERR_EXPLAIN("Cannot load assembly (refonly): " + p_project_dll_name);
+ ERR_FAIL_COND_V(!load_success, ERR_CANT_RESOLVE);
+
+ Vector<String> search_dirs;
+ GDMonoAssembly::fill_search_dirs(search_dirs, p_build_config, p_custom_lib_dir);
-GodotSharpExport::~GodotSharpExport() {
- if (aname_prealloc)
- mono_free(aname_prealloc);
+ return get_assembly_dependencies(scripts_assembly, search_dirs, r_dependencies);
}
diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h
index 4dc8ea75d5..8d121a6bc3 100644
--- a/modules/mono/editor/godotsharp_export.h
+++ b/modules/mono/editor/godotsharp_export.h
@@ -31,29 +31,19 @@
#ifndef GODOTSHARP_EXPORT_H
#define GODOTSHARP_EXPORT_H
-#include <mono/metadata/image.h>
-
-#include "editor/editor_export.h"
+#include "core/dictionary.h"
+#include "core/error_list.h"
+#include "core/ustring.h"
#include "../mono_gd/gd_mono_header.h"
-class GodotSharpExport : public EditorExportPlugin {
-
- MonoAssemblyName *aname_prealloc;
-
- bool _add_file(const String &p_src_path, const String &p_dst_path, bool p_remap = false);
-
- Error _get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Map<String, String> &r_dependencies);
-
-protected:
- virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features);
- virtual void _export_begin(const Set<String> &p_features, bool p_debug, const String &p_path, int p_flags);
+namespace GodotSharpExport {
-public:
- static void register_internal_calls();
+Error get_exported_assembly_dependencies(const String &p_project_dll_name,
+ const String &p_project_dll_src_path, const String &p_build_config,
+ const String &p_custom_lib_dir, Dictionary &r_dependencies);
+Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_dependencies);
- GodotSharpExport();
- ~GodotSharpExport();
-};
+} // namespace GodotSharpExport
#endif // GODOTSHARP_EXPORT_H
diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp
deleted file mode 100644
index 5d9e39b6c2..0000000000
--- a/modules/mono/editor/mono_bottom_panel.cpp
+++ /dev/null
@@ -1,528 +0,0 @@
-/*************************************************************************/
-/* mono_bottom_panel.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "mono_bottom_panel.h"
-
-#include "editor/plugins/script_editor_plugin.h"
-#include "editor/script_editor_debugger.h"
-
-#include "../csharp_script.h"
-#include "../godotsharp_dirs.h"
-#include "csharp_project.h"
-#include "godotsharp_editor.h"
-
-MonoBottomPanel *MonoBottomPanel::singleton = NULL;
-
-void MonoBottomPanel::_update_build_tabs_list() {
-
- build_tabs_list->clear();
-
- int current_tab = build_tabs->get_current_tab();
-
- bool no_current_tab = current_tab < 0 || current_tab >= build_tabs->get_tab_count();
-
- for (int i = 0; i < build_tabs->get_child_count(); i++) {
-
- MonoBuildTab *tab = Object::cast_to<MonoBuildTab>(build_tabs->get_child(i));
-
- if (tab) {
- String item_name = tab->build_info.solution.get_file().get_basename();
- item_name += " [" + tab->build_info.configuration + "]";
-
- build_tabs_list->add_item(item_name, tab->get_icon_texture());
-
- String item_tooltip = "Solution: " + tab->build_info.solution;
- item_tooltip += "\nConfiguration: " + tab->build_info.configuration;
- item_tooltip += "\nStatus: ";
-
- if (tab->build_exited) {
- item_tooltip += tab->build_result == MonoBuildTab::RESULT_SUCCESS ? "Succeeded" : "Errored";
- } else {
- item_tooltip += "Running";
- }
-
- if (!tab->build_exited || tab->build_result == MonoBuildTab::RESULT_ERROR) {
- item_tooltip += "\nErrors: " + itos(tab->error_count);
- }
-
- item_tooltip += "\nWarnings: " + itos(tab->warning_count);
-
- build_tabs_list->set_item_tooltip(i, item_tooltip);
-
- if (no_current_tab || current_tab == i) {
- build_tabs_list->select(i);
- _build_tabs_item_selected(i);
- }
- }
- }
-}
-
-void MonoBottomPanel::add_build_tab(MonoBuildTab *p_build_tab) {
-
- build_tabs->add_child(p_build_tab);
- raise_build_tab(p_build_tab);
-}
-
-void MonoBottomPanel::raise_build_tab(MonoBuildTab *p_build_tab) {
-
- ERR_FAIL_COND(p_build_tab->get_parent() != build_tabs);
- build_tabs->move_child(p_build_tab, 0);
- _update_build_tabs_list();
-}
-
-void MonoBottomPanel::show_build_tab() {
-
- for (int i = 0; i < panel_tabs->get_tab_count(); i++) {
- if (panel_tabs->get_tab_control(i) == panel_builds_tab) {
- panel_tabs->set_current_tab(i);
- editor->make_bottom_panel_item_visible(this);
- return;
- }
- }
-
- ERR_PRINT("Builds tab not found");
-}
-
-void MonoBottomPanel::_build_tabs_item_selected(int p_idx) {
-
- ERR_FAIL_INDEX(p_idx, build_tabs->get_tab_count());
-
- build_tabs->set_current_tab(p_idx);
- if (!build_tabs->is_visible())
- build_tabs->set_visible(true);
-
- warnings_btn->set_visible(true);
- errors_btn->set_visible(true);
- view_log_btn->set_visible(true);
-}
-
-void MonoBottomPanel::_build_tabs_nothing_selected() {
-
- if (build_tabs->get_tab_count() != 0) { // just in case
- build_tabs->set_visible(false);
-
- // This callback is called when clicking on the empty space of the list.
- // ItemList won't deselect the items automatically, so we must do it ourselves.
- build_tabs_list->unselect_all();
- }
-
- warnings_btn->set_visible(false);
- errors_btn->set_visible(false);
- view_log_btn->set_visible(false);
-}
-
-void MonoBottomPanel::_warnings_toggled(bool p_pressed) {
-
- int current_tab = build_tabs->get_current_tab();
- ERR_FAIL_INDEX(current_tab, build_tabs->get_tab_count());
- MonoBuildTab *build_tab = Object::cast_to<MonoBuildTab>(build_tabs->get_child(current_tab));
- build_tab->warnings_visible = p_pressed;
- build_tab->_update_issues_list();
-}
-
-void MonoBottomPanel::_errors_toggled(bool p_pressed) {
-
- int current_tab = build_tabs->get_current_tab();
- ERR_FAIL_INDEX(current_tab, build_tabs->get_tab_count());
- MonoBuildTab *build_tab = Object::cast_to<MonoBuildTab>(build_tabs->get_child(current_tab));
- build_tab->errors_visible = p_pressed;
- build_tab->_update_issues_list();
-}
-
-void MonoBottomPanel::_build_project_pressed() {
-
- if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
- return; // No solution to build
-
- String scripts_metadata_path_editor = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor");
- String scripts_metadata_path_player = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor_player");
-
- Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path_editor);
- ERR_FAIL_COND(metadata_err != OK);
-
- if (FileAccess::exists(scripts_metadata_path_editor)) {
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- Error copy_err = da->copy(scripts_metadata_path_editor, scripts_metadata_path_player);
-
- ERR_EXPLAIN("Failed to copy scripts metadata file");
- ERR_FAIL_COND(copy_err != OK);
- }
-
- Vector<String> godot_defines;
- godot_defines.push_back(OS::get_singleton()->get_name());
- godot_defines.push_back((sizeof(void *) == 4 ? "32" : "64"));
- bool build_success = GodotSharpBuilds::get_singleton()->build_project_blocking("Tools", godot_defines);
-
- if (build_success) {
- // Notify running game for hot-reload
- ScriptEditor::get_singleton()->get_debugger()->reload_scripts();
-
- // Hot-reload in the editor
- MonoReloadNode::get_singleton()->restart_reload_timer();
-
- if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) {
- CSharpLanguage::get_singleton()->reload_assemblies(false);
- }
- }
-}
-
-void MonoBottomPanel::_view_log_pressed() {
-
- if (build_tabs_list->is_anything_selected()) {
- Vector<int> selected_items = build_tabs_list->get_selected_items();
- CRASH_COND(selected_items.size() != 1);
- int selected_item = selected_items[0];
-
- MonoBuildTab *build_tab = Object::cast_to<MonoBuildTab>(build_tabs->get_tab_control(selected_item));
- ERR_FAIL_NULL(build_tab);
-
- String log_dirpath = build_tab->get_build_info().get_log_dirpath();
-
- OS::get_singleton()->shell_open(log_dirpath.plus_file(GodotSharpBuilds::get_msbuild_log_filename()));
- }
-}
-
-void MonoBottomPanel::_notification(int p_what) {
-
- switch (p_what) {
-
- case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- panel_tabs->add_style_override("panel", editor->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles"));
- panel_tabs->add_style_override("tab_fg", editor->get_gui_base()->get_stylebox("DebuggerTabFG", "EditorStyles"));
- panel_tabs->add_style_override("tab_bg", editor->get_gui_base()->get_stylebox("DebuggerTabBG", "EditorStyles"));
- } break;
- }
-}
-
-void MonoBottomPanel::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_build_project_pressed"), &MonoBottomPanel::_build_project_pressed);
- ClassDB::bind_method(D_METHOD("_view_log_pressed"), &MonoBottomPanel::_view_log_pressed);
- ClassDB::bind_method(D_METHOD("_warnings_toggled", "pressed"), &MonoBottomPanel::_warnings_toggled);
- ClassDB::bind_method(D_METHOD("_errors_toggled", "pressed"), &MonoBottomPanel::_errors_toggled);
- ClassDB::bind_method(D_METHOD("_build_tabs_item_selected", "idx"), &MonoBottomPanel::_build_tabs_item_selected);
- ClassDB::bind_method(D_METHOD("_build_tabs_nothing_selected"), &MonoBottomPanel::_build_tabs_nothing_selected);
-}
-
-MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) {
-
- singleton = this;
-
- editor = p_editor;
-
- set_v_size_flags(SIZE_EXPAND_FILL);
- set_anchors_and_margins_preset(Control::PRESET_WIDE);
-
- panel_tabs = memnew(TabContainer);
- panel_tabs->set_tab_align(TabContainer::ALIGN_LEFT);
- panel_tabs->add_style_override("panel", editor->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles"));
- panel_tabs->add_style_override("tab_fg", editor->get_gui_base()->get_stylebox("DebuggerTabFG", "EditorStyles"));
- panel_tabs->add_style_override("tab_bg", editor->get_gui_base()->get_stylebox("DebuggerTabBG", "EditorStyles"));
- panel_tabs->set_custom_minimum_size(Size2(0, 228) * EDSCALE);
- panel_tabs->set_v_size_flags(SIZE_EXPAND_FILL);
- add_child(panel_tabs);
-
- { // Builds
- panel_builds_tab = memnew(VBoxContainer);
- panel_builds_tab->set_name(TTR("Builds"));
- panel_builds_tab->set_h_size_flags(SIZE_EXPAND_FILL);
- panel_tabs->add_child(panel_builds_tab);
-
- HBoxContainer *toolbar_hbc = memnew(HBoxContainer);
- toolbar_hbc->set_h_size_flags(SIZE_EXPAND_FILL);
- panel_builds_tab->add_child(toolbar_hbc);
-
- Button *build_project_btn = memnew(Button);
- build_project_btn->set_text(TTR("Build Project"));
- build_project_btn->set_focus_mode(FOCUS_NONE);
- build_project_btn->connect("pressed", this, "_build_project_pressed");
- toolbar_hbc->add_child(build_project_btn);
-
- toolbar_hbc->add_spacer();
-
- warnings_btn = memnew(ToolButton);
- warnings_btn->set_text(TTR("Warnings"));
- warnings_btn->set_toggle_mode(true);
- warnings_btn->set_pressed(true);
- warnings_btn->set_visible(false);
- warnings_btn->set_focus_mode(FOCUS_NONE);
- warnings_btn->connect("toggled", this, "_warnings_toggled");
- toolbar_hbc->add_child(warnings_btn);
-
- errors_btn = memnew(ToolButton);
- errors_btn->set_text(TTR("Errors"));
- errors_btn->set_toggle_mode(true);
- errors_btn->set_pressed(true);
- errors_btn->set_visible(false);
- errors_btn->set_focus_mode(FOCUS_NONE);
- errors_btn->connect("toggled", this, "_errors_toggled");
- toolbar_hbc->add_child(errors_btn);
-
- toolbar_hbc->add_spacer();
-
- view_log_btn = memnew(Button);
- view_log_btn->set_text(TTR("View log"));
- view_log_btn->set_focus_mode(FOCUS_NONE);
- view_log_btn->set_visible(false);
- view_log_btn->connect("pressed", this, "_view_log_pressed");
- toolbar_hbc->add_child(view_log_btn);
-
- HSplitContainer *hsc = memnew(HSplitContainer);
- hsc->set_h_size_flags(SIZE_EXPAND_FILL);
- hsc->set_v_size_flags(SIZE_EXPAND_FILL);
- panel_builds_tab->add_child(hsc);
-
- build_tabs_list = memnew(ItemList);
- build_tabs_list->set_h_size_flags(SIZE_EXPAND_FILL);
- build_tabs_list->connect("item_selected", this, "_build_tabs_item_selected");
- build_tabs_list->connect("nothing_selected", this, "_build_tabs_nothing_selected");
- hsc->add_child(build_tabs_list);
-
- build_tabs = memnew(TabContainer);
- build_tabs->set_tab_align(TabContainer::ALIGN_LEFT);
- build_tabs->set_h_size_flags(SIZE_EXPAND_FILL);
- build_tabs->set_tabs_visible(false);
- hsc->add_child(build_tabs);
- }
-}
-
-MonoBottomPanel::~MonoBottomPanel() {
-
- singleton = NULL;
-}
-
-void MonoBuildTab::_load_issues_from_file(const String &p_csv_file) {
-
- FileAccessRef f = FileAccess::open(p_csv_file, FileAccess::READ);
-
- if (!f)
- return;
-
- while (!f->eof_reached()) {
- Vector<String> csv_line = f->get_csv_line();
-
- if (csv_line.size() == 1 && csv_line[0].empty())
- return;
-
- ERR_CONTINUE(csv_line.size() != 7);
-
- BuildIssue issue;
- issue.warning = csv_line[0] == "warning";
- issue.file = csv_line[1];
- issue.line = csv_line[2].to_int();
- issue.column = csv_line[3].to_int();
- issue.code = csv_line[4];
- issue.message = csv_line[5];
- issue.project_file = csv_line[6];
-
- if (issue.warning)
- warning_count += 1;
- else
- error_count += 1;
-
- issues.push_back(issue);
- }
-}
-
-void MonoBuildTab::_update_issues_list() {
-
- issues_list->clear();
-
- Ref<Texture> warning_icon = get_icon("Warning", "EditorIcons");
- Ref<Texture> error_icon = get_icon("Error", "EditorIcons");
-
- for (int i = 0; i < issues.size(); i++) {
-
- const BuildIssue &issue = issues[i];
-
- if (!(issue.warning ? warnings_visible : errors_visible))
- continue;
-
- String tooltip;
- tooltip += String("Message: ") + issue.message;
-
- if (issue.code.length()) {
- tooltip += String("\nCode: ") + issue.code;
- }
-
- tooltip += String("\nType: ") + (issue.warning ? "warning" : "error");
-
- String text;
-
- if (issue.file.length()) {
- String sline = String::num_int64(issue.line);
- String scolumn = String::num_int64(issue.column);
-
- text += issue.file + "(";
- text += sline + ",";
- text += scolumn + "): ";
-
- tooltip += "\nFile: " + issue.file;
- tooltip += "\nLine: " + sline;
- tooltip += "\nColumn: " + scolumn;
- }
-
- if (issue.project_file.length()) {
- tooltip += "\nProject: " + issue.project_file;
- }
-
- text += issue.message;
-
- int line_break_idx = text.find("\n");
- issues_list->add_item(line_break_idx == -1 ? text : text.substr(0, line_break_idx),
- issue.warning ? warning_icon : error_icon);
- int index = issues_list->get_item_count() - 1;
- issues_list->set_item_tooltip(index, tooltip);
- issues_list->set_item_metadata(index, i);
- }
-}
-
-Ref<Texture> MonoBuildTab::get_icon_texture() const {
-
- if (build_exited) {
- if (build_result == RESULT_ERROR) {
- return get_icon("StatusError", "EditorIcons");
- } else {
- return get_icon("StatusSuccess", "EditorIcons");
- }
- } else {
- return get_icon("Stop", "EditorIcons");
- }
-}
-
-MonoBuildInfo MonoBuildTab::get_build_info() {
-
- return build_info;
-}
-
-void MonoBuildTab::on_build_start() {
-
- build_exited = false;
-
- issues.clear();
- warning_count = 0;
- error_count = 0;
- _update_issues_list();
-
- MonoBottomPanel::get_singleton()->raise_build_tab(this);
-}
-
-void MonoBuildTab::on_build_exit(BuildResult result) {
-
- build_exited = true;
- build_result = result;
-
- _load_issues_from_file(logs_dir.plus_file(GodotSharpBuilds::get_msbuild_issues_filename()));
- _update_issues_list();
-
- MonoBottomPanel::get_singleton()->raise_build_tab(this);
-}
-
-void MonoBuildTab::on_build_exec_failed(const String &p_cause) {
-
- build_exited = true;
- build_result = RESULT_ERROR;
-
- issues_list->clear();
-
- BuildIssue issue;
- issue.message = p_cause;
- issue.warning = false;
-
- error_count += 1;
- issues.push_back(issue);
-
- _update_issues_list();
-
- MonoBottomPanel::get_singleton()->raise_build_tab(this);
-}
-
-void MonoBuildTab::restart_build() {
-
- ERR_FAIL_COND(!build_exited);
- GodotSharpBuilds::get_singleton()->restart_build(this);
-}
-
-void MonoBuildTab::stop_build() {
-
- ERR_FAIL_COND(build_exited);
- GodotSharpBuilds::get_singleton()->stop_build(this);
-}
-
-void MonoBuildTab::_issue_activated(int p_idx) {
-
- ERR_FAIL_INDEX(p_idx, issues_list->get_item_count());
-
- // Get correct issue idx from issue list
- int issue_idx = this->issues_list->get_item_metadata(p_idx);
-
- ERR_FAIL_INDEX(issue_idx, issues.size());
-
- const BuildIssue &issue = issues[issue_idx];
-
- if (issue.project_file.empty() && issue.file.empty())
- return;
-
- String project_dir = issue.project_file.length() ? issue.project_file.get_base_dir() : build_info.solution.get_base_dir();
-
- String file = project_dir.simplify_path().plus_file(issue.file.simplify_path());
-
- if (!FileAccess::exists(file))
- return;
-
- file = ProjectSettings::get_singleton()->localize_path(file);
-
- if (file.begins_with("res://")) {
- Ref<Script> script = ResourceLoader::load(file, CSharpLanguage::get_singleton()->get_type());
-
- if (script.is_valid() && ScriptEditor::get_singleton()->edit(script, issue.line, issue.column)) {
- EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
- }
- }
-}
-
-void MonoBuildTab::_bind_methods() {
-
- ClassDB::bind_method("_issue_activated", &MonoBuildTab::_issue_activated);
-}
-
-MonoBuildTab::MonoBuildTab(const MonoBuildInfo &p_build_info, const String &p_logs_dir) :
- build_exited(false),
- issues_list(memnew(ItemList)),
- error_count(0),
- warning_count(0),
- errors_visible(true),
- warnings_visible(true),
- logs_dir(p_logs_dir),
- build_info(p_build_info) {
- issues_list->set_v_size_flags(SIZE_EXPAND_FILL);
- issues_list->connect("item_activated", this, "_issue_activated");
- add_child(issues_list);
-}
diff --git a/modules/mono/editor/mono_bottom_panel.h b/modules/mono/editor/mono_bottom_panel.h
deleted file mode 100644
index 9b362e51df..0000000000
--- a/modules/mono/editor/mono_bottom_panel.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*************************************************************************/
-/* mono_bottom_panel.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef MONO_BOTTOM_PANEL_H
-#define MONO_BOTTOM_PANEL_H
-
-#include "editor/editor_node.h"
-#include "scene/gui/control.h"
-
-#include "mono_build_info.h"
-
-class MonoBuildTab;
-
-class MonoBottomPanel : public VBoxContainer {
-
- GDCLASS(MonoBottomPanel, VBoxContainer);
-
- EditorNode *editor;
-
- TabContainer *panel_tabs;
-
- VBoxContainer *panel_builds_tab;
-
- ItemList *build_tabs_list;
- TabContainer *build_tabs;
-
- ToolButton *warnings_btn;
- ToolButton *errors_btn;
- Button *view_log_btn;
-
- void _update_build_tabs_list();
-
- void _build_tabs_item_selected(int p_idx);
- void _build_tabs_nothing_selected();
-
- void _warnings_toggled(bool p_pressed);
- void _errors_toggled(bool p_pressed);
-
- void _build_project_pressed();
- void _view_log_pressed();
-
- static MonoBottomPanel *singleton;
-
-protected:
- void _notification(int p_what);
-
- static void _bind_methods();
-
-public:
- _FORCE_INLINE_ static MonoBottomPanel *get_singleton() { return singleton; }
-
- void add_build_tab(MonoBuildTab *p_build_tab);
- void raise_build_tab(MonoBuildTab *p_build_tab);
-
- void show_build_tab();
-
- MonoBottomPanel(EditorNode *p_editor = NULL);
- ~MonoBottomPanel();
-};
-
-class MonoBuildTab : public VBoxContainer {
-
- GDCLASS(MonoBuildTab, VBoxContainer);
-
-public:
- enum BuildResult {
- RESULT_ERROR,
- RESULT_SUCCESS
- };
-
- struct BuildIssue {
- bool warning;
- String file;
- int line;
- int column;
- String code;
- String message;
- String project_file;
- };
-
-private:
- friend class MonoBottomPanel;
-
- bool build_exited;
- BuildResult build_result;
-
- Vector<BuildIssue> issues;
- ItemList *issues_list;
-
- int error_count;
- int warning_count;
-
- bool errors_visible;
- bool warnings_visible;
-
- String logs_dir;
-
- MonoBuildInfo build_info;
-
- void _load_issues_from_file(const String &p_csv_file);
- void _update_issues_list();
-
- void _issue_activated(int p_idx);
-
-protected:
- static void _bind_methods();
-
-public:
- Ref<Texture> get_icon_texture() const;
-
- MonoBuildInfo get_build_info();
-
- void on_build_start();
- void on_build_exit(BuildResult result);
- void on_build_exec_failed(const String &p_cause);
-
- void restart_build();
- void stop_build();
-
- MonoBuildTab(const MonoBuildInfo &p_build_info, const String &p_logs_dir);
-};
-
-#endif // MONO_BOTTOM_PANEL_H
diff --git a/modules/mono/editor/mono_build_info.cpp b/modules/mono/editor/mono_build_info.cpp
deleted file mode 100644
index b386c06435..0000000000
--- a/modules/mono/editor/mono_build_info.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*************************************************************************/
-/* mono_build_info.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "mono_build_info.h"
-
-#include "../godotsharp_dirs.h"
-#include "../mono_gd/gd_mono_utils.h"
-
-uint32_t MonoBuildInfo::Hasher::hash(const MonoBuildInfo &p_key) {
-
- uint32_t hash = 0;
-
- GDMonoUtils::hash_combine(hash, p_key.solution.hash());
- GDMonoUtils::hash_combine(hash, p_key.configuration.hash());
-
- return hash;
-}
-
-bool MonoBuildInfo::operator==(const MonoBuildInfo &p_b) const {
-
- return p_b.solution == solution && p_b.configuration == configuration;
-}
-
-String MonoBuildInfo::get_log_dirpath() {
-
- return GodotSharpDirs::get_build_logs_dir().plus_file(solution.md5_text() + "_" + configuration);
-}
-
-MonoBuildInfo::MonoBuildInfo() {}
-
-MonoBuildInfo::MonoBuildInfo(const String &p_solution, const String &p_config) {
-
- solution = p_solution;
- configuration = p_config;
-}
diff --git a/modules/mono/editor/monodevelop_instance.cpp b/modules/mono/editor/monodevelop_instance.cpp
deleted file mode 100644
index 3caa56d1d0..0000000000
--- a/modules/mono/editor/monodevelop_instance.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*************************************************************************/
-/* monodevelop_instance.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "monodevelop_instance.h"
-
-#include "../mono_gd/gd_mono.h"
-#include "../mono_gd/gd_mono_class.h"
-
-void MonoDevelopInstance::execute(const Vector<String> &p_files) {
-
- _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
-
- ERR_FAIL_NULL(execute_method);
- ERR_FAIL_COND(gc_handle.is_null());
-
- MonoException *exc = NULL;
-
- Variant files = p_files;
- const Variant *args[1] = { &files };
- execute_method->invoke(gc_handle->get_target(), args, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- ERR_FAIL();
- }
-}
-
-void MonoDevelopInstance::execute(const String &p_file) {
-
- Vector<String> files;
- files.push_back(p_file);
- execute(files);
-}
-
-MonoDevelopInstance::MonoDevelopInstance(const String &p_solution, EditorId p_editor_id) {
-
- _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
-
- GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Editor", "MonoDevelopInstance");
-
- MonoObject *obj = mono_object_new(TOOLS_DOMAIN, klass->get_mono_ptr());
-
- GDMonoMethod *ctor = klass->get_method(".ctor", 2);
- MonoException *exc = NULL;
-
- Variant solution = p_solution;
- Variant editor_id = p_editor_id;
- const Variant *args[2] = { &solution, &editor_id };
- ctor->invoke(obj, args, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- ERR_FAIL();
- }
-
- gc_handle = MonoGCHandle::create_strong(obj);
- execute_method = klass->get_method("Execute", 1);
-}
diff --git a/modules/mono/editor/monodevelop_instance.h b/modules/mono/editor/monodevelop_instance.h
deleted file mode 100644
index 3b3af9607b..0000000000
--- a/modules/mono/editor/monodevelop_instance.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*************************************************************************/
-/* monodevelop_instance.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef MONODEVELOP_INSTANCE_H
-#define MONODEVELOP_INSTANCE_H
-
-#include "core/reference.h"
-
-#include "../mono_gc_handle.h"
-#include "../mono_gd/gd_mono_method.h"
-
-class MonoDevelopInstance {
-
- Ref<MonoGCHandle> gc_handle;
- GDMonoMethod *execute_method;
-
-public:
- enum EditorId {
- MONODEVELOP = 0,
- VISUALSTUDIO_FOR_MAC = 1
- };
-
- void execute(const Vector<String> &p_files);
- void execute(const String &p_file);
-
- MonoDevelopInstance(const String &p_solution, EditorId p_editor_id);
-};
-
-#endif // MONODEVELOP_INSTANCE_H