C#: Fix detection of outdated release Godot API assemblies
This commit is contained in:
parent
f4afaecdd1
commit
8c438a2197
@ -160,9 +160,16 @@ namespace GodotTools
|
|||||||
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
|
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
|
||||||
return true; // No solution to build
|
return true; // No solution to build
|
||||||
|
|
||||||
// Make sure to update the API assemblies if they happen to be missing. Just in
|
// Make sure the API assemblies are up to date before building the project.
|
||||||
// case the user decided to delete them at some point after they were loaded.
|
// We may not have had the chance to update the release API assemblies, and the debug ones
|
||||||
Internal.UpdateApiAssembliesFromPrebuilt();
|
// may have been deleted by the user at some point after they were loaded by the Godot editor.
|
||||||
|
string apiAssembliesUpdateError = Internal.UpdateApiAssembliesFromPrebuilt(config == "Release" ? "Release" : "Debug");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(apiAssembliesUpdateError))
|
||||||
|
{
|
||||||
|
ShowBuildErrorDialog("Failed to update the Godot API assemblies");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
|
var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
|
||||||
var buildTool = (BuildTool) editorSettings.GetSetting("mono/builds/build_tool");
|
var buildTool = (BuildTool) editorSettings.GetSetting("mono/builds/build_tool");
|
||||||
|
@ -34,7 +34,7 @@ namespace GodotTools
|
|||||||
|
|
||||||
private bool CreateProjectSolution()
|
private bool CreateProjectSolution()
|
||||||
{
|
{
|
||||||
using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 2))
|
using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 3))
|
||||||
{
|
{
|
||||||
pr.Step("Generating C# project...".TTR());
|
pr.Step("Generating C# project...".TTR());
|
||||||
|
|
||||||
@ -73,9 +73,23 @@ namespace GodotTools
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure to update the API assemblies if they happen to be missing. Just in
|
pr.Step("Updating Godot API assemblies...".TTR());
|
||||||
// case the user decided to delete them at some point after they were loaded.
|
|
||||||
Internal.UpdateApiAssembliesFromPrebuilt();
|
string debugApiAssembliesError = Internal.UpdateApiAssembliesFromPrebuilt("Debug");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(debugApiAssembliesError))
|
||||||
|
{
|
||||||
|
ShowErrorDialog("Failed to update the Godot API assemblies: " + debugApiAssembliesError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string releaseApiAssembliesError = Internal.UpdateApiAssembliesFromPrebuilt("Release");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(releaseApiAssembliesError))
|
||||||
|
{
|
||||||
|
ShowErrorDialog("Failed to update the Godot API assemblies: " + releaseApiAssembliesError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pr.Step("Done".TTR());
|
pr.Step("Done".TTR());
|
||||||
|
|
||||||
|
@ -40,8 +40,7 @@ namespace GodotTools.Ides
|
|||||||
|
|
||||||
protected ILogger Logger
|
protected ILogger Logger
|
||||||
{
|
{
|
||||||
get => logger ?? (logger = new ConsoleLogger());
|
get => logger ?? (logger = new GodotLogger());
|
||||||
set => logger = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartServer()
|
private void StartServer()
|
||||||
|
@ -10,8 +10,8 @@ namespace GodotTools.Internals
|
|||||||
public const string CSharpLanguageType = "CSharpScript";
|
public const string CSharpLanguageType = "CSharpScript";
|
||||||
public const string CSharpLanguageExtension = "cs";
|
public const string CSharpLanguageExtension = "cs";
|
||||||
|
|
||||||
public static string UpdateApiAssembliesFromPrebuilt() =>
|
public static string UpdateApiAssembliesFromPrebuilt(string config) =>
|
||||||
internal_UpdateApiAssembliesFromPrebuilt();
|
internal_UpdateApiAssembliesFromPrebuilt(config);
|
||||||
|
|
||||||
public static string FullTemplatesDir =>
|
public static string FullTemplatesDir =>
|
||||||
internal_FullTemplatesDir();
|
internal_FullTemplatesDir();
|
||||||
@ -55,7 +55,7 @@ namespace GodotTools.Internals
|
|||||||
// Internal Calls
|
// Internal Calls
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern string internal_UpdateApiAssembliesFromPrebuilt();
|
private static extern string internal_UpdateApiAssembliesFromPrebuilt(string config);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern string internal_FullTemplatesDir();
|
private static extern string internal_FullTemplatesDir();
|
||||||
|
@ -75,7 +75,7 @@ bool generate_api_solution(const String &p_solution_dir, const String &p_core_pr
|
|||||||
p_editor_proj_dir, p_editor_compile_items,
|
p_editor_proj_dir, p_editor_compile_items,
|
||||||
GDMono::get_singleton()->get_tools_project_editor_assembly());
|
GDMono::get_singleton()->get_tools_project_editor_assembly());
|
||||||
} else {
|
} else {
|
||||||
MonoDomain *temp_domain = GDMonoUtils::create_domain("GodotEngine.ApiSolutionGenerationDomain");
|
MonoDomain *temp_domain = GDMonoUtils::create_domain("GodotEngine.Domain.ApiSolutionGeneration");
|
||||||
CRASH_COND(temp_domain == NULL);
|
CRASH_COND(temp_domain == NULL);
|
||||||
_GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(temp_domain);
|
_GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(temp_domain);
|
||||||
|
|
||||||
|
@ -230,31 +230,9 @@ 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);
|
return GodotSharpExport::get_exported_assembly_dependencies(project_dll_name, project_dll_src_path, build_config, custom_lib_dir, dependencies);
|
||||||
}
|
}
|
||||||
|
|
||||||
float godot_icall_Globals_EditorScale() {
|
MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt(MonoString *p_config) {
|
||||||
return EDSCALE;
|
String config = GDMonoMarshal::mono_string_to_godot(p_config);
|
||||||
}
|
String error_str = GDMono::get_singleton()->update_api_assemblies_from_prebuilt(config);
|
||||||
|
|
||||||
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_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 = _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);
|
return GDMonoMarshal::mono_string_from_godot(error_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,6 +343,29 @@ void godot_icall_Internal_ScriptEditorDebugger_ReloadScripts() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float godot_icall_Globals_EditorScale() {
|
||||||
|
return EDSCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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 = _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_Utils_OS_GetPlatformName() {
|
MonoString *godot_icall_Utils_OS_GetPlatformName() {
|
||||||
String os_name = OS::get_singleton()->get_name();
|
String os_name = OS::get_singleton()->get_name();
|
||||||
return GDMonoMarshal::mono_string_from_godot(os_name);
|
return GDMonoMarshal::mono_string_from_godot(os_name);
|
||||||
|
@ -32,9 +32,13 @@
|
|||||||
|
|
||||||
#include <mono/metadata/image.h>
|
#include <mono/metadata/image.h>
|
||||||
|
|
||||||
|
#include "core/os/os.h"
|
||||||
|
|
||||||
#include "../mono_gd/gd_mono.h"
|
#include "../mono_gd/gd_mono.h"
|
||||||
#include "../mono_gd/gd_mono_assembly.h"
|
#include "../mono_gd/gd_mono_assembly.h"
|
||||||
|
|
||||||
|
namespace GodotSharpExport {
|
||||||
|
|
||||||
String get_assemblyref_name(MonoImage *p_image, int index) {
|
String get_assemblyref_name(MonoImage *p_image, int index) {
|
||||||
const MonoTableInfo *table_info = mono_image_get_table_info(p_image, MONO_TABLE_ASSEMBLYREF);
|
const MonoTableInfo *table_info = mono_image_get_table_info(p_image, MONO_TABLE_ASSEMBLYREF);
|
||||||
|
|
||||||
@ -45,7 +49,7 @@ String get_assemblyref_name(MonoImage *p_image, int index) {
|
|||||||
return String::utf8(mono_metadata_string_heap(p_image, cols[MONO_ASSEMBLYREF_NAME]));
|
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, Dictionary &r_dependencies) {
|
Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_dependencies) {
|
||||||
MonoImage *image = p_assembly->get_image();
|
MonoImage *image = p_assembly->get_image();
|
||||||
|
|
||||||
for (int i = 0; i < mono_image_get_table_rows(image, MONO_TABLE_ASSEMBLYREF); i++) {
|
for (int i = 0; i < mono_image_get_table_rows(image, MONO_TABLE_ASSEMBLYREF); i++) {
|
||||||
@ -96,8 +100,8 @@ Error GodotSharpExport::get_assembly_dependencies(GDMonoAssembly *p_assembly, co
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
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_bcl_dir, Dictionary &r_dependencies) {
|
||||||
MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain");
|
MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.Domain.ProjectExport");
|
||||||
ERR_FAIL_NULL_V(export_domain, FAILED);
|
ERR_FAIL_NULL_V(export_domain, FAILED);
|
||||||
_GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain);
|
_GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain);
|
||||||
|
|
||||||
@ -110,7 +114,9 @@ Error GodotSharpExport::get_exported_assembly_dependencies(const String &p_proje
|
|||||||
ERR_FAIL_COND_V_MSG(!load_success, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + p_project_dll_name + "'.");
|
ERR_FAIL_COND_V_MSG(!load_success, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + p_project_dll_name + "'.");
|
||||||
|
|
||||||
Vector<String> search_dirs;
|
Vector<String> search_dirs;
|
||||||
GDMonoAssembly::fill_search_dirs(search_dirs, p_build_config, p_custom_lib_dir);
|
GDMonoAssembly::fill_search_dirs(search_dirs, p_build_config, p_custom_bcl_dir);
|
||||||
|
|
||||||
return get_assembly_dependencies(scripts_assembly, search_dirs, r_dependencies);
|
return get_assembly_dependencies(scripts_assembly, search_dirs, r_dependencies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace GodotSharpExport
|
||||||
|
@ -39,10 +39,11 @@
|
|||||||
|
|
||||||
namespace GodotSharpExport {
|
namespace GodotSharpExport {
|
||||||
|
|
||||||
|
Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_dependencies);
|
||||||
|
|
||||||
Error get_exported_assembly_dependencies(const String &p_project_dll_name,
|
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_project_dll_src_path, const String &p_build_config,
|
||||||
const String &p_custom_lib_dir, Dictionary &r_dependencies);
|
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);
|
|
||||||
|
|
||||||
} // namespace GodotSharpExport
|
} // namespace GodotSharpExport
|
||||||
|
|
||||||
|
@ -43,6 +43,8 @@
|
|||||||
#include "utils/android_utils.h"
|
#include "utils/android_utils.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "mono_gd/gd_mono.h"
|
||||||
|
|
||||||
namespace GodotSharpDirs {
|
namespace GodotSharpDirs {
|
||||||
|
|
||||||
String _get_expected_build_config() {
|
String _get_expected_build_config() {
|
||||||
@ -59,20 +61,6 @@ String _get_expected_build_config() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
String _get_expected_api_build_config() {
|
|
||||||
#ifdef TOOLS_ENABLED
|
|
||||||
return "Debug";
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
|
||||||
return "Debug";
|
|
||||||
#else
|
|
||||||
return "Release";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
String _get_mono_user_dir() {
|
String _get_mono_user_dir() {
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
if (EditorSettings::get_singleton()) {
|
if (EditorSettings::get_singleton()) {
|
||||||
@ -134,7 +122,7 @@ private:
|
|||||||
res_data_dir = "res://.mono";
|
res_data_dir = "res://.mono";
|
||||||
res_metadata_dir = res_data_dir.plus_file("metadata");
|
res_metadata_dir = res_data_dir.plus_file("metadata");
|
||||||
res_assemblies_base_dir = res_data_dir.plus_file("assemblies");
|
res_assemblies_base_dir = res_data_dir.plus_file("assemblies");
|
||||||
res_assemblies_dir = res_assemblies_base_dir.plus_file(_get_expected_api_build_config());
|
res_assemblies_dir = res_assemblies_base_dir.plus_file(GDMono::get_expected_api_build_config());
|
||||||
res_config_dir = res_data_dir.plus_file("etc").plus_file("mono");
|
res_config_dir = res_data_dir.plus_file("etc").plus_file("mono");
|
||||||
|
|
||||||
// TODO use paths from csproj
|
// TODO use paths from csproj
|
||||||
|
@ -381,10 +381,10 @@ void GDMono::initialize_load_assemblies() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GDMono::_are_api_assemblies_out_of_sync() {
|
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);
|
bool out_of_sync = core_api_assembly.assembly && (core_api_assembly.out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated);
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
if (!out_of_sync)
|
if (!out_of_sync)
|
||||||
out_of_sync = editor_api_assembly && editor_api_assembly_out_of_sync;
|
out_of_sync = editor_api_assembly.assembly && editor_api_assembly.out_of_sync;
|
||||||
#endif
|
#endif
|
||||||
return out_of_sync;
|
return out_of_sync;
|
||||||
}
|
}
|
||||||
@ -523,10 +523,10 @@ bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMo
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
APIAssembly::Version APIAssembly::Version::get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, APIAssembly::Type p_api_type) {
|
ApiAssemblyInfo::Version ApiAssemblyInfo::Version::get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, ApiAssemblyInfo::Type p_api_type) {
|
||||||
APIAssembly::Version api_assembly_version;
|
ApiAssemblyInfo::Version api_assembly_version;
|
||||||
|
|
||||||
const char *nativecalls_name = p_api_type == APIAssembly::API_CORE ?
|
const char *nativecalls_name = p_api_type == ApiAssemblyInfo::API_CORE ?
|
||||||
BINDINGS_CLASS_NATIVECALLS :
|
BINDINGS_CLASS_NATIVECALLS :
|
||||||
BINDINGS_CLASS_NATIVECALLS_EDITOR;
|
BINDINGS_CLASS_NATIVECALLS_EDITOR;
|
||||||
|
|
||||||
@ -549,8 +549,8 @@ APIAssembly::Version APIAssembly::Version::get_from_loaded_assembly(GDMonoAssemb
|
|||||||
return api_assembly_version;
|
return api_assembly_version;
|
||||||
}
|
}
|
||||||
|
|
||||||
String APIAssembly::to_string(APIAssembly::Type p_type) {
|
String ApiAssemblyInfo::to_string(ApiAssemblyInfo::Type p_type) {
|
||||||
return p_type == APIAssembly::API_CORE ? "API_CORE" : "API_EDITOR";
|
return p_type == ApiAssemblyInfo::API_CORE ? "API_CORE" : "API_EDITOR";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GDMono::_load_corlib_assembly() {
|
bool GDMono::_load_corlib_assembly() {
|
||||||
@ -567,16 +567,12 @@ bool GDMono::_load_corlib_assembly() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
bool GDMono::copy_prebuilt_api_assembly(APIAssembly::Type p_api_type, const String &p_config) {
|
bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const String &p_config) {
|
||||||
|
|
||||||
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(p_config);
|
String src_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
|
||||||
String dst_dir = GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config);
|
String dst_dir = GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config);
|
||||||
|
|
||||||
String assembly_name = p_api_type == APIAssembly::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
|
String assembly_name = p_api_type == ApiAssemblyInfo::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
|
||||||
|
|
||||||
// Create destination directory if needed
|
// Create destination directory if needed
|
||||||
if (!DirAccess::exists(dst_dir)) {
|
if (!DirAccess::exists(dst_dir)) {
|
||||||
@ -590,35 +586,102 @@ bool GDMono::copy_prebuilt_api_assembly(APIAssembly::Type p_api_type, const Stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||||
|
|
||||||
|
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 = 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 + "'.");
|
||||||
|
|
||||||
String assembly_file = assembly_name + ".dll";
|
String assembly_file = assembly_name + ".dll";
|
||||||
String assembly_src = src_dir.plus_file(assembly_file);
|
if (da->copy(src_dir.plus_file(assembly_file), dst_dir.plus_file(assembly_file)) != OK) {
|
||||||
String assembly_dst = dst_dir.plus_file(assembly_file);
|
ERR_PRINTS("Failed to copy '" + assembly_file + "'.");
|
||||||
|
return false;
|
||||||
if (!FileAccess::exists(assembly_dst) || api_assembly_out_of_sync) {
|
|
||||||
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
|
||||||
|
|
||||||
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 = 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);
|
|
||||||
|
|
||||||
if (err != OK) {
|
|
||||||
ERR_PRINTS("Failed to copy '" + assembly_file + "'.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
api_assembly_out_of_sync = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String GDMono::update_api_assemblies_from_prebuilt() {
|
static bool try_get_cached_api_hash_for(const String &p_api_assemblies_dir, bool &r_out_of_sync) {
|
||||||
|
String core_api_assembly_path = p_api_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
|
||||||
|
String editor_api_assembly_path = p_api_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
|
||||||
|
|
||||||
|
if (!FileAccess::exists(core_api_assembly_path) || !FileAccess::exists(editor_api_assembly_path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg");
|
||||||
|
|
||||||
|
if (!FileAccess::exists(cached_api_hash_path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Ref<ConfigFile> cfg;
|
||||||
|
cfg.instance();
|
||||||
|
Error cfg_err = cfg->load(cached_api_hash_path);
|
||||||
|
ERR_FAIL_COND_V(cfg_err != OK, false);
|
||||||
|
|
||||||
|
// Checking the modified time is good enough
|
||||||
|
if (FileAccess::get_modified_time(core_api_assembly_path) != (uint64_t)cfg->get_value("core", "modified_time") ||
|
||||||
|
FileAccess::get_modified_time(editor_api_assembly_path) != (uint64_t)cfg->get_value("editor", "modified_time")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
r_out_of_sync = GodotSharpBindings::get_bindings_version() != (uint32_t)cfg->get_value("core", "bindings_version") ||
|
||||||
|
GodotSharpBindings::get_cs_glue_version() != (uint32_t)cfg->get_value("core", "cs_glue_version") ||
|
||||||
|
GodotSharpBindings::get_bindings_version() != (uint32_t)cfg->get_value("editor", "bindings_version") ||
|
||||||
|
GodotSharpBindings::get_cs_glue_version() != (uint32_t)cfg->get_value("editor", "cs_glue_version") ||
|
||||||
|
GodotSharpBindings::get_core_api_hash() != (uint64_t)cfg->get_value("core", "api_hash") ||
|
||||||
|
GodotSharpBindings::get_editor_api_hash() != (uint64_t)cfg->get_value("editor", "api_hash");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_cached_api_hash_for(const String &p_api_assemblies_dir) {
|
||||||
|
|
||||||
|
String core_api_assembly_path = p_api_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
|
||||||
|
String editor_api_assembly_path = p_api_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
|
||||||
|
String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg");
|
||||||
|
|
||||||
|
Ref<ConfigFile> cfg;
|
||||||
|
cfg.instance();
|
||||||
|
|
||||||
|
cfg->set_value("core", "modified_time", FileAccess::get_modified_time(core_api_assembly_path));
|
||||||
|
cfg->set_value("editor", "modified_time", FileAccess::get_modified_time(editor_api_assembly_path));
|
||||||
|
|
||||||
|
cfg->set_value("core", "bindings_version", GodotSharpBindings::get_bindings_version());
|
||||||
|
cfg->set_value("core", "cs_glue_version", GodotSharpBindings::get_cs_glue_version());
|
||||||
|
cfg->set_value("editor", "bindings_version", GodotSharpBindings::get_bindings_version());
|
||||||
|
cfg->set_value("editor", "cs_glue_version", GodotSharpBindings::get_cs_glue_version());
|
||||||
|
|
||||||
|
// This assumes the prebuilt api assemblies we copied to the project are not out of sync
|
||||||
|
cfg->set_value("core", "api_hash", GodotSharpBindings::get_core_api_hash());
|
||||||
|
cfg->set_value("editor", "api_hash", GodotSharpBindings::get_editor_api_hash());
|
||||||
|
|
||||||
|
Error err = cfg->save(cached_api_hash_path);
|
||||||
|
ERR_FAIL_COND(err != OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GDMono::_temp_domain_load_are_assemblies_out_of_sync(const String &p_config) {
|
||||||
|
MonoDomain *temp_domain = GDMonoUtils::create_domain("GodotEngine.Domain.CheckApiAssemblies");
|
||||||
|
ERR_FAIL_NULL_V(temp_domain, "Failed to create temporary domain to check API assemblies");
|
||||||
|
_GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(temp_domain);
|
||||||
|
|
||||||
|
_GDMONO_SCOPE_DOMAIN_(temp_domain);
|
||||||
|
|
||||||
|
GDMono::LoadedApiAssembly temp_core_api_assembly;
|
||||||
|
GDMono::LoadedApiAssembly temp_editor_api_assembly;
|
||||||
|
|
||||||
|
if (!_try_load_api_assemblies(temp_core_api_assembly, temp_editor_api_assembly,
|
||||||
|
p_config, /* refonly: */ true, /* loaded_callback: */ NULL)) {
|
||||||
|
return temp_core_api_assembly.out_of_sync || temp_editor_api_assembly.out_of_sync;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // Failed to load, assume they're outdated assemblies
|
||||||
|
}
|
||||||
|
|
||||||
|
String GDMono::update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync, const bool *p_editor_api_out_of_sync) {
|
||||||
|
|
||||||
#define FAIL_REASON(m_out_of_sync, m_prebuilt_exists) \
|
#define FAIL_REASON(m_out_of_sync, m_prebuilt_exists) \
|
||||||
( \
|
( \
|
||||||
@ -629,46 +692,55 @@ String GDMono::update_api_assemblies_from_prebuilt() {
|
|||||||
String("and the prebuilt assemblies are missing.") : \
|
String("and the prebuilt assemblies are missing.") : \
|
||||||
String("and we failed to copy the prebuilt assemblies.")))
|
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 dst_assemblies_dir = GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config);
|
||||||
|
|
||||||
String core_assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(CORE_API_ASSEMBLY_NAME ".dll");
|
String core_assembly_path = dst_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");
|
String editor_assembly_path = dst_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))
|
bool api_assemblies_out_of_sync = false;
|
||||||
return String(); // No update needed
|
|
||||||
|
|
||||||
const int CONFIGS_LEN = 2;
|
if (p_core_api_out_of_sync && p_editor_api_out_of_sync) {
|
||||||
String configs[CONFIGS_LEN] = { String("Debug"), String("Release") };
|
api_assemblies_out_of_sync = p_core_api_out_of_sync || p_editor_api_out_of_sync;
|
||||||
|
} else if (FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path)) {
|
||||||
for (int i = 0; i < CONFIGS_LEN; i++) {
|
// Determine if they're out of sync
|
||||||
String config = configs[i];
|
if (!try_get_cached_api_hash_for(dst_assemblies_dir, api_assemblies_out_of_sync)) {
|
||||||
|
api_assemblies_out_of_sync = _temp_domain_load_are_assemblies_out_of_sync(p_config);
|
||||||
print_verbose("Updating '" + config + "' API assemblies");
|
|
||||||
|
|
||||||
String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(config);
|
|
||||||
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_exists: */ false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the prebuilt Api
|
|
||||||
if (!copy_prebuilt_api_assembly(APIAssembly::API_CORE, config) ||
|
|
||||||
!copy_prebuilt_api_assembly(APIAssembly::API_EDITOR, config)) {
|
|
||||||
return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exists: */ true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: Even if only one of the assemblies if missing or out of sync, we update both
|
||||||
|
|
||||||
|
if (!api_assemblies_out_of_sync && FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path))
|
||||||
|
return String(); // No update needed
|
||||||
|
|
||||||
|
print_verbose("Updating '" + p_config + "' API assemblies");
|
||||||
|
|
||||||
|
String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
|
||||||
|
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_assemblies_out_of_sync, /* prebuilt_exists: */ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the prebuilt Api
|
||||||
|
if (!copy_prebuilt_api_assembly(ApiAssemblyInfo::API_CORE, p_config) ||
|
||||||
|
!copy_prebuilt_api_assembly(ApiAssemblyInfo::API_EDITOR, p_config)) {
|
||||||
|
return FAIL_REASON(api_assemblies_out_of_sync, /* prebuilt_exists: */ true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache the api hash of the assemblies we just copied
|
||||||
|
create_cached_api_hash_for(dst_assemblies_dir);
|
||||||
|
|
||||||
return String(); // Updated successfully
|
return String(); // Updated successfully
|
||||||
|
|
||||||
#undef FAIL_REASON
|
#undef FAIL_REASON
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool GDMono::_load_core_api_assembly() {
|
bool GDMono::_load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly) {
|
||||||
|
|
||||||
if (core_api_assembly)
|
if (r_loaded_api_assembly.assembly)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
@ -676,101 +748,115 @@ bool GDMono::_load_core_api_assembly() {
|
|||||||
|
|
||||||
// If running the project manager, load it from the prebuilt API directory
|
// If running the project manager, load it from the prebuilt API directory
|
||||||
String assembly_dir = !Main::is_project_manager() ?
|
String assembly_dir = !Main::is_project_manager() ?
|
||||||
GodotSharpDirs::get_res_assemblies_dir() :
|
GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config) :
|
||||||
GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug");
|
GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
|
||||||
|
|
||||||
String assembly_path = assembly_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
|
String assembly_path = assembly_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
|
||||||
|
|
||||||
bool success = FileAccess::exists(assembly_path) &&
|
bool success = FileAccess::exists(assembly_path) &&
|
||||||
load_assembly_from(CORE_API_ASSEMBLY_NAME, assembly_path, &core_api_assembly);
|
load_assembly_from(CORE_API_ASSEMBLY_NAME, assembly_path, &r_loaded_api_assembly.assembly, p_refonly);
|
||||||
#else
|
#else
|
||||||
bool success = load_assembly(CORE_API_ASSEMBLY_NAME, &core_api_assembly);
|
bool success = load_assembly(CORE_API_ASSEMBLY_NAME, &core_api_assembly, p_refonly);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(core_api_assembly, APIAssembly::API_CORE);
|
ApiAssemblyInfo::Version api_assembly_ver = ApiAssemblyInfo::Version::get_from_loaded_assembly(r_loaded_api_assembly.assembly, ApiAssemblyInfo::API_CORE);
|
||||||
core_api_assembly_out_of_sync = GodotSharpBindings::get_core_api_hash() != api_assembly_ver.godot_api_hash ||
|
r_loaded_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 ||
|
GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
|
||||||
GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
|
GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
|
||||||
if (!core_api_assembly_out_of_sync) {
|
|
||||||
GDMonoUtils::update_godot_api_cache();
|
|
||||||
|
|
||||||
_install_trace_listener();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
core_api_assembly_out_of_sync = false;
|
r_loaded_api_assembly.out_of_sync = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
bool GDMono::_load_editor_api_assembly() {
|
bool GDMono::_load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly) {
|
||||||
|
|
||||||
if (editor_api_assembly)
|
if (r_loaded_api_assembly.assembly)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// 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
|
// 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
|
||||||
|
|
||||||
// If running the project manager, load it from the prebuilt API directory
|
// If running the project manager, load it from the prebuilt API directory
|
||||||
String assembly_dir = !Main::is_project_manager() ?
|
String assembly_dir = !Main::is_project_manager() ?
|
||||||
GodotSharpDirs::get_res_assemblies_dir() :
|
GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config) :
|
||||||
GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug");
|
GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
|
||||||
|
|
||||||
String assembly_path = assembly_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
|
String assembly_path = assembly_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
|
||||||
|
|
||||||
bool success = FileAccess::exists(assembly_path) &&
|
bool success = FileAccess::exists(assembly_path) &&
|
||||||
load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &editor_api_assembly);
|
load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &r_loaded_api_assembly.assembly, p_refonly);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(editor_api_assembly, APIAssembly::API_EDITOR);
|
ApiAssemblyInfo::Version api_assembly_ver = ApiAssemblyInfo::Version::get_from_loaded_assembly(r_loaded_api_assembly.assembly, ApiAssemblyInfo::API_EDITOR);
|
||||||
editor_api_assembly_out_of_sync = GodotSharpBindings::get_editor_api_hash() != api_assembly_ver.godot_api_hash ||
|
r_loaded_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 ||
|
GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
|
||||||
GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
|
GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
|
||||||
} else {
|
} else {
|
||||||
editor_api_assembly_out_of_sync = false;
|
r_loaded_api_assembly.out_of_sync = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool GDMono::_try_load_api_assemblies() {
|
bool GDMono::_try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, LoadedApiAssembly &r_editor_api_assembly,
|
||||||
|
const String &p_config, bool p_refonly, CoreApiAssemblyLoadedCallback p_callback) {
|
||||||
if (!_load_core_api_assembly()) {
|
if (!_load_core_api_assembly(r_core_api_assembly, p_config, p_refonly)) {
|
||||||
if (OS::get_singleton()->is_stdout_verbose())
|
if (OS::get_singleton()->is_stdout_verbose())
|
||||||
print_error("Mono: Failed to load Core API assembly");
|
print_error("Mono: Failed to load Core API assembly");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
if (!_load_editor_api_assembly()) {
|
if (!_load_editor_api_assembly(r_editor_api_assembly, p_config, p_refonly)) {
|
||||||
if (OS::get_singleton()->is_stdout_verbose())
|
if (OS::get_singleton()->is_stdout_verbose())
|
||||||
print_error("Mono: Failed to load Editor API assembly");
|
print_error("Mono: Failed to load Editor API assembly");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editor_api_assembly_out_of_sync)
|
if (r_editor_api_assembly.out_of_sync)
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Check if the core API assembly is out of sync only after trying to load the
|
// Check if the core API assembly is out of sync only after trying to load the
|
||||||
// editor API assembly. Otherwise, if both assemblies are out of sync, we would
|
// editor API assembly. Otherwise, if both assemblies are out of sync, we would
|
||||||
// only update the former as we won't know the latter also needs to be updated.
|
// only update the former as we won't know the latter also needs to be updated.
|
||||||
if (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)
|
if (r_core_api_assembly.out_of_sync)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (p_callback)
|
||||||
|
return p_callback();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GDMono::_on_core_api_assembly_loaded() {
|
||||||
|
GDMonoUtils::update_godot_api_cache();
|
||||||
|
|
||||||
|
if (!GDMonoUtils::mono_cache.godot_api_cache_updated)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
get_singleton()->_install_trace_listener();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GDMono::_try_load_api_assemblies_preset() {
|
||||||
|
return _try_load_api_assemblies(core_api_assembly, editor_api_assembly,
|
||||||
|
get_expected_api_build_config(), /* refonly: */ false, _on_core_api_assembly_loaded);
|
||||||
|
}
|
||||||
|
|
||||||
void GDMono::_load_api_assemblies() {
|
void GDMono::_load_api_assemblies() {
|
||||||
|
|
||||||
bool api_assemblies_loaded = _try_load_api_assemblies();
|
bool api_assemblies_loaded = _try_load_api_assemblies_preset();
|
||||||
|
|
||||||
if (!api_assemblies_loaded) {
|
if (!api_assemblies_loaded) {
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
// The API assemblies are out of sync. Fine, try one more time, but this time
|
// The API assemblies are out of sync or some other error happened. Fine, try one more time, but
|
||||||
// update them from the prebuilt assemblies directory before trying to load them.
|
// this time update them from the prebuilt assemblies directory before trying to load them again.
|
||||||
|
|
||||||
// Shouldn't happen. The project manager loads the prebuilt API assemblies
|
// Shouldn't happen. The project manager loads the prebuilt API assemblies
|
||||||
CRASH_COND_MSG(Main::is_project_manager(), "Failed to load one of the prebuilt API assemblies.");
|
CRASH_COND_MSG(Main::is_project_manager(), "Failed to load one of the prebuilt API assemblies.");
|
||||||
@ -780,7 +866,7 @@ void GDMono::_load_api_assemblies() {
|
|||||||
CRASH_COND_MSG(domain_unload_err != OK, "Mono: Failed to unload scripts domain.");
|
CRASH_COND_MSG(domain_unload_err != OK, "Mono: Failed to unload scripts domain.");
|
||||||
|
|
||||||
// 2. Update the API assemblies
|
// 2. Update the API assemblies
|
||||||
String update_error = update_api_assemblies_from_prebuilt();
|
String update_error = update_api_assemblies_from_prebuilt("Debug", &core_api_assembly.out_of_sync, &editor_api_assembly.out_of_sync);
|
||||||
CRASH_COND_MSG(!update_error.empty(), update_error);
|
CRASH_COND_MSG(!update_error.empty(), update_error);
|
||||||
|
|
||||||
// 3. Load the scripts domain again
|
// 3. Load the scripts domain again
|
||||||
@ -788,7 +874,7 @@ void GDMono::_load_api_assemblies() {
|
|||||||
CRASH_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
|
CRASH_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
|
||||||
|
|
||||||
// 4. Try loading the updated assemblies
|
// 4. Try loading the updated assemblies
|
||||||
api_assemblies_loaded = _try_load_api_assemblies();
|
api_assemblies_loaded = _try_load_api_assemblies_preset();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -796,14 +882,14 @@ void GDMono::_load_api_assemblies() {
|
|||||||
// welp... too bad
|
// welp... too bad
|
||||||
|
|
||||||
if (_are_api_assemblies_out_of_sync()) {
|
if (_are_api_assemblies_out_of_sync()) {
|
||||||
if (core_api_assembly_out_of_sync) {
|
if (core_api_assembly.out_of_sync) {
|
||||||
ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync.");
|
ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync.");
|
||||||
} else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
|
} 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.");
|
ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
if (editor_api_assembly_out_of_sync) {
|
if (editor_api_assembly.out_of_sync) {
|
||||||
ERR_PRINT("The assembly '" EDITOR_API_ASSEMBLY_NAME "' is out of sync.");
|
ERR_PRINT("The assembly '" EDITOR_API_ASSEMBLY_NAME "' is out of sync.");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -852,15 +938,14 @@ void GDMono::_install_trace_listener() {
|
|||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
// Install the trace listener now before the project assembly is loaded
|
// Install the trace listener now before the project assembly is loaded
|
||||||
typedef void (*DebuggingUtils_InstallTraceListener)(MonoObject **);
|
GDMonoClass *debug_utils = get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, "DebuggingUtils");
|
||||||
|
GDMonoMethod *install_func = debug_utils->get_method("InstallTraceListener");
|
||||||
|
|
||||||
MonoException *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
GDMonoClass *debug_utils = core_api_assembly->get_class(BINDINGS_NAMESPACE, "DebuggingUtils");
|
install_func->invoke_raw(NULL, NULL, &exc);
|
||||||
DebuggingUtils_InstallTraceListener install_func =
|
|
||||||
(DebuggingUtils_InstallTraceListener)debug_utils->get_method_thunk("InstallTraceListener");
|
|
||||||
install_func((MonoObject **)&exc);
|
|
||||||
if (exc) {
|
if (exc) {
|
||||||
ERR_PRINT("Failed to install 'System.Diagnostics.Trace' listener.");
|
|
||||||
GDMonoUtils::debug_print_unhandled_exception(exc);
|
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||||
|
ERR_PRINT("Failed to install 'System.Diagnostics.Trace' listener.");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -871,7 +956,7 @@ Error GDMono::_load_scripts_domain() {
|
|||||||
|
|
||||||
print_verbose("Mono: Loading scripts domain...");
|
print_verbose("Mono: Loading scripts domain...");
|
||||||
|
|
||||||
scripts_domain = GDMonoUtils::create_domain("GodotEngine.ScriptsDomain");
|
scripts_domain = GDMonoUtils::create_domain("GodotEngine.Domain.Scripts");
|
||||||
|
|
||||||
ERR_FAIL_NULL_V_MSG(scripts_domain, ERR_CANT_CREATE, "Mono: Could not create scripts app domain.");
|
ERR_FAIL_NULL_V_MSG(scripts_domain, ERR_CANT_CREATE, "Mono: Could not create scripts app domain.");
|
||||||
|
|
||||||
@ -903,10 +988,8 @@ Error GDMono::_unload_scripts_domain() {
|
|||||||
|
|
||||||
_domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
|
_domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
|
||||||
|
|
||||||
core_api_assembly = NULL;
|
|
||||||
project_assembly = NULL;
|
project_assembly = NULL;
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
editor_api_assembly = NULL;
|
|
||||||
tools_assembly = NULL;
|
tools_assembly = NULL;
|
||||||
tools_project_editor_assembly = NULL;
|
tools_project_editor_assembly = NULL;
|
||||||
#endif
|
#endif
|
||||||
@ -1076,16 +1159,9 @@ GDMono::GDMono() {
|
|||||||
root_domain = NULL;
|
root_domain = NULL;
|
||||||
scripts_domain = NULL;
|
scripts_domain = NULL;
|
||||||
|
|
||||||
core_api_assembly_out_of_sync = false;
|
|
||||||
#ifdef TOOLS_ENABLED
|
|
||||||
editor_api_assembly_out_of_sync = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
corlib_assembly = NULL;
|
corlib_assembly = NULL;
|
||||||
core_api_assembly = NULL;
|
|
||||||
project_assembly = NULL;
|
project_assembly = NULL;
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
editor_api_assembly = NULL;
|
|
||||||
tools_assembly = NULL;
|
tools_assembly = NULL;
|
||||||
tools_project_editor_assembly = NULL;
|
tools_project_editor_assembly = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
#include "../utils/mono_reg_utils.h"
|
#include "../utils/mono_reg_utils.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace APIAssembly {
|
namespace ApiAssemblyInfo {
|
||||||
enum Type {
|
enum Type {
|
||||||
API_CORE,
|
API_CORE,
|
||||||
API_EDITOR
|
API_EDITOR
|
||||||
@ -76,7 +76,7 @@ struct Version {
|
|||||||
};
|
};
|
||||||
|
|
||||||
String to_string(Type p_type);
|
String to_string(Type p_type);
|
||||||
} // namespace APIAssembly
|
} // namespace ApiAssemblyInfo
|
||||||
|
|
||||||
class GDMono {
|
class GDMono {
|
||||||
|
|
||||||
@ -86,44 +86,58 @@ public:
|
|||||||
POLICY_LOG_ERROR
|
POLICY_LOG_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LoadedApiAssembly {
|
||||||
|
GDMonoAssembly *assembly;
|
||||||
|
bool out_of_sync;
|
||||||
|
|
||||||
|
LoadedApiAssembly() :
|
||||||
|
assembly(NULL),
|
||||||
|
out_of_sync(false) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool runtime_initialized;
|
bool runtime_initialized;
|
||||||
bool finalizing_scripts_domain;
|
bool finalizing_scripts_domain;
|
||||||
|
|
||||||
|
UnhandledExceptionPolicy unhandled_exception_policy;
|
||||||
|
|
||||||
MonoDomain *root_domain;
|
MonoDomain *root_domain;
|
||||||
MonoDomain *scripts_domain;
|
MonoDomain *scripts_domain;
|
||||||
|
|
||||||
bool core_api_assembly_out_of_sync;
|
HashMap<uint32_t, HashMap<String, GDMonoAssembly *> > assemblies;
|
||||||
#ifdef TOOLS_ENABLED
|
|
||||||
bool editor_api_assembly_out_of_sync;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GDMonoAssembly *corlib_assembly;
|
GDMonoAssembly *corlib_assembly;
|
||||||
GDMonoAssembly *core_api_assembly;
|
|
||||||
GDMonoAssembly *project_assembly;
|
GDMonoAssembly *project_assembly;
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
GDMonoAssembly *editor_api_assembly;
|
|
||||||
GDMonoAssembly *tools_assembly;
|
GDMonoAssembly *tools_assembly;
|
||||||
GDMonoAssembly *tools_project_editor_assembly;
|
GDMonoAssembly *tools_project_editor_assembly;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
HashMap<uint32_t, HashMap<String, GDMonoAssembly *> > assemblies;
|
LoadedApiAssembly core_api_assembly;
|
||||||
|
LoadedApiAssembly editor_api_assembly;
|
||||||
|
|
||||||
UnhandledExceptionPolicy unhandled_exception_policy;
|
typedef bool (*CoreApiAssemblyLoadedCallback)();
|
||||||
|
|
||||||
void _domain_assemblies_cleanup(uint32_t p_domain_id);
|
|
||||||
|
|
||||||
bool _are_api_assemblies_out_of_sync();
|
bool _are_api_assemblies_out_of_sync();
|
||||||
|
bool _temp_domain_load_are_assemblies_out_of_sync(const String &p_config);
|
||||||
|
|
||||||
|
bool _load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly);
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
bool _load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool _on_core_api_assembly_loaded();
|
||||||
|
|
||||||
bool _load_corlib_assembly();
|
bool _load_corlib_assembly();
|
||||||
bool _load_core_api_assembly();
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
bool _load_editor_api_assembly();
|
|
||||||
bool _load_tools_assemblies();
|
bool _load_tools_assemblies();
|
||||||
#endif
|
#endif
|
||||||
bool _load_project_assembly();
|
bool _load_project_assembly();
|
||||||
|
|
||||||
bool _try_load_api_assemblies();
|
bool _try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, LoadedApiAssembly &r_editor_api_assembly,
|
||||||
|
const String &p_config, bool p_refonly, CoreApiAssemblyLoadedCallback p_callback);
|
||||||
|
bool _try_load_api_assemblies_preset();
|
||||||
void _load_api_assemblies();
|
void _load_api_assemblies();
|
||||||
|
|
||||||
void _install_trace_listener();
|
void _install_trace_listener();
|
||||||
@ -133,6 +147,8 @@ private:
|
|||||||
Error _load_scripts_domain();
|
Error _load_scripts_domain();
|
||||||
Error _unload_scripts_domain();
|
Error _unload_scripts_domain();
|
||||||
|
|
||||||
|
void _domain_assemblies_cleanup(uint32_t p_domain_id);
|
||||||
|
|
||||||
uint64_t api_core_hash;
|
uint64_t api_core_hash;
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
uint64_t api_editor_hash;
|
uint64_t api_editor_hash;
|
||||||
@ -166,9 +182,21 @@ public:
|
|||||||
#endif // TOOLS_ENABLED
|
#endif // TOOLS_ENABLED
|
||||||
#endif // DEBUG_METHODS_ENABLED
|
#endif // DEBUG_METHODS_ENABLED
|
||||||
|
|
||||||
|
_FORCE_INLINE_ static String get_expected_api_build_config() {
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
bool copy_prebuilt_api_assembly(APIAssembly::Type p_api_type, const String &p_config);
|
return "Debug";
|
||||||
String update_api_assemblies_from_prebuilt();
|
#else
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
return "Debug";
|
||||||
|
#else
|
||||||
|
return "Release";
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
bool copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const String &p_config);
|
||||||
|
String update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync = NULL, const bool *p_editor_api_out_of_sync = NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static GDMono *get_singleton() { return singleton; }
|
static GDMono *get_singleton() { return singleton; }
|
||||||
@ -188,10 +216,10 @@ public:
|
|||||||
_FORCE_INLINE_ MonoDomain *get_scripts_domain() { return scripts_domain; }
|
_FORCE_INLINE_ MonoDomain *get_scripts_domain() { return scripts_domain; }
|
||||||
|
|
||||||
_FORCE_INLINE_ GDMonoAssembly *get_corlib_assembly() const { return corlib_assembly; }
|
_FORCE_INLINE_ GDMonoAssembly *get_corlib_assembly() const { return corlib_assembly; }
|
||||||
_FORCE_INLINE_ GDMonoAssembly *get_core_api_assembly() const { return core_api_assembly; }
|
_FORCE_INLINE_ GDMonoAssembly *get_core_api_assembly() const { return core_api_assembly.assembly; }
|
||||||
_FORCE_INLINE_ GDMonoAssembly *get_project_assembly() const { return project_assembly; }
|
_FORCE_INLINE_ GDMonoAssembly *get_project_assembly() const { return project_assembly; }
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
_FORCE_INLINE_ GDMonoAssembly *get_editor_api_assembly() const { return editor_api_assembly; }
|
_FORCE_INLINE_ GDMonoAssembly *get_editor_api_assembly() const { return editor_api_assembly.assembly; }
|
||||||
_FORCE_INLINE_ GDMonoAssembly *get_tools_assembly() const { return tools_assembly; }
|
_FORCE_INLINE_ GDMonoAssembly *get_tools_assembly() const { return tools_assembly; }
|
||||||
_FORCE_INLINE_ GDMonoAssembly *get_tools_project_editor_assembly() const { return tools_project_editor_assembly; }
|
_FORCE_INLINE_ GDMonoAssembly *get_tools_project_editor_assembly() const { return tools_project_editor_assembly; }
|
||||||
#endif
|
#endif
|
||||||
|
@ -550,6 +550,8 @@ MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class)
|
|||||||
}
|
}
|
||||||
|
|
||||||
MonoDomain *create_domain(const String &p_friendly_name) {
|
MonoDomain *create_domain(const String &p_friendly_name) {
|
||||||
|
print_verbose("Mono: Creating domain '" + p_friendly_name + "'...");
|
||||||
|
|
||||||
MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL);
|
MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL);
|
||||||
|
|
||||||
if (domain) {
|
if (domain) {
|
||||||
|
Loading…
Reference in New Issue
Block a user