Merge pull request #30584 from neikeq/yatta
Mono: Better handling of missing/outdated API assemblies
This commit is contained in:
commit
7f3490c5e1
@ -114,15 +114,20 @@ void CSharpLanguage::init() {
|
||||
gdmono = memnew(GDMono);
|
||||
gdmono->initialize();
|
||||
|
||||
#ifndef MONO_GLUE_ENABLED
|
||||
WARN_PRINT("This binary is built with `mono_glue=no` and cannot be used for scripting");
|
||||
#endif
|
||||
|
||||
#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED)
|
||||
// Generate bindings here, before loading assemblies. `initialize_load_assemblies` aborts
|
||||
// the applications if the api assemblies or the main tools assembly is missing, but this
|
||||
// is not a problem for BindingsGenerator as it only needs the tools project editor assembly.
|
||||
List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
|
||||
BindingsGenerator::handle_cmdline_args(cmdline_args);
|
||||
#endif
|
||||
|
||||
#ifndef MONO_GLUE_ENABLED
|
||||
print_line("Run this binary with `--generate-mono-glue path/to/modules/mono/glue`");
|
||||
#endif
|
||||
|
||||
gdmono->initialize_load_assemblies();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
EditorNode::add_init_callback(&_editor_init_callback);
|
||||
|
||||
@ -710,14 +715,6 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
|
||||
return false; // No assembly to load
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!gdmono->get_core_api_assembly() && gdmono->metadata_is_api_assembly_invalidated(APIAssembly::API_CORE))
|
||||
return false; // The core API assembly to load is invalidated
|
||||
|
||||
if (!gdmono->get_editor_api_assembly() && gdmono->metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR))
|
||||
return false; // The editor API assembly to load is invalidated
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Godot.Collections;
|
||||
using GodotTools.Internals;
|
||||
using GodotTools.ProjectEditor;
|
||||
using static GodotTools.Internals.Globals;
|
||||
using File = GodotTools.Utils.File;
|
||||
using Directory = GodotTools.Utils.Directory;
|
||||
|
||||
@ -26,7 +26,7 @@ namespace GodotTools
|
||||
|
||||
public static void AddItem(string projectPath, string itemType, string include)
|
||||
{
|
||||
if (!(bool) Internal.GlobalDef("mono/project/auto_update_project", true))
|
||||
if (!(bool) GlobalDef("mono/project/auto_update_project", true))
|
||||
return;
|
||||
|
||||
ProjectUtils.AddItemToProjectChecked(projectPath, itemType, include);
|
||||
|
@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using GodotTools.Build;
|
||||
using GodotTools.Internals;
|
||||
using GodotTools.Utils;
|
||||
using static GodotTools.Internals.Globals;
|
||||
using Error = Godot.Error;
|
||||
using File = GodotTools.Utils.File;
|
||||
using Directory = GodotTools.Utils.Directory;
|
||||
@ -192,134 +193,14 @@ namespace GodotTools
|
||||
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;
|
||||
// Make sure to update the API assemblies if they happen to be missing. Just in
|
||||
// case the user decided to delete them at some point after they were loaded.
|
||||
Internal.UpdateApiAssembliesFromPrebuilt();
|
||||
|
||||
using (var pr = new EditorProgress("mono_project_debug_build", "Building project solution...", 1))
|
||||
{
|
||||
@ -376,7 +257,7 @@ namespace GodotTools
|
||||
{
|
||||
// Build tool settings
|
||||
|
||||
Internal.EditorDef("mono/builds/build_tool", OS.IsWindows() ? BuildTool.MsBuildVs : BuildTool.MsBuildMono);
|
||||
EditorDef("mono/builds/build_tool", OS.IsWindows() ? BuildTool.MsBuildVs : BuildTool.MsBuildMono);
|
||||
|
||||
var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
|
||||
|
||||
@ -390,7 +271,7 @@ namespace GodotTools
|
||||
$"{PropNameMsbuildMono},{PropNameXbuild}"
|
||||
});
|
||||
|
||||
Internal.EditorDef("mono/builds/print_build_output", false);
|
||||
EditorDef("mono/builds/print_build_output", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using GodotTools.Internals;
|
||||
using GodotTools.ProjectEditor;
|
||||
using static GodotTools.Internals.Globals;
|
||||
using File = GodotTools.Utils.File;
|
||||
using Path = System.IO.Path;
|
||||
using OS = GodotTools.Utils.OS;
|
||||
@ -26,15 +27,15 @@ namespace GodotTools
|
||||
private MonoDevelopInstance monoDevelopInstance;
|
||||
private MonoDevelopInstance visualStudioForMacInstance;
|
||||
|
||||
private WeakReference<GodotSharpExport> exportPluginWeak;
|
||||
private WeakRef exportPluginWeak; // TODO Use WeakReference once we have proper serialization
|
||||
|
||||
public MonoBottomPanel MonoBottomPanel { get; private set; }
|
||||
|
||||
private bool CreateProjectSolution()
|
||||
{
|
||||
using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...", 2)) // TTR("Generating solution...")
|
||||
using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 2))
|
||||
{
|
||||
pr.Step("Generating C# project..."); // TTR("Generating C# project...")
|
||||
pr.Step("Generating C# project...".TTR());
|
||||
|
||||
string resourceDir = ProjectSettings.GlobalizePath("res://");
|
||||
|
||||
@ -67,96 +68,28 @@ namespace GodotTools
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
ShowErrorDialog($"Failed to save solution. Exception message: {e.Message}"); // TTR
|
||||
ShowErrorDialog("Failed to save solution. Exception message: ".TTR() + e.Message);
|
||||
return false;
|
||||
}
|
||||
|
||||
string apiConfig = "Debug";
|
||||
// Make sure to update the API assemblies if they happen to be missing. Just in
|
||||
// case the user decided to delete them at some point after they were loaded.
|
||||
Internal.UpdateApiAssembliesFromPrebuilt();
|
||||
|
||||
if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Core, apiConfig))
|
||||
return false;
|
||||
|
||||
if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Editor, apiConfig))
|
||||
return false;
|
||||
|
||||
pr.Step("Done"); // TTR("Done")
|
||||
pr.Step("Done".TTR());
|
||||
|
||||
// Here, after all calls to progress_task_step
|
||||
CallDeferred(nameof(_RemoveCreateSlnMenuOption));
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowErrorDialog("Failed to create C# project."); // TTR
|
||||
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));
|
||||
@ -407,7 +340,7 @@ namespace GodotTools
|
||||
|
||||
MonoBottomPanel = new MonoBottomPanel();
|
||||
|
||||
bottomPanelBtn = AddControlToBottomPanel(MonoBottomPanel, "Mono"); // TTR("Mono")
|
||||
bottomPanelBtn = AddControlToBottomPanel(MonoBottomPanel, "Mono".TTR());
|
||||
|
||||
AddChild(new HotReloadAssemblyWatcher {Name = "HotReloadAssemblyWatcher"});
|
||||
|
||||
@ -419,7 +352,7 @@ namespace GodotTools
|
||||
|
||||
// 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")
|
||||
menuPopup.AddItem("About C# support".TTR(), (int) MenuOptions.AboutCSharp);
|
||||
aboutDialog = new AcceptDialog();
|
||||
editorBaseControl.AddChild(aboutDialog);
|
||||
aboutDialog.WindowTitle = "Important: C# support is not feature-complete";
|
||||
@ -441,7 +374,7 @@ namespace GodotTools
|
||||
|
||||
var aboutLabel = new Label();
|
||||
aboutHBox.AddChild(aboutLabel);
|
||||
aboutLabel.RectMinSize = new Vector2(600, 150) * Internal.EditorScale;
|
||||
aboutLabel.RectMinSize = new Vector2(600, 150) * EditorScale;
|
||||
aboutLabel.SizeFlagsVertical = (int) Control.SizeFlags.ExpandFill;
|
||||
aboutLabel.Autowrap = true;
|
||||
aboutLabel.Text =
|
||||
@ -454,7 +387,7 @@ namespace GodotTools
|
||||
" 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);
|
||||
EditorDef("mono/editor/show_info_on_start", true);
|
||||
|
||||
// CheckBox in main container
|
||||
aboutDialogCheckBox = new CheckBox {Text = "Show this warning when starting the editor"};
|
||||
@ -464,16 +397,13 @@ namespace GodotTools
|
||||
|
||||
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));
|
||||
|
||||
// Make sure the existing project has Api assembly references configured correctly
|
||||
CSharpProject.FixApiHintPath(GodotSharpDirs.ProjectCsProjPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
bottomPanelBtn.Hide();
|
||||
menuPopup.AddItem("Create C# solution", (int) MenuOptions.CreateSln); // TTR("Create C# solution")
|
||||
menuPopup.AddItem("Create C# solution".TTR(), (int) MenuOptions.CreateSln);
|
||||
}
|
||||
|
||||
menuPopup.Connect("id_pressed", this, nameof(_MenuOptionPressed));
|
||||
@ -488,7 +418,7 @@ namespace GodotTools
|
||||
AddControlToContainer(CustomControlContainer.Toolbar, buildButton);
|
||||
|
||||
// External editor settings
|
||||
Internal.EditorDef("mono/editor/external_editor", ExternalEditor.None);
|
||||
EditorDef("mono/editor/external_editor", ExternalEditor.None);
|
||||
|
||||
string settingsHintStr = "Disabled";
|
||||
|
||||
@ -520,7 +450,7 @@ namespace GodotTools
|
||||
// Export plugin
|
||||
var exportPlugin = new GodotSharpExport();
|
||||
AddExportPlugin(exportPlugin);
|
||||
exportPluginWeak = new WeakReference<GodotSharpExport>(exportPlugin);
|
||||
exportPluginWeak = WeakRef(exportPlugin);
|
||||
|
||||
GodotSharpBuilds.Initialize();
|
||||
}
|
||||
@ -529,13 +459,15 @@ namespace GodotTools
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (exportPluginWeak.TryGetTarget(out var exportPlugin))
|
||||
if (exportPluginWeak != null)
|
||||
{
|
||||
// We need to dispose our export plugin before the editor destroys EditorSettings.
|
||||
// Otherwise, if the GC disposes it at a later time, EditorExportPlatformAndroid
|
||||
// will be freed after EditorSettings already was, and its device polling thread
|
||||
// will try to access the EditorSettings singleton, resulting in null dereferencing.
|
||||
exportPlugin.Dispose();
|
||||
(exportPluginWeak.GetRef() as GodotSharpExport)?.Dispose();
|
||||
|
||||
exportPluginWeak.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,7 @@
|
||||
<Compile Include="Internals\GodotSharpDirs.cs" />
|
||||
<Compile Include="Internals\Internal.cs" />
|
||||
<Compile Include="Internals\ScriptClassParser.cs" />
|
||||
<Compile Include="Internals\Globals.cs" />
|
||||
<Compile Include="MonoDevelopInstance.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Build\BuildSystem.cs" />
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Godot;
|
||||
using GodotTools.Internals;
|
||||
using static GodotTools.Internals.Globals;
|
||||
|
||||
namespace GodotTools
|
||||
{
|
||||
@ -37,7 +38,7 @@ namespace GodotTools
|
||||
watchTimer = new Timer
|
||||
{
|
||||
OneShot = false,
|
||||
WaitTime = (float) Internal.EditorDef("mono/assembly_watch_interval_sec", 0.5)
|
||||
WaitTime = (float) EditorDef("mono/assembly_watch_interval_sec", 0.5)
|
||||
};
|
||||
watchTimer.Connect("timeout", this, nameof(TimerTimeout));
|
||||
AddChild(watchTimer);
|
||||
|
@ -0,0 +1,33 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace GodotTools.Internals
|
||||
{
|
||||
public static class Globals
|
||||
{
|
||||
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);
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public static string TTR(this string text) => internal_TTR(text);
|
||||
|
||||
// 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_TTR(string text);
|
||||
}
|
||||
}
|
@ -10,13 +10,8 @@ namespace GodotTools.Internals
|
||||
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 UpdateApiAssembliesFromPrebuilt() =>
|
||||
internal_UpdateApiAssembliesFromPrebuilt();
|
||||
|
||||
public static string FullTemplatesDir =>
|
||||
internal_FullTemplatesDir();
|
||||
@ -25,14 +20,6 @@ namespace GodotTools.Internals
|
||||
|
||||
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();
|
||||
@ -62,13 +49,7 @@ namespace GodotTools.Internals
|
||||
// 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);
|
||||
private static extern string internal_UpdateApiAssembliesFromPrebuilt();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
private static extern string internal_FullTemplatesDir();
|
||||
@ -79,15 +60,6 @@ namespace GodotTools.Internals
|
||||
[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();
|
||||
|
||||
|
@ -3,6 +3,7 @@ using System;
|
||||
using System.IO;
|
||||
using Godot.Collections;
|
||||
using GodotTools.Internals;
|
||||
using static GodotTools.Internals.Globals;
|
||||
using File = GodotTools.Utils.File;
|
||||
using Path = System.IO.Path;
|
||||
|
||||
@ -254,7 +255,7 @@ namespace GodotTools
|
||||
panelTabs = new TabContainer
|
||||
{
|
||||
TabAlign = TabContainer.TabAlignEnum.Left,
|
||||
RectMinSize = new Vector2(0, 228) * Internal.EditorScale,
|
||||
RectMinSize = new Vector2(0, 228) * EditorScale,
|
||||
SizeFlagsVertical = (int) SizeFlags.ExpandFill
|
||||
};
|
||||
panelTabs.AddStyleboxOverride("panel", editorBaseControl.GetStylebox("DebuggerPanel", "EditorStyles"));
|
||||
@ -266,7 +267,7 @@ namespace GodotTools
|
||||
// Builds tab
|
||||
panelBuildsTab = new VBoxContainer
|
||||
{
|
||||
Name = "Builds", // TTR
|
||||
Name = "Builds".TTR(),
|
||||
SizeFlagsHorizontal = (int) SizeFlags.ExpandFill
|
||||
};
|
||||
panelTabs.AddChild(panelBuildsTab);
|
||||
@ -276,7 +277,7 @@ namespace GodotTools
|
||||
|
||||
var buildProjectBtn = new Button
|
||||
{
|
||||
Text = "Build Project", // TTR
|
||||
Text = "Build Project".TTR(),
|
||||
FocusMode = FocusModeEnum.None
|
||||
};
|
||||
buildProjectBtn.Connect("pressed", this, nameof(BuildProjectPressed));
|
||||
@ -286,7 +287,7 @@ namespace GodotTools
|
||||
|
||||
warningsBtn = new ToolButton
|
||||
{
|
||||
Text = "Warnings", // TTR
|
||||
Text = "Warnings".TTR(),
|
||||
ToggleMode = true,
|
||||
Pressed = true,
|
||||
Visible = false,
|
||||
@ -297,7 +298,7 @@ namespace GodotTools
|
||||
|
||||
errorsBtn = new ToolButton
|
||||
{
|
||||
Text = "Errors", // TTR
|
||||
Text = "Errors".TTR(),
|
||||
ToggleMode = true,
|
||||
Pressed = true,
|
||||
Visible = false,
|
||||
@ -310,7 +311,7 @@ namespace GodotTools
|
||||
|
||||
viewLogBtn = new Button
|
||||
{
|
||||
Text = "View log", // TTR
|
||||
Text = "View log".TTR(),
|
||||
FocusMode = FocusModeEnum.None,
|
||||
Visible = false
|
||||
};
|
||||
|
@ -30,7 +30,6 @@
|
||||
|
||||
#include "editor_internal_calls.h"
|
||||
|
||||
#include "core/message_queue.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/version.h"
|
||||
#include "editor/editor_node.h"
|
||||
@ -231,24 +230,34 @@ uint32_t godot_icall_GodotSharpExport_GetExportedAssemblyDependencies(MonoString
|
||||
return GodotSharpExport::get_exported_assembly_dependencies(project_dll_name, project_dll_src_path, build_config, custom_lib_dir, dependencies);
|
||||
}
|
||||
|
||||
float godot_icall_Internal_EditorScale() {
|
||||
float godot_icall_Globals_EditorScale() {
|
||||
return EDSCALE;
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_Internal_GlobalDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) {
|
||||
MonoObject *godot_icall_Globals_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) {
|
||||
MonoObject *godot_icall_Globals_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);
|
||||
Variant result = _EDITOR_DEF(setting, default_value, (bool)p_restart_if_changed);
|
||||
return GDMonoMarshal::variant_to_mono_object(result);
|
||||
}
|
||||
|
||||
MonoString *godot_icall_Globals_TTR(MonoString *p_text) {
|
||||
String text = GDMonoMarshal::mono_string_to_godot(p_text);
|
||||
return GDMonoMarshal::mono_string_from_godot(TTR(text));
|
||||
}
|
||||
|
||||
MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt() {
|
||||
String error_str = GDMono::get_singleton()->update_api_assemblies_from_prebuilt();
|
||||
return GDMonoMarshal::mono_string_from_godot(error_str);
|
||||
}
|
||||
|
||||
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);
|
||||
@ -269,18 +278,6 @@ MonoBoolean godot_icall_Internal_IsOsxAppBundleInstalled(MonoString *p_bundle_id
|
||||
#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;
|
||||
}
|
||||
@ -402,15 +399,10 @@ void register_editor_internal_calls() {
|
||||
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_UpdateApiAssembliesFromPrebuilt", (void *)godot_icall_Internal_UpdateApiAssembliesFromPrebuilt);
|
||||
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);
|
||||
@ -424,6 +416,12 @@ void register_editor_internal_calls() {
|
||||
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);
|
||||
|
||||
// Globals
|
||||
mono_add_internal_call("GodotTools.Internals.Globals::internal_EditorScale", (void *)godot_icall_Globals_EditorScale);
|
||||
mono_add_internal_call("GodotTools.Internals.Globals::internal_GlobalDef", (void *)godot_icall_Globals_GlobalDef);
|
||||
mono_add_internal_call("GodotTools.Internals.Globals::internal_EditorDef", (void *)godot_icall_Globals_EditorDef);
|
||||
mono_add_internal_call("GodotTools.Internals.Globals::internal_TTR", (void *)godot_icall_Globals_TTR);
|
||||
|
||||
// Utils.OS
|
||||
mono_add_internal_call("GodotTools.Utils.OS::GetPlatformName", (void *)godot_icall_Utils_OS_GetPlatformName);
|
||||
}
|
||||
|
@ -59,10 +59,6 @@
|
||||
#include "android_mono_config.gen.h"
|
||||
#endif
|
||||
|
||||
#define OUT_OF_SYNC_ERR_MESSAGE(m_assembly_name) "The assembly '" m_assembly_name "' is out of sync. " \
|
||||
"This error is expected if you just upgraded to a newer Godot version. " \
|
||||
"Building the project will update the assembly to the correct version."
|
||||
|
||||
GDMono *GDMono::singleton = NULL;
|
||||
|
||||
namespace {
|
||||
@ -304,26 +300,9 @@ void GDMono::initialize() {
|
||||
mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL);
|
||||
|
||||
#ifndef TOOLS_ENABLED
|
||||
if (!DirAccess::exists("res://.mono")) {
|
||||
// 'res://.mono/' is missing so there is nothing to load. We don't need to initialize mono, but
|
||||
// we still do so unless mscorlib is missing (which is the case for projects that don't use C#).
|
||||
|
||||
String mscorlib_fname("mscorlib.dll");
|
||||
|
||||
Vector<String> search_dirs;
|
||||
GDMonoAssembly::fill_search_dirs(search_dirs);
|
||||
|
||||
bool found = false;
|
||||
for (int i = 0; i < search_dirs.size(); i++) {
|
||||
if (FileAccess::exists(search_dirs[i].plus_file(mscorlib_fname))) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return; // mscorlib is missing, do not initialize mono
|
||||
}
|
||||
// Export templates only load the Mono runtime if the project uses it
|
||||
if (!DirAccess::exists("res://.mono"))
|
||||
return;
|
||||
#endif
|
||||
|
||||
root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
|
||||
@ -354,63 +333,48 @@ void GDMono::initialize() {
|
||||
|
||||
_register_internal_calls();
|
||||
|
||||
// The following assemblies are not required at initialization
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
if (_load_api_assemblies()) {
|
||||
// Everything is fine with the api assemblies, load the tools and project assemblies
|
||||
|
||||
#if defined(TOOLS_ENABLED)
|
||||
ERR_EXPLAIN("Mono: Failed to load GodotTools assemblies");
|
||||
ERR_FAIL_COND(!_load_tools_assemblies());
|
||||
#endif
|
||||
|
||||
_load_project_assembly();
|
||||
|
||||
} else {
|
||||
if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated))
|
||||
#ifdef TOOLS_ENABLED
|
||||
|| (editor_api_assembly && editor_api_assembly_out_of_sync)
|
||||
#endif
|
||||
) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
// The assembly was successfully loaded, but the full api could not be cached.
|
||||
// This is most likely an outdated assembly loaded because of an invalid version in the
|
||||
// metadata, so we invalidate the version in the metadata and unload the script domain.
|
||||
|
||||
if (core_api_assembly_out_of_sync) {
|
||||
ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(CORE_API_ASSEMBLY_NAME));
|
||||
metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
|
||||
} else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
|
||||
ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed");
|
||||
metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
|
||||
}
|
||||
|
||||
if (editor_api_assembly_out_of_sync) {
|
||||
ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(EDITOR_API_ASSEMBLY_NAME));
|
||||
metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true);
|
||||
}
|
||||
|
||||
print_line("Mono: Proceeding to unload scripts domain because of invalid API assemblies.");
|
||||
|
||||
Error err = _unload_scripts_domain();
|
||||
if (err != OK) {
|
||||
WARN_PRINT("Mono: Failed to unload scripts domain");
|
||||
}
|
||||
#else
|
||||
ERR_PRINT("The loaded API assembly is invalid");
|
||||
CRASH_NOW();
|
||||
#endif // TOOLS_ENABLED
|
||||
}
|
||||
}
|
||||
#else
|
||||
print_verbose("Mono: Glue disabled, ignoring script assemblies.");
|
||||
#endif // MONO_GLUE_ENABLED
|
||||
|
||||
print_verbose("Mono: INITIALIZED");
|
||||
}
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
void GDMono::initialize_load_assemblies() {
|
||||
|
||||
#ifndef MONO_GLUE_ENABLED
|
||||
ERR_EXPLAIN("Mono: This binary was built with `mono_glue=no`; cannot load assemblies");
|
||||
CRASH_NOW();
|
||||
#endif
|
||||
|
||||
// Load assemblies. The API and tools assemblies are required,
|
||||
// the application is aborted if these assemblies cannot be loaded.
|
||||
|
||||
_load_api_assemblies();
|
||||
|
||||
#if defined(TOOLS_ENABLED)
|
||||
if (!_load_tools_assemblies()) {
|
||||
ERR_EXPLAIN("Mono: Failed to load GodotTools assemblies");
|
||||
CRASH_NOW();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Load the project's main assembly. This doesn't necessarily need to succeed.
|
||||
// The game may not be using .NET at all, or if the project does use .NET and
|
||||
// we're running in the editor, it may just happen to be it wasn't built yet.
|
||||
if (!_load_project_assembly()) {
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
print_error("Mono: Failed to load project assembly");
|
||||
}
|
||||
}
|
||||
|
||||
bool GDMono::_are_api_assemblies_out_of_sync() {
|
||||
bool out_of_sync = core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated);
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!out_of_sync)
|
||||
out_of_sync = editor_api_assembly && editor_api_assembly_out_of_sync;
|
||||
#endif
|
||||
return out_of_sync;
|
||||
}
|
||||
|
||||
namespace GodotSharpBindings {
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
uint64_t get_core_api_hash();
|
||||
#ifdef TOOLS_ENABLED
|
||||
@ -419,13 +383,33 @@ uint64_t get_editor_api_hash();
|
||||
uint32_t get_bindings_version();
|
||||
|
||||
void register_generated_icalls();
|
||||
} // namespace GodotSharpBindings
|
||||
|
||||
#else
|
||||
|
||||
uint64_t get_core_api_hash() {
|
||||
CRASH_NOW();
|
||||
GD_UNREACHABLE();
|
||||
}
|
||||
#ifdef TOOLS_ENABLED
|
||||
uint64_t get_editor_api_hash() {
|
||||
CRASH_NOW();
|
||||
GD_UNREACHABLE();
|
||||
}
|
||||
#endif
|
||||
uint32_t get_bindings_version() {
|
||||
CRASH_NOW();
|
||||
GD_UNREACHABLE();
|
||||
}
|
||||
|
||||
void register_generated_icalls() {
|
||||
/* Fine, just do nothing */
|
||||
}
|
||||
|
||||
#endif // MONO_GLUE_ENABLED
|
||||
} // namespace GodotSharpBindings
|
||||
|
||||
void GDMono::_register_internal_calls() {
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
GodotSharpBindings::register_generated_icalls();
|
||||
#endif
|
||||
}
|
||||
|
||||
void GDMono::_initialize_and_check_api_hashes() {
|
||||
@ -565,12 +549,21 @@ bool GDMono::_load_corlib_assembly() {
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
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) {
|
||||
bool GDMono::copy_prebuilt_api_assembly(APIAssembly::Type p_api_type) {
|
||||
|
||||
bool &api_assembly_out_of_sync = (p_api_type == APIAssembly::API_CORE) ?
|
||||
GDMono::get_singleton()->core_api_assembly_out_of_sync :
|
||||
GDMono::get_singleton()->editor_api_assembly_out_of_sync;
|
||||
|
||||
String src_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug");
|
||||
String dst_dir = GodotSharpDirs::get_res_assemblies_dir();
|
||||
|
||||
String assembly_name = p_api_type == APIAssembly::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
|
||||
|
||||
// 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);
|
||||
if (!DirAccess::exists(dst_dir)) {
|
||||
DirAccess *da = DirAccess::create_for_path(dst_dir);
|
||||
Error err = da->make_dir_recursive(dst_dir);
|
||||
memdelete(da);
|
||||
|
||||
if (err != OK) {
|
||||
@ -579,21 +572,19 @@ static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir,
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
String assembly_file = assembly_name + ".dll";
|
||||
String assembly_src = src_dir.plus_file(assembly_file);
|
||||
String assembly_dst = 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)) {
|
||||
if (!FileAccess::exists(assembly_dst) || api_assembly_out_of_sync) {
|
||||
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)
|
||||
String xml_file = assembly_name + ".xml";
|
||||
if (da->copy(src_dir.plus_file(xml_file), 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)
|
||||
String pdb_file = assembly_name + ".pdb";
|
||||
if (da->copy(src_dir.plus_file(pdb_file), dst_dir.plus_file(pdb_file)) != OK)
|
||||
WARN_PRINTS("Failed to copy " + pdb_file);
|
||||
|
||||
Error err = da->copy(assembly_src, assembly_dst);
|
||||
@ -603,11 +594,46 @@ static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir,
|
||||
return false;
|
||||
}
|
||||
|
||||
GDMono::get_singleton()->metadata_set_api_assembly_invalidated(p_api_type, false);
|
||||
api_assembly_out_of_sync = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String GDMono::update_api_assemblies_from_prebuilt() {
|
||||
|
||||
#define FAIL_REASON(m_out_of_sync, m_prebuilt_exist) \
|
||||
( \
|
||||
(m_out_of_sync ? \
|
||||
String("The assembly is invalidated") : \
|
||||
String("The assembly was not found")) + \
|
||||
(m_prebuilt_exist ? \
|
||||
String(" and the prebuilt assemblies are missing") : \
|
||||
String(" and we failed to copy the prebuilt assemblies")))
|
||||
|
||||
bool api_assembly_out_of_sync = core_api_assembly_out_of_sync || editor_api_assembly_out_of_sync;
|
||||
|
||||
String core_assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(CORE_API_ASSEMBLY_NAME ".dll");
|
||||
String editor_assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
|
||||
|
||||
if (!api_assembly_out_of_sync && FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path))
|
||||
return String(); // No update needed
|
||||
|
||||
String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug");
|
||||
String prebuilt_core_dll_path = prebuilt_api_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
|
||||
String prebuilt_editor_dll_path = prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
|
||||
|
||||
if (!FileAccess::exists(prebuilt_core_dll_path) || !FileAccess::exists(prebuilt_editor_dll_path))
|
||||
return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exist: */ false);
|
||||
|
||||
// Copy the prebuilt Api
|
||||
if (!copy_prebuilt_api_assembly(APIAssembly::API_CORE) || !copy_prebuilt_api_assembly(APIAssembly::API_EDITOR))
|
||||
return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exist: */ true);
|
||||
|
||||
return String(); // Updated successfully
|
||||
|
||||
#undef FAIL_REASON
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GDMono::_load_core_api_assembly() {
|
||||
@ -616,35 +642,15 @@ bool GDMono::_load_core_api_assembly() {
|
||||
return true;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) {
|
||||
String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug");
|
||||
String prebuilt_dll_path = prebuilt_api_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
|
||||
String invalidated_dll_path = get_invalidated_api_assembly_path(APIAssembly::API_CORE);
|
||||
|
||||
if (!FileAccess::exists(prebuilt_dll_path) ||
|
||||
FileAccess::get_modified_time(invalidated_dll_path) == FileAccess::get_modified_time(prebuilt_dll_path)) {
|
||||
print_verbose("Mono: Skipping loading of Core API assembly because it was invalidated");
|
||||
return false;
|
||||
} else {
|
||||
// Copy the prebuilt Api
|
||||
String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
|
||||
if (!copy_api_assembly(prebuilt_api_dir, res_assemblies_dir, CORE_API_ASSEMBLY_NAME, APIAssembly::API_CORE) ||
|
||||
!copy_api_assembly(prebuilt_api_dir, res_assemblies_dir, EDITOR_API_ASSEMBLY_NAME, APIAssembly::API_EDITOR)) {
|
||||
print_verbose("Mono: Failed to copy prebuilt API. Skipping loading of Core API assembly because it was invalidated");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date
|
||||
String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(CORE_API_ASSEMBLY_NAME ".dll");
|
||||
bool success = FileAccess::exists(assembly_path) &&
|
||||
load_assembly_from(CORE_API_ASSEMBLY_NAME, assembly_path, &core_api_assembly);
|
||||
#else
|
||||
bool success = load_assembly(CORE_API_ASSEMBLY_NAME, &core_api_assembly);
|
||||
#endif
|
||||
|
||||
String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(CORE_API_ASSEMBLY_NAME ".dll");
|
||||
|
||||
bool success = (FileAccess::exists(assembly_path) &&
|
||||
load_assembly_from(CORE_API_ASSEMBLY_NAME, assembly_path, &core_api_assembly)) ||
|
||||
load_assembly(CORE_API_ASSEMBLY_NAME, &core_api_assembly);
|
||||
|
||||
if (success) {
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(core_api_assembly, APIAssembly::API_CORE);
|
||||
core_api_assembly_out_of_sync = GodotSharpBindings::get_core_api_hash() != api_assembly_ver.godot_api_hash ||
|
||||
GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
|
||||
@ -654,9 +660,8 @@ bool GDMono::_load_core_api_assembly() {
|
||||
|
||||
_install_trace_listener();
|
||||
}
|
||||
#else
|
||||
GDMonoUtils::update_godot_api_cache();
|
||||
#endif
|
||||
} else {
|
||||
core_api_assembly_out_of_sync = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
@ -668,44 +673,100 @@ bool GDMono::_load_editor_api_assembly() {
|
||||
if (editor_api_assembly)
|
||||
return true;
|
||||
|
||||
if (metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) {
|
||||
String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug");
|
||||
String prebuilt_dll_path = prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
|
||||
String invalidated_dll_path = get_invalidated_api_assembly_path(APIAssembly::API_EDITOR);
|
||||
|
||||
if (!FileAccess::exists(prebuilt_dll_path) ||
|
||||
FileAccess::get_modified_time(invalidated_dll_path) == FileAccess::get_modified_time(prebuilt_dll_path)) {
|
||||
print_verbose("Mono: Skipping loading of Editor API assembly because it was invalidated");
|
||||
return false;
|
||||
} else {
|
||||
// Copy the prebuilt editor Api (no need to copy the core api if we got to this point)
|
||||
String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
|
||||
if (!copy_api_assembly(prebuilt_api_dir, res_assemblies_dir, EDITOR_API_ASSEMBLY_NAME, APIAssembly::API_EDITOR)) {
|
||||
print_verbose("Mono: Failed to copy prebuilt API. Skipping loading of Editor API assembly because it was invalidated");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date
|
||||
String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
|
||||
|
||||
bool success = (FileAccess::exists(assembly_path) &&
|
||||
load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &editor_api_assembly)) ||
|
||||
load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly);
|
||||
bool success = FileAccess::exists(assembly_path) &&
|
||||
load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &editor_api_assembly);
|
||||
|
||||
if (success) {
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(editor_api_assembly, APIAssembly::API_EDITOR);
|
||||
editor_api_assembly_out_of_sync = GodotSharpBindings::get_editor_api_hash() != api_assembly_ver.godot_api_hash ||
|
||||
GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
|
||||
CS_GLUE_VERSION != api_assembly_ver.cs_glue_version;
|
||||
#endif
|
||||
} else {
|
||||
editor_api_assembly_out_of_sync = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GDMono::_try_load_api_assemblies() {
|
||||
|
||||
if (!_load_core_api_assembly()) {
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
print_error("Mono: Failed to load Core API assembly");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)
|
||||
return false;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!_load_editor_api_assembly()) {
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
print_error("Mono: Failed to load Editor API assembly");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (editor_api_assembly_out_of_sync)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GDMono::_load_api_assemblies() {
|
||||
|
||||
if (!_try_load_api_assemblies()) {
|
||||
// The API assemblies are out of sync. Fine, try one more time, but this time
|
||||
// update them from the prebuilt assemblies directory before trying to load them.
|
||||
|
||||
// 1. Unload the scripts domain
|
||||
if (_unload_scripts_domain() != OK) {
|
||||
ERR_EXPLAIN("Mono: Failed to unload scripts domain");
|
||||
CRASH_NOW();
|
||||
}
|
||||
|
||||
// 2. Update the API assemblies
|
||||
String update_error = update_api_assemblies_from_prebuilt();
|
||||
if (!update_error.empty()) {
|
||||
ERR_EXPLAIN(update_error);
|
||||
CRASH_NOW();
|
||||
}
|
||||
|
||||
// 3. Load the scripts domain again
|
||||
if (_load_scripts_domain() != OK) {
|
||||
ERR_EXPLAIN("Mono: Failed to load scripts domain");
|
||||
CRASH_NOW();
|
||||
}
|
||||
|
||||
// 4. Try loading the updated assemblies
|
||||
if (!_try_load_api_assemblies()) {
|
||||
// welp... too bad
|
||||
|
||||
if (_are_api_assemblies_out_of_sync()) {
|
||||
if (core_api_assembly_out_of_sync) {
|
||||
ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync");
|
||||
} else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
|
||||
ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed");
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (editor_api_assembly_out_of_sync) {
|
||||
ERR_PRINT("The assembly '" EDITOR_API_ASSEMBLY_NAME "' is out of sync");
|
||||
}
|
||||
#endif
|
||||
|
||||
CRASH_NOW();
|
||||
} else {
|
||||
ERR_EXPLAIN("Failed to load one of the API assemblies");
|
||||
CRASH_NOW();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
bool GDMono::_load_tools_assemblies() {
|
||||
|
||||
@ -734,39 +795,11 @@ bool GDMono::_load_project_assembly() {
|
||||
|
||||
if (success) {
|
||||
mono_assembly_set_main(project_assembly->get_assembly());
|
||||
} else {
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
print_error("Mono: Failed to load project assembly");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GDMono::_load_api_assemblies() {
|
||||
|
||||
if (!_load_core_api_assembly()) {
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
print_error("Mono: Failed to load Core API assembly");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)
|
||||
return false;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!_load_editor_api_assembly()) {
|
||||
if (OS::get_singleton()->is_stdout_verbose())
|
||||
print_error("Mono: Failed to load Editor API assembly");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (editor_api_assembly_out_of_sync)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GDMono::_install_trace_listener() {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
@ -784,78 +817,6 @@ void GDMono::_install_trace_listener() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
String GDMono::_get_api_assembly_metadata_path() {
|
||||
|
||||
return GodotSharpDirs::get_res_metadata_dir().plus_file("api_assemblies.cfg");
|
||||
}
|
||||
|
||||
void GDMono::metadata_set_api_assembly_invalidated(APIAssembly::Type p_api_type, bool p_invalidated) {
|
||||
|
||||
String section = APIAssembly::to_string(p_api_type);
|
||||
String path = _get_api_assembly_metadata_path();
|
||||
|
||||
Ref<ConfigFile> metadata;
|
||||
metadata.instance();
|
||||
metadata->load(path);
|
||||
|
||||
metadata->set_value(section, "invalidated", p_invalidated);
|
||||
|
||||
String assembly_path = GodotSharpDirs::get_res_assemblies_dir()
|
||||
.plus_file(p_api_type == APIAssembly::API_CORE ?
|
||||
CORE_API_ASSEMBLY_NAME ".dll" :
|
||||
EDITOR_API_ASSEMBLY_NAME ".dll");
|
||||
|
||||
ERR_FAIL_COND(!FileAccess::exists(assembly_path));
|
||||
|
||||
uint64_t modified_time = FileAccess::get_modified_time(assembly_path);
|
||||
|
||||
metadata->set_value(section, "invalidated_asm_modified_time", String::num_uint64(modified_time));
|
||||
|
||||
String dir = path.get_base_dir();
|
||||
if (!DirAccess::exists(dir)) {
|
||||
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
ERR_FAIL_COND(!da);
|
||||
Error err = da->make_dir_recursive(ProjectSettings::get_singleton()->globalize_path(dir));
|
||||
ERR_FAIL_COND(err != OK);
|
||||
}
|
||||
|
||||
Error save_err = metadata->save(path);
|
||||
ERR_FAIL_COND(save_err != OK);
|
||||
}
|
||||
|
||||
bool GDMono::metadata_is_api_assembly_invalidated(APIAssembly::Type p_api_type) {
|
||||
|
||||
String section = APIAssembly::to_string(p_api_type);
|
||||
|
||||
Ref<ConfigFile> metadata;
|
||||
metadata.instance();
|
||||
metadata->load(_get_api_assembly_metadata_path());
|
||||
|
||||
String assembly_path = GodotSharpDirs::get_res_assemblies_dir()
|
||||
.plus_file(p_api_type == APIAssembly::API_CORE ?
|
||||
CORE_API_ASSEMBLY_NAME ".dll" :
|
||||
EDITOR_API_ASSEMBLY_NAME ".dll");
|
||||
|
||||
if (!FileAccess::exists(assembly_path))
|
||||
return false;
|
||||
|
||||
uint64_t modified_time = FileAccess::get_modified_time(assembly_path);
|
||||
|
||||
uint64_t stored_modified_time = metadata->get_value(section, "invalidated_asm_modified_time", 0);
|
||||
|
||||
return metadata->get_value(section, "invalidated", false) && modified_time <= stored_modified_time;
|
||||
}
|
||||
|
||||
String GDMono::get_invalidated_api_assembly_path(APIAssembly::Type p_api_type) {
|
||||
|
||||
return GodotSharpDirs::get_res_assemblies_dir()
|
||||
.plus_file(p_api_type == APIAssembly::API_CORE ?
|
||||
CORE_API_ASSEMBLY_NAME ".dll" :
|
||||
EDITOR_API_ASSEMBLY_NAME ".dll");
|
||||
}
|
||||
#endif
|
||||
|
||||
Error GDMono::_load_scripts_domain() {
|
||||
|
||||
ERR_FAIL_COND_V(scripts_domain != NULL, ERR_BUG);
|
||||
@ -903,11 +864,6 @@ Error GDMono::_unload_scripts_domain() {
|
||||
tools_project_editor_assembly = NULL;
|
||||
#endif
|
||||
|
||||
core_api_assembly_out_of_sync = false;
|
||||
#ifdef TOOLS_ENABLED
|
||||
editor_api_assembly_out_of_sync = false;
|
||||
#endif
|
||||
|
||||
MonoDomain *domain = scripts_domain;
|
||||
scripts_domain = NULL;
|
||||
|
||||
@ -944,57 +900,25 @@ Error GDMono::reload_scripts_domain() {
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
if (!_load_api_assemblies()) {
|
||||
if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated))
|
||||
#ifdef TOOLS_ENABLED
|
||||
|| (editor_api_assembly && editor_api_assembly_out_of_sync)
|
||||
#endif
|
||||
) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
// The assembly was successfully loaded, but the full api could not be cached.
|
||||
// This is most likely an outdated assembly loaded because of an invalid version in the
|
||||
// metadata, so we invalidate the version in the metadata and unload the script domain.
|
||||
// Load assemblies. The API and tools assemblies are required,
|
||||
// the application is aborted if these assemblies cannot be loaded.
|
||||
|
||||
if (core_api_assembly_out_of_sync) {
|
||||
ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(CORE_API_ASSEMBLY_NAME));
|
||||
metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
|
||||
} else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
|
||||
ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed");
|
||||
metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
|
||||
}
|
||||
_load_api_assemblies();
|
||||
|
||||
if (editor_api_assembly_out_of_sync) {
|
||||
ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(EDITOR_API_ASSEMBLY_NAME));
|
||||
metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true);
|
||||
}
|
||||
|
||||
err = _unload_scripts_domain();
|
||||
if (err != OK) {
|
||||
WARN_PRINT("Mono: Failed to unload scripts domain");
|
||||
}
|
||||
|
||||
return ERR_CANT_RESOLVE;
|
||||
#else
|
||||
ERR_PRINT("The loaded API assembly is invalid");
|
||||
CRASH_NOW();
|
||||
#endif
|
||||
} else {
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
#if defined(TOOLS_ENABLED)
|
||||
if (!_load_tools_assemblies()) {
|
||||
ERR_EXPLAIN("Mono: Failed to load GodotTools assemblies");
|
||||
CRASH_NOW();
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
ERR_EXPLAIN("Mono: Failed to load GodotTools assemblies");
|
||||
ERR_FAIL_COND_V(!_load_tools_assemblies(), ERR_CANT_OPEN);
|
||||
#endif
|
||||
|
||||
// Load the project's main assembly. Here, during hot-reloading, we do
|
||||
// consider failing to load the project's main assembly to be an error.
|
||||
// However, unlike the API and tools assemblies, the application can continue working.
|
||||
if (!_load_project_assembly()) {
|
||||
print_error("Mono: Failed to load project assembly");
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
#else
|
||||
print_verbose("Mono: Glue disabled, ignoring script assemblies.");
|
||||
#endif // MONO_GLUE_ENABLED
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
@ -104,6 +104,8 @@ class GDMono {
|
||||
|
||||
void _domain_assemblies_cleanup(uint32_t p_domain_id);
|
||||
|
||||
bool _are_api_assemblies_out_of_sync();
|
||||
|
||||
bool _load_corlib_assembly();
|
||||
bool _load_core_api_assembly();
|
||||
#ifdef TOOLS_ENABLED
|
||||
@ -112,11 +114,8 @@ class GDMono {
|
||||
#endif
|
||||
bool _load_project_assembly();
|
||||
|
||||
bool _load_api_assemblies();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
String _get_api_assembly_metadata_path();
|
||||
#endif
|
||||
bool _try_load_api_assemblies();
|
||||
void _load_api_assemblies();
|
||||
|
||||
void _install_trace_listener();
|
||||
|
||||
@ -157,9 +156,8 @@ public:
|
||||
#endif
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void metadata_set_api_assembly_invalidated(APIAssembly::Type p_api_type, bool p_invalidated);
|
||||
bool metadata_is_api_assembly_invalidated(APIAssembly::Type p_api_type);
|
||||
String get_invalidated_api_assembly_path(APIAssembly::Type p_api_type);
|
||||
bool copy_prebuilt_api_assembly(APIAssembly::Type p_api_type);
|
||||
String update_api_assemblies_from_prebuilt();
|
||||
#endif
|
||||
|
||||
static GDMono *get_singleton() { return singleton; }
|
||||
@ -203,6 +201,7 @@ public:
|
||||
Error finalize_and_unload_domain(MonoDomain *p_domain);
|
||||
|
||||
void initialize();
|
||||
void initialize_load_assemblies();
|
||||
|
||||
GDMono();
|
||||
~GDMono();
|
||||
|
Loading…
Reference in New Issue
Block a user