diff options
Diffstat (limited to 'modules/mono/editor')
10 files changed, 85 insertions, 58 deletions
| diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs index c2549b4ad5..5edf72d63e 100644 --- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs +++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs @@ -70,13 +70,14 @@ namespace GodotTools.BuildLogger          {              string line = $"{e.File}({e.LineNumber},{e.ColumnNumber}): error {e.Code}: {e.Message}"; -            if (e.ProjectFile.Length > 0) +            if (!string.IsNullOrEmpty(e.ProjectFile))                  line += $" [{e.ProjectFile}]";              WriteLine(line);              string errorLine = $@"error,{e.File.CsvEscape()},{e.LineNumber},{e.ColumnNumber}," + -                               $@"{e.Code.CsvEscape()},{e.Message.CsvEscape()},{e.ProjectFile.CsvEscape()}"; +                               $"{e.Code?.CsvEscape() ?? string.Empty},{e.Message.CsvEscape()}," + +                               $"{e.ProjectFile?.CsvEscape() ?? string.Empty}";              issuesStreamWriter.WriteLine(errorLine);          } @@ -89,8 +90,9 @@ namespace GodotTools.BuildLogger              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)}"; +            string warningLine = $@"warning,{e.File.CsvEscape()},{e.LineNumber},{e.ColumnNumber}," + +                                 $"{e.Code?.CsvEscape() ?? string.Empty},{e.Message.CsvEscape()}," + +                                 $"{e.ProjectFile?.CsvEscape() ?? string.Empty}";              issuesStreamWriter.WriteLine(warningLine);          } diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs index 012b69032e..e6b0e8f1df 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs +++ b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs @@ -43,7 +43,7 @@ namespace GodotTools.Core                     path.StartsWith(DriveRoot, StringComparison.Ordinal);          } -        public static string ToSafeDirName(this string dirName, bool allowDirSeparator) +        public static string ToSafeDirName(this string dirName, bool allowDirSeparator = false)          {              var invalidChars = new List<string> { ":", "*", "?", "\"", "<", ">", "|" }; diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj index 9cb50014b0..e4d6b2e010 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj @@ -11,13 +11,21 @@    <ItemGroup>      <ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj" />    </ItemGroup> +  <!-- +  The Microsoft.Build.Runtime package is too problematic so we create a MSBuild.exe stub. The workaround described +  here doesn't work with Microsoft.NETFramework.ReferenceAssemblies: https://github.com/microsoft/msbuild/issues/3486 +  We need a MSBuild.exe file as there's an issue in Microsoft.Build where it executes platform dependent code when +  searching for MSBuild.exe before the fallback to not using it. A stub is fine as it should never be executed. +  -->    <ItemGroup> -    <!-- -    The Microsoft.Build.Runtime package is too problematic so we create a MSBuild.exe stub. The workaround described -    here doesn't work with Microsoft.NETFramework.ReferenceAssemblies: https://github.com/microsoft/msbuild/issues/3486 -    We need a MSBuild.exe file as there's an issue in Microsoft.Build where it executes platform dependent code when -    searching for MSBuild.exe before the fallback to not using it. A stub is fine as it should never be executed. -    -->      <None Include="MSBuild.exe" CopyToOutputDirectory="Always" />    </ItemGroup> +  <Target Name="CopyMSBuildStubWindows" AfterTargets="Build" Condition=" '$(GodotPlatform)' == 'windows' Or ( '$(GodotPlatform)' == '' And '$(OS)' == 'Windows_NT' ) "> +    <PropertyGroup> +      <GodotSourceRootPath>$(SolutionDir)/../../../../</GodotSourceRootPath> +      <GodotOutputDataDir>$(GodotSourceRootPath)/bin/GodotSharp</GodotOutputDataDir> +    </PropertyGroup> +    <!-- Need to copy it here as well on Windows --> +    <Copy SourceFiles="MSBuild.exe" DestinationFiles="$(GodotOutputDataDir)\Mono\lib\mono\v4.0\MSBuild.exe" /> +  </Target>  </Project> diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs index 5541876f9e..01d7c99662 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs @@ -1,5 +1,6 @@  using System;  using System.IO; +using System.Text;  using Microsoft.Build.Construction;  using Microsoft.Build.Evaluation; @@ -41,7 +42,8 @@ namespace GodotTools.ProjectEditor              var root = GenGameProject(name); -            root.Save(path); +            // Save (without BOM) +            root.Save(path, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));              return Guid.NewGuid().ToString().ToUpper();          } diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs index f36e581a5f..7bfba779fb 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs @@ -161,8 +161,21 @@ namespace GodotTools.Build              // Try to find 15.0 with vswhere -            string vsWherePath = Environment.GetEnvironmentVariable(Internal.GodotIs32Bits() ? "ProgramFiles" : "ProgramFiles(x86)"); -            vsWherePath += "\\Microsoft Visual Studio\\Installer\\vswhere.exe"; +            var envNames = Internal.GodotIs32Bits() ? new[] { "ProgramFiles", "ProgramW6432" } : new[] { "ProgramFiles(x86)", "ProgramFiles" }; + +            string vsWherePath = null; +            foreach (var envName in envNames) +            { +                vsWherePath = Environment.GetEnvironmentVariable(envName); +                if (!string.IsNullOrEmpty(vsWherePath)) +                { +                    vsWherePath += "\\Microsoft Visual Studio\\Installer\\vswhere.exe"; +                    if (File.Exists(vsWherePath)) +                        break; +                } + +                vsWherePath = null; +            }              var vsWhereArgs = new[] {"-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild"}; diff --git a/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs b/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs index 6399991b84..ff7ce97c47 100644 --- a/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs +++ b/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs @@ -205,23 +205,8 @@ namespace GodotTools              if (File.Exists(editorScriptsMetadataPath))                  File.Copy(editorScriptsMetadataPath, playerScriptsMetadataPath); -            var currentPlayRequest = GodotSharpEditor.Instance.CurrentPlaySettings; - -            if (currentPlayRequest != null) -            { -                if (currentPlayRequest.Value.HasDebugger) -                { -                    // Set the environment variable that will tell the player to connect to the IDE debugger -                    // TODO: We should probably add a better way to do this -                    Environment.SetEnvironmentVariable("GODOT_MONO_DEBUGGER_AGENT", -                        "--debugger-agent=transport=dt_socket" + -                        $",address={currentPlayRequest.Value.DebuggerHost}:{currentPlayRequest.Value.DebuggerPort}" + -                        ",server=n"); -                } - -                if (!currentPlayRequest.Value.BuildBeforePlaying) -                    return true; // Requested play from an external editor/IDE which already built the project -            } +            if (GodotSharpEditor.Instance.SkipBuildBeforePlaying) +                return true; // Requested play from an external editor/IDE which already built the project              return BuildProjectBlocking("Debug");          } diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs index 554763eecb..599ca94699 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -19,7 +19,7 @@ namespace GodotTools.Export      public class ExportPlugin : EditorExportPlugin      {          [Flags] -        enum I18NCodesets +        enum I18NCodesets : long          {              None = 0,              CJK = 1, @@ -430,7 +430,7 @@ namespace GodotTools.Export          private static string DetermineDataDirNameForProject()          {              var appName = (string)ProjectSettings.GetSetting("application/config/name"); -            string appNameSafe = appName.ToSafeDirName(allowDirSeparator: false); +            string appNameSafe = appName.ToSafeDirName();              return $"data_{appNameSafe}";          } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index a363ecc920..3148458d7e 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -38,13 +38,14 @@ namespace GodotTools          public BottomPanel BottomPanel { get; private set; } -        public PlaySettings? CurrentPlaySettings { get; set; } +        public bool SkipBuildBeforePlaying { get; set; } = false;          public static string ProjectAssemblyName          {              get              {                  var projectAssemblyName = (string)ProjectSettings.GetSetting("application/config/name"); +                projectAssemblyName = projectAssemblyName.ToSafeDirName();                  if (string.IsNullOrEmpty(projectAssemblyName))                      projectAssemblyName = "UnnamedProject";                  return projectAssemblyName; diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs index 17f3339560..eb34a2d0f7 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs @@ -330,9 +330,10 @@ namespace GodotTools.Ides              {                  DispatchToMainThread(() =>                  { -                    GodotSharpEditor.Instance.CurrentPlaySettings = new PlaySettings(); +                    // TODO: Add BuildBeforePlaying flag to PlayRequest + +                    // Run the game                      Internal.EditorRunPlay(); -                    GodotSharpEditor.Instance.CurrentPlaySettings = null;                  });                  return Task.FromResult<Response>(new PlayResponse());              } @@ -341,10 +342,22 @@ namespace GodotTools.Ides              {                  DispatchToMainThread(() =>                  { -                    GodotSharpEditor.Instance.CurrentPlaySettings = -                        new PlaySettings(request.DebuggerHost, request.DebuggerPort, request.BuildBeforePlaying ?? true); +                    // Tell the build callback whether the editor already built the solution or not +                    GodotSharpEditor.Instance.SkipBuildBeforePlaying = !(request.BuildBeforePlaying ?? true); + +                    // Pass the debugger agent settings to the player via an environment variables +                    // TODO: It would be better if this was an argument in EditorRunPlay instead +                    Environment.SetEnvironmentVariable("GODOT_MONO_DEBUGGER_AGENT", +                        "--debugger-agent=transport=dt_socket" + +                        $",address={request.DebuggerHost}:{request.DebuggerPort}" + +                        ",server=n"); + +                    // Run the game                      Internal.EditorRunPlay(); -                    GodotSharpEditor.Instance.CurrentPlaySettings = null; + +                    // Restore normal settings +                    Environment.SetEnvironmentVariable("GODOT_MONO_DEBUGGER_AGENT", ""); +                    GodotSharpEditor.Instance.SkipBuildBeforePlaying = false;                  });                  return Task.FromResult<Response>(new DebugPlayResponse());              } diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp index b15e9b060a..2edd8c87dc 100644 --- a/modules/mono/editor/godotsharp_export.cpp +++ b/modules/mono/editor/godotsharp_export.cpp @@ -43,6 +43,16 @@  namespace GodotSharpExport { +MonoAssemblyName *new_mono_assembly_name() { +	// Mono has no public API to create an empty MonoAssemblyName and the struct is private. +	// As such the only way to create it is with a stub name and then clear it. + +	MonoAssemblyName *aname = mono_assembly_name_new("stub"); +	CRASH_COND(aname == nullptr); +	mono_assembly_name_free(aname); // Frees the string fields, not the struct +	return aname; +} +  struct AssemblyRefInfo {  	String name;  	uint16_t major; @@ -67,7 +77,7 @@ AssemblyRefInfo get_assemblyref_name(MonoImage *p_image, int index) {  	};  } -Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_assembly_dependencies) { +Error get_assembly_dependencies(GDMonoAssembly *p_assembly, MonoAssemblyName *reusable_aname, const Vector<String> &p_search_dirs, Dictionary &r_assembly_dependencies) {  	MonoImage *image = p_assembly->get_image();  	for (int i = 0; i < mono_image_get_table_rows(image, MONO_TABLE_ASSEMBLYREF); i++) { @@ -79,26 +89,16 @@ Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String>  			continue;  		} -		GDMonoAssembly *ref_assembly = nullptr; - -		{ -			MonoAssemblyName *ref_aname = mono_assembly_name_new("A"); // We can't allocate an empty MonoAssemblyName, hence "A" -			CRASH_COND(ref_aname == nullptr); -			SCOPE_EXIT { -				mono_assembly_name_free(ref_aname); -				mono_free(ref_aname); -			}; - -			mono_assembly_get_assemblyref(image, i, ref_aname); +		mono_assembly_get_assemblyref(image, i, reusable_aname); -			if (!GDMono::get_singleton()->load_assembly(ref_name, ref_aname, &ref_assembly, /* refonly: */ true, p_search_dirs)) { -				ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'."); -			} - -			r_assembly_dependencies[ref_name] = ref_assembly->get_path(); +		GDMonoAssembly *ref_assembly = NULL; +		if (!GDMono::get_singleton()->load_assembly(ref_name, reusable_aname, &ref_assembly, /* refonly: */ true, p_search_dirs)) { +			ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'.");  		} -		Error err = get_assembly_dependencies(ref_assembly, p_search_dirs, r_assembly_dependencies); +		r_assembly_dependencies[ref_name] = ref_assembly->get_path(); + +		Error err = get_assembly_dependencies(ref_assembly, reusable_aname, p_search_dirs, r_assembly_dependencies);  		ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot load one of the dependencies for the assembly: '" + ref_name + "'.");  	} @@ -130,7 +130,10 @@ Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies,  		ERR_FAIL_COND_V_MSG(!load_success, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + assembly_name + "'."); -		Error err = get_assembly_dependencies(assembly, search_dirs, r_assembly_dependencies); +		MonoAssemblyName *reusable_aname = new_mono_assembly_name(); +		SCOPE_EXIT { mono_free(reusable_aname); }; + +		Error err = get_assembly_dependencies(assembly, reusable_aname, search_dirs, r_assembly_dependencies);  		if (err != OK) {  			return err;  		} |