summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compat.py29
-rw-r--r--editor/SCsub14
-rw-r--r--editor/editor_settings.cpp2
-rw-r--r--modules/mono/csharp_script.cpp78
-rw-r--r--modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs2
-rw-r--r--modules/mono/editor/godotsharp_builds.cpp6
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp34
-rw-r--r--modules/mono/mono_gd/gd_mono.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp97
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h8
-rw-r--r--modules/mono/mono_reg_utils.py6
-rw-r--r--platform/osx/detect.py2
12 files changed, 184 insertions, 96 deletions
diff --git a/compat.py b/compat.py
index 7338c479fb..e1bc0ed673 100644
--- a/compat.py
+++ b/compat.py
@@ -14,6 +14,17 @@ if sys.version_info < (3,):
return x
def iteritems(d):
return d.iteritems()
+ def escape_string(s):
+ if isinstance(s, unicode):
+ s = s.encode('ascii')
+ result = ''
+ for c in s:
+ if not (32 <= ord(c) < 127) or c in ('\\', '"'):
+ result += '\\%03o' % ord(c)
+ else:
+ result += c
+ return result
+
else:
def isbasestring(s):
return isinstance(s, (str, bytes))
@@ -29,3 +40,21 @@ else:
return codecs.utf_8_encode(x)[0]
def iteritems(d):
return iter(d.items())
+ def charcode_to_c_escapes(c):
+ rev_result = []
+ while c >= 256:
+ c, low = (c // 256, c % 256)
+ rev_result.append('\\%03o' % low)
+ rev_result.append('\\%03o' % c)
+ return ''.join(reversed(rev_result))
+ def escape_string(s):
+ result = ''
+ if isinstance(s, str):
+ s = s.encode('utf-8')
+ for c in s:
+ if not(32 <= c < 127) or c in (ord('\\'), ord('"')):
+ result += charcode_to_c_escapes(c)
+ else:
+ result += chr(c)
+ return result
+
diff --git a/editor/SCsub b/editor/SCsub
index 11cdb471a8..e44b4e4bb2 100644
--- a/editor/SCsub
+++ b/editor/SCsub
@@ -4,18 +4,8 @@ Import('env')
env.editor_sources = []
import os
-from compat import encode_utf8, byte_to_str, open_utf8
-
-def escape_string(s, encoding='ascii'):
- if isinstance(s, unicode):
- s = s.encode(encoding)
- result = ''
- for c in s:
- if not (32 <= ord(c) < 127) or c in ('\\', '"'):
- result += '\\%03o' % ord(c)
- else:
- result += c
- return result
+from compat import encode_utf8, byte_to_str, open_utf8, escape_string
+
def make_certs_header(target, source, env):
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 84b0917c78..b532bb793a 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -1225,8 +1225,6 @@ void EditorSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &EditorSettings::set_initial_value);
- ClassDB::bind_method(D_METHOD("set_favorite_dirs", "dirs"), &EditorSettings::set_favorite_dirs);
-
ADD_SIGNAL(MethodInfo("settings_changed"));
}
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 5301ea72b4..7de90dfbc3 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -1201,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
@@ -1226,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];
+
+ if (field->is_static() || field->get_visibility() != GDMono::PUBLIC)
+ continue;
+
+ String name = field->get_name();
+ StringName cname = name;
- String name = field->get_name();
- StringName cname = name;
+ if (member_info.has(cname))
+ continue;
- Variant::Type type = GDMonoMarshal::managed_to_variant_type(field->get_type());
+ Variant::Type type = GDMonoMarshal::managed_to_variant_type(field->get_type());
- if (field->has_attribute(CACHED_CLASS(ExportAttribute))) {
- MonoObject *attr = field->get_attribute(CACHED_CLASS(ExportAttribute));
+ if (field->has_attribute(CACHED_CLASS(ExportAttribute))) {
+ MonoObject *attr = field->get_attribute(CACHED_CLASS(ExportAttribute));
- // 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);
+ // 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);
- PropertyInfo prop_info = PropertyInfo(type, name, PropertyHint(hint), hint_string, PropertyUsageFlags(usage));
+ PropertyInfo prop_info = PropertyInfo(type, name, PropertyHint(hint), hint_string, PropertyUsageFlags(usage));
- member_info[cname] = prop_info;
- exported_members_cache.push_back(prop_info);
+ 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));
+ 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();
}
}
@@ -1795,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)
diff --git a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
index 329b6d2008..5544233eb7 100644
--- a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
+++ b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
@@ -106,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/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp
index b7e3fb0a32..1bad8a3f85 100644
--- a/modules/mono/editor/godotsharp_builds.cpp
+++ b/modules/mono/editor/godotsharp_builds.cpp
@@ -59,7 +59,7 @@ String _find_build_engine_on_unix(const String &p_name) {
"/opt/novell/mono/bin/"
};
- for (int i = 0; i < sizeof(locations) / sizeof(char); i++) {
+ for (int i = 0; i < sizeof(locations) / sizeof(const char *); i++) {
String location = locations[i];
if (FileAccess::exists(location + p_name)) {
@@ -461,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/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index d0b5b12d4b..2c88832998 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -266,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);
@@ -278,34 +285,17 @@ bool GDMono::_load_assembly(const String &p_name, GDMonoAssembly **r_assembly) {
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);
-
- 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);
+ ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false);
+ ERR_FAIL_COND_V(stored_assembly == NULL, false);
- 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());
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..a623b34b68 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) {
+ no_search = true; // Avoid the recursion madness
- (void)user_data; // UNUSED
+ GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name);
+ if (loaded_asm)
+ return (*loaded_asm)->get_assembly();
+
+ 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_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):
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index f66c3f00da..31032659b6 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -62,7 +62,7 @@ def configure(env):
## Compiler configuration
- if (not os.environ.has_key("OSXCROSS_ROOT")): # regular native build
+ if "OSXCROSS_ROOT" not in os.environ: # regular native build
if (env["bits"] == "fat"):
env.Append(CCFLAGS=['-arch', 'i386', '-arch', 'x86_64'])
env.Append(LINKFLAGS=['-arch', 'i386', '-arch', 'x86_64'])