diff options
Diffstat (limited to 'modules/mono')
-rw-r--r-- | modules/mono/SCsub | 5 | ||||
-rw-r--r-- | modules/mono/csharp_script.cpp | 139 | ||||
-rw-r--r-- | modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs | 12 | ||||
-rw-r--r-- | modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs | 5 | ||||
-rw-r--r-- | modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs | 4 | ||||
-rw-r--r-- | modules/mono/editor/godotsharp_builds.cpp | 62 | ||||
-rw-r--r-- | modules/mono/editor/godotsharp_editor.cpp | 4 | ||||
-rw-r--r-- | modules/mono/mono_gd/gd_mono.cpp | 41 | ||||
-rw-r--r-- | modules/mono/mono_gd/gd_mono.h | 2 | ||||
-rw-r--r-- | modules/mono/mono_gd/gd_mono_assembly.cpp | 97 | ||||
-rw-r--r-- | modules/mono/mono_gd/gd_mono_assembly.h | 8 | ||||
-rw-r--r-- | modules/mono/mono_gd/gd_mono_field.cpp | 4 | ||||
-rw-r--r-- | modules/mono/mono_gd/gd_mono_marshal.cpp | 55 | ||||
-rw-r--r-- | modules/mono/mono_gd/gd_mono_marshal.h | 19 | ||||
-rw-r--r-- | modules/mono/mono_reg_utils.py | 6 |
15 files changed, 298 insertions, 165 deletions
diff --git a/modules/mono/SCsub b/modules/mono/SCsub index 0af2056c5c..caf4fdb3ca 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -2,9 +2,10 @@ Import('env') +from compat import byte_to_str def make_cs_files_header(src, dst): - with open(dst, 'wb') as header: + with open(dst, 'w') as header: header.write('/* This is an automatically generated file; DO NOT EDIT! OK THX */\n') header.write('#ifndef _CS_FILES_DATA_H\n') header.write('#define _CS_FILES_DATA_H\n\n') @@ -26,7 +27,7 @@ def make_cs_files_header(src, dst): for i, buf_idx in enumerate(range(len(buf))): if i > 0: header.write(', ') - header.write(str(ord(buf[buf_idx]))) + header.write(byte_to_str(buf[buf_idx])) inserted_files += '\tr_files.insert(\"' + file + '\", ' \ 'CompressedFile(_cs_' + name + '_compressed_size, ' \ '_cs_' + name + '_uncompressed_size, ' \ diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 67b4e67e2b..fe78ce423c 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -50,6 +50,21 @@ #define CACHED_STRING_NAME(m_var) (CSharpLanguage::get_singleton()->string_names.m_var) +static bool _create_project_solution_if_needed() { + + String sln_path = GodotSharpDirs::get_project_sln_path(); + String csproj_path = GodotSharpDirs::get_project_csproj_path(); + + if (!FileAccess::exists(sln_path) || !FileAccess::exists(csproj_path)) { + // A solution does not yet exist, create a new one + + CRASH_COND(GodotSharpEditor::get_singleton() == NULL); + return GodotSharpEditor::get_singleton()->call("_create_project_solution"); + } + + return true; +} + CSharpLanguage *CSharpLanguage::singleton = NULL; String CSharpLanguage::get_name() const { @@ -767,7 +782,7 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) { if (method) { MonoObject *ret = method->invoke(mono_object, args); - if (ret && UNBOX_BOOLEAN(ret)) + if (ret && GDMonoMarshal::unbox<MonoBoolean>(ret) == true) return true; } @@ -1186,8 +1201,6 @@ bool CSharpScript::_update_exports() { exported_members_cache.clear(); exported_members_defval_cache.clear(); - const Vector<GDMonoField *> &fields = script_class->get_all_fields(); - // We are creating a temporary new instance of the class here to get the default value // TODO Workaround. Should be replaced with IL opcodes analysis @@ -1211,36 +1224,47 @@ bool CSharpScript::_update_exports() { return false; } - for (int i = 0; i < fields.size(); i++) { - GDMonoField *field = fields[i]; + GDMonoClass *top = script_class; - if (field->is_static() || field->get_visibility() != GDMono::PUBLIC) - continue; + while (top && top != native) { + const Vector<GDMonoField *> &fields = top->get_all_fields(); + + for (int i = 0; i < fields.size(); i++) { + GDMonoField *field = fields[i]; - String name = field->get_name(); - StringName cname = name; + if (field->is_static() || field->get_visibility() != GDMono::PUBLIC) + continue; - Variant::Type type = GDMonoMarshal::managed_to_variant_type(field->get_type()); + String name = field->get_name(); + StringName cname = name; - if (field->has_attribute(CACHED_CLASS(ExportAttribute))) { - MonoObject *attr = field->get_attribute(CACHED_CLASS(ExportAttribute)); + if (member_info.has(cname)) + continue; - // Field has Export attribute - int hint = CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr); - String hint_string = CACHED_FIELD(ExportAttribute, hint_string)->get_string_value(attr); - int usage = CACHED_FIELD(ExportAttribute, usage)->get_int_value(attr); + Variant::Type type = GDMonoMarshal::managed_to_variant_type(field->get_type()); - PropertyInfo prop_info = PropertyInfo(type, name, PropertyHint(hint), hint_string, PropertyUsageFlags(usage)); + if (field->has_attribute(CACHED_CLASS(ExportAttribute))) { + MonoObject *attr = field->get_attribute(CACHED_CLASS(ExportAttribute)); - member_info[cname] = prop_info; - exported_members_cache.push_back(prop_info); + // Field has Export attribute + int hint = CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr); + String hint_string = CACHED_FIELD(ExportAttribute, hint_string)->get_string_value(attr); + int usage = CACHED_FIELD(ExportAttribute, usage)->get_int_value(attr); - if (tmp_object) { - exported_members_defval_cache[cname] = GDMonoMarshal::mono_object_to_variant(field->get_value(tmp_object)); + PropertyInfo prop_info = PropertyInfo(type, name, PropertyHint(hint), hint_string, PropertyUsageFlags(usage)); + + member_info[cname] = prop_info; + exported_members_cache.push_back(prop_info); + + if (tmp_object) { + exported_members_defval_cache[cname] = GDMonoMarshal::mono_object_to_variant(field->get_value(tmp_object)); + } + } else { + member_info[cname] = PropertyInfo(type, name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE); } - } else { - member_info[cname] = PropertyInfo(type, name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE); } + + top = top->get_parent_class(); } } @@ -1359,7 +1383,18 @@ Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class) { bool CSharpScript::can_instance() const { - // TODO does the second condition even make sense? +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + if (_create_project_solution_if_needed()) { + CSharpProject::add_item(GodotSharpDirs::get_project_csproj_path(), + "Compile", + ProjectSettings::get_singleton()->globalize_path(get_path())); + } else { + ERR_PRINTS("Cannot add " + get_path() + " to the C# project because it could not be created."); + } + } +#endif + return valid || (!tool && !ScriptServer::is_scripting_enabled()); } @@ -1545,6 +1580,18 @@ Error CSharpScript::reload(bool p_keep_state) { if (project_assembly) { script_class = project_assembly->get_object_derived_class(name); + + if (!script_class) { + ERR_PRINTS("Cannot find class " + name + " for script " + get_path()); + } +#ifdef DEBUG_ENABLED + else if (OS::get_singleton()->is_stdout_verbose()) { + OS::get_singleton()->print(String("Found class " + script_class->get_namespace() + "." + + script_class->get_name() + " for script " + get_path() + "\n") + .utf8()); + } +#endif + valid = script_class != NULL; if (script_class) { @@ -1757,6 +1804,31 @@ RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p #endif script->set_path(p_original_path); + +#ifndef TOOLS_ENABLED + +#ifdef DEBUG_ENABLED + // User is responsible for thread attach/detach + ERR_EXPLAIN("Thread is not attached"); + CRASH_COND(mono_domain_get() == NULL); +#endif + +#else + if (Engine::get_singleton()->is_editor_hint() && mono_domain_get() == NULL) { + + CRASH_COND(Thread::get_caller_id() == Thread::get_main_id()); + + // Thread is not attached, but we will make an exception in this case + // because this may be called by one of the editor's worker threads. + // Attach this thread temporarily to reload the script. + + MonoThread *mono_thread = mono_thread_attach(SCRIPTS_DOMAIN); + CRASH_COND(mono_thread == NULL); + script->reload(); + mono_thread_detach(mono_thread); + + } else // just reload it normally +#endif script->reload(); if (r_error) @@ -1791,21 +1863,12 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r if (!FileAccess::exists(p_path)) { // The file does not yet exists, let's assume the user just created this script - String sln_path = GodotSharpDirs::get_project_sln_path(); - String csproj_path = GodotSharpDirs::get_project_csproj_path(); - - if (!FileAccess::exists(sln_path) || !FileAccess::exists(csproj_path)) { - // A solution does not yet exist, create a new one - - CRASH_COND(GodotSharpEditor::get_singleton() == NULL); - GodotSharpEditor::get_singleton()->call("_create_project_solution"); - } - - // Add the file to the C# project - if (FileAccess::exists(csproj_path)) { - CSharpProject::add_item(csproj_path, "Compile", ProjectSettings::get_singleton()->globalize_path(p_path)); + if (_create_project_solution_if_needed()) { + CSharpProject::add_item(GodotSharpDirs::get_project_csproj_path(), + "Compile", + ProjectSettings::get_singleton()->globalize_path(p_path)); } else { - ERR_PRINT("C# project not found!"); + ERR_PRINTS("Cannot add " + p_path + " to the C# project because it could not be created."); } } #endif diff --git a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs index 256e64ddde..5544233eb7 100644 --- a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs +++ b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs @@ -19,7 +19,15 @@ namespace GodotSharpTools.Build private static string MSBuildPath { - get { return godot_icall_BuildInstance_get_MSBuildPath(); } + get + { + string ret = godot_icall_BuildInstance_get_MSBuildPath(); + + if (ret == null) + throw new FileNotFoundException("Cannot find the MSBuild executable."); + + return ret; + } } private string solution; @@ -98,7 +106,7 @@ namespace GodotSharpTools.Build private string BuildArguments(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties) { - string arguments = string.Format("{0} /v:normal /t:Build /p:{1} /l:{2},{3};{4}", + string arguments = string.Format(@"""{0}"" /v:normal /t:Build ""/p:{1}"" ""/l:{2},{3};{4}""", solution, "Configuration=" + config, typeof(GodotBuildLogger).FullName, diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs index 6a97731539..f00ec5a2ad 100644 --- a/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs +++ b/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs @@ -27,12 +27,15 @@ namespace GodotSharpTools.Project return false; } - public static void AddItemChecked(this ProjectRootElement root, string itemType, string include) + public static bool AddItemChecked(this ProjectRootElement root, string itemType, string include) { if (!root.HasItem(itemType, include)) { root.AddItem(itemType, include); + return true; } + + return false; } public static Guid GetGuid(this ProjectRootElement root) diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs index a50b4fb064..6889ea715f 100644 --- a/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs +++ b/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs @@ -10,8 +10,8 @@ namespace GodotSharpTools.Project { var dir = Directory.GetParent(projectPath).FullName; var root = ProjectRootElement.Open(projectPath); - root.AddItemChecked(itemType, include.RelativeToPath(dir).Replace("/", "\\")); - root.Save(); + if (root.AddItemChecked(itemType, include.RelativeToPath(dir).Replace("/", "\\"))) + root.Save(); } } } diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index e7d9c83421..1bad8a3f85 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -29,13 +29,14 @@ /*************************************************************************/ #include "godotsharp_builds.h" +#include "main/main.h" + #include "../godotsharp_dirs.h" #include "../mono_gd/gd_mono_class.h" #include "../mono_gd/gd_mono_marshal.h" #include "../utils/path_utils.h" #include "bindings_generator.h" #include "godotsharp_editor.h" -#include "main/main.h" void godot_icall_BuildInstance_ExitCallback(MonoString *p_solution, MonoString *p_config, int p_exit_code) { @@ -44,11 +45,37 @@ void godot_icall_BuildInstance_ExitCallback(MonoString *p_solution, MonoString * GodotSharpBuilds::get_singleton()->build_exit_callback(MonoBuildInfo(solution, config), p_exit_code); } +#ifdef UNIX_ENABLED +String _find_build_engine_on_unix(const String &p_name) { + String ret = path_which(p_name); + + if (ret.length()) + return ret; + + const char *locations[] = { +#ifdef OSX_ENABLED + "/Library/Frameworks/Mono.framework/Versions/Current/bin/", +#endif + "/opt/novell/mono/bin/" + }; + + for (int i = 0; i < sizeof(locations) / sizeof(const char *); i++) { + String location = locations[i]; + + if (FileAccess::exists(location + p_name)) { + return location; + } + } + + return String(); +} +#endif + MonoString *godot_icall_BuildInstance_get_MSBuildPath() { GodotSharpBuilds::BuildTool build_tool = GodotSharpBuilds::BuildTool(int(EditorSettings::get_singleton()->get("mono/builds/build_tool"))); -#ifdef WINDOWS_ENABLED +#if defined(WINDOWS_ENABLED) switch (build_tool) { case GodotSharpBuilds::MSBUILD: { static String msbuild_tools_path = MonoRegUtils::find_msbuild_tools_path(); @@ -84,14 +111,25 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() { ERR_EXPLAIN("You don't deserve to live"); CRASH_NOW(); } -#else - static bool msbuild_found = path_which("msbuild").length(); - - if (build_tool != GodotSharpBuilds::XBUILD && !msbuild_found) { - WARN_PRINT("Cannot find msbuild ('mono/builds/build_tool')."); +#elif defined(UNIX_ENABLED) + static String msbuild_path = _find_build_engine_on_unix("msbuild"); + static String xbuild_path = _find_build_engine_on_unix("xbuild"); + + if (build_tool != GodotSharpBuilds::XBUILD) { + if (msbuild_path.empty()) { + WARN_PRINT("Cannot find msbuild ('mono/builds/build_tool')."); + return NULL; + } + } else { + if (xbuild_path.empty()) { + WARN_PRINT("Cannot find xbuild ('mono/builds/build_tool')."); + return NULL; + } } - return GDMonoMarshal::mono_string_from_godot(build_tool != GodotSharpBuilds::XBUILD ? "msbuild" : "xbuild"); + return GDMonoMarshal::mono_string_from_godot(build_tool != GodotSharpBuilds::XBUILD ? msbuild_path : xbuild_path); +#else + return NULL; #endif } @@ -314,8 +352,8 @@ GodotSharpBuilds::GodotSharpBuilds() { // Build tool settings EditorSettings *ed_settings = EditorSettings::get_singleton(); - if (!ed_settings->has("mono/builds/build_tool")) { - ed_settings->set("mono/builds/build_tool", MSBUILD); + if (!ed_settings->has_setting("mono/builds/build_tool")) { + ed_settings->set_setting("mono/builds/build_tool", MSBUILD); } ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/builds/build_tool", PROPERTY_HINT_ENUM, "MSBuild (System),MSBuild (Mono),xbuild")); } @@ -423,6 +461,10 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) { if (p_blocking) { exited = true; exit_code = klass->get_field("exitCode")->get_int_value(mono_object); + + if (exit_code != 0 && OS::get_singleton()->is_stdout_verbose()) + OS::get_singleton()->print(String("MSBuild finished with exit code " + itos(exit_code) + "\n").utf8()); + build_tab->on_build_exit(exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR); } else { build_instance = MonoGCHandle::create_strong(mono_object); diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index 5aaf029495..30e7653256 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -237,8 +237,8 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { // External editor settings EditorSettings *ed_settings = EditorSettings::get_singleton(); - if (!ed_settings->has("mono/editor/external_editor")) { - ed_settings->set("mono/editor/external_editor", EDITOR_NONE); + if (!ed_settings->has_setting("mono/editor/external_editor")) { + ed_settings->set_setting("mono/editor/external_editor", EDITOR_NONE); } ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/editor/external_editor", PROPERTY_HINT_ENUM, "None,MonoDevelop,Visual Studio,Visual Studio Code")); } diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 77f01842bb..2c88832998 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -31,6 +31,7 @@ #include <mono/metadata/mono-config.h> #include <mono/metadata/mono-debug.h> +#include <mono/metadata/mono-gc.h> #include "os/dir_access.h" #include "os/file_access.h" @@ -265,6 +266,13 @@ void GDMono::add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly) { assemblies[p_domain_id][p_assembly->get_name()] = p_assembly; } +GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) { + + MonoDomain *domain = mono_domain_get(); + uint32_t domain_id = domain ? mono_domain_get_id(domain) : 0; + return assemblies[domain_id].getptr(p_name); +} + bool GDMono::_load_assembly(const String &p_name, GDMonoAssembly **r_assembly) { CRASH_COND(!r_assembly); @@ -272,39 +280,22 @@ bool GDMono::_load_assembly(const String &p_name, GDMonoAssembly **r_assembly) { if (OS::get_singleton()->is_stdout_verbose()) OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + "...\n").utf8()); - MonoImageOpenStatus status; + MonoImageOpenStatus status = MONO_IMAGE_OK; MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8()); MonoAssembly *assembly = mono_assembly_load_full(aname, NULL, &status, false); mono_assembly_name_free(aname); - if (!assembly) - return false; + ERR_FAIL_NULL_V(assembly, false); uint32_t domain_id = mono_domain_get_id(mono_domain_get()); GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name); - if (stored_assembly) { - // Loaded by our preload hook (status is not initialized when returning from a preload hook) - ERR_FAIL_COND_V((*stored_assembly)->get_assembly() != assembly, false); - *r_assembly = *stored_assembly; - } else { - ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false); - - MonoImage *assembly_image = mono_assembly_get_image(assembly); - ERR_FAIL_NULL_V(assembly_image, false); + ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false); + ERR_FAIL_COND_V(stored_assembly == NULL, false); - const char *path = mono_image_get_filename(assembly_image); - - *r_assembly = memnew(GDMonoAssembly(p_name, path)); - Error error = (*r_assembly)->wrapper_for_image(assembly_image); - - if (error != OK) { - memdelete(*r_assembly); - *r_assembly = NULL; - ERR_FAIL_V(false); - } - } + ERR_FAIL_COND_V((*stored_assembly)->get_assembly() != assembly, false); + *r_assembly = *stored_assembly; if (OS::get_singleton()->is_stdout_verbose()) OS::get_singleton()->print(String("Mono: Assembly " + p_name + " loaded from path: " + (*r_assembly)->get_path() + "\n").utf8()); @@ -438,10 +429,14 @@ Error GDMono::_unload_scripts_domain() { if (mono_domain_get() != root_domain) mono_domain_set(root_domain, true); + mono_gc_collect(mono_gc_max_generation()); + finalizing_scripts_domain = true; mono_domain_finalize(scripts_domain, 2000); finalizing_scripts_domain = false; + mono_gc_collect(mono_gc_max_generation()); + _domain_assemblies_cleanup(mono_domain_get_id(scripts_domain)); api_assembly = NULL; diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index ab96d575e6..b188c0730a 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -122,7 +122,9 @@ public: static GDMono *get_singleton() { return singleton; } + // Do not use these, unless you know what you're doing void add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly); + GDMonoAssembly **get_loaded_assembly(const String &p_name); _FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized; } _FORCE_INLINE_ bool is_finalizing_scripts_domain() const { return finalizing_scripts_domain; } diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index a98537b9e1..4b370295f3 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -39,28 +39,60 @@ #include "../godotsharp_dirs.h" #include "gd_mono_class.h" -MonoAssembly *gdmono_load_assembly_from(const String &p_name, const String &p_path) { +bool GDMonoAssembly::no_search = false; +Vector<String> GDMonoAssembly::search_dirs; - MonoDomain *domain = mono_domain_get(); +MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_data) { - GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path)); - Error err = assembly->load(domain); - ERR_FAIL_COND_V(err != OK, NULL); + (void)user_data; // UNUSED - GDMono::get_singleton()->add_assembly(mono_domain_get_id(domain), assembly); + String name = mono_assembly_name_get_name(aname); + bool has_extension = name.ends_with(".dll") || name.ends_with(".exe"); - return assembly->get_assembly(); -} + if (no_search) + return NULL; -MonoAssembly *gdmono_MonoAssemblyPreLoad(MonoAssemblyName *aname, char **assemblies_path, void *user_data) { + GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name); + if (loaded_asm) + return (*loaded_asm)->get_assembly(); - (void)user_data; // UNUSED + no_search = true; // Avoid the recursion madness + + String path; + MonoAssembly *res = NULL; + + for (int i = 0; i < search_dirs.size(); i++) { + const String &search_dir = search_dirs[i]; - MonoAssembly *assembly_loaded = mono_assembly_loaded(aname); - if (assembly_loaded) // Already loaded - return assembly_loaded; + if (has_extension) { + path = search_dir.plus_file(name); + if (FileAccess::exists(path)) { + res = _load_assembly_from(name.get_basename(), path); + break; + } + } else { + path = search_dir.plus_file(name + ".dll"); + if (FileAccess::exists(path)) { + res = _load_assembly_from(name, path); + break; + } + + path = search_dir.plus_file(name + ".exe"); + if (FileAccess::exists(path)) { + res = _load_assembly_from(name, path); + break; + } + } + } - static Vector<String> search_dirs; + no_search = false; + + return res; +} + +MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) { + + (void)user_data; // UNUSED if (search_dirs.empty()) { search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir()); @@ -80,35 +112,32 @@ MonoAssembly *gdmono_MonoAssemblyPreLoad(MonoAssemblyName *aname, char **assembl } } - String name = mono_assembly_name_get_name(aname); - bool has_extension = name.ends_with(".dll") || name.ends_with(".exe"); + return NULL; +} - String path; +MonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path) { - for (int i = 0; i < search_dirs.size(); i++) { - const String &search_dir = search_dirs[i]; + GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path)); - if (has_extension) { - path = search_dir.plus_file(name); - if (FileAccess::exists(path)) - return gdmono_load_assembly_from(name.get_basename(), path); - } else { - path = search_dir.plus_file(name + ".dll"); - if (FileAccess::exists(path)) - return gdmono_load_assembly_from(name, path); + MonoDomain *domain = mono_domain_get(); - path = search_dir.plus_file(name + ".exe"); - if (FileAccess::exists(path)) - return gdmono_load_assembly_from(name, path); - } + Error err = assembly->load(domain); + + if (err != OK) { + memdelete(assembly); + ERR_FAIL_V(NULL); } - return NULL; + GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, assembly); + + return assembly->get_assembly(); } void GDMonoAssembly::initialize() { - mono_install_assembly_preload_hook(&gdmono_MonoAssemblyPreLoad, NULL); + // TODO refonly as well? + mono_install_assembly_preload_hook(&GDMonoAssembly::_preload_hook, NULL); + mono_install_assembly_search_hook(&GDMonoAssembly::_search_hook, NULL); } Error GDMonoAssembly::load(MonoDomain *p_domain) { @@ -153,7 +182,7 @@ no_pdb: ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN); - if (mono_image_get_entry_point(image)) { + if (p_domain && mono_image_get_entry_point(image)) { // TODO should this be removed? do we want to call main? what other effects does this have? mono_jit_exec(p_domain, assembly, 0, NULL); } diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h index 89e091549c..710b674622 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.h +++ b/modules/mono/mono_gd/gd_mono_assembly.h @@ -86,6 +86,14 @@ class GDMonoAssembly { Vector<uint8_t> pdb_data; #endif + static bool no_search; + static Vector<String> search_dirs; + + static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data); + static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data); + + static MonoAssembly *_load_assembly_from(const String &p_name, const String &p_path); + friend class GDMono; static void initialize(); diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 0c64380e31..c2d8eeaa32 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -279,11 +279,11 @@ void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) { } bool GDMonoField::get_bool_value(MonoObject *p_object) { - return UNBOX_BOOLEAN(get_value(p_object)); + return (bool)GDMonoMarshal::unbox<MonoBoolean>(get_value(p_object)); } int GDMonoField::get_int_value(MonoObject *p_object) { - return UNBOX_INT32(get_value(p_object)); + return GDMonoMarshal::unbox<int32_t>(get_value(p_object)); } String GDMonoField::get_string_value(MonoObject *p_object) { diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index b5419952de..b64915109f 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -41,11 +41,11 @@ namespace GDMonoMarshal { return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_t), raw); \ } -#define RETURN_UNBOXED_STRUCT(m_t, m_var_in) \ - { \ - float *raw = UNBOX_FLOAT_PTR(m_var_in); \ - MARSHALLED_IN(m_t, raw, ret); \ - return ret; \ +#define RETURN_UNBOXED_STRUCT(m_t, m_var_in) \ + { \ + float *raw = (float *)mono_object_unbox(m_var_in); \ + MARSHALLED_IN(m_t, raw, ret); \ + return ret; \ } Variant::Type managed_to_variant_type(const ManagedType &p_type) { @@ -453,30 +453,30 @@ Variant mono_object_to_variant(MonoObject *p_obj) { Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) { switch (p_type.type_encoding) { case MONO_TYPE_BOOLEAN: - return (bool)UNBOX_BOOLEAN(p_obj); + return (bool)unbox<MonoBoolean>(p_obj); case MONO_TYPE_I1: - return UNBOX_INT8(p_obj); + return unbox<int8_t>(p_obj); case MONO_TYPE_I2: - return UNBOX_INT16(p_obj); + return unbox<int16_t>(p_obj); case MONO_TYPE_I4: - return UNBOX_INT32(p_obj); + return unbox<int32_t>(p_obj); case MONO_TYPE_I8: - return UNBOX_INT64(p_obj); + return unbox<int64_t>(p_obj); case MONO_TYPE_U1: - return UNBOX_UINT8(p_obj); + return unbox<uint8_t>(p_obj); case MONO_TYPE_U2: - return UNBOX_UINT16(p_obj); + return unbox<uint16_t>(p_obj); case MONO_TYPE_U4: - return UNBOX_UINT32(p_obj); + return unbox<uint32_t>(p_obj); case MONO_TYPE_U8: - return UNBOX_UINT64(p_obj); + return unbox<uint64_t>(p_obj); case MONO_TYPE_R4: - return UNBOX_FLOAT(p_obj); + return unbox<float>(p_obj); case MONO_TYPE_R8: - return UNBOX_DOUBLE(p_obj); + return unbox<double>(p_obj); case MONO_TYPE_STRING: { String str = mono_string_to_godot((MonoString *)p_obj); @@ -554,29 +554,18 @@ Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) { // GodotObject if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - GDMonoField *ptr_field = CACHED_FIELD(GodotObject, ptr); - - ERR_FAIL_NULL_V(ptr_field, Variant()); - - void *ptr_to_unmanaged = UNBOX_PTR(ptr_field->get_value(p_obj)); - - if (!ptr_to_unmanaged) // IntPtr.Zero - return Variant(); - - Object *object_ptr = static_cast<Object *>(ptr_to_unmanaged); - - if (!object_ptr) - return Variant(); - - return object_ptr; + Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj)); + return ptr ? Variant(ptr) : Variant(); } if (CACHED_CLASS(NodePath) == type_class) { - return UNBOX_PTR(CACHED_FIELD(NodePath, ptr)->get_value(p_obj)); + NodePath *ptr = unbox<NodePath *>(CACHED_FIELD(NodePath, ptr)->get_value(p_obj)); + return ptr ? Variant(*ptr) : Variant(); } if (CACHED_CLASS(RID) == type_class) { - return UNBOX_PTR(CACHED_FIELD(RID, ptr)->get_value(p_obj)); + RID *ptr = unbox<RID *>(CACHED_FIELD(RID, ptr)->get_value(p_obj)); + return ptr ? Variant(*ptr) : Variant(); } } break; diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 5fbafa0acb..38dd22357d 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -36,21 +36,10 @@ namespace GDMonoMarshal { -#define UNBOX_CHAR_PTR(x) (char *)mono_object_unbox(x) -#define UNBOX_FLOAT_PTR(x) (float *)mono_object_unbox(x) - -#define UNBOX_DOUBLE(x) *(double *)mono_object_unbox(x) -#define UNBOX_FLOAT(x) *(float *)mono_object_unbox(x) -#define UNBOX_INT64(x) *(int64_t *)mono_object_unbox(x) -#define UNBOX_INT32(x) *(int32_t *)mono_object_unbox(x) -#define UNBOX_INT16(x) *(int16_t *)mono_object_unbox(x) -#define UNBOX_INT8(x) *(int8_t *)mono_object_unbox(x) -#define UNBOX_UINT64(x) *(uint64_t *)mono_object_unbox(x) -#define UNBOX_UINT32(x) *(uint32_t *)mono_object_unbox(x) -#define UNBOX_UINT16(x) *(uint16_t *)mono_object_unbox(x) -#define UNBOX_UINT8(x) *(uint8_t *)mono_object_unbox(x) -#define UNBOX_BOOLEAN(x) *(MonoBoolean *)mono_object_unbox(x) -#define UNBOX_PTR(x) mono_object_unbox(x) +template <typename T> +T unbox(MonoObject *p_obj) { + return *(T *)mono_object_unbox(p_obj); +} #define BOX_DOUBLE(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(double), &x) #define BOX_FLOAT(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(float), &x) diff --git a/modules/mono/mono_reg_utils.py b/modules/mono/mono_reg_utils.py index 6f1620ff49..e9988625f5 100644 --- a/modules/mono/mono_reg_utils.py +++ b/modules/mono/mono_reg_utils.py @@ -1,7 +1,11 @@ import os if os.name == 'nt': - import _winreg as winreg + import sys + if sys.version_info < (3,): + import _winreg as winreg + else: + import winreg def _reg_open_key(key, subkey): |