diff options
Diffstat (limited to 'modules/mono')
57 files changed, 2559 insertions, 1155 deletions
diff --git a/modules/mono/SCsub b/modules/mono/SCsub index 320bbe7090..a1dfcf6377 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -31,11 +31,18 @@ def make_cs_files_header(src, dst): if i > 0: header.write(', ') header.write(byte_to_str(buf[buf_idx])) - inserted_files += '\tr_files.insert(\"' + file + '\", ' \ + inserted_files += '\tr_files.insert("' + file + '", ' \ 'CompressedFile(_cs_' + name + '_compressed_size, ' \ '_cs_' + name + '_uncompressed_size, ' \ '_cs_' + name + '_compressed));\n' header.write(' };\n') + version_file = os.path.join(src, 'VERSION.txt') + with open(version_file, 'r') as content_file: + try: + glue_version = int(content_file.read()) # make sure the format is valid + header.write('\n#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n') + except ValueError: + raise ValueError('Invalid C# glue version in: ' + version_file) header.write('\nstruct CompressedFile\n' '{\n' '\tint compressed_size;\n' '\tint uncompressed_size;\n' '\tconst unsigned char* data;\n' '\n\tCompressedFile(int p_comp_size, int p_uncomp_size, const unsigned char* p_data)\n' @@ -57,10 +64,10 @@ if env['tools']: vars = Variables() vars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True)) vars.Add(BoolVariable('xbuild_fallback', 'If MSBuild is not found, fallback to xbuild', False)) -vars.Update(env) +vars.Update(env_mono) # Glue sources -if env['mono_glue']: +if env_mono['mono_glue']: env_mono.add_source_files(env.modules_sources, 'glue/*.cpp') else: env_mono.Append(CPPDEFINES=['MONO_GLUE_DISABLED']) @@ -80,23 +87,23 @@ def find_msbuild_unix(filename): import sys hint_dirs = ['/opt/novell/mono/bin'] - if sys.platform == "darwin": + if sys.platform == 'darwin': hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin'] + hint_dirs for hint_dir in hint_dirs: hint_path = os.path.join(hint_dir, filename) if os.path.isfile(hint_path): return hint_path - elif os.path.isfile(hint_path + ".exe"): - return hint_path + ".exe" + elif os.path.isfile(hint_path + '.exe'): + return hint_path + '.exe' - for hint_dir in os.environ["PATH"].split(os.pathsep): + for hint_dir in os.environ['PATH'].split(os.pathsep): hint_dir = hint_dir.strip('"') hint_path = os.path.join(hint_dir, filename) if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK): return hint_path - if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK): - return hint_path + ".exe" + if os.path.isfile(hint_path + '.exe') and os.access(hint_path + '.exe', os.X_OK): + return hint_path + '.exe' return None @@ -152,7 +159,7 @@ def mono_build_solution(source, target, env): xbuild_fallback = env['xbuild_fallback'] if xbuild_fallback and os.name == 'nt': - print("Option 'xbuild_fallback' not supported on Windows") + print('Option \'xbuild_fallback\' not supported on Windows') xbuild_fallback = False if xbuild_fallback: @@ -202,10 +209,16 @@ def mono_build_solution(source, target, env): copyfile(os.path.join(src_dir, asm_file), os.path.join(dst_dir, asm_file)) +output_dir = Dir('#bin').abspath +assemblies_output_dir = Dir(env['mono_assemblies_output_dir']).abspath -mono_sln_builder = Builder(action = mono_build_solution) +mono_sln_builder = Builder(action=mono_build_solution) env_mono.Append(BUILDERS={'MonoBuildSolution': mono_sln_builder}) env_mono.MonoBuildSolution( - os.path.join(Dir('#bin').abspath, 'GodotSharpTools.dll'), + os.path.join(assemblies_output_dir, 'GodotSharpTools.dll'), 'editor/GodotSharpTools/GodotSharpTools.sln' ) + +if os.path.normpath(output_dir) != os.path.normpath(assemblies_output_dir): + rel_assemblies_output_dir = os.path.relpath(assemblies_output_dir, output_dir) + env_mono.Append(CPPDEFINES={'GD_MONO_EDITOR_ASSEMBLIES_DIR': rel_assemblies_output_dir}) diff --git a/modules/mono/config.py b/modules/mono/config.py index b4e6433256..18d9c67795 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -2,8 +2,9 @@ import imp import os import sys +import subprocess -from SCons.Script import BoolVariable, Environment, Variables +from SCons.Script import BoolVariable, Dir, Environment, PathVariable, Variables monoreg = imp.load_source('mono_reg_utils', 'modules/mono/mono_reg_utils.py') @@ -29,20 +30,16 @@ def is_enabled(): return False -def copy_file_no_replace(src_dir, dst_dir, name): +def copy_file(src_dir, dst_dir, name): from shutil import copyfile src_path = os.path.join(src_dir, name) dst_path = os.path.join(dst_dir, name) - need_copy = True if not os.path.isdir(dst_dir): os.mkdir(dst_dir) - elif os.path.exists(dst_path): - need_copy = False - if need_copy: - copyfile(src_path, dst_path) + copyfile(src_path, dst_path) def configure(env): @@ -51,18 +48,17 @@ def configure(env): envvars = Variables() envvars.Add(BoolVariable('mono_static', 'Statically link mono', False)) + envvars.Add(PathVariable('mono_assemblies_output_dir', 'Path to the assemblies output directory', '#bin', PathVariable.PathIsDirCreate)) envvars.Update(env) bits = env['bits'] mono_static = env['mono_static'] + assemblies_output_dir = Dir(env['mono_assemblies_output_dir']).abspath mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0'] if env['platform'] == 'windows': - if mono_static: - raise RuntimeError('mono-static: Not supported on Windows') - if bits == '32': if os.getenv('MONO32_PREFIX'): mono_root = os.getenv('MONO32_PREFIX') @@ -82,28 +78,48 @@ def configure(env): env.Append(LIBPATH=mono_lib_path) env.Append(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0')) - mono_lib_name = find_file_in_dir(mono_lib_path, mono_lib_names, extension='.lib') + if mono_static: + lib_suffix = Environment()['LIBSUFFIX'] + mono_static_lib_name = 'libmono-static-sgen' + + if not os.path.isfile(os.path.join(mono_lib_path, mono_static_lib_name + lib_suffix)): + raise RuntimeError('Could not find static mono library in: ' + mono_lib_path) - if not mono_lib_name: - raise RuntimeError('Could not find mono library in: ' + mono_lib_path) + if env.msvc: + env.Append(LINKFLAGS=mono_static_lib_name + lib_suffix) - if os.getenv('VCINSTALLDIR'): - env.Append(LINKFLAGS=mono_lib_name + Environment()['LIBSUFFIX']) + env.Append(LINKFLAGS='Mincore' + lib_suffix) + env.Append(LINKFLAGS='msvcrt' + lib_suffix) + env.Append(LINKFLAGS='LIBCMT' + lib_suffix) + env.Append(LINKFLAGS='Psapi' + lib_suffix) + else: + env.Append(LIBS=mono_static_lib_name) else: - env.Append(LIBS=mono_lib_name) + mono_lib_name = find_file_in_dir(mono_lib_path, mono_lib_names, extension='.lib') - mono_bin_path = os.path.join(mono_root, 'bin') + if not mono_lib_name: + raise RuntimeError('Could not find mono library in: ' + mono_lib_path) - mono_dll_name = find_file_in_dir(mono_bin_path, mono_lib_names, extension='.dll') + if env.msvc: + env.Append(LINKFLAGS=mono_lib_name + Environment()['LIBSUFFIX']) + else: + env.Append(LIBS=mono_lib_name) + + mono_bin_path = os.path.join(mono_root, 'bin') + + mono_dll_name = find_file_in_dir(mono_bin_path, mono_lib_names, extension='.dll') - if not mono_dll_name: - raise RuntimeError('Could not find mono shared library in: ' + mono_bin_path) + if not mono_dll_name: + raise RuntimeError('Could not find mono shared library in: ' + mono_bin_path) - copy_file_no_replace(mono_bin_path, 'bin', mono_dll_name + '.dll') + copy_file(mono_bin_path, 'bin', mono_dll_name + '.dll') + + copy_file(os.path.join(mono_lib_path, 'mono', '4.5'), assemblies_output_dir, 'mscorlib.dll') else: sharedlib_ext = '.dylib' if sys.platform == 'darwin' else '.so' mono_root = '' + mono_lib_path = '' if bits == '32': if os.getenv('MONO32_PREFIX'): @@ -148,7 +164,9 @@ def configure(env): if not mono_so_name: raise RuntimeError('Could not find mono shared library in: ' + mono_lib_path) - copy_file_no_replace(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext) + copy_file(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext) + + copy_file(os.path.join(mono_lib_path, 'mono', '4.5'), assemblies_output_dir, 'mscorlib.dll') else: if mono_static: raise RuntimeError('mono-static: Not supported with pkg-config. Specify a mono prefix manually') @@ -157,8 +175,10 @@ def configure(env): mono_lib_path = '' mono_so_name = '' + mono_prefix = subprocess.check_output(["pkg-config", "mono-2", "--variable=prefix"]).decode("utf8").strip() tmpenv = Environment() + tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH')) tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L') for hint_dir in tmpenv['LIBPATH']: @@ -171,7 +191,8 @@ def configure(env): if not mono_so_name: raise RuntimeError('Could not find mono shared library in: ' + str(tmpenv['LIBPATH'])) - copy_file_no_replace(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext) + copy_file(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext) + copy_file(os.path.join(mono_prefix, 'lib', 'mono', '4.5'), assemblies_output_dir, 'mscorlib.dll') env.Append(LINKFLAGS='-rdynamic') diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index aee2481366..161e62c81f 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -118,6 +118,8 @@ void CSharpLanguage::init() { #ifdef TOOLS_ENABLED EditorNode::add_init_callback(&gdsharp_editor_init_callback); + + GLOBAL_DEF("mono/export/include_scripts_content", true); #endif } @@ -176,7 +178,7 @@ void CSharpLanguage::get_reserved_words(List<String> *p_words) const { "fixed", "float", "for", - "forech", + "foreach", "goto", "if", "implicit", @@ -222,14 +224,17 @@ void CSharpLanguage::get_reserved_words(List<String> *p_words) const { "ushort", "using", "virtual", - "volatile", "void", + "volatile", "while", // Contextual keywords. Not reserved words, but I guess we should include // them because this seems to be used only for syntax highlighting. "add", + "alias", "ascending", + "async", + "await", "by", "descending", "dynamic", @@ -238,10 +243,10 @@ void CSharpLanguage::get_reserved_words(List<String> *p_words) const { "get", "global", "group", - "in", "into", "join", "let", + "nameof", "on", "orderby", "partial", @@ -250,6 +255,7 @@ void CSharpLanguage::get_reserved_words(List<String> *p_words) const { "set", "value", "var", + "when", "where", "yield", 0 @@ -276,6 +282,15 @@ void CSharpLanguage::get_string_delimiters(List<String> *p_delimiters) const { p_delimiters->push_back("@\" \""); // verbatim string literal } +static String get_base_class_name(const String &p_base_class_name, const String p_class_name) { + + String base_class = p_base_class_name; + if (p_class_name == base_class) { + base_class = "Godot." + base_class; + } + return base_class; +} + Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { String script_template = "using " BINDINGS_NAMESPACE ";\n" @@ -290,7 +305,7 @@ Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const Strin " public override void _Ready()\n" " {\n" " // Called every time the node is added to the scene.\n" - " // Initialization here\n" + " // Initialization here.\n" " \n" " }\n" "\n" @@ -302,7 +317,8 @@ Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const Strin "// }\n" "}\n"; - script_template = script_template.replace("%BASE_CLASS_NAME%", p_base_class_name) + String base_class_name = get_base_class_name(p_base_class_name, p_class_name); + script_template = script_template.replace("%BASE_CLASS_NAME%", base_class_name) .replace("%CLASS_NAME%", p_class_name); Ref<CSharpScript> script; @@ -321,12 +337,24 @@ bool CSharpLanguage::is_using_templates() { void CSharpLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) { String src = p_script->get_source_code(); - src = src.replace("%BASE%", p_base_class_name) + String base_class_name = get_base_class_name(p_base_class_name, p_class_name); + src = src.replace("%BASE%", base_class_name) .replace("%CLASS%", p_class_name) .replace("%TS%", _get_indentation()); p_script->set_source_code(src); } +String CSharpLanguage::validate_path(const String &p_path) const { + + String class_name = p_path.get_file().get_basename(); + List<String> keywords; + get_reserved_words(&keywords); + if (keywords.find(class_name)) { + return TTR("Class name can't be a reserved keyword"); + } + return ""; +} + Script *CSharpLanguage::create_script() const { return memnew(CSharpScript); @@ -447,9 +475,10 @@ String CSharpLanguage::_get_indentation() const { Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() { +#ifdef DEBUG_ENABLED // Printing an error here will result in endless recursion, so we must be careful - if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_api_assembly() || !GDMonoUtils::mono_cache.corlib_cache_updated) + if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoUtils::mono_cache.corlib_cache_updated) return Vector<StackInfo>(); MonoObject *stack_trace = mono_object_new(mono_domain_get(), CACHED_CLASS(System_Diagnostics_StackTrace)->get_mono_ptr()); @@ -463,8 +492,12 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() si = stack_trace_get_info(stack_trace); return si; +#else + return Vector<StackInfo>(); +#endif } +#ifdef DEBUG_ENABLED Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObject *p_stack_trace) { // Printing an error here could result in endless recursion, so we must be careful @@ -514,6 +547,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec return si; } +#endif void CSharpLanguage::frame() { @@ -711,8 +745,10 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { for (Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) { Ref<CSharpScript> scr = E->key(); + scr->signals_invalidated = true; scr->exports_invalidated = true; scr->reload(p_soft_reload); + scr->update_signals(); scr->update_exports(); //restore state if saved @@ -745,8 +781,10 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { //if instance states were saved, set them! } - if (Engine::get_singleton()->is_editor_hint()) - EditorNode::get_singleton()->get_property_editor()->update_tree(); + if (Engine::get_singleton()->is_editor_hint()) { + EditorNode::get_singleton()->get_inspector()->update_tree(); + NodeDock::singleton->update_lists(); + } } #endif @@ -941,19 +979,6 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) { #endif } -void CSharpInstance::_ml_call_reversed(MonoObject *p_mono_object, GDMonoClass *p_klass, const StringName &p_method, const Variant **p_args, int p_argcount) { - - GDMonoClass *base = p_klass->get_parent_class(); - if (base && base != script->native) - _ml_call_reversed(p_mono_object, base, p_method, p_args, p_argcount); - - GDMonoMethod *method = p_klass->get_method(p_method, p_argcount); - - if (method) { - method->invoke(p_mono_object, p_args); - } -} - CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const Ref<MonoGCHandle> &p_gchandle) { CSharpInstance *instance = memnew(CSharpInstance); @@ -1022,6 +1047,8 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) { if (ret && GDMonoMarshal::unbox<MonoBoolean>(ret) == true) return true; + + break; } top = top->get_parent_class(); @@ -1082,6 +1109,8 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const { r_ret = GDMonoMarshal::mono_object_to_variant(ret); return true; } + + break; } top = top->get_parent_class(); @@ -1133,10 +1162,13 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, MonoObject *mono_object = get_mono_object(); - ERR_FAIL_NULL_V(mono_object, Variant()); + if (!mono_object) { + r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL; + ERR_FAIL_V(Variant()); + } if (!script.is_valid()) - return Variant(); + ERR_FAIL_V(Variant()); GDMonoClass *top = script->script_class; @@ -1146,6 +1178,8 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, if (method) { MonoObject *return_value = method->invoke(mono_object, p_args); + r_error.error = Variant::CallError::CALL_OK; + if (return_value) { return GDMonoMarshal::mono_object_to_variant(return_value); } else { @@ -1179,8 +1213,10 @@ void CSharpInstance::_call_multilevel(MonoObject *p_mono_object, const StringNam while (top && top != script->native) { GDMonoMethod *method = top->get_method(p_method, p_argcount); - if (method) + if (method) { method->invoke(p_mono_object, p_args); + return; + } top = top->get_parent_class(); } @@ -1188,13 +1224,9 @@ void CSharpInstance::_call_multilevel(MonoObject *p_mono_object, const StringNam void CSharpInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - if (script.is_valid()) { - MonoObject *mono_object = get_mono_object(); - - ERR_FAIL_NULL(mono_object); + // Sorry, the method is the one that controls the call order - _ml_call_reversed(mono_object, script->script_class, p_method, p_args, p_argcount); - } + call_multilevel(p_method, p_args, p_argcount); } void CSharpInstance::_reference_owner_unsafe() { @@ -1541,6 +1573,75 @@ bool CSharpScript::_update_exports() { return false; } +bool CSharpScript::_update_signals() { + if (!valid) + return false; + + bool changed = false; + + if (signals_invalidated) { + signals_invalidated = false; + + GDMonoClass *top = script_class; + + _signals.clear(); + changed = true; // TODO Do a real check for change + + while (top && top != native) { + const Vector<GDMonoClass *> &delegates = top->get_all_delegates(); + for (int i = delegates.size() - 1; i >= 0; --i) { + Vector<Argument> parameters; + + GDMonoClass *delegate = delegates[i]; + + if (_get_signal(top, delegate, parameters)) { + _signals[delegate->get_name()] = parameters; + } + } + + top = top->get_parent_class(); + } + } + + return changed; +} + +bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms) { + if (p_delegate->has_attribute(CACHED_CLASS(SignalAttribute))) { + MonoType *raw_type = GDMonoClass::get_raw_type(p_delegate); + + if (mono_type_get_type(raw_type) == MONO_TYPE_CLASS) { + // Arguments are accessibles as arguments of .Invoke method + GDMonoMethod *invoke = p_delegate->get_method("Invoke", -1); + + Vector<StringName> names; + Vector<ManagedType> types; + invoke->get_parameter_names(names); + invoke->get_parameter_types(types); + + if (names.size() == types.size()) { + for (int i = 0; i < names.size(); ++i) { + Argument arg; + arg.name = names[i]; + arg.type = GDMonoMarshal::managed_to_variant_type(types[i]); + + if (arg.type == Variant::NIL) { + ERR_PRINTS("Unknown type of signal parameter: " + arg.name + " in " + p_class->get_full_name()); + return false; + } + + params.push_back(arg); + } + + return true; + } + } + } + + return false; +} + +#ifdef TOOLS_ENABLED bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported) { StringName name = p_member->get_name(); @@ -1611,6 +1712,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p return true; } +#endif void CSharpScript::_clear() { @@ -1852,20 +1954,27 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Variant::Call ScriptInstance *CSharpScript::instance_create(Object *p_this) { - if (!valid) - return NULL; + if (!script_class) { + ERR_EXPLAIN("Cannot find class " + name + " for script " + get_path()); + ERR_FAIL_V(NULL); + } + + ERR_FAIL_COND_V(!valid, NULL); if (!tool && !ScriptServer::is_scripting_enabled()) { #ifdef TOOLS_ENABLED PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this)); placeholders.insert(si); _update_exports(); + _update_signals(); return si; #else return NULL; #endif } + update_signals(); + if (native) { String native_name = native->get_name(); if (!ClassDB::is_parent_class(p_this->get_class_name(), native_name)) { @@ -1940,20 +2049,15 @@ 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()); - } + valid = script_class != NULL; + + if (script_class) { #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) { tool = script_class->has_attribute(CACHED_CLASS(ToolAttribute)); native = GDMonoUtils::get_class_native_base(script_class); @@ -2029,6 +2133,31 @@ void CSharpScript::update_exports() { #endif } +bool CSharpScript::has_script_signal(const StringName &p_signal) const { + if (_signals.has(p_signal)) + return true; + + return false; +} + +void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const { + for (const Map<StringName, Vector<Argument> >::Element *E = _signals.front(); E; E = E->next()) { + MethodInfo mi; + + mi.name = E->key(); + for (int i = 0; i < E->get().size(); i++) { + PropertyInfo arg; + arg.name = E->get()[i].name; + mi.arguments.push_back(arg); + } + r_signals->push_back(mi); + } +} + +void CSharpScript::update_signals() { + _update_signals(); +} + Ref<Script> CSharpScript::get_base_script() const { // TODO search in metadata file once we have it, not important any way? @@ -2093,6 +2222,7 @@ CSharpScript::CSharpScript() : #ifdef TOOLS_ENABLED source_changed_cache = false; exports_invalidated = true; + signals_invalidated = true; #endif _resource_path_changed(); @@ -2157,7 +2287,9 @@ RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p CRASH_COND(mono_domain_get() == NULL); #endif -#else +#endif + +#ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() && mono_domain_get() == NULL) { CRASH_COND(Thread::get_caller_id() == Thread::get_main_id()); @@ -2166,14 +2298,20 @@ RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p // 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); + if (SCRIPTS_DOMAIN) { + 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(); - mono_thread_detach(mono_thread); - } else // just reload it normally +#ifdef TOOLS_ENABLED + } #endif - script->reload(); if (r_error) *r_error = OK; diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 3ce8a9b64e..8666149111 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -85,13 +85,20 @@ class CSharpScript : public Script { SelfList<CSharpScript> script_list; + struct Argument { + String name; + Variant::Type type; + }; + + Map<StringName, Vector<Argument> > _signals; + bool signals_invalidated; + #ifdef TOOLS_ENABLED List<PropertyInfo> exported_members_cache; // members_cache Map<StringName, Variant> exported_members_defval_cache; // member_default_values_cache Set<PlaceHolderScriptInstance *> placeholders; bool source_changed_cache; bool exports_invalidated; - void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames); virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder); #endif @@ -104,8 +111,13 @@ class CSharpScript : public Script { void _clear(); + bool _update_signals(); + bool _get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms); + bool _update_exports(); +#ifdef TOOLS_ENABLED bool _get_member_export(GDMonoClass *p_class, GDMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported); +#endif CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error); Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error); @@ -135,8 +147,9 @@ public: virtual Error reload(bool p_keep_state = false); - /* TODO */ virtual bool has_script_signal(const StringName &p_signal) const { return false; } - /* TODO */ virtual void get_script_signal_list(List<MethodInfo> *r_signals) const {} + virtual bool has_script_signal(const StringName &p_signal) const; + virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; + virtual void update_signals(); /* TODO */ virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const; virtual void get_script_property_list(List<PropertyInfo> *p_list) const; @@ -170,8 +183,6 @@ class CSharpInstance : public ScriptInstance { bool base_ref; bool ref_dying; - void _ml_call_reversed(MonoObject *p_mono_object, GDMonoClass *klass, const StringName &p_method, const Variant **p_args, int p_argcount); - void _reference_owner_unsafe(); void _unreference_owner_unsafe(); @@ -283,6 +294,7 @@ public: virtual bool is_using_templates(); virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); /* TODO */ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { return true; } + virtual String validate_path(const String &p_path) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; @@ -335,7 +347,9 @@ public: virtual void *alloc_instance_binding_data(Object *p_object); virtual void free_instance_binding_data(void *p_data); +#ifdef DEBUG_ENABLED Vector<StackInfo> stack_trace_get_info(MonoObject *p_stack_trace); +#endif CSharpLanguage(); ~CSharpLanguage(); diff --git a/modules/mono/doc_classes/@C#.xml b/modules/mono/doc_classes/@C#.xml index a9dccea3c1..082bc30fd8 100644 --- a/modules/mono/doc_classes/@C#.xml +++ b/modules/mono/doc_classes/@C#.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="@C#" category="Core" version="3.0-rc1"> +<class name="@C#" category="Core" version="3.1"> <brief_description> </brief_description> <description> diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml index 9a3631d2f2..a1f7399653 100644 --- a/modules/mono/doc_classes/CSharpScript.xml +++ b/modules/mono/doc_classes/CSharpScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSharpScript" inherits="Script" category="Core" version="3.0-rc1"> +<class name="CSharpScript" inherits="Script" category="Core" version="3.1"> <brief_description> </brief_description> <description> diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml index 219d041b67..985c66464b 100644 --- a/modules/mono/doc_classes/GodotSharp.xml +++ b/modules/mono/doc_classes/GodotSharp.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GodotSharp" inherits="Object" category="Core" version="3.0-rc1"> +<class name="GodotSharp" inherits="Object" category="Core" version="3.1"> <brief_description> </brief_description> <description> diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 9bf81b52bb..4c598d4f37 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -70,8 +70,6 @@ #define LOCAL_RET "ret" -#define CS_CLASS_NATIVECALLS "NativeCalls" -#define CS_CLASS_NATIVECALLS_EDITOR "EditorNativeCalls" #define CS_FIELD_MEMORYOWN "memoryOwn" #define CS_PARAM_METHODBIND "method" #define CS_PARAM_INSTANCE "ptr" @@ -105,6 +103,8 @@ #define C_METHOD_MANAGED_TO_DICT C_NS_MONOMARSHAL "::mono_object_to_Dictionary" #define C_METHOD_MANAGED_FROM_DICT C_NS_MONOMARSHAL "::Dictionary_to_mono_object" +#define BINDINGS_GENERATOR_VERSION UINT32_C(2) + const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n"; bool BindingsGenerator::verbose_output = false; @@ -248,40 +248,59 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) { if (imethod.is_virtual) continue; - const TypeInterface *return_type = _get_type_by_name_or_placeholder(imethod.return_type); + const TypeInterface *return_type = _get_type_or_placeholder(imethod.return_type); + + String im_sig; + String im_unique_sig; - String im_sig = "IntPtr " CS_PARAM_METHODBIND ", IntPtr " CS_PARAM_INSTANCE; - String im_unique_sig = imethod.return_type.operator String() + ",IntPtr,IntPtr"; + if (p_itype.is_object_type) { + im_sig += "IntPtr " CS_PARAM_METHODBIND ", "; + im_unique_sig += imethod.return_type.cname.operator String() + ",IntPtr,IntPtr"; + } + + im_sig += "IntPtr " CS_PARAM_INSTANCE; // Get arguments information int i = 0; for (const List<ArgumentInterface>::Element *F = imethod.arguments.front(); F; F = F->next()) { - const TypeInterface *arg_type = _get_type_by_name_or_placeholder(F->get().type); + const TypeInterface *arg_type = _get_type_or_placeholder(F->get().type); im_sig += ", "; im_sig += arg_type->im_type_in; im_sig += " arg"; im_sig += itos(i + 1); - im_unique_sig += ","; - im_unique_sig += get_unique_sig(*arg_type); + if (p_itype.is_object_type) { + im_unique_sig += ","; + im_unique_sig += get_unique_sig(*arg_type); + } i++; } - // godot_icall_{argc}_{icallcount} - String icall_method = ICALL_PREFIX + itos(imethod.arguments.size()) + "_" + itos(method_icalls.size()); + String icall_method = ICALL_PREFIX; + + if (p_itype.is_object_type) { + icall_method += itos(imethod.arguments.size()) + "_" + itos(method_icalls.size()); // godot_icall_{argc}_{icallcount} + } else { + icall_method += p_itype.name + "_" + imethod.name; // godot_icall_{Type}_{method} + } InternalCall im_icall = InternalCall(p_itype.api_type, icall_method, return_type->im_type_out, im_sig, im_unique_sig); - List<InternalCall>::Element *match = method_icalls.find(im_icall); + if (p_itype.is_object_type) { + List<InternalCall>::Element *match = method_icalls.find(im_icall); - if (match) { - if (p_itype.api_type != ClassDB::API_EDITOR) - match->get().editor_only = false; - method_icalls_map.insert(&E->get(), &match->get()); + if (match) { + if (p_itype.api_type != ClassDB::API_EDITOR) + match->get().editor_only = false; + method_icalls_map.insert(&E->get(), &match->get()); + } else { + List<InternalCall>::Element *added = method_icalls.push_back(im_icall); + method_icalls_map.insert(&E->get(), &added->get()); + } } else { - List<InternalCall>::Element *added = method_icalls.push_back(im_icall); + List<InternalCall>::Element *added = builtin_method_icalls.push_back(im_icall); method_icalls_map.insert(&E->get(), &added->get()); } } @@ -510,7 +529,15 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo "using System.Collections.Generic;\n" "\n"); cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); - cs_icalls_content.push_back(INDENT1 "internal static class " CS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK); + cs_icalls_content.push_back(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK); + + cs_icalls_content.push_back(INDENT2 "internal static ulong godot_api_hash = "); + cs_icalls_content.push_back(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + ";\n"); + cs_icalls_content.push_back(INDENT2 "internal static uint bindings_version = "); + cs_icalls_content.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n"); + cs_icalls_content.push_back(INDENT2 "internal static uint cs_glue_version = "); + cs_icalls_content.push_back(String::num_uint64(CS_GLUE_VERSION) + ";\n"); + cs_icalls_content.push_back("\n"); #define ADD_INTERNAL_CALL(m_icall) \ if (!m_icall.editor_only) { \ @@ -525,12 +552,14 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo ADD_INTERNAL_CALL(E->get()); for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next()) ADD_INTERNAL_CALL(E->get()); + for (const List<InternalCall>::Element *E = builtin_method_icalls.front(); E; E = E->next()) + ADD_INTERNAL_CALL(E->get()); #undef ADD_INTERNAL_CALL cs_icalls_content.push_back(INDENT1 CLOSE_BLOCK CLOSE_BLOCK); - String internal_methods_file = path_join(core_dir, CS_CLASS_NATIVECALLS ".cs"); + String internal_methods_file = path_join(core_dir, BINDINGS_CLASS_NATIVECALLS ".cs"); Error err = _save_file(internal_methods_file, cs_icalls_content); if (err != OK) @@ -605,7 +634,15 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir, "using System.Collections.Generic;\n" "\n"); cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); - cs_icalls_content.push_back(INDENT1 "internal static class " CS_CLASS_NATIVECALLS_EDITOR "\n" INDENT1 OPEN_BLOCK); + cs_icalls_content.push_back(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS_EDITOR "\n" INDENT1 OPEN_BLOCK); + + cs_icalls_content.push_back(INDENT2 "internal static ulong godot_api_hash = "); + cs_icalls_content.push_back(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) + ";\n"); + cs_icalls_content.push_back(INDENT2 "internal static uint bindings_version = "); + cs_icalls_content.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n"); + cs_icalls_content.push_back(INDENT2 "internal static uint cs_glue_version = "); + cs_icalls_content.push_back(String::num_uint64(CS_GLUE_VERSION) + ";\n"); + cs_icalls_content.push_back("\n"); #define ADD_INTERNAL_CALL(m_icall) \ if (m_icall.editor_only) { \ @@ -616,6 +653,8 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir, cs_icalls_content.push_back(m_icall.im_sig + ");\n"); \ } + // No need to add builtin_method_icalls. Builtin types are core only + for (const List<InternalCall>::Element *E = editor_custom_icalls.front(); E; E = E->next()) ADD_INTERNAL_CALL(E->get()); for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next()) @@ -625,7 +664,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir, cs_icalls_content.push_back(INDENT1 CLOSE_BLOCK CLOSE_BLOCK); - String internal_methods_file = path_join(core_dir, CS_CLASS_NATIVECALLS_EDITOR ".cs"); + String internal_methods_file = path_join(core_dir, BINDINGS_CLASS_NATIVECALLS_EDITOR ".cs"); Error err = _save_file(internal_methods_file, cs_icalls_content); if (err != OK) @@ -691,12 +730,13 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str } output.push_back(INDENT1 "public "); - output.push_back(itype.is_singleton ? "static class " : "class "); + bool is_abstract = itype.is_object_type && !ClassDB::can_instance(itype.name) && ClassDB::is_class_enabled(itype.name); // can_instance returns true if there's a constructor and the class is not 'disabled' + output.push_back(itype.is_singleton ? "static class " : (is_abstract ? "abstract class " : "class ")); output.push_back(itype.proxy_name); - if (itype.is_singleton || !itype.is_object_type) { + if (itype.is_singleton) { output.push_back("\n"); - } else if (!is_derived_type) { + } else if (!is_derived_type || !itype.is_object_type /* assuming only object types inherit */) { output.push_back(" : IDisposable\n"); } else if (obj_types.has(itype.base_name)) { output.push_back(" : "); @@ -838,7 +878,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.push_back(MEMBER_BEGIN "public void Dispose()\n" OPEN_BLOCK_L2 "Dispose(true);\n" INDENT3 "GC.SuppressFinalize(this);\n" CLOSE_BLOCK_L2); // Add the virtual Dispose - output.push_back(MEMBER_BEGIN "public virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2 + output.push_back(MEMBER_BEGIN "protected virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2 "if (disposed) return;\n" INDENT3 "if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3 "NativeCalls.godot_icall_"); output.push_back(itype.proxy_name); @@ -859,7 +899,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.push_back("\";\n"); output.push_back(INDENT2 "internal static IntPtr " BINDINGS_PTR_FIELD " = "); - output.push_back(itype.api_type == ClassDB::API_EDITOR ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS); + output.push_back(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); output.push_back("." ICALL_PREFIX); output.push_back(itype.name); output.push_back(SINGLETON_ICALL_SUFFIX "();\n"); @@ -889,7 +929,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str // The engine will initialize the pointer field of the managed side before calling the constructor // This is why we only allocate a new native object from the constructor if the pointer field is not set output.push_back(")\n" OPEN_BLOCK_L2 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" INDENT4 BINDINGS_PTR_FIELD " = "); - output.push_back(itype.api_type == ClassDB::API_EDITOR ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS); + output.push_back(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); output.push_back("." + ctor_method); output.push_back("(this);\n" CLOSE_BLOCK_L2); } else { @@ -929,11 +969,11 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.push_back(MEMBER_BEGIN "public void Dispose()\n" OPEN_BLOCK_L2 "Dispose(true);\n" INDENT3 "GC.SuppressFinalize(this);\n" CLOSE_BLOCK_L2); // Add the virtual Dispose - output.push_back(MEMBER_BEGIN "public virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2 + output.push_back(MEMBER_BEGIN "protected virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2 "if (disposed) return;\n" INDENT3 "if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3 "if (" CS_FIELD_MEMORYOWN ")\n" OPEN_BLOCK_L4 CS_FIELD_MEMORYOWN - " = false;\n" INDENT5 CS_CLASS_NATIVECALLS "." ICALL_OBJECT_DTOR + " = false;\n" INDENT5 BINDINGS_CLASS_NATIVECALLS "." ICALL_OBJECT_DTOR "(this, " BINDINGS_PTR_FIELD ");\n" CLOSE_BLOCK_L4 CLOSE_BLOCK_L3 INDENT3 "this." BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" INDENT3 "GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2); @@ -1029,12 +1069,12 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte } if (getter && setter) { - ERR_FAIL_COND_V(getter->return_type != setter->arguments.back()->get().type, ERR_BUG); + ERR_FAIL_COND_V(getter->return_type.cname != setter->arguments.back()->get().type.cname, ERR_BUG); } - StringName proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type; + const TypeReference &proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type; - const TypeInterface *prop_itype = _get_type_by_name_or_null(proptype_name); + const TypeInterface *prop_itype = _get_type_or_null(proptype_name); ERR_FAIL_NULL_V(prop_itype, ERR_BUG); // Property type not found String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_iprop.cname)); @@ -1082,9 +1122,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.push_back(getter->proxy_name + "("); if (p_iprop.index != -1) { const ArgumentInterface &idx_arg = getter->arguments.front()->get(); - if (idx_arg.type != name_cache.type_int) { + if (idx_arg.type.cname != name_cache.type_int) { // Assume the index parameter is an enum - const TypeInterface *idx_arg_type = _get_type_by_name_or_null(idx_arg.type); + const TypeInterface *idx_arg_type = _get_type_or_null(idx_arg.type); CRASH_COND(idx_arg_type == NULL); p_output.push_back("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index)); } else { @@ -1099,9 +1139,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.push_back(setter->proxy_name + "("); if (p_iprop.index != -1) { const ArgumentInterface &idx_arg = setter->arguments.front()->get(); - if (idx_arg.type != name_cache.type_int) { + if (idx_arg.type.cname != name_cache.type_int) { // Assume the index parameter is an enum - const TypeInterface *idx_arg_type = _get_type_by_name_or_null(idx_arg.type); + const TypeInterface *idx_arg_type = _get_type_or_null(idx_arg.type); CRASH_COND(idx_arg_type == NULL); p_output.push_back("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index) + ", "); } else { @@ -1118,20 +1158,24 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, List<String> &p_output) { - const TypeInterface *return_type = _get_type_by_name_or_placeholder(p_imethod.return_type); + const TypeInterface *return_type = _get_type_or_placeholder(p_imethod.return_type); String method_bind_field = "method_bind_" + itos(p_method_bind_count); - String icall_params = method_bind_field + ", " + sformat(p_itype.cs_in, "this"); String arguments_sig; String cs_in_statements; + String icall_params; + if (p_itype.is_object_type) + icall_params += method_bind_field + ", "; + icall_params += sformat(p_itype.cs_in, "this"); + List<String> default_args_doc; // Retrieve information from the arguments for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) { const ArgumentInterface &iarg = F->get(); - const TypeInterface *arg_type = _get_type_by_name_or_placeholder(iarg.type); + const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type); // Add the current arguments to the signature // If the argument has a default value which is not a constant, we will make it Nullable @@ -1200,10 +1244,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf // Generate method { - if (!p_imethod.is_virtual && !p_imethod.requires_object_call) { - p_output.push_back(MEMBER_BEGIN "private "); - p_output.push_back(p_itype.is_singleton ? "static IntPtr " : "IntPtr "); - p_output.push_back(method_bind_field + " = " CS_CLASS_NATIVECALLS "." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \""); + if (p_itype.is_object_type && !p_imethod.is_virtual && !p_imethod.requires_object_call) { + p_output.push_back(MEMBER_BEGIN "private static IntPtr "); + p_output.push_back(method_bind_field + " = " BINDINGS_CLASS_NATIVECALLS "." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \""); p_output.push_back(p_imethod.name); p_output.push_back("\");\n"); } @@ -1284,22 +1327,20 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf const InternalCall *im_icall = match->value(); - String im_call = im_icall->editor_only ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS; - im_call += "." + im_icall->name + "(" + icall_params + ");\n"; + String im_call = im_icall->editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS; + im_call += "." + im_icall->name + "(" + icall_params + ")"; if (p_imethod.arguments.size()) p_output.push_back(cs_in_statements); if (return_type->cname == name_cache.type_void) { - p_output.push_back(im_call); + p_output.push_back(im_call + ";\n"); } else if (return_type->cs_out.empty()) { - p_output.push_back("return " + im_call); + p_output.push_back("return " + im_call + ";\n"); } else { - p_output.push_back(return_type->im_type_out); - p_output.push_back(" " LOCAL_RET " = "); - p_output.push_back(im_call); p_output.push_back(INDENT3); - p_output.push_back(sformat(return_type->cs_out, LOCAL_RET) + "\n"); + p_output.push_back(sformat(return_type->cs_out, im_call, return_type->cs_type, return_type->im_type_out)); + p_output.push_back("\n"); } p_output.push_back(CLOSE_BLOCK_L2); @@ -1374,24 +1415,33 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { } output.push_back("namespace GodotSharpBindings\n" OPEN_BLOCK); + output.push_back("uint64_t get_core_api_hash() { return "); - output.push_back(itos(GDMono::get_singleton()->get_api_core_hash()) + "; }\n"); + output.push_back(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + "; }\n"); + output.push_back("#ifdef TOOLS_ENABLED\n" "uint64_t get_editor_api_hash() { return "); - output.push_back(itos(GDMono::get_singleton()->get_api_editor_hash()) + + output.push_back(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) + "; }\n#endif // TOOLS_ENABLED\n"); - output.push_back("void register_generated_icalls() " OPEN_BLOCK); -#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \ - { \ - output.push_back("\tmono_add_internal_call("); \ - output.push_back("\"" BINDINGS_NAMESPACE "."); \ - output.push_back(m_icall.editor_only ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS); \ - output.push_back("::"); \ - output.push_back(m_icall.name); \ - output.push_back("\", (void*)"); \ - output.push_back(m_icall.name); \ - output.push_back(");\n"); \ + output.push_back("uint32_t get_bindings_version() { return "); + output.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + "; }\n"); + output.push_back("uint32_t get_cs_glue_version() { return "); + output.push_back(String::num_uint64(CS_GLUE_VERSION) + "; }\n"); + + output.push_back("void register_generated_icalls() " OPEN_BLOCK); + output.push_back("\tgodot_register_header_icalls();"); + +#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \ + { \ + output.push_back("\tmono_add_internal_call("); \ + output.push_back("\"" BINDINGS_NAMESPACE "."); \ + output.push_back(m_icall.editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); \ + output.push_back("::"); \ + output.push_back(m_icall.name); \ + output.push_back("\", (void*)"); \ + output.push_back(m_icall.name); \ + output.push_back(");\n"); \ } bool tools_sequence = false; @@ -1443,6 +1493,9 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { output.push_back("#endif\n"); } + for (const List<InternalCall>::Element *E = builtin_method_icalls.front(); E; E = E->next()) + ADD_INTERNAL_CALL_REGISTRATION(E->get()); + #undef ADD_INTERNAL_CALL_REGISTRATION output.push_back(CLOSE_BLOCK "}\n"); @@ -1456,6 +1509,14 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { return OK; } +uint32_t BindingsGenerator::get_version() { + return BINDINGS_GENERATOR_VERSION; +} + +uint32_t BindingsGenerator::get_cs_glue_version() { + return CS_GLUE_VERSION; +} + Error BindingsGenerator::_save_file(const String &p_path, const List<String> &p_content) { FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE); @@ -1477,9 +1538,9 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte if (p_imethod.is_virtual) return OK; // Ignore - bool ret_void = p_imethod.return_type == name_cache.type_void; + bool ret_void = p_imethod.return_type.cname == name_cache.type_void; - const TypeInterface *return_type = _get_type_by_name_or_placeholder(p_imethod.return_type); + const TypeInterface *return_type = _get_type_or_placeholder(p_imethod.return_type); String argc_str = itos(p_imethod.arguments.size()); @@ -1491,16 +1552,16 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte int i = 0; for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) { const ArgumentInterface &iarg = F->get(); - const TypeInterface *arg_type = _get_type_by_name_or_placeholder(iarg.type); + const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type); String c_param_name = "arg" + itos(i + 1); if (p_imethod.is_vararg) { if (i < p_imethod.arguments.size() - 1) { c_in_statements += sformat(arg_type->c_in.size() ? arg_type->c_in : TypeInterface::DEFAULT_VARARG_C_IN, "Variant", c_param_name); - c_in_statements += "\t" C_LOCAL_PTRCALL_ARGS ".set(0, "; - c_in_statements += sformat("&%s_in", c_param_name); - c_in_statements += ");\n"; + c_in_statements += "\t" C_LOCAL_PTRCALL_ARGS ".set("; + c_in_statements += itos(i); + c_in_statements += sformat(", &%s_in);\n", c_param_name); } } else { if (i > 0) @@ -1518,6 +1579,9 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte i++; } + if (!p_itype.is_object_type) + return OK; // no auto-generated icall functions for builtin types + const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod); ERR_FAIL_NULL_V(match, ERR_BUG); @@ -1629,42 +1693,49 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte return OK; } -const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_null(const StringName &p_cname) { +const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_null(const TypeReference &p_typeref) { - const Map<StringName, TypeInterface>::Element *builtin_type_match = builtin_types.find(p_cname); + const Map<StringName, TypeInterface>::Element *builtin_type_match = builtin_types.find(p_typeref.cname); if (builtin_type_match) return &builtin_type_match->get(); - const OrderedHashMap<StringName, TypeInterface>::Element obj_type_match = obj_types.find(p_cname); + const OrderedHashMap<StringName, TypeInterface>::Element obj_type_match = obj_types.find(p_typeref.cname); if (obj_type_match) return &obj_type_match.get(); - const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(p_cname); + if (p_typeref.is_enum) { + const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(p_typeref.cname); - if (enum_match) - return &enum_match->get(); + if (enum_match) + return &enum_match->get(); + + // Enum not found. Most likely because none of its constants were bound, so it's empty. That's fine. Use int instead. + const Map<StringName, TypeInterface>::Element *int_match = builtin_types.find(name_cache.type_int); + ERR_FAIL_NULL_V(int_match, NULL); + return &int_match->get(); + } return NULL; } -const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_placeholder(const StringName &p_cname) { +const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placeholder(const TypeReference &p_typeref) { - const TypeInterface *found = _get_type_by_name_or_null(p_cname); + const TypeInterface *found = _get_type_or_null(p_typeref); if (found) return found; - ERR_PRINTS(String() + "Type not found. Creating placeholder: " + p_cname.operator String()); + ERR_PRINTS(String() + "Type not found. Creating placeholder: " + p_typeref.cname.operator String()); - const Map<StringName, TypeInterface>::Element *match = placeholder_types.find(p_cname); + const Map<StringName, TypeInterface>::Element *match = placeholder_types.find(p_typeref.cname); if (match) return &match->get(); TypeInterface placeholder; - TypeInterface::create_placeholder_type(placeholder, p_cname); + TypeInterface::create_placeholder_type(placeholder, p_typeref.cname); return &placeholder_types.insert(placeholder.cname, placeholder)->get(); } @@ -1808,7 +1879,7 @@ void BindingsGenerator::_populate_object_type_interfaces() { // The method Object.free is registered as a virtual method, but without the virtual flag. // This is because this method is not supposed to be overridden, but called. // We assume the return type is void. - imethod.return_type = name_cache.type_void; + imethod.return_type.cname = name_cache.type_void; // Actually, more methods like this may be added in the future, // which could actually will return something different. @@ -1823,21 +1894,22 @@ void BindingsGenerator::_populate_object_type_interfaces() { } else { ERR_PRINTS("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name); } - } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { // TODO redundant? - imethod.return_type = return_info.class_name; + } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + imethod.return_type.cname = return_info.class_name; + imethod.return_type.is_enum = true; } else if (return_info.class_name != StringName()) { - imethod.return_type = return_info.class_name; + imethod.return_type.cname = return_info.class_name; } else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { - imethod.return_type = return_info.hint_string; + imethod.return_type.cname = return_info.hint_string; } else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) { - imethod.return_type = name_cache.type_Variant; + imethod.return_type.cname = name_cache.type_Variant; } else if (return_info.type == Variant::NIL) { - imethod.return_type = name_cache.type_void; + imethod.return_type.cname = name_cache.type_void; } else { - imethod.return_type = Variant::get_type_name(return_info.type); + imethod.return_type.cname = Variant::get_type_name(return_info.type); } - if (!itype.requires_collections && imethod.return_type == name_cache.type_Dictionary) + if (!itype.requires_collections && imethod.return_type.cname == name_cache.type_Dictionary) itype.requires_collections = true; for (int i = 0; i < argc; i++) { @@ -1846,21 +1918,22 @@ void BindingsGenerator::_populate_object_type_interfaces() { ArgumentInterface iarg; iarg.name = arginfo.name; - if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { // TODO redundant? - iarg.type = arginfo.class_name; + if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + iarg.type.cname = arginfo.class_name; + iarg.type.is_enum = true; } else if (arginfo.class_name != StringName()) { - iarg.type = arginfo.class_name; + iarg.type.cname = arginfo.class_name; } else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) { - iarg.type = arginfo.hint_string; + iarg.type.cname = arginfo.hint_string; } else if (arginfo.type == Variant::NIL) { - iarg.type = name_cache.type_Variant; + iarg.type.cname = name_cache.type_Variant; } else { - iarg.type = Variant::get_type_name(arginfo.type); + iarg.type.cname = Variant::get_type_name(arginfo.type); } iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name)); - if (!itype.requires_collections && iarg.type == name_cache.type_Dictionary) + if (!itype.requires_collections && iarg.type.cname == name_cache.type_Dictionary) itype.requires_collections = true; if (m && m->has_default_argument(i)) { @@ -1872,7 +1945,7 @@ void BindingsGenerator::_populate_object_type_interfaces() { if (imethod.is_vararg) { ArgumentInterface ivararg; - ivararg.type = name_cache.type_VarArg; + ivararg.type.cname = name_cache.type_VarArg; ivararg.name = "@args"; imethod.add_argument(ivararg); } @@ -1957,17 +2030,11 @@ void BindingsGenerator::_populate_object_type_interfaces() { itype.enums.push_back(ienum); TypeInterface enum_itype; + enum_itype.is_enum = true; enum_itype.name = itype.name + "." + String(*k); enum_itype.cname = StringName(enum_itype.name); enum_itype.proxy_name = itype.proxy_name + "." + enum_proxy_name; - enum_itype.c_arg_in = "&%s"; - enum_itype.c_type = "int"; - enum_itype.c_type_in = "int"; - enum_itype.c_type_out = "int"; - enum_itype.cs_type = enum_itype.proxy_name; - enum_itype.im_type_in = enum_itype.proxy_name; - enum_itype.im_type_out = enum_itype.proxy_name; - enum_itype.class_doc = &EditorHelp::get_doc_data()->class_list[enum_itype.proxy_name]; + TypeInterface::postsetup_enum_type(enum_itype); enum_types.insert(enum_itype.cname, enum_itype); } @@ -2002,7 +2069,7 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg switch (p_val.get_type()) { case Variant::NIL: - if (ClassDB::class_exists(r_iarg.type)) { + if (ClassDB::class_exists(r_iarg.type.cname)) { // Object type r_iarg.default_argument = "null"; } else { @@ -2015,7 +2082,7 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg r_iarg.default_argument = bool(p_val) ? "true" : "false"; break; case Variant::INT: - if (r_iarg.type != name_cache.type_int) { + if (r_iarg.type.cname != name_cache.type_int) { r_iarg.default_argument = "(%s)" + r_iarg.default_argument; } break; @@ -2076,7 +2143,7 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg default: {} } - if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type == name_cache.type_Variant && r_iarg.default_argument != "null") + if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type.cname == name_cache.type_Variant && r_iarg.default_argument != "null") r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; } @@ -2095,7 +2162,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_arg_in = "&%s_in"; \ itype.c_type_in = m_type_in; \ itype.cs_in = "ref %s"; \ - itype.cs_out = "return (" #m_type ")%0;"; \ + itype.cs_out = "return (%1)%0;"; \ itype.im_type_out = "object"; \ builtin_types.insert(itype.cname, itype); \ } @@ -2113,36 +2180,34 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { #undef INSERT_STRUCT_TYPE -#define INSERT_PRIMITIVE_TYPE(m_type) \ - { \ - itype = TypeInterface::create_value_type(String(#m_type)); \ - itype.c_arg_in = "&%s"; \ - itype.c_type_in = #m_type; \ - itype.c_type_out = #m_type; \ - itype.im_type_in = #m_type; \ - itype.im_type_out = #m_type; \ - builtin_types.insert(itype.cname, itype); \ - } - - INSERT_PRIMITIVE_TYPE(bool) - //INSERT_PRIMITIVE_TYPE(int) + // bool + itype = TypeInterface::create_value_type(String("bool")); + itype.c_arg_in = "&%s"; + // /* MonoBoolean <---> bool + itype.c_in = "\t%0 %1_in = (%0)%1;\n"; + itype.c_out = "\treturn (%0)%1;\n"; + itype.c_type = "bool"; + // */ + itype.c_type_in = "MonoBoolean"; + itype.c_type_out = itype.c_type_in; + itype.im_type_in = itype.name; + itype.im_type_out = itype.name; + builtin_types.insert(itype.cname, itype); // int itype = TypeInterface::create_value_type(String("int")); itype.c_arg_in = "&%s_in"; - //* ptrcall only supports int64_t and uint64_t + // /* ptrcall only supports int64_t and uint64_t itype.c_in = "\t%0 %1_in = (%0)%1;\n"; itype.c_out = "\treturn (%0)%1;\n"; itype.c_type = "int64_t"; - //*/ - itype.c_type_in = itype.name; - itype.c_type_out = itype.name; + // */ + itype.c_type_in = "int32_t"; + itype.c_type_out = itype.c_type_in; itype.im_type_in = itype.name; itype.im_type_out = itype.name; builtin_types.insert(itype.cname, itype); -#undef INSERT_PRIMITIVE_TYPE - // real_t itype = TypeInterface(); #ifdef REAL_T_IS_DOUBLE @@ -2192,7 +2257,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_out = itype.c_type + "*"; itype.cs_type = itype.proxy_name; itype.cs_in = "NodePath." CS_SMETHOD_GETINSTANCE "(%0)"; - itype.cs_out = "return new NodePath(%0);"; + itype.cs_out = "return new %1(%0);"; itype.im_type_in = "IntPtr"; itype.im_type_out = "IntPtr"; _populate_builtin_type(itype, Variant::NODE_PATH); @@ -2200,7 +2265,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { "this." BINDINGS_PTR_FIELD " = NativeCalls.godot_icall_NodePath_Ctor(path);\n" CLOSE_BLOCK_L2 MEMBER_BEGIN "public static implicit operator NodePath(string from)\n" OPEN_BLOCK_L2 "return new NodePath(from);\n" CLOSE_BLOCK_L2 MEMBER_BEGIN "public static implicit operator string(NodePath from)\n" OPEN_BLOCK_L2 - "return NativeCalls." ICALL_PREFIX "NodePath_operator_String(NodePath." CS_SMETHOD_GETINSTANCE "(from));\n" CLOSE_BLOCK_L2); + "return NativeCalls." ICALL_PREFIX "NodePath_operator_String(NodePath." CS_SMETHOD_GETINSTANCE "(from));\n" CLOSE_BLOCK_L2 + MEMBER_BEGIN "public override string ToString()\n" OPEN_BLOCK_L2 "return (string)this;\n" CLOSE_BLOCK_L2); builtin_types.insert(itype.cname, itype); // RID @@ -2214,7 +2280,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_out = itype.c_type + "*"; itype.cs_type = itype.proxy_name; itype.cs_in = "RID." CS_SMETHOD_GETINSTANCE "(%0)"; - itype.cs_out = "return new RID(%0);"; + itype.cs_out = "return new %1(%0);"; itype.im_type_in = "IntPtr"; itype.im_type_out = "IntPtr"; _populate_builtin_type(itype, Variant::_RID); @@ -2334,7 +2400,7 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant:: imethod.name = mi.name; imethod.cname = imethod.name; - imethod.proxy_name = mi.name; + imethod.proxy_name = escape_csharp_keyword(snake_to_pascal_case(mi.name)); for (int i = 0; i < mi.arguments.size(); i++) { ArgumentInterface iarg; @@ -2343,11 +2409,11 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant:: iarg.name = pi.name; if (pi.type == Variant::NIL) - iarg.type = name_cache.type_Variant; + iarg.type.cname = name_cache.type_Variant; else - iarg.type = Variant::get_type_name(pi.type); + iarg.type.cname = Variant::get_type_name(pi.type); - if (!r_itype.requires_collections && iarg.type == name_cache.type_Dictionary) + if (!r_itype.requires_collections && iarg.type.cname == name_cache.type_Dictionary) r_itype.requires_collections = true; if ((mi.default_arguments.size() - mi.arguments.size() + i) >= 0) @@ -2358,12 +2424,12 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant:: if (mi.return_val.type == Variant::NIL) { if (mi.return_val.name != "") - imethod.return_type = name_cache.type_Variant; + imethod.return_type.cname = name_cache.type_Variant; } else { - imethod.return_type = Variant::get_type_name(mi.return_val.type); + imethod.return_type.cname = Variant::get_type_name(mi.return_val.type); } - if (!r_itype.requires_collections && imethod.return_type == name_cache.type_Dictionary) + if (!r_itype.requires_collections && imethod.return_type.cname == name_cache.type_Dictionary) r_itype.requires_collections = true; if (r_itype.class_doc) { @@ -2429,13 +2495,11 @@ void BindingsGenerator::_populate_global_constants() { EnumInterface &ienum = E->get(); TypeInterface enum_itype; - enum_itype = TypeInterface::create_value_type(ienum.cname); - enum_itype.c_arg_in = "&%s"; - enum_itype.c_type = "int"; - enum_itype.c_type_in = "int"; - enum_itype.c_type_out = "int"; - enum_itype.im_type_in = enum_itype.name; - enum_itype.im_type_out = enum_itype.name; + enum_itype.is_enum = true; + enum_itype.name = ienum.cname.operator String(); + enum_itype.cname = ienum.cname; + enum_itype.proxy_name = enum_itype.name; + TypeInterface::postsetup_enum_type(enum_itype); enum_types.insert(enum_itype.cname, enum_itype); ienum.prefix = _determine_enum_prefix(ienum); @@ -2456,15 +2520,13 @@ void BindingsGenerator::_populate_global_constants() { hardcoded_enums.push_back("Vector3.Axis"); for (List<StringName>::Element *E = hardcoded_enums.front(); E; E = E->next()) { // These enums are not generated and must be written manually (e.g.: Vector3.Axis) - // Here, we are assuming core types do not begin with underscore + // Here, we assume core types do not begin with underscore TypeInterface enum_itype; - enum_itype = TypeInterface::create_value_type(E->get()); - enum_itype.c_arg_in = "&%s"; - enum_itype.c_type = "int"; - enum_itype.c_type_in = "int"; - enum_itype.c_type_out = "int"; - enum_itype.im_type_in = enum_itype.name; - enum_itype.im_type_out = enum_itype.name; + enum_itype.is_enum = true; + enum_itype.name = E->get().operator String(); + enum_itype.cname = E->get(); + enum_itype.proxy_name = enum_itype.name; + TypeInterface::postsetup_enum_type(enum_itype); enum_types.insert(enum_itype.cname, enum_itype); } } diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 8929b45cce..5b33a0e53f 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -81,6 +81,15 @@ class BindingsGenerator { const DocData::PropertyDoc *prop_doc; }; + struct TypeReference { + StringName cname; + bool is_enum; + + TypeReference() { + is_enum = false; + } + }; + struct ArgumentInterface { enum DefaultParamMode { CONSTANT, @@ -88,7 +97,8 @@ class BindingsGenerator { NULLABLE_REF }; - StringName type; + TypeReference type; + String name; String default_argument; DefaultParamMode def_param_mode; @@ -110,7 +120,7 @@ class BindingsGenerator { /** * [TypeInterface::name] of the return type */ - StringName return_type; + TypeReference return_type; /** * Determines if the method has a variable number of arguments (VarArg) @@ -146,7 +156,7 @@ class BindingsGenerator { } MethodInterface() { - return_type = BindingsGenerator::get_singleton()->name_cache.type_void; + return_type.cname = BindingsGenerator::get_singleton()->name_cache.type_void; is_vararg = false; is_virtual = false; requires_object_call = false; @@ -175,6 +185,7 @@ class BindingsGenerator { ClassDB::APIType api_type; + bool is_enum; bool is_object_type; bool is_singleton; bool is_reference; @@ -276,7 +287,9 @@ class BindingsGenerator { * One or more statements that determine how a variable of this type is returned from a method. * It must contain the return statement(s). * Formatting elements: - * %0 or %s: name of the variable to be returned + * %0: internal method call statement + * %1: [cs_type] of the return type + * %2: [im_type_out] of the return type */ String cs_out; @@ -293,8 +306,6 @@ class BindingsGenerator { /** * Type used for the return type of internal call methods. - * If [cs_out] is not empty and the method return type is not void, - * it is also used for the type of the return variable. */ String im_type_out; @@ -379,10 +390,24 @@ class BindingsGenerator { r_itype.im_type_out = r_itype.proxy_name; } + static void postsetup_enum_type(TypeInterface &r_enum_itype) { + r_enum_itype.c_arg_in = "&%s"; + r_enum_itype.c_type = "int"; + r_enum_itype.c_type_in = "int"; + r_enum_itype.c_type_out = "int"; + r_enum_itype.cs_type = r_enum_itype.proxy_name; + r_enum_itype.cs_in = "(int)%s"; + r_enum_itype.cs_out = "return (%1)%0;"; + r_enum_itype.im_type_in = "int"; + r_enum_itype.im_type_out = "int"; + r_enum_itype.class_doc = &EditorHelp::get_doc_data()->class_list[r_enum_itype.proxy_name]; + } + TypeInterface() { api_type = ClassDB::API_NONE; + is_enum = false; is_object_type = false; is_singleton = false; is_reference = false; @@ -441,6 +466,7 @@ class BindingsGenerator { Map<StringName, String> extra_members; List<InternalCall> method_icalls; + List<InternalCall> builtin_method_icalls; Map<const MethodInterface *, const InternalCall *> method_icalls_map; List<const InternalCall *> generated_icall_funcs; @@ -491,6 +517,8 @@ class BindingsGenerator { return "Ref"; else if (p_type.is_object_type) return "Obj"; + else if (p_type.is_enum) + return "int"; return p_type.name; } @@ -500,11 +528,11 @@ class BindingsGenerator { void _generate_header_icalls(); void _generate_method_icalls(const TypeInterface &p_itype); - const TypeInterface *_get_type_by_name_or_null(const StringName &p_cname); - const TypeInterface *_get_type_by_name_or_placeholder(const StringName &p_cname); + const TypeInterface *_get_type_or_null(const TypeReference &p_typeref); + const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref); - void _default_argument_from_variant(const Variant &p_var, ArgumentInterface &r_iarg); - void _populate_builtin_type(TypeInterface &r_type, Variant::Type vtype); + void _default_argument_from_variant(const Variant &p_val, ArgumentInterface &r_iarg); + void _populate_builtin_type(TypeInterface &r_itype, Variant::Type vtype); void _populate_object_type_interfaces(); void _populate_builtin_type_interfaces(); @@ -513,14 +541,14 @@ class BindingsGenerator { Error _generate_cs_type(const TypeInterface &itype, const String &p_output_file); - Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_prop_doc, List<String> &p_output); + Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_iprop, List<String> &p_output); Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, List<String> &p_output); void _generate_global_constants(List<String> &p_output); Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, List<String> &p_output); - Error _save_file(const String &path, const List<String> &content); + Error _save_file(const String &p_path, const List<String> &p_content); BindingsGenerator() {} @@ -535,6 +563,9 @@ public: Error generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output = true); Error generate_glue(const String &p_output_dir); + static uint32_t get_version(); + static uint32_t get_cs_glue_version(); + void initialize(); _FORCE_INLINE_ static BindingsGenerator *get_singleton() { diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index 6b41b10981..2f2b5768db 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -33,7 +33,6 @@ #include "main/main.h" #include "../godotsharp_dirs.h" -#include "../mono_gd/gd_mono.h" #include "../mono_gd/gd_mono_class.h" #include "../mono_gd/gd_mono_marshal.h" #include "../utils/path_utils.h" @@ -178,13 +177,15 @@ bool GodotSharpBuilds::build_api_sln(const String &p_name, const String &p_api_s return true; } -bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name) { +bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type) { String assembly_file = p_assembly_name + ".dll"; String assembly_src = p_src_dir.plus_file(assembly_file); String assembly_dst = p_dst_dir.plus_file(assembly_file); - if (!FileAccess::exists(assembly_dst) || FileAccess::get_modified_time(assembly_src) > FileAccess::get_modified_time(assembly_dst)) { + if (!FileAccess::exists(assembly_dst) || + FileAccess::get_modified_time(assembly_src) > FileAccess::get_modified_time(assembly_dst) || + GDMono::get_singleton()->metadata_is_api_assembly_invalidated(p_api_type)) { DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); String xml_file = p_assembly_name + ".xml"; @@ -200,36 +201,49 @@ bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String & memdelete(da); if (err != OK) { - show_build_error_dialog("Failed to copy " API_ASSEMBLY_NAME ".dll"); + show_build_error_dialog("Failed to copy " + assembly_file); return false; } + + GDMono::get_singleton()->metadata_set_api_assembly_invalidated(p_api_type, false); } return true; } -bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) { +String GodotSharpBuilds::_api_folder_name(APIAssembly::Type p_api_type) { + + uint64_t api_hash = p_api_type == APIAssembly::API_CORE ? + GDMono::get_singleton()->get_api_core_hash() : + GDMono::get_singleton()->get_api_editor_hash(); + return String::num_uint64(api_hash) + + "_" + String::num_uint64(BindingsGenerator::get_version()) + + "_" + String::num_uint64(BindingsGenerator::get_cs_glue_version()); +} + +bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) { - String api_name = p_api_type == API_CORE ? API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME; + String api_name = p_api_type == APIAssembly::API_CORE ? API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME; String api_build_config = "Release"; EditorProgress pr("mono_build_release_" + api_name, "Building " + api_name + " solution...", 4); pr.step("Generating " + api_name + " solution"); - uint64_t core_hash = GDMono::get_singleton()->get_api_core_hash(); - uint64_t editor_hash = GDMono::get_singleton()->get_api_editor_hash(); - - String core_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir().plus_file(API_ASSEMBLY_NAME "_" + itos(core_hash)); - String editor_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir().plus_file(EDITOR_API_ASSEMBLY_NAME "_" + itos(editor_hash)); + String core_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir() + .plus_file(_api_folder_name(APIAssembly::API_CORE)) + .plus_file(API_ASSEMBLY_NAME); + String editor_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir() + .plus_file(_api_folder_name(APIAssembly::API_EDITOR)) + .plus_file(EDITOR_API_ASSEMBLY_NAME); - String api_sln_dir = p_api_type == API_CORE ? core_api_sln_dir : editor_api_sln_dir; + String api_sln_dir = p_api_type == APIAssembly::API_CORE ? core_api_sln_dir : editor_api_sln_dir; String api_sln_file = api_sln_dir.plus_file(api_name + ".sln"); if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) { String core_api_assembly; - if (p_api_type == API_EDITOR) { + if (p_api_type == APIAssembly::API_EDITOR) { core_api_assembly = core_api_sln_dir.plus_file("bin") .plus_file(api_build_config) .plus_file(API_ASSEMBLY_NAME ".dll"); @@ -242,7 +256,7 @@ bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) { BindingsGenerator *gen = BindingsGenerator::get_singleton(); bool gen_verbose = OS::get_singleton()->is_stdout_verbose(); - Error err = p_api_type == API_CORE ? + Error err = p_api_type == APIAssembly::API_CORE ? gen->generate_cs_core_project(api_sln_dir, gen_verbose) : gen->generate_cs_editor_project(api_sln_dir, core_api_assembly, gen_verbose); @@ -275,7 +289,7 @@ bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) { // Copy the built assembly to the assemblies directory String api_assembly_dir = api_sln_dir.plus_file("bin").plus_file(api_build_config); - if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name)) + if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name, p_api_type)) return false; pr.step("Done"); @@ -283,22 +297,22 @@ bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) { return true; } -bool GodotSharpBuilds::build_project_blocking() { +bool GodotSharpBuilds::build_project_blocking(const String &p_config) { if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path())) return true; // No solution to build - if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_CORE)) + if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE)) return false; - if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_EDITOR)) + if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR)) return false; EditorProgress pr("mono_project_debug_build", "Building project solution...", 2); pr.step("Building project solution"); - MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), "Tools"); + MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), p_config); if (!GodotSharpBuilds::get_singleton()->build(build_info)) { GodotSharpBuilds::show_build_error_dialog("Failed to build project solution"); return false; @@ -309,6 +323,11 @@ bool GodotSharpBuilds::build_project_blocking() { return true; } +bool GodotSharpBuilds::editor_build_callback() { + + return build_project_blocking("Tools"); +} + GodotSharpBuilds *GodotSharpBuilds::singleton = NULL; void GodotSharpBuilds::build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code) { @@ -362,7 +381,7 @@ GodotSharpBuilds::GodotSharpBuilds() { singleton = this; - EditorNode::get_singleton()->add_build_callback(&GodotSharpBuilds::build_project_blocking); + EditorNode::get_singleton()->add_build_callback(&GodotSharpBuilds::editor_build_callback); // Build tool settings EditorSettings *ed_settings = EditorSettings::get_singleton(); @@ -462,6 +481,7 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) { if (ex) { exited = true; + GDMonoUtils::print_unhandled_exception(ex); String message = "The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex); build_tab->on_build_exec_failed(message); ERR_EXPLAIN(message); @@ -482,6 +502,7 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) { if (ex) { exited = true; + GDMonoUtils::print_unhandled_exception(ex); String message = "The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex); build_tab->on_build_exec_failed(message); ERR_EXPLAIN(message); @@ -504,11 +525,10 @@ void GodotSharpBuilds::BuildProcess::start(bool p_blocking) { } } -GodotSharpBuilds::BuildProcess::BuildProcess(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback) { - - build_info = p_build_info; - build_tab = NULL; - exit_callback = p_callback; - exited = true; - exit_code = -1; +GodotSharpBuilds::BuildProcess::BuildProcess(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback) : + build_info(p_build_info), + build_tab(NULL), + exit_callback(p_callback), + exited(true), + exit_code(-1) { } diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h index 5d2390ecd9..27b771e324 100644 --- a/modules/mono/editor/godotsharp_builds.h +++ b/modules/mono/editor/godotsharp_builds.h @@ -31,6 +31,7 @@ #ifndef GODOTSHARP_BUILDS_H #define GODOTSHARP_BUILDS_H +#include "../mono_gd/gd_mono.h" #include "mono_bottom_panel.h" #include "mono_build_info.h" @@ -56,17 +57,14 @@ private: HashMap<MonoBuildInfo, BuildProcess, MonoBuildInfo::Hasher> builds; + static String _api_folder_name(APIAssembly::Type p_api_type); + static GodotSharpBuilds *singleton; friend class GDMono; static void _register_internal_calls(); public: - enum APIType { - API_CORE, - API_EDITOR - }; - enum BuildTool { MSBUILD_MONO, #ifdef WINDOWS_ENABLED @@ -89,11 +87,13 @@ public: bool build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback = NULL); static bool build_api_sln(const String &p_name, const String &p_api_sln_dir, const String &p_config); - static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name); + static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type); + + static bool make_api_sln(APIAssembly::Type p_api_type); - static bool make_api_sln(APIType p_api_type); + static bool build_project_blocking(const String &p_config); - static bool build_project_blocking(); + static bool editor_build_callback(); GodotSharpBuilds(); ~GodotSharpBuilds(); diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index 9e48da68c1..998da8bda3 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -41,6 +41,7 @@ #include "../utils/path_utils.h" #include "bindings_generator.h" #include "csharp_project.h" +#include "godotsharp_export.h" #include "net_solution.h" #ifdef WINDOWS_ENABLED @@ -84,10 +85,10 @@ bool GodotSharpEditor::_create_project_solution() { return false; } - if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_CORE)) + if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE)) return false; - if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_EDITOR)) + if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR)) return false; pr.step(TTR("Done")); @@ -112,6 +113,21 @@ void GodotSharpEditor::_remove_create_sln_menu_option() { bottom_panel_btn->show(); } +void GodotSharpEditor::_show_about_dialog() { + + bool show_on_start = EDITOR_GET("mono/editor/show_info_on_start"); + about_dialog_checkbox->set_pressed(show_on_start); + about_dialog->popup_centered_minsize(); +} + +void GodotSharpEditor::_toggle_about_dialog_on_start(bool p_enabled) { + + bool show_on_start = EDITOR_GET("mono/editor/show_info_on_start"); + if (show_on_start != p_enabled) { + EditorSettings::get_singleton()->set_setting("mono/editor/show_info_on_start", p_enabled); + } +} + void GodotSharpEditor::_menu_option_pressed(int p_id) { switch (p_id) { @@ -119,15 +135,37 @@ void GodotSharpEditor::_menu_option_pressed(int p_id) { _create_project_solution(); } break; + case MENU_ABOUT_CSHARP: { + + _show_about_dialog(); + } break; default: ERR_FAIL(); } } +void GodotSharpEditor::_notification(int p_notification) { + + switch (p_notification) { + + case NOTIFICATION_READY: { + + bool show_info_dialog = EDITOR_GET("mono/editor/show_info_on_start"); + if (show_info_dialog) { + about_dialog->set_exclusive(true); + _show_about_dialog(); + // Once shown a first time, it can be seen again via the Mono menu - it doesn't have to be exclusive then. + about_dialog->set_exclusive(false); + } + } + } +} + void GodotSharpEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_create_project_solution"), &GodotSharpEditor::_create_project_solution); ClassDB::bind_method(D_METHOD("_remove_create_sln_menu_option"), &GodotSharpEditor::_remove_create_sln_menu_option); + ClassDB::bind_method(D_METHOD("_toggle_about_dialog_on_start"), &GodotSharpEditor::_toggle_about_dialog_on_start); ClassDB::bind_method(D_METHOD("_menu_option_pressed", "id"), &GodotSharpEditor::_menu_option_pressed); } @@ -210,6 +248,56 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { menu_button->set_text(TTR("Mono")); menu_popup = menu_button->get_popup(); + // TODO: Remove or edit this info dialog once Mono support is no longer in alpha + { + menu_popup->add_item(TTR("About C# support"), MENU_ABOUT_CSHARP); + about_dialog = memnew(AcceptDialog); + editor->get_gui_base()->add_child(about_dialog); + about_dialog->set_title("Important: C# support is not feature-complete"); + + // We don't use set_text() as the default AcceptDialog Label doesn't play well with the TextureRect and CheckBox + // we'll add. Instead we add containers and a new autowrapped Label inside. + + // Main VBoxContainer (icon + label on top, checkbox at bottom) + VBoxContainer *about_vbc = memnew(VBoxContainer); + about_dialog->add_child(about_vbc); + + // HBoxContainer for icon + label + HBoxContainer *about_hbc = memnew(HBoxContainer); + about_vbc->add_child(about_hbc); + + TextureRect *about_icon = memnew(TextureRect); + about_hbc->add_child(about_icon); + Ref<Texture> about_icon_tex = about_icon->get_icon("NodeWarning", "EditorIcons"); + about_icon->set_texture(about_icon_tex); + + Label *about_label = memnew(Label); + about_hbc->add_child(about_label); + about_label->set_custom_minimum_size(Size2(600, 150) * EDSCALE); + about_label->set_v_size_flags(Control::SIZE_EXPAND_FILL); + about_label->set_autowrap(true); + String about_text = + String("C# support in Godot Engine is a brand new feature and a work in progress.\n") + + "It is at the alpha stage and thus not suitable for use in production.\n\n" + + "As of Godot 3.0, C# support is not feature-complete and may crash in some situations. " + + "Bugs and usability issues will be addressed gradually over 3.0.x and 3.x releases, " + + "including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" + + "The main missing feature is the ability to export games using C# assemblies - you will therefore be able to develop and run games in the editor, " + + "but not to share them as standalone binaries yet. This feature is of course high on the priority list and should be available as soon as possible.\n\n" + + "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, Mono version, IDE, etc.:\n\n" + + " https://github.com/godotengine/godot/issues\n\n" + + "Your critical feedback at this stage will play a great role in shaping the C# support in future releases, so thank you!"; + about_label->set_text(about_text); + + EDITOR_DEF("mono/editor/show_info_on_start", true); + + // CheckBox in main container + about_dialog_checkbox = memnew(CheckBox); + about_vbc->add_child(about_dialog_checkbox); + about_dialog_checkbox->set_text("Show this warning when starting the editor"); + about_dialog_checkbox->connect("toggled", this, "_toggle_about_dialog_on_start"); + } + String sln_path = GodotSharpDirs::get_project_sln_path(); String csproj_path = GodotSharpDirs::get_project_csproj_path(); @@ -229,6 +317,11 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { EditorSettings *ed_settings = EditorSettings::get_singleton(); EDITOR_DEF("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 Code")); + + // Export plugin + Ref<GodotSharpExport> godotsharp_export; + godotsharp_export.instance(); + EditorExport::get_singleton()->add_export_plugin(godotsharp_export); } GodotSharpEditor::~GodotSharpEditor() { diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h index 1b83bae1cd..66da814c8b 100644 --- a/modules/mono/editor/godotsharp_editor.h +++ b/modules/mono/editor/godotsharp_editor.h @@ -32,7 +32,6 @@ #define GODOTSHARP_EDITOR_H #include "godotsharp_builds.h" - #include "monodevelop_instance.h" class GodotSharpEditor : public Node { @@ -44,6 +43,8 @@ class GodotSharpEditor : public Node { PopupMenu *menu_popup; AcceptDialog *error_dialog; + AcceptDialog *about_dialog; + CheckBox *about_dialog_checkbox; ToolButton *bottom_panel_btn; @@ -54,17 +55,21 @@ class GodotSharpEditor : public Node { bool _create_project_solution(); void _remove_create_sln_menu_option(); + void _show_about_dialog(); + void _toggle_about_dialog_on_start(bool p_enabled); void _menu_option_pressed(int p_id); static GodotSharpEditor *singleton; protected: + void _notification(int p_notification); static void _bind_methods(); public: enum MenuOptions { - MENU_CREATE_SLN + MENU_CREATE_SLN, + MENU_ABOUT_CSHARP, }; enum ExternalEditor { diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp new file mode 100644 index 0000000000..cd09e6516a --- /dev/null +++ b/modules/mono/editor/godotsharp_export.cpp @@ -0,0 +1,166 @@ +/*************************************************************************/ +/* godotsharp_export.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "godotsharp_export.h" + +#include "../csharp_script.h" +#include "../godotsharp_defs.h" +#include "../godotsharp_dirs.h" +#include "godotsharp_builds.h" + +void GodotSharpExport::_export_file(const String &p_path, const String &p_type, const Set<String> &p_features) { + + if (p_type != CSharpLanguage::get_singleton()->get_type()) + return; + + ERR_FAIL_COND(p_path.get_extension() != CSharpLanguage::get_singleton()->get_extension()); + + // TODO what if the source file is not part of the game's C# project + + if (!GLOBAL_GET("mono/export/include_scripts_content")) { + // We don't want to include the source code on exported games + add_file(p_path, Vector<uint8_t>(), false); + skip(); + } +} + +void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug, const String &p_path, int p_flags) { + + // TODO right now there is no way to stop the export process with an error + + ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized()); + ERR_FAIL_NULL(GDMono::get_singleton()->get_tools_domain()); + + String build_config = p_debug ? "Debug" : "Release"; + + ERR_FAIL_COND(!GodotSharpBuilds::build_project_blocking(build_config)); + + // Add API assemblies + + String core_api_dll_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(API_ASSEMBLY_NAME ".dll"); + ERR_FAIL_COND(!_add_assembly(core_api_dll_path, core_api_dll_path)); + + String editor_api_dll_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); + ERR_FAIL_COND(!_add_assembly(editor_api_dll_path, editor_api_dll_path)); + + // Add project assembly + + String project_dll_name = ProjectSettings::get_singleton()->get("application/config/name"); + if (project_dll_name.empty()) { + project_dll_name = "UnnamedProject"; + } + + String project_dll_src_path = GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(build_config).plus_file(project_dll_name + ".dll"); + String project_dll_dst_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(project_dll_name + ".dll"); + ERR_FAIL_COND(!_add_assembly(project_dll_src_path, project_dll_dst_path)); + + // Add dependencies + + MonoDomain *prev_domain = mono_domain_get(); + MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain"); + + ERR_FAIL_COND(!export_domain); + ERR_FAIL_COND(!mono_domain_set(export_domain, false)); + + Map<String, String> dependencies; + dependencies.insert("mscorlib", GDMono::get_singleton()->get_corlib_assembly()->get_path()); + + GDMonoAssembly *scripts_assembly = GDMonoAssembly::load_from(project_dll_name, project_dll_src_path, /* refonly: */ true); + + ERR_EXPLAIN("Cannot load refonly assembly: " + project_dll_name); + ERR_FAIL_COND(!scripts_assembly); + + Error depend_error = _get_assembly_dependencies(scripts_assembly, dependencies); + + GDMono::get_singleton()->finalize_and_unload_domain(export_domain); + mono_domain_set(prev_domain, false); + + ERR_FAIL_COND(depend_error != OK); + + for (Map<String, String>::Element *E = dependencies.front(); E; E = E->next()) { + String depend_src_path = E->value(); + String depend_dst_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(depend_src_path.get_file()); + ERR_FAIL_COND(!_add_assembly(depend_src_path, depend_dst_path)); + } +} + +bool GodotSharpExport::_add_assembly(const String &p_src_path, const String &p_dst_path) { + + FileAccessRef f = FileAccess::open(p_src_path, FileAccess::READ); + ERR_FAIL_COND_V(!f, false); + + Vector<uint8_t> data; + data.resize(f->get_len()); + f->get_buffer(data.ptrw(), data.size()); + + add_file(p_dst_path, data, false); + + return true; +} + +Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, Map<String, String> &r_dependencies) { + + MonoImage *image = p_assembly->get_image(); + + for (int i = 0; i < mono_image_get_table_rows(image, MONO_TABLE_ASSEMBLYREF); i++) { + MonoAssemblyName *ref_aname = aname_prealloc; + mono_assembly_get_assemblyref(image, i, ref_aname); + String ref_name = mono_assembly_name_get_name(ref_aname); + + if (ref_name == "mscorlib" || r_dependencies.find(ref_name)) + continue; + + GDMonoAssembly *ref_assembly = NULL; + if (!GDMono::get_singleton()->load_assembly(ref_name, ref_aname, &ref_assembly, /* refonly: */ true)) { + ERR_EXPLAIN("Cannot load refonly assembly: " + ref_name); + ERR_FAIL_V(ERR_CANT_RESOLVE); + } + + r_dependencies.insert(ref_name, ref_assembly->get_path()); + + Error err = _get_assembly_dependencies(ref_assembly, r_dependencies); + if (err != OK) + return err; + } + + return OK; +} + +GodotSharpExport::GodotSharpExport() { + // MonoAssemblyName is an incomplete type (internal to mono), so we can't allocate it ourselves. + // There isn't any api to allocate an empty one either, so we need to do it this way. + aname_prealloc = mono_assembly_name_new("whatever"); + mono_assembly_name_free(aname_prealloc); // "it does not frees the object itself, only the name members" (typo included) +} + +GodotSharpExport::~GodotSharpExport() { + if (aname_prealloc) + mono_free(aname_prealloc); +} diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h new file mode 100644 index 0000000000..b38db9660c --- /dev/null +++ b/modules/mono/editor/godotsharp_export.h @@ -0,0 +1,57 @@ +/*************************************************************************/ +/* godotsharp_export.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GODOTSHARP_EXPORT_H +#define GODOTSHARP_EXPORT_H + +#include <mono/metadata/image.h> + +#include "editor/editor_export.h" + +#include "../mono_gd/gd_mono_header.h" + +class GodotSharpExport : public EditorExportPlugin { + + MonoAssemblyName *aname_prealloc; + + bool _add_assembly(const String &p_src_path, const String &p_dst_path); + + Error _get_assembly_dependencies(GDMonoAssembly *p_assembly, Map<String, String> &r_dependencies); + +protected: + virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features); + virtual void _export_begin(const Set<String> &p_features, bool p_debug, const String &p_path, int p_flags); + +public: + GodotSharpExport(); + ~GodotSharpExport(); +}; + +#endif // GODOTSHARP_EXPORT_H diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp index 43689548b5..1b5a303835 100644 --- a/modules/mono/editor/mono_bottom_panel.cpp +++ b/modules/mono/editor/mono_bottom_panel.cpp @@ -142,7 +142,7 @@ void MonoBottomPanel::_errors_toggled(bool p_pressed) { void MonoBottomPanel::_build_project_pressed() { - GodotSharpBuilds::get_singleton()->build_project_blocking(); + GodotSharpBuilds::get_singleton()->build_project_blocking("Tools"); MonoReloadNode::get_singleton()->restart_reload_timer(); CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true); @@ -197,7 +197,7 @@ MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) { toolbar_hbc->set_h_size_flags(SIZE_EXPAND_FILL); panel_builds_tab->add_child(toolbar_hbc); - ToolButton *build_project_btn = memnew(ToolButton); + Button *build_project_btn = memnew(Button); build_project_btn->set_text(TTR("Build Project")); build_project_btn->set_focus_mode(FOCUS_NONE); build_project_btn->connect("pressed", this, "_build_project_pressed"); @@ -335,16 +335,14 @@ void MonoBuildTab::_update_issues_list() { Ref<Texture> MonoBuildTab::get_icon_texture() const { - // FIXME these icons were removed... find something better - if (build_exited) { if (build_result == RESULT_ERROR) { - return get_icon("DependencyChangedHl", "EditorIcons"); + return get_icon("StatusError", "EditorIcons"); } else { - return get_icon("DependencyOkHl", "EditorIcons"); + return get_icon("StatusSuccess", "EditorIcons"); } } else { - return get_icon("GraphTime", "EditorIcons"); + return get_icon("Stop", "EditorIcons"); } } @@ -409,9 +407,14 @@ void MonoBuildTab::stop_build() { void MonoBuildTab::_issue_activated(int p_idx) { - ERR_FAIL_INDEX(p_idx, issues.size()); + ERR_FAIL_INDEX(p_idx, issues_list->get_item_count()); + + // Get correct issue idx from issue list + int issue_idx = this->issues_list->get_item_metadata(p_idx); + + ERR_FAIL_INDEX(issue_idx, issues.size()); - const BuildIssue &issue = issues[p_idx]; + const BuildIssue &issue = issues[issue_idx]; if (issue.project_file.empty() && issue.file.empty()) return; @@ -439,21 +442,16 @@ void MonoBuildTab::_bind_methods() { ClassDB::bind_method("_issue_activated", &MonoBuildTab::_issue_activated); } -MonoBuildTab::MonoBuildTab(const MonoBuildInfo &p_build_info, const String &p_logs_dir) { - - build_info = p_build_info; - logs_dir = p_logs_dir; - - build_exited = false; - - issues_list = memnew(ItemList); +MonoBuildTab::MonoBuildTab(const MonoBuildInfo &p_build_info, const String &p_logs_dir) : + build_info(p_build_info), + logs_dir(p_logs_dir), + build_exited(false), + issues_list(memnew(ItemList)), + error_count(0), + warning_count(0), + errors_visible(true), + warnings_visible(true) { issues_list->set_v_size_flags(SIZE_EXPAND_FILL); issues_list->connect("item_activated", this, "_issue_activated"); add_child(issues_list); - - error_count = 0; - warning_count = 0; - - errors_visible = true; - warnings_visible = true; } diff --git a/modules/mono/editor/monodevelop_instance.h b/modules/mono/editor/monodevelop_instance.h index 7e8a76b595..552c10a61d 100644 --- a/modules/mono/editor/monodevelop_instance.h +++ b/modules/mono/editor/monodevelop_instance.h @@ -43,7 +43,7 @@ class MonoDevelopInstance { public: void execute(const Vector<String> &p_files); - void execute(const String &p_files); + void execute(const String &p_file); MonoDevelopInstance(const String &p_solution); }; diff --git a/modules/mono/glue/builtin_types_glue.h b/modules/mono/glue/builtin_types_glue.h new file mode 100644 index 0000000000..ef9f152682 --- /dev/null +++ b/modules/mono/glue/builtin_types_glue.h @@ -0,0 +1,89 @@ +/*************************************************************************/ +/* builtin_types_glue.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef BUILTIN_TYPES_GLUE_H +#define BUILTIN_TYPES_GLUE_H + +#include "core/node_path.h" +#include "core/rid.h" + +#include <mono/metadata/object.h> + +#include "../mono_gd/gd_mono_marshal.h" + +MonoBoolean godot_icall_NodePath_is_absolute(NodePath *p_ptr) { + return (MonoBoolean)p_ptr->is_absolute(); +} + +uint32_t godot_icall_NodePath_get_name_count(NodePath *p_ptr) { + return p_ptr->get_name_count(); +} + +MonoString *godot_icall_NodePath_get_name(NodePath *p_ptr, uint32_t p_idx) { + return GDMonoMarshal::mono_string_from_godot(p_ptr->get_name(p_idx)); +} + +uint32_t godot_icall_NodePath_get_subname_count(NodePath *p_ptr) { + return p_ptr->get_subname_count(); +} + +MonoString *godot_icall_NodePath_get_subname(NodePath *p_ptr, uint32_t p_idx) { + return GDMonoMarshal::mono_string_from_godot(p_ptr->get_subname(p_idx)); +} + +MonoString *godot_icall_NodePath_get_concatenated_subnames(NodePath *p_ptr) { + return GDMonoMarshal::mono_string_from_godot(p_ptr->get_concatenated_subnames()); +} + +NodePath *godot_icall_NodePath_get_as_property_path(NodePath *p_ptr) { + return memnew(NodePath(p_ptr->get_as_property_path())); +} + +MonoBoolean godot_icall_NodePath_is_empty(NodePath *p_ptr) { + return (MonoBoolean)p_ptr->is_empty(); +} + +uint32_t godot_icall_RID_get_id(RID *p_ptr) { + return p_ptr->get_id(); +} + +void godot_register_builtin_type_icalls() { + mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_as_property_path", (void *)godot_icall_NodePath_get_as_property_path); + mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_concatenated_subnames", (void *)godot_icall_NodePath_get_concatenated_subnames); + mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_name", (void *)godot_icall_NodePath_get_name); + mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_name_count", (void *)godot_icall_NodePath_get_name_count); + mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_subname", (void *)godot_icall_NodePath_get_subname); + mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_subname_count", (void *)godot_icall_NodePath_get_subname_count); + mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_is_absolute", (void *)godot_icall_NodePath_is_absolute); + mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_is_empty", (void *)godot_icall_NodePath_is_empty); + mono_add_internal_call("Godot.NativeCalls::godot_icall_RID_get_id", (void *)godot_icall_RID_get_id); +} + +#endif // BUILTIN_TYPES_GLUE_H diff --git a/modules/mono/glue/cs_files/AABB.cs b/modules/mono/glue/cs_files/AABB.cs index e6e12f7ba3..39f2d2ed51 100644 --- a/modules/mono/glue/cs_files/AABB.cs +++ b/modules/mono/glue/cs_files/AABB.cs @@ -1,11 +1,15 @@ -using System; - // file: core/math/aabb.h // commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451 // file: core/math/aabb.cpp // commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0 // file: core/variant_call.cpp // commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685 +using System; +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif namespace Godot { @@ -45,12 +49,12 @@ namespace Godot Vector3 dst_min = with.position; Vector3 dst_max = with.position + with.size; - return ((src_min.x <= dst_min.x) && - (src_max.x > dst_max.x) && - (src_min.y <= dst_min.y) && - (src_max.y > dst_max.y) && - (src_min.z <= dst_min.z) && - (src_max.z > dst_max.z)); + return src_min.x <= dst_min.x && + src_max.x > dst_max.x && + src_min.y <= dst_min.y && + src_max.y > dst_max.y && + src_min.z <= dst_min.z && + src_max.z > dst_max.z; } public AABB Expand(Vector3 to_point) @@ -75,7 +79,7 @@ namespace Godot return new AABB(begin, end - begin); } - public float GetArea() + public real_t GetArea() { return size.x * size.y * size.z; } @@ -107,8 +111,8 @@ namespace Godot public Vector3 GetLongestAxis() { - Vector3 axis = new Vector3(1f, 0f, 0f); - float max_size = size.x; + var axis = new Vector3(1f, 0f, 0f); + real_t max_size = size.x; if (size.y > max_size) { @@ -119,7 +123,6 @@ namespace Godot if (size.z > max_size) { axis = new Vector3(0f, 0f, 1f); - max_size = size.z; } return axis; @@ -127,8 +130,8 @@ namespace Godot public Vector3.Axis GetLongestAxisIndex() { - Vector3.Axis axis = Vector3.Axis.X; - float max_size = size.x; + var axis = Vector3.Axis.X; + real_t max_size = size.x; if (size.y > max_size) { @@ -139,15 +142,14 @@ namespace Godot if (size.z > max_size) { axis = Vector3.Axis.Z; - max_size = size.z; } return axis; } - public float GetLongestAxisSize() + public real_t GetLongestAxisSize() { - float max_size = size.x; + real_t max_size = size.x; if (size.y > max_size) max_size = size.y; @@ -160,8 +162,8 @@ namespace Godot public Vector3 GetShortestAxis() { - Vector3 axis = new Vector3(1f, 0f, 0f); - float max_size = size.x; + var axis = new Vector3(1f, 0f, 0f); + real_t max_size = size.x; if (size.y < max_size) { @@ -172,7 +174,6 @@ namespace Godot if (size.z < max_size) { axis = new Vector3(0f, 0f, 1f); - max_size = size.z; } return axis; @@ -180,8 +181,8 @@ namespace Godot public Vector3.Axis GetShortestAxisIndex() { - Vector3.Axis axis = Vector3.Axis.X; - float max_size = size.x; + var axis = Vector3.Axis.X; + real_t max_size = size.x; if (size.y < max_size) { @@ -192,15 +193,14 @@ namespace Godot if (size.z < max_size) { axis = Vector3.Axis.Z; - max_size = size.z; } return axis; } - public float GetShortestAxisSize() + public real_t GetShortestAxisSize() { - float max_size = size.x; + real_t max_size = size.x; if (size.y < max_size) max_size = size.y; @@ -217,14 +217,14 @@ namespace Godot Vector3 ofs = position + half_extents; return ofs + new Vector3( - (dir.x > 0f) ? -half_extents.x : half_extents.x, - (dir.y > 0f) ? -half_extents.y : half_extents.y, - (dir.z > 0f) ? -half_extents.z : half_extents.z); + dir.x > 0f ? -half_extents.x : half_extents.x, + dir.y > 0f ? -half_extents.y : half_extents.y, + dir.z > 0f ? -half_extents.z : half_extents.z); } - public AABB Grow(float by) + public AABB Grow(real_t by) { - AABB res = this; + var res = this; res.position.x -= by; res.position.y -= by; @@ -277,48 +277,42 @@ namespace Godot { return new AABB(); } - else - { - min.x = (src_min.x > dst_min.x) ? src_min.x : dst_min.x; - max.x = (src_max.x < dst_max.x) ? src_max.x : dst_max.x; - } + + min.x = src_min.x > dst_min.x ? src_min.x : dst_min.x; + max.x = src_max.x < dst_max.x ? src_max.x : dst_max.x; if (src_min.y > dst_max.y || src_max.y < dst_min.y) { return new AABB(); } - else - { - min.y = (src_min.y > dst_min.y) ? src_min.y : dst_min.y; - max.y = (src_max.y < dst_max.y) ? src_max.y : dst_max.y; - } + + min.y = src_min.y > dst_min.y ? src_min.y : dst_min.y; + max.y = src_max.y < dst_max.y ? src_max.y : dst_max.y; if (src_min.z > dst_max.z || src_max.z < dst_min.z) { return new AABB(); } - else - { - min.z = (src_min.z > dst_min.z) ? src_min.z : dst_min.z; - max.z = (src_max.z < dst_max.z) ? src_max.z : dst_max.z; - } + + min.z = src_min.z > dst_min.z ? src_min.z : dst_min.z; + max.z = src_max.z < dst_max.z ? src_max.z : dst_max.z; return new AABB(min, max - min); } public bool Intersects(AABB with) { - if (position.x >= (with.position.x + with.size.x)) + if (position.x >= with.position.x + with.size.x) return false; - if ((position.x + size.x) <= with.position.x) + if (position.x + size.x <= with.position.x) return false; - if (position.y >= (with.position.y + with.size.y)) + if (position.y >= with.position.y + with.size.y) return false; - if ((position.y + size.y) <= with.position.y) + if (position.y + size.y <= with.position.y) return false; - if (position.z >= (with.position.z + with.size.z)) + if (position.z >= with.position.z + with.size.z) return false; - if ((position.z + size.z) <= with.position.z) + if (position.z + size.z <= with.position.z) return false; return true; @@ -335,7 +329,7 @@ namespace Godot new Vector3(position.x + size.x, position.y, position.z), new Vector3(position.x + size.x, position.y, position.z + size.z), new Vector3(position.x + size.x, position.y + size.y, position.z), - new Vector3(position.x + size.x, position.y + size.y, position.z + size.z), + new Vector3(position.x + size.x, position.y + size.y, position.z + size.z) }; bool over = false; @@ -354,23 +348,23 @@ namespace Godot public bool IntersectsSegment(Vector3 from, Vector3 to) { - float min = 0f; - float max = 1f; + real_t min = 0f; + real_t max = 1f; for (int i = 0; i < 3; i++) { - float seg_from = from[i]; - float seg_to = to[i]; - float box_begin = position[i]; - float box_end = box_begin + size[i]; - float cmin, cmax; + real_t seg_from = from[i]; + real_t seg_to = to[i]; + real_t box_begin = position[i]; + real_t box_end = box_begin + size[i]; + real_t cmin, cmax; if (seg_from < seg_to) { if (seg_from > box_end || seg_to < box_begin) return false; - float length = seg_to - seg_from; + real_t length = seg_to - seg_from; cmin = seg_from < box_begin ? (box_begin - seg_from) / length : 0f; cmax = seg_to > box_end ? (box_end - seg_from) / length : 1f; } @@ -379,7 +373,7 @@ namespace Godot if (seg_to > box_end || seg_from < box_begin) return false; - float length = seg_to - seg_from; + real_t length = seg_to - seg_from; cmin = seg_from > box_end ? (box_end - seg_from) / length : 0f; cmax = seg_to < box_begin ? (box_begin - seg_from) / length : 1f; } @@ -402,24 +396,25 @@ namespace Godot { Vector3 beg_1 = position; Vector3 beg_2 = with.position; - Vector3 end_1 = new Vector3(size.x, size.y, size.z) + beg_1; - Vector3 end_2 = new Vector3(with.size.x, with.size.y, with.size.z) + beg_2; + var end_1 = new Vector3(size.x, size.y, size.z) + beg_1; + var end_2 = new Vector3(with.size.x, with.size.y, with.size.z) + beg_2; - Vector3 min = new Vector3( - (beg_1.x < beg_2.x) ? beg_1.x : beg_2.x, - (beg_1.y < beg_2.y) ? beg_1.y : beg_2.y, - (beg_1.z < beg_2.z) ? beg_1.z : beg_2.z + var min = new Vector3( + beg_1.x < beg_2.x ? beg_1.x : beg_2.x, + beg_1.y < beg_2.y ? beg_1.y : beg_2.y, + beg_1.z < beg_2.z ? beg_1.z : beg_2.z ); - Vector3 max = new Vector3( - (end_1.x > end_2.x) ? end_1.x : end_2.x, - (end_1.y > end_2.y) ? end_1.y : end_2.y, - (end_1.z > end_2.z) ? end_1.z : end_2.z + var max = new Vector3( + end_1.x > end_2.x ? end_1.x : end_2.x, + end_1.y > end_2.y ? end_1.y : end_2.y, + end_1.z > end_2.z ? end_1.z : end_2.z ); return new AABB(min, max - min); } - + + // Constructors public AABB(Vector3 position, Vector3 size) { this.position = position; @@ -460,8 +455,8 @@ namespace Godot { return String.Format("{0} - {1}", new object[] { - this.position.ToString(), - this.size.ToString() + position.ToString(), + size.ToString() }); } @@ -469,8 +464,8 @@ namespace Godot { return String.Format("{0} - {1}", new object[] { - this.position.ToString(format), - this.size.ToString(format) + position.ToString(format), + size.ToString(format) }); } } diff --git a/modules/mono/glue/cs_files/Basis.cs b/modules/mono/glue/cs_files/Basis.cs index ea92b1641b..929b13d70c 100644 --- a/modules/mono/glue/cs_files/Basis.cs +++ b/modules/mono/glue/cs_files/Basis.cs @@ -1,5 +1,10 @@ using System; using System.Runtime.InteropServices; +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif namespace Godot { @@ -13,8 +18,7 @@ namespace Godot new Vector3(0f, 0f, 1f) ); - private static readonly Basis[] orthoBases = new Basis[24] - { + private static readonly Basis[] orthoBases = { new Basis(1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f), new Basis(0f, -1f, 0f, 1f, 0f, 0f, 0f, 0f, 1f), new Basis(-1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f), @@ -41,9 +45,27 @@ namespace Godot new Basis(0f, -1f, 0f, 0f, 0f, -1f, 1f, 0f, 0f) }; - public Vector3 x; - public Vector3 y; - public Vector3 z; + public Vector3 x + { + get { return GetAxis(0); } + set { SetAxis(0, value); } + } + + public Vector3 y + { + get { return GetAxis(1); } + set { SetAxis(1, value); } + } + + public Vector3 z + { + get { return GetAxis(2); } + set { SetAxis(2, value); } + } + + private Vector3 _x; + private Vector3 _y; + private Vector3 _z; public static Basis Identity { @@ -70,11 +92,11 @@ namespace Godot switch (index) { case 0: - return x; + return _x; case 1: - return y; + return _y; case 2: - return z; + return _z; default: throw new IndexOutOfRangeException(); } @@ -84,13 +106,13 @@ namespace Godot switch (index) { case 0: - x = value; + _x = value; return; case 1: - y = value; + _y = value; return; case 2: - z = value; + _z = value; return; default: throw new IndexOutOfRangeException(); @@ -98,18 +120,18 @@ namespace Godot } } - public float this[int index, int axis] + public real_t this[int index, int axis] { get { switch (index) { case 0: - return x[axis]; + return _x[axis]; case 1: - return y[axis]; + return _y[axis]; case 2: - return z[axis]; + return _z[axis]; default: throw new IndexOutOfRangeException(); } @@ -119,13 +141,13 @@ namespace Godot switch (index) { case 0: - x[axis] = value; + _x[axis] = value; return; case 1: - y[axis] = value; + _y[axis] = value; return; case 2: - z[axis] = value; + _z[axis] = value; return; default: throw new IndexOutOfRangeException(); @@ -143,7 +165,7 @@ namespace Godot ); } - public float Determinant() + public real_t Determinant() { return this[0, 0] * (this[1, 1] * this[2, 2] - this[2, 1] * this[1, 2]) - this[1, 0] * (this[0, 1] * this[2, 2] - this[2, 1] * this[0, 2]) + @@ -155,14 +177,21 @@ namespace Godot return new Vector3(this[0, axis], this[1, axis], this[2, axis]); } + public void SetAxis(int axis, Vector3 value) + { + this[0, axis] = value.x; + this[1, axis] = value.y; + this[2, axis] = value.z; + } + public Vector3 GetEuler() { - Basis m = this.Orthonormalized(); + Basis m = Orthonormalized(); Vector3 euler; euler.z = 0.0f; - float mxy = m.y[2]; + real_t mxy = m[1, 2]; if (mxy < 1.0f) @@ -170,19 +199,19 @@ namespace Godot if (mxy > -1.0f) { euler.x = Mathf.Asin(-mxy); - euler.y = Mathf.Atan2(m.x[2], m.z[2]); - euler.z = Mathf.Atan2(m.y[0], m.y[1]); + euler.y = Mathf.Atan2(m[0, 2], m[2, 2]); + euler.z = Mathf.Atan2(m[1, 0], m[1, 1]); } else { - euler.x = Mathf.PI * 0.5f; - euler.y = -Mathf.Atan2(-m.x[1], m.x[0]); + euler.x = Mathf.Pi * 0.5f; + euler.y = -Mathf.Atan2(-m[0, 1], m[0, 0]); } } else { - euler.x = -Mathf.PI * 0.5f; - euler.y = -Mathf.Atan2(m.x[1], m.x[0]); + euler.x = -Mathf.Pi * 0.5f; + euler.y = -Mathf.Atan2(-m[0, 1], m[0, 0]); } return euler; @@ -190,13 +219,13 @@ namespace Godot public int GetOrthogonalIndex() { - Basis orth = this; + var orth = this; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - float v = orth[i, j]; + real_t v = orth[i, j]; if (v > 0.5f) v = 1.0f; @@ -220,28 +249,27 @@ namespace Godot public Basis Inverse() { - Basis inv = this; + var inv = this; - float[] co = new float[3] - { + real_t[] co = { inv[1, 1] * inv[2, 2] - inv[1, 2] * inv[2, 1], inv[1, 2] * inv[2, 0] - inv[1, 0] * inv[2, 2], inv[1, 0] * inv[2, 1] - inv[1, 1] * inv[2, 0] }; - float det = inv[0, 0] * co[0] + inv[0, 1] * co[1] + inv[0, 2] * co[2]; + real_t det = inv[0, 0] * co[0] + inv[0, 1] * co[1] + inv[0, 2] * co[2]; if (det == 0) { return new Basis ( - float.NaN, float.NaN, float.NaN, - float.NaN, float.NaN, float.NaN, - float.NaN, float.NaN, float.NaN + real_t.NaN, real_t.NaN, real_t.NaN, + real_t.NaN, real_t.NaN, real_t.NaN, + real_t.NaN, real_t.NaN, real_t.NaN ); } - float s = 1.0f / det; + real_t s = 1.0f / det; inv = new Basis ( @@ -266,22 +294,22 @@ namespace Godot Vector3 zAxis = GetAxis(2); xAxis.Normalize(); - yAxis = (yAxis - xAxis * (xAxis.Dot(yAxis))); + yAxis = yAxis - xAxis * xAxis.Dot(yAxis); yAxis.Normalize(); - zAxis = (zAxis - xAxis * (xAxis.Dot(zAxis)) - yAxis * (yAxis.Dot(zAxis))); + zAxis = zAxis - xAxis * xAxis.Dot(zAxis) - yAxis * yAxis.Dot(zAxis); zAxis.Normalize(); - return Basis.CreateFromAxes(xAxis, yAxis, zAxis); + return CreateFromAxes(xAxis, yAxis, zAxis); } - public Basis Rotated(Vector3 axis, float phi) + public Basis Rotated(Vector3 axis, real_t phi) { return new Basis(axis, phi) * this; } public Basis Scaled(Vector3 scale) { - Basis m = this; + var m = this; m[0, 0] *= scale.x; m[0, 1] *= scale.x; @@ -296,26 +324,26 @@ namespace Godot return m; } - public float Tdotx(Vector3 with) + public real_t Tdotx(Vector3 with) { return this[0, 0] * with[0] + this[1, 0] * with[1] + this[2, 0] * with[2]; } - public float Tdoty(Vector3 with) + public real_t Tdoty(Vector3 with) { return this[0, 1] * with[0] + this[1, 1] * with[1] + this[2, 1] * with[2]; } - public float Tdotz(Vector3 with) + public real_t Tdotz(Vector3 with) { return this[0, 2] * with[0] + this[1, 2] * with[1] + this[2, 2] * with[2]; } public Basis Transposed() { - Basis tr = this; + var tr = this; - float temp = this[0, 1]; + real_t temp = this[0, 1]; this[0, 1] = this[1, 0]; this[1, 0] = temp; @@ -344,98 +372,102 @@ namespace Godot { return new Vector3 ( - (this[0, 0] * v.x) + (this[1, 0] * v.y) + (this[2, 0] * v.z), - (this[0, 1] * v.x) + (this[1, 1] * v.y) + (this[2, 1] * v.z), - (this[0, 2] * v.x) + (this[1, 2] * v.y) + (this[2, 2] * v.z) + this[0, 0] * v.x + this[1, 0] * v.y + this[2, 0] * v.z, + this[0, 1] * v.x + this[1, 1] * v.y + this[2, 1] * v.z, + this[0, 2] * v.x + this[1, 2] * v.y + this[2, 2] * v.z ); } public Quat Quat() { - float trace = x[0] + y[1] + z[2]; + real_t trace = _x[0] + _y[1] + _z[2]; if (trace > 0.0f) { - float s = Mathf.Sqrt(trace + 1.0f) * 2f; - float inv_s = 1f / s; + real_t s = Mathf.Sqrt(trace + 1.0f) * 2f; + real_t inv_s = 1f / s; return new Quat( - (z[1] - y[2]) * inv_s, - (x[2] - z[0]) * inv_s, - (y[0] - x[1]) * inv_s, + (_z[1] - _y[2]) * inv_s, + (_x[2] - _z[0]) * inv_s, + (_y[0] - _x[1]) * inv_s, s * 0.25f ); - } else if (x[0] > y[1] && x[0] > z[2]) { - float s = Mathf.Sqrt(x[0] - y[1] - z[2] + 1.0f) * 2f; - float inv_s = 1f / s; - return new Quat( - s * 0.25f, - (x[1] + y[0]) * inv_s, - (x[2] + z[0]) * inv_s, - (z[1] - y[2]) * inv_s - ); - } else if (y[1] > z[2]) { - float s = Mathf.Sqrt(-x[0] + y[1] - z[2] + 1.0f) * 2f; - float inv_s = 1f / s; - return new Quat( - (x[1] + y[0]) * inv_s, - s * 0.25f, - (y[2] + z[1]) * inv_s, - (x[2] - z[0]) * inv_s - ); - } else { - float s = Mathf.Sqrt(-x[0] - y[1] + z[2] + 1.0f) * 2f; - float inv_s = 1f / s; - return new Quat( - (x[2] + z[0]) * inv_s, - (y[2] + z[1]) * inv_s, - s * 0.25f, - (y[0] - x[1]) * inv_s - ); } + + if (_x[0] > _y[1] && _x[0] > _z[2]) { + real_t s = Mathf.Sqrt(_x[0] - _y[1] - _z[2] + 1.0f) * 2f; + real_t inv_s = 1f / s; + return new Quat( + s * 0.25f, + (_x[1] + _y[0]) * inv_s, + (_x[2] + _z[0]) * inv_s, + (_z[1] - _y[2]) * inv_s + ); + } + + if (_y[1] > _z[2]) { + real_t s = Mathf.Sqrt(-_x[0] + _y[1] - _z[2] + 1.0f) * 2f; + real_t inv_s = 1f / s; + return new Quat( + (_x[1] + _y[0]) * inv_s, + s * 0.25f, + (_y[2] + _z[1]) * inv_s, + (_x[2] - _z[0]) * inv_s + ); + } else { + real_t s = Mathf.Sqrt(-_x[0] - _y[1] + _z[2] + 1.0f) * 2f; + real_t inv_s = 1f / s; + return new Quat( + (_x[2] + _z[0]) * inv_s, + (_y[2] + _z[1]) * inv_s, + s * 0.25f, + (_y[0] - _x[1]) * inv_s + ); + } } public Basis(Quat quat) { - float s = 2.0f / quat.LengthSquared(); - - float xs = quat.x * s; - float ys = quat.y * s; - float zs = quat.z * s; - float wx = quat.w * xs; - float wy = quat.w * ys; - float wz = quat.w * zs; - float xx = quat.x * xs; - float xy = quat.x * ys; - float xz = quat.x * zs; - float yy = quat.y * ys; - float yz = quat.y * zs; - float zz = quat.z * zs; - - this.x = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy); - this.y = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx); - this.z = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy)); + real_t s = 2.0f / quat.LengthSquared(); + + real_t xs = quat.x * s; + real_t ys = quat.y * s; + real_t zs = quat.z * s; + real_t wx = quat.w * xs; + real_t wy = quat.w * ys; + real_t wz = quat.w * zs; + real_t xx = quat.x * xs; + real_t xy = quat.x * ys; + real_t xz = quat.x * zs; + real_t yy = quat.y * ys; + real_t yz = quat.y * zs; + real_t zz = quat.z * zs; + + _x = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy); + _y = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx); + _z = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy)); } - public Basis(Vector3 axis, float phi) + public Basis(Vector3 axis, real_t phi) { - Vector3 axis_sq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z); + var axis_sq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z); - float cosine = Mathf.Cos(phi); - float sine = Mathf.Sin(phi); + real_t cosine = Mathf.Cos( phi); + real_t sine = Mathf.Sin( phi); - this.x = new Vector3 + _x = new Vector3 ( axis_sq.x + cosine * (1.0f - axis_sq.x), axis.x * axis.y * (1.0f - cosine) - axis.z * sine, axis.z * axis.x * (1.0f - cosine) + axis.y * sine ); - this.y = new Vector3 + _y = new Vector3 ( axis.x * axis.y * (1.0f - cosine) + axis.z * sine, axis_sq.y + cosine * (1.0f - axis_sq.y), axis.y * axis.z * (1.0f - cosine) - axis.x * sine ); - this.z = new Vector3 + _z = new Vector3 ( axis.z * axis.x * (1.0f - cosine) - axis.y * sine, axis.y * axis.z * (1.0f - cosine) + axis.x * sine, @@ -445,16 +477,16 @@ namespace Godot public Basis(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis) { - this.x = xAxis; - this.y = yAxis; - this.z = zAxis; + _x = xAxis; + _y = yAxis; + _z = zAxis; } - public Basis(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz) + public Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) { - this.x = new Vector3(xx, xy, xz); - this.y = new Vector3(yx, yy, yz); - this.z = new Vector3(zx, zy, zz); + _x = new Vector3(xx, xy, xz); + _y = new Vector3(yx, yy, yz); + _z = new Vector3(zx, zy, zz); } public static Basis operator *(Basis left, Basis right) @@ -489,21 +521,21 @@ namespace Godot public bool Equals(Basis other) { - return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z); + return _x.Equals(other[0]) && _y.Equals(other[1]) && _z.Equals(other[2]); } public override int GetHashCode() { - return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); + return _x.GetHashCode() ^ _y.GetHashCode() ^ _z.GetHashCode(); } public override string ToString() { return String.Format("({0}, {1}, {2})", new object[] { - this.x.ToString(), - this.y.ToString(), - this.z.ToString() + _x.ToString(), + _y.ToString(), + _z.ToString() }); } @@ -511,9 +543,9 @@ namespace Godot { return String.Format("({0}, {1}, {2})", new object[] { - this.x.ToString(format), - this.y.ToString(format), - this.z.ToString(format) + _x.ToString(format), + _y.ToString(format), + _z.ToString(format) }); } } diff --git a/modules/mono/glue/cs_files/Color.cs b/modules/mono/glue/cs_files/Color.cs index f9e31e9703..af94bb616e 100644 --- a/modules/mono/glue/cs_files/Color.cs +++ b/modules/mono/glue/cs_files/Color.cs @@ -45,8 +45,8 @@ namespace Godot { get { - float max = Mathf.Max(r, Mathf.Max(g, b)); - float min = Mathf.Min(r, Mathf.Min(g, b)); + float max = Math.Max(r, Math.Max(g, b)); + float min = Math.Min(r, Math.Min(g, b)); float delta = max - min; @@ -79,8 +79,8 @@ namespace Godot { get { - float max = Mathf.Max(r, Mathf.Max(g, b)); - float min = Mathf.Min(r, Mathf.Min(g, b)); + float max = Math.Max(r, Math.Max(g, b)); + float min = Math.Min(r, Math.Min(g, b)); float delta = max - min; @@ -96,7 +96,7 @@ namespace Godot { get { - return Mathf.Max(r, Mathf.Max(g, b)); + return Math.Max(r, Math.Max(g, b)); } set { @@ -104,7 +104,7 @@ namespace Godot } } - private static readonly Color black = new Color(0f, 0f, 0f, 1.0f); + private static readonly Color black = new Color(0f, 0f, 0f); public Color Black { @@ -180,7 +180,7 @@ namespace Godot hue += 1.0f; } - saturation = (max == 0) ? 0 : 1f - (1f * min / max); + saturation = max == 0 ? 0 : 1f - 1f * min / max; value = max / 255f; } @@ -232,12 +232,10 @@ namespace Godot { return new Color(0, 0, 0, 0); } - else - { - res.r = (r * a * sa + over.r * over.a) / res.a; - res.g = (g * a * sa + over.g * over.a) / res.a; - res.b = (b * a * sa + over.b * over.a) / res.a; - } + + res.r = (r * a * sa + over.r * over.a) / res.a; + res.g = (g * a * sa + over.g * over.a) / res.a; + res.b = (b * a * sa + over.b * over.a) / res.a; return res; } @@ -265,14 +263,14 @@ namespace Godot ); } - public Color LinearInterpolate(Color b, float t) + public Color LinearInterpolate(Color c, float t) { - Color res = this; + var res = this; - res.r += (t * (b.r - this.r)); - res.g += (t * (b.g - this.g)); - res.b += (t * (b.b - this.b)); - res.a += (t * (b.a - this.a)); + res.r += t * (c.r - r); + res.g += t * (c.g - g); + res.b += t * (c.b - b); + res.a += t * (c.a - a); return res; } @@ -305,7 +303,7 @@ namespace Godot public string ToHtml(bool include_alpha = true) { - String txt = string.Empty; + var txt = string.Empty; txt += _to_hex(r); txt += _to_hex(g); @@ -316,7 +314,8 @@ namespace Godot return txt; } - + + // Constructors public Color(float r, float g, float b, float a = 1.0f) { this.r = r; @@ -327,13 +326,13 @@ namespace Godot public Color(int rgba) { - this.a = (rgba & 0xFF) / 255.0f; + a = (rgba & 0xFF) / 255.0f; rgba >>= 8; - this.b = (rgba & 0xFF) / 255.0f; + b = (rgba & 0xFF) / 255.0f; rgba >>= 8; - this.g = (rgba & 0xFF) / 255.0f; + g = (rgba & 0xFF) / 255.0f; rgba >>= 8; - this.r = (rgba & 0xFF) / 255.0f; + r = (rgba & 0xFF) / 255.0f; } private static int _parse_col(string str, int ofs) @@ -343,7 +342,7 @@ namespace Godot for (int i = 0; i < 2; i++) { int c = str[i + ofs]; - int v = 0; + int v; if (c >= '0' && c <= '9') { @@ -375,9 +374,9 @@ namespace Godot private String _to_hex(float val) { - int v = (int)Mathf.Clamp(val * 255.0f, 0, 255); + var v = (int) Mathf.Clamp(val * 255.0f, 0, 255); - string ret = string.Empty; + var ret = string.Empty; for (int i = 0; i < 2; i++) { @@ -404,7 +403,7 @@ namespace Godot if (color[0] == '#') color = color.Substring(1, color.Length - 1); - bool alpha = false; + bool alpha; if (color.Length == 8) alpha = true; @@ -433,7 +432,7 @@ namespace Godot public static Color Color8(byte r8, byte g8, byte b8, byte a8) { - return new Color((float)r8 / 255f, (float)g8 / 255f, (float)b8 / 255f, (float)a8 / 255f); + return new Color(r8 / 255f, g8 / 255f, b8 / 255f, a8 / 255f); } public Color(string rgba) @@ -450,7 +449,7 @@ namespace Godot if (rgba[0] == '#') rgba = rgba.Substring(1); - bool alpha = false; + bool alpha; if (rgba.Length == 8) { @@ -512,14 +511,11 @@ namespace Godot if (left.g == right.g) { if (left.b == right.b) - return (left.a < right.a); - else - return (left.b < right.b); - } - else - { - return left.g < right.g; + return left.a < right.a; + return left.b < right.b; } + + return left.g < right.g; } return left.r < right.r; @@ -532,14 +528,11 @@ namespace Godot if (left.g == right.g) { if (left.b == right.b) - return (left.a > right.a); - else - return (left.b > right.b); - } - else - { - return left.g > right.g; + return left.a > right.a; + return left.b > right.b; } + + return left.g > right.g; } return left.r > right.r; @@ -567,24 +560,12 @@ namespace Godot public override string ToString() { - return String.Format("{0},{1},{2},{3}", new object[] - { - this.r.ToString(), - this.g.ToString(), - this.b.ToString(), - this.a.ToString() - }); + return String.Format("{0},{1},{2},{3}", r.ToString(), g.ToString(), b.ToString(), a.ToString()); } public string ToString(string format) { - return String.Format("{0},{1},{2},{3}", new object[] - { - this.r.ToString(format), - this.g.ToString(format), - this.b.ToString(format), - this.a.ToString(format) - }); + return String.Format("{0},{1},{2},{3}", r.ToString(format), g.ToString(format), b.ToString(format), a.ToString(format)); } } } diff --git a/modules/mono/glue/cs_files/DebuggingUtils.cs b/modules/mono/glue/cs_files/DebuggingUtils.cs index ffaaf00837..b27816084e 100644 --- a/modules/mono/glue/cs_files/DebuggingUtils.cs +++ b/modules/mono/glue/cs_files/DebuggingUtils.cs @@ -14,7 +14,7 @@ namespace Godot else if (type == typeof(void)) sb.Append("void"); else - sb.Append(type.ToString()); + sb.Append(type); sb.Append(" "); } @@ -32,7 +32,7 @@ namespace Godot return; } - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); if (methodBase is MethodInfo) sb.AppendTypeName(((MethodInfo)methodBase).ReturnType); diff --git a/modules/mono/glue/cs_files/GD.cs b/modules/mono/glue/cs_files/GD.cs index b335ef55e4..ec1534cb9a 100644 --- a/modules/mono/glue/cs_files/GD.cs +++ b/modules/mono/glue/cs_files/GD.cs @@ -1,5 +1,7 @@ using System; +// TODO: Add comments describing what this class does. It is not obvious. + namespace Godot { public static partial class GD @@ -89,7 +91,7 @@ namespace Godot public static int[] Range(int length) { - int[] ret = new int[length]; + var ret = new int[length]; for (int i = 0; i < length; i++) { @@ -104,7 +106,7 @@ namespace Godot if (to < from) return new int[0]; - int[] ret = new int[to - from]; + var ret = new int[to - from]; for (int i = from; i < to; i++) { @@ -122,14 +124,14 @@ namespace Godot return new int[0]; // Calculate count - int count = 0; + int count; if (increment > 0) - count = ((to - from - 1) / increment) + 1; + count = (to - from - 1) / increment + 1; else - count = ((from - to - 1) / -increment) + 1; + count = (from - to - 1) / -increment + 1; - int[] ret = new int[count]; + var ret = new int[count]; if (increment > 0) { diff --git a/modules/mono/glue/cs_files/GodotMethodAttribute.cs b/modules/mono/glue/cs_files/GodotMethodAttribute.cs index 21333c8dab..55848769d5 100644 --- a/modules/mono/glue/cs_files/GodotMethodAttribute.cs +++ b/modules/mono/glue/cs_files/GodotMethodAttribute.cs @@ -2,7 +2,7 @@ using System; namespace Godot { - [AttributeUsage(AttributeTargets.Method, Inherited = true)] + [AttributeUsage(AttributeTargets.Method)] internal class GodotMethodAttribute : Attribute { private string methodName; diff --git a/modules/mono/glue/cs_files/GodotSynchronizationContext.cs b/modules/mono/glue/cs_files/GodotSynchronizationContext.cs index eb4d0bed1c..da3c7bac83 100644 --- a/modules/mono/glue/cs_files/GodotSynchronizationContext.cs +++ b/modules/mono/glue/cs_files/GodotSynchronizationContext.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; diff --git a/modules/mono/glue/cs_files/GodotTaskScheduler.cs b/modules/mono/glue/cs_files/GodotTaskScheduler.cs index f587645a49..3d23ec10f1 100644 --- a/modules/mono/glue/cs_files/GodotTaskScheduler.cs +++ b/modules/mono/glue/cs_files/GodotTaskScheduler.cs @@ -14,6 +14,7 @@ namespace Godot public GodotTaskScheduler() { Context = new GodotSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(Context); } protected sealed override void QueueTask(Task task) @@ -36,7 +37,7 @@ namespace Godot TryDequeue(task); } - return base.TryExecuteTask(task); + return TryExecuteTask(task); } protected sealed override bool TryDequeue(Task task) @@ -57,7 +58,6 @@ namespace Godot public void Activate() { - SynchronizationContext.SetSynchronizationContext(Context); ExecuteQueuedTasks(); Context.ExecutePendingContinuations(); } diff --git a/modules/mono/glue/cs_files/IAwaiter.cs b/modules/mono/glue/cs_files/IAwaiter.cs index 73c71b5634..b5aa1a5389 100644 --- a/modules/mono/glue/cs_files/IAwaiter.cs +++ b/modules/mono/glue/cs_files/IAwaiter.cs @@ -1,4 +1,3 @@ -using System; using System.Runtime.CompilerServices; namespace Godot diff --git a/modules/mono/glue/cs_files/MarshalUtils.cs b/modules/mono/glue/cs_files/MarshalUtils.cs index 2bdfb95c51..ff4477cc6c 100644 --- a/modules/mono/glue/cs_files/MarshalUtils.cs +++ b/modules/mono/glue/cs_files/MarshalUtils.cs @@ -7,7 +7,7 @@ namespace Godot { private static Dictionary<object, object> ArraysToDictionary(object[] keys, object[] values) { - Dictionary<object, object> ret = new Dictionary<object, object>(); + var ret = new Dictionary<object, object>(); for (int i = 0; i < keys.Length; i++) { @@ -19,11 +19,11 @@ namespace Godot private static void DictionaryToArrays(Dictionary<object, object> from, out object[] keysTo, out object[] valuesTo) { - Dictionary<object, object>.KeyCollection keys = from.Keys; + var keys = from.Keys; keysTo = new object[keys.Count]; keys.CopyTo(keysTo, 0); - Dictionary<object, object>.ValueCollection values = from.Values; + var values = from.Values; valuesTo = new object[values.Count]; values.CopyTo(valuesTo, 0); } diff --git a/modules/mono/glue/cs_files/Mathf.cs b/modules/mono/glue/cs_files/Mathf.cs index 6951ace4fc..0d20a12563 100644 --- a/modules/mono/glue/cs_files/Mathf.cs +++ b/modules/mono/glue/cs_files/Mathf.cs @@ -1,77 +1,87 @@ using System; +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif namespace Godot { - public static class Mathf + public static partial class Mathf { - public const float PI = 3.14159274f; - public const float Epsilon = 1e-06f; + // Define constants with Decimal precision and cast down to double or float. - private const float Deg2RadConst = 0.0174532924f; - private const float Rad2DegConst = 57.29578f; + public const real_t Tau = (real_t) 6.2831853071795864769252867666M; // 6.2831855f and 6.28318530717959 + public const real_t Pi = (real_t) 3.1415926535897932384626433833M; // 3.1415927f and 3.14159265358979 + public const real_t Inf = real_t.PositiveInfinity; + public const real_t NaN = real_t.NaN; - public static float Abs(float s) + private const real_t Deg2RadConst = (real_t) 0.0174532925199432957692369077M; // 0.0174532924f and 0.0174532925199433 + private const real_t Rad2DegConst = (real_t) 57.295779513082320876798154814M; // 57.29578f and 57.2957795130823 + + public static real_t Abs(real_t s) { return Math.Abs(s); } - public static float Acos(float s) + public static int Abs(int s) { - return (float)Math.Acos(s); + return Math.Abs(s); } - public static float Asin(float s) + public static real_t Acos(real_t s) { - return (float)Math.Asin(s); + return (real_t)Math.Acos(s); } - public static float Atan(float s) + public static real_t Asin(real_t s) { - return (float)Math.Atan(s); + return (real_t)Math.Asin(s); } - public static float Atan2(float x, float y) + public static real_t Atan(real_t s) { - return (float)Math.Atan2(x, y); + return (real_t)Math.Atan(s); } - public static Vector2 Cartesian2Polar(float x, float y) - { - return new Vector2(Sqrt(x * x + y * y), Atan2(y, x)); - } + public static real_t Atan2(real_t x, real_t y) + { + return (real_t)Math.Atan2(x, y); + } - public static float Ceil(float s) + public static Vector2 Cartesian2Polar(real_t x, real_t y) { - return (float)Math.Ceiling(s); + return new Vector2(Sqrt(x * x + y * y), Atan2(y, x)); } - public static float Clamp(float val, float min, float max) + public static real_t Ceil(real_t s) { - if (val < min) - { - return min; - } - else if (val > max) - { - return max; - } + return (real_t)Math.Ceiling(s); + } - return val; + public static int Clamp(int value, int min, int max) + { + return value < min ? min : value > max ? max : value; } - public static float Cos(float s) + public static real_t Clamp(real_t value, real_t min, real_t max) { - return (float)Math.Cos(s); + return value < min ? min : value > max ? max : value; } - public static float Cosh(float s) + public static real_t Cos(real_t s) { - return (float)Math.Cosh(s); + return (real_t)Math.Cos(s); } - public static int Decimals(float step) + public static real_t Cosh(real_t s) { - return Decimals(step); + return (real_t)Math.Cosh(s); + } + + public static int Decimals(real_t step) + { + return Decimals((decimal)step); } public static int Decimals(decimal step) @@ -79,12 +89,12 @@ namespace Godot return BitConverter.GetBytes(decimal.GetBits(step)[3])[2]; } - public static float Deg2Rad(float deg) + public static real_t Deg2Rad(real_t deg) { return deg * Deg2RadConst; } - public static float Ease(float s, float curve) + public static real_t Ease(real_t s, real_t curve) { if (s < 0f) { @@ -104,7 +114,8 @@ namespace Godot return Pow(s, curve); } - else if (curve < 0f) + + if (curve < 0f) { if (s < 0.5f) { @@ -117,111 +128,129 @@ namespace Godot return 0f; } - public static float Exp(float s) + public static real_t Exp(real_t s) { - return (float)Math.Exp(s); + return (real_t)Math.Exp(s); } - public static float Floor(float s) + public static real_t Floor(real_t s) { - return (float)Math.Floor(s); + return (real_t)Math.Floor(s); } - public static float Fposmod(float x, float y) + public static real_t Fposmod(real_t x, real_t y) { if (x >= 0f) { return x % y; } - else - { - return y - (-x % y); - } + + return y - -x % y; } - public static float Lerp(float from, float to, float weight) + public static real_t InverseLerp(real_t from, real_t to, real_t weight) + { + return (Clamp(weight, 0f, 1f) - from) / (to - from); + } + + public static bool IsInf(real_t s) + { + return real_t.IsInfinity(s); + } + + public static bool IsNaN(real_t s) + { + return real_t.IsNaN(s); + } + + public static real_t Lerp(real_t from, real_t to, real_t weight) { return from + (to - from) * Clamp(weight, 0f, 1f); } - public static float Log(float s) + public static real_t Log(real_t s) { - return (float)Math.Log(s); + return (real_t)Math.Log(s); } public static int Max(int a, int b) { - return (a > b) ? a : b; + return a > b ? a : b; } - public static float Max(float a, float b) + public static real_t Max(real_t a, real_t b) { - return (a > b) ? a : b; + return a > b ? a : b; } public static int Min(int a, int b) { - return (a < b) ? a : b; + return a < b ? a : b; } - public static float Min(float a, float b) + public static real_t Min(real_t a, real_t b) { - return (a < b) ? a : b; + return a < b ? a : b; } - public static int NearestPo2(int val) + public static int NearestPo2(int value) { - val--; - val |= val >> 1; - val |= val >> 2; - val |= val >> 4; - val |= val >> 8; - val |= val >> 16; - val++; - return val; + value--; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + value++; + return value; } - public static Vector2 Polar2Cartesian(float r, float th) - { - return new Vector2(r * Cos(th), r * Sin(th)); - } + public static Vector2 Polar2Cartesian(real_t r, real_t th) + { + return new Vector2(r * Cos(th), r * Sin(th)); + } - public static float Pow(float x, float y) + public static real_t Pow(real_t x, real_t y) { - return (float)Math.Pow(x, y); + return (real_t)Math.Pow(x, y); } - public static float Rad2Deg(float rad) + public static real_t Rad2Deg(real_t rad) { return rad * Rad2DegConst; } - public static float Round(float s) + public static real_t Round(real_t s) { - return (float)Math.Round(s); + return (real_t)Math.Round(s); } - public static float Sign(float s) + public static int Sign(int s) { - return (s < 0f) ? -1f : 1f; + return s < 0 ? -1 : 1; } - public static float Sin(float s) + public static real_t Sign(real_t s) { - return (float)Math.Sin(s); + return s < 0f ? -1f : 1f; } - public static float Sinh(float s) + public static real_t Sin(real_t s) { - return (float)Math.Sinh(s); + return (real_t)Math.Sin(s); } - public static float Sqrt(float s) + public static real_t Sinh(real_t s) { - return (float)Math.Sqrt(s); + return (real_t)Math.Sinh(s); } - public static float Stepify(float s, float step) + public static real_t Sqrt(real_t s) + { + return (real_t)Math.Sqrt(s); + } + + public static real_t Stepify(real_t s, real_t step) { if (step != 0f) { @@ -231,14 +260,26 @@ namespace Godot return s; } - public static float Tan(float s) + public static real_t Tan(real_t s) + { + return (real_t)Math.Tan(s); + } + + public static real_t Tanh(real_t s) + { + return (real_t)Math.Tanh(s); + } + + public static int Wrap(int value, int min, int max) { - return (float)Math.Tan(s); + int rng = max - min; + return min + ((value - min) % rng + rng) % rng; } - public static float Tanh(float s) + public static real_t Wrap(real_t value, real_t min, real_t max) { - return (float)Math.Tanh(s); + real_t rng = max - min; + return min + ((value - min) % rng + rng) % rng; } } } diff --git a/modules/mono/glue/cs_files/MathfEx.cs b/modules/mono/glue/cs_files/MathfEx.cs new file mode 100644 index 0000000000..739b7fb568 --- /dev/null +++ b/modules/mono/glue/cs_files/MathfEx.cs @@ -0,0 +1,39 @@ +using System; + +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif + +namespace Godot +{ + public static partial class Mathf + { + // Define constants with Decimal precision and cast down to double or float. + + public const real_t E = (real_t) 2.7182818284590452353602874714M; // 2.7182817f and 2.718281828459045 + public const real_t Sqrt2 = (real_t) 1.4142135623730950488016887242M; // 1.4142136f and 1.414213562373095 + +#if REAL_T_IS_DOUBLE + public const real_t Epsilon = 1e-14; // Epsilon size should depend on the precision used. +#else + public const real_t Epsilon = 1e-06f; +#endif + + public static int CeilToInt(real_t s) + { + return (int)Math.Ceiling(s); + } + + public static int FloorToInt(real_t s) + { + return (int)Math.Floor(s); + } + + public static int RoundToInt(real_t s) + { + return (int)Math.Round(s); + } + } +}
\ No newline at end of file diff --git a/modules/mono/glue/cs_files/Plane.cs b/modules/mono/glue/cs_files/Plane.cs index b347c0835a..8b92522029 100644 --- a/modules/mono/glue/cs_files/Plane.cs +++ b/modules/mono/glue/cs_files/Plane.cs @@ -1,4 +1,9 @@ using System; +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif namespace Godot { @@ -6,7 +11,7 @@ namespace Godot { Vector3 normal; - public float x + public real_t x { get { @@ -18,7 +23,7 @@ namespace Godot } } - public float y + public real_t y { get { @@ -30,7 +35,7 @@ namespace Godot } } - public float z + public real_t z { get { @@ -42,7 +47,7 @@ namespace Godot } } - float d; + real_t d; public Vector3 Center { @@ -52,7 +57,7 @@ namespace Godot } } - public float DistanceTo(Vector3 point) + public real_t DistanceTo(Vector3 point) { return normal.Dot(point) - d; } @@ -62,34 +67,34 @@ namespace Godot return normal * d; } - public bool HasPoint(Vector3 point, float epsilon = Mathf.Epsilon) + public bool HasPoint(Vector3 point, real_t epsilon = Mathf.Epsilon) { - float dist = normal.Dot(point) - d; + real_t dist = normal.Dot(point) - d; return Mathf.Abs(dist) <= epsilon; } public Vector3 Intersect3(Plane b, Plane c) { - float denom = normal.Cross(b.normal).Dot(c.normal); + real_t denom = normal.Cross(b.normal).Dot(c.normal); if (Mathf.Abs(denom) <= Mathf.Epsilon) return new Vector3(); - Vector3 result = (b.normal.Cross(c.normal) * this.d) + - (c.normal.Cross(normal) * b.d) + - (normal.Cross(b.normal) * c.d); + Vector3 result = b.normal.Cross(c.normal) * d + + c.normal.Cross(normal) * b.d + + normal.Cross(b.normal) * c.d; return result / denom; } public Vector3 IntersectRay(Vector3 from, Vector3 dir) { - float den = normal.Dot(dir); + real_t den = normal.Dot(dir); if (Mathf.Abs(den) <= Mathf.Epsilon) return new Vector3(); - float dist = (normal.Dot(from) - d) / den; + real_t dist = (normal.Dot(from) - d) / den; // This is a ray, before the emitting pos (from) does not exist if (dist > Mathf.Epsilon) @@ -101,14 +106,14 @@ namespace Godot public Vector3 IntersectSegment(Vector3 begin, Vector3 end) { Vector3 segment = begin - end; - float den = normal.Dot(segment); + real_t den = normal.Dot(segment); if (Mathf.Abs(den) <= Mathf.Epsilon) return new Vector3(); - float dist = (normal.Dot(begin) - d) / den; + real_t dist = (normal.Dot(begin) - d) / den; - if (dist < -Mathf.Epsilon || dist > (1.0f + Mathf.Epsilon)) + if (dist < -Mathf.Epsilon || dist > 1.0f + Mathf.Epsilon) return new Vector3(); return begin + segment * -dist; @@ -121,7 +126,7 @@ namespace Godot public Plane Normalized() { - float len = normal.Length(); + real_t len = normal.Length(); if (len == 0) return new Plane(0, 0, 0, 0); @@ -133,14 +138,14 @@ namespace Godot { return point - normal * DistanceTo(point); } - - public Plane(float a, float b, float c, float d) + + // Constructors + public Plane(real_t a, real_t b, real_t c, real_t d) { normal = new Vector3(a, b, c); this.d = d; } - - public Plane(Vector3 normal, float d) + public Plane(Vector3 normal, real_t d) { this.normal = normal; this.d = d; @@ -192,8 +197,8 @@ namespace Godot { return String.Format("({0}, {1})", new object[] { - this.normal.ToString(), - this.d.ToString() + normal.ToString(), + d.ToString() }); } @@ -201,8 +206,8 @@ namespace Godot { return String.Format("({0}, {1})", new object[] { - this.normal.ToString(format), - this.d.ToString(format) + normal.ToString(format), + d.ToString(format) }); } } diff --git a/modules/mono/glue/cs_files/Quat.cs b/modules/mono/glue/cs_files/Quat.cs index c0ac41c5d7..c69c55d997 100644 --- a/modules/mono/glue/cs_files/Quat.cs +++ b/modules/mono/glue/cs_files/Quat.cs @@ -1,5 +1,10 @@ using System; using System.Runtime.InteropServices; +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif namespace Godot { @@ -8,17 +13,17 @@ namespace Godot { private static readonly Quat identity = new Quat(0f, 0f, 0f, 1f); - public float x; - public float y; - public float z; - public float w; + public real_t x; + public real_t y; + public real_t z; + public real_t w; public static Quat Identity { get { return identity; } } - public float this[int index] + public real_t this[int index] { get { @@ -58,15 +63,15 @@ namespace Godot } } - public Quat CubicSlerp(Quat b, Quat preA, Quat postB, float t) + public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t t) { - float t2 = (1.0f - t) * t * 2f; + real_t t2 = (1.0f - t) * t * 2f; Quat sp = Slerp(b, t); Quat sq = preA.Slerpni(postB, t); return sp.Slerpni(sq, t2); } - public float Dot(Quat b) + public real_t Dot(Quat b) { return x * b.x + y * b.y + z * b.z + w * b.w; } @@ -76,12 +81,12 @@ namespace Godot return new Quat(-x, -y, -z, w); } - public float Length() + public real_t Length() { return Mathf.Sqrt(LengthSquared()); } - public float LengthSquared() + public real_t LengthSquared() { return Dot(this); } @@ -91,20 +96,27 @@ namespace Godot return this / Length(); } - public void Set(float x, float y, float z, float w) + public void Set(real_t x, real_t y, real_t z, real_t w) { this.x = x; this.y = y; this.z = z; this.w = w; } + public void Set(Quat q) + { + x = q.x; + y = q.y; + z = q.z; + w = q.w; + } - public Quat Slerp(Quat b, float t) + public Quat Slerp(Quat b, real_t t) { // Calculate cosine - float cosom = x * b.x + y * b.y + z * b.z + w * b.w; + real_t cosom = x * b.x + y * b.y + z * b.z + w * b.w; - float[] to1 = new float[4]; + var to1 = new real_t[4]; // Adjust signs if necessary if (cosom < 0.0) @@ -122,13 +134,13 @@ namespace Godot to1[3] = b.w; } - float sinom, scale0, scale1; + real_t sinom, scale0, scale1; // Calculate coefficients - if ((1.0 - cosom) > Mathf.Epsilon) + if (1.0 - cosom > Mathf.Epsilon) { // Standard case (Slerp) - float omega = Mathf.Acos(cosom); + real_t omega = Mathf.Acos(cosom); sinom = Mathf.Sin(omega); scale0 = Mathf.Sin((1.0f - t) * omega) / sinom; scale1 = Mathf.Sin(t * omega) / sinom; @@ -150,47 +162,56 @@ namespace Godot ); } - public Quat Slerpni(Quat b, float t) + public Quat Slerpni(Quat b, real_t t) { - float dot = this.Dot(b); + real_t dot = Dot(b); if (Mathf.Abs(dot) > 0.9999f) { return this; } - float theta = Mathf.Acos(dot); - float sinT = 1.0f / Mathf.Sin(theta); - float newFactor = Mathf.Sin(t * theta) * sinT; - float invFactor = Mathf.Sin((1.0f - t) * theta) * sinT; + real_t theta = Mathf.Acos(dot); + real_t sinT = 1.0f / Mathf.Sin(theta); + real_t newFactor = Mathf.Sin(t * theta) * sinT; + real_t invFactor = Mathf.Sin((1.0f - t) * theta) * sinT; return new Quat ( - invFactor * this.x + newFactor * b.x, - invFactor * this.y + newFactor * b.y, - invFactor * this.z + newFactor * b.z, - invFactor * this.w + newFactor * b.w + invFactor * x + newFactor * b.x, + invFactor * y + newFactor * b.y, + invFactor * z + newFactor * b.z, + invFactor * w + newFactor * b.w ); } public Vector3 Xform(Vector3 v) { Quat q = this * v; - q *= this.Inverse(); + q *= Inverse(); return new Vector3(q.x, q.y, q.z); } - public Quat(float x, float y, float z, float w) + // Constructors + public Quat(real_t x, real_t y, real_t z, real_t w) { this.x = x; this.y = y; this.z = z; this.w = w; + } + public Quat(Quat q) + { + x = q.x; + y = q.y; + z = q.z; + w = q.w; } - - public Quat(Vector3 axis, float angle) + + public Quat(Vector3 axis, real_t angle) { - float d = axis.Length(); + real_t d = axis.Length(); + real_t angle_t = angle; if (d == 0f) { @@ -201,12 +222,12 @@ namespace Godot } else { - float s = Mathf.Sin(angle * 0.5f) / d; + real_t s = Mathf.Sin(angle_t * 0.5f) / d; x = axis.x * s; y = axis.y * s; z = axis.z * s; - w = Mathf.Cos(angle * 0.5f); + w = Mathf.Cos(angle_t * 0.5f); } } @@ -258,17 +279,17 @@ namespace Godot ); } - public static Quat operator *(Quat left, float right) + public static Quat operator *(Quat left, real_t right) { return new Quat(left.x * right, left.y * right, left.z * right, left.w * right); } - public static Quat operator *(float left, Quat right) + public static Quat operator *(real_t left, Quat right) { return new Quat(right.x * left, right.y * left, right.z * left, right.w * left); } - public static Quat operator /(Quat left, float right) + public static Quat operator /(Quat left, real_t right) { return left * (1.0f / right); } @@ -305,24 +326,12 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1}, {2}, {3})", new object[] - { - this.x.ToString(), - this.y.ToString(), - this.z.ToString(), - this.w.ToString() - }); + return String.Format("({0}, {1}, {2}, {3})", x.ToString(), y.ToString(), z.ToString(), w.ToString()); } public string ToString(string format) { - return String.Format("({0}, {1}, {2}, {3})", new object[] - { - this.x.ToString(format), - this.y.ToString(format), - this.z.ToString(format), - this.w.ToString(format) - }); + return String.Format("({0}, {1}, {2}, {3})", x.ToString(format), y.ToString(format), z.ToString(format), w.ToString(format)); } } } diff --git a/modules/mono/glue/cs_files/Rect2.cs b/modules/mono/glue/cs_files/Rect2.cs index e1fbb65da5..6f16656573 100644 --- a/modules/mono/glue/cs_files/Rect2.cs +++ b/modules/mono/glue/cs_files/Rect2.cs @@ -1,5 +1,10 @@ using System; using System.Runtime.InteropServices; +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif namespace Godot { @@ -26,14 +31,14 @@ namespace Godot get { return position + size; } } - public float Area + public real_t Area { get { return GetArea(); } } public Rect2 Clip(Rect2 b) { - Rect2 newRect = b; + var newRect = b; if (!Intersects(newRect)) return new Rect2(); @@ -52,14 +57,14 @@ namespace Godot public bool Encloses(Rect2 b) { - return (b.position.x >= position.x) && (b.position.y >= position.y) && - ((b.position.x + b.size.x) < (position.x + size.x)) && - ((b.position.y + b.size.y) < (position.y + size.y)); + return b.position.x >= position.x && b.position.y >= position.y && + b.position.x + b.size.x < position.x + size.x && + b.position.y + b.size.y < position.y + size.y; } public Rect2 Expand(Vector2 to) { - Rect2 expanded = this; + var expanded = this; Vector2 begin = expanded.position; Vector2 end = expanded.position + expanded.size; @@ -80,14 +85,14 @@ namespace Godot return expanded; } - public float GetArea() + public real_t GetArea() { return size.x * size.y; } - public Rect2 Grow(float by) + public Rect2 Grow(real_t by) { - Rect2 g = this; + var g = this; g.position.x -= by; g.position.y -= by; @@ -97,9 +102,9 @@ namespace Godot return g; } - public Rect2 GrowIndividual(float left, float top, float right, float bottom) + public Rect2 GrowIndividual(real_t left, real_t top, real_t right, real_t bottom) { - Rect2 g = this; + var g = this; g.position.x -= left; g.position.y -= top; @@ -109,14 +114,14 @@ namespace Godot return g; } - public Rect2 GrowMargin(Margin margin, float by) + public Rect2 GrowMargin(Margin margin, real_t by) { - Rect2 g = this; + var g = this; - g.GrowIndividual((Margin.Left == margin) ? by : 0, - (Margin.Top == margin) ? by : 0, - (Margin.Right == margin) ? by : 0, - (Margin.Bottom == margin) ? by : 0); + g.GrowIndividual(Margin.Left == margin ? by : 0, + Margin.Top == margin ? by : 0, + Margin.Right == margin ? by : 0, + Margin.Bottom == margin ? by : 0); return g; } @@ -133,9 +138,9 @@ namespace Godot if (point.y < position.y) return false; - if (point.x >= (position.x + size.x)) + if (point.x >= position.x + size.x) return false; - if (point.y >= (position.y + size.y)) + if (point.y >= position.y + size.y) return false; return true; @@ -143,13 +148,13 @@ namespace Godot public bool Intersects(Rect2 b) { - if (position.x > (b.position.x + b.size.x)) + if (position.x > b.position.x + b.size.x) return false; - if ((position.x + size.x) < b.position.x) + if (position.x + size.x < b.position.x) return false; - if (position.y > (b.position.y + b.size.y)) + if (position.y > b.position.y + b.size.y) return false; - if ((position.y + size.y) < b.position.y) + if (position.y + size.y < b.position.y) return false; return true; @@ -169,17 +174,27 @@ namespace Godot return newRect; } - + + // Constructors public Rect2(Vector2 position, Vector2 size) { this.position = position; this.size = size; } - - public Rect2(float x, float y, float width, float height) + public Rect2(Vector2 position, real_t width, real_t height) + { + this.position = position; + size = new Vector2(width, height); + } + public Rect2(real_t x, real_t y, Vector2 size) + { + position = new Vector2(x, y); + this.size = size; + } + public Rect2(real_t x, real_t y, real_t width, real_t height) { - this.position = new Vector2(x, y); - this.size = new Vector2(width, height); + position = new Vector2(x, y); + size = new Vector2(width, height); } public static bool operator ==(Rect2 left, Rect2 right) @@ -216,8 +231,8 @@ namespace Godot { return String.Format("({0}, {1})", new object[] { - this.position.ToString(), - this.size.ToString() + position.ToString(), + size.ToString() }); } @@ -225,8 +240,8 @@ namespace Godot { return String.Format("({0}, {1})", new object[] { - this.position.ToString(format), - this.size.ToString(format) + position.ToString(format), + size.ToString(format) }); } } diff --git a/modules/mono/glue/cs_files/SignalAttribute.cs b/modules/mono/glue/cs_files/SignalAttribute.cs new file mode 100644 index 0000000000..3957387be9 --- /dev/null +++ b/modules/mono/glue/cs_files/SignalAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Godot +{ + [AttributeUsage(AttributeTargets.Delegate)] + public class SignalAttribute : Attribute + { + } +} diff --git a/modules/mono/glue/cs_files/SignalAwaiter.cs b/modules/mono/glue/cs_files/SignalAwaiter.cs index 19ccc26e79..c06f6b05c9 100644 --- a/modules/mono/glue/cs_files/SignalAwaiter.cs +++ b/modules/mono/glue/cs_files/SignalAwaiter.cs @@ -4,15 +4,15 @@ namespace Godot { public class SignalAwaiter : IAwaiter<object[]>, IAwaitable<object[]> { - private bool completed = false; - private object[] result = null; - private Action action = null; + private bool completed; + private object[] result; + private Action action; - public SignalAwaiter(Godot.Object source, string signal, Godot.Object target) + public SignalAwaiter(Object source, string signal, Object target) { NativeCalls.godot_icall_Object_connect_signal_awaiter( - Godot.Object.GetPtr(source), - signal, Godot.Object.GetPtr(target), this + Object.GetPtr(source), + signal, Object.GetPtr(target), this ); } diff --git a/modules/mono/glue/cs_files/StringExtensions.cs b/modules/mono/glue/cs_files/StringExtensions.cs index 5c3ceff97d..21090fb68d 100644 --- a/modules/mono/glue/cs_files/StringExtensions.cs +++ b/modules/mono/glue/cs_files/StringExtensions.cs @@ -1,4 +1,5 @@ //using System; + using System; using System.Collections.Generic; using System.Globalization; @@ -43,11 +44,9 @@ namespace Godot { return instance.Substring(prev, i - prev); } - else - { - count++; - prev = i + 1; - } + + count++; + prev = i + 1; } i++; @@ -83,7 +82,7 @@ namespace Godot // </summary> public static string[] Bigrams(this string instance) { - string[] b = new string[instance.Length - 1]; + var b = new string[instance.Length - 1]; for (int i = 0; i < b.Length; i++) { @@ -98,7 +97,7 @@ namespace Godot // </summary> public static string CEscape(this string instance) { - StringBuilder sb = new StringBuilder(string.Copy(instance)); + var sb = new StringBuilder(string.Copy(instance)); sb.Replace("\\", "\\\\"); sb.Replace("\a", "\\a"); @@ -120,7 +119,7 @@ namespace Godot // </summary> public static string CUnescape(this string instance) { - StringBuilder sb = new StringBuilder(string.Copy(instance)); + var sb = new StringBuilder(string.Copy(instance)); sb.Replace("\\a", "\a"); sb.Replace("\\b", "\b"); @@ -143,7 +142,7 @@ namespace Godot public static string Capitalize(this string instance) { string aux = instance.Replace("_", " ").ToLower(); - string cap = string.Empty; + var cap = string.Empty; for (int i = 0; i < aux.GetSliceCount(" "); i++) { @@ -178,13 +177,13 @@ namespace Godot { if (to[to_idx] == 0 && instance[instance_idx] == 0) return 0; // We're equal - else if (instance[instance_idx] == 0) + if (instance[instance_idx] == 0) return -1; // If this is empty, and the other one is not, then we're less... I think? - else if (to[to_idx] == 0) + if (to[to_idx] == 0) return 1; // Otherwise the other one is smaller... - else if (instance[instance_idx] < to[to_idx]) // More than + if (instance[instance_idx] < to[to_idx]) // More than return -1; - else if (instance[instance_idx] > to[to_idx]) // Less than + if (instance[instance_idx] > to[to_idx]) // Less than return 1; instance_idx++; @@ -260,12 +259,12 @@ namespace Godot { int basepos = instance.Find("://"); - string rs = string.Empty; - string @base = string.Empty; + string rs; + var @base = string.Empty; if (basepos != -1) { - int end = basepos + 3; + var end = basepos + 3; rs = instance.Substring(end, instance.Length); @base = instance.Substring(0, end); } @@ -287,7 +286,7 @@ namespace Godot if (sep == -1) return @base; - return @base + rs.substr(0, sep); + return @base + rs.Substr(0, sep); } // <summary> @@ -312,8 +311,8 @@ namespace Godot int hashv = 5381; int c; - while ((c = (int)instance[index++]) != 0) - hashv = ((hashv << 5) + hashv) + c; // hash * 33 + c + while ((c = instance[index++]) != 0) + hashv = (hashv << 5) + hashv + c; // hash * 33 + c return hashv; } @@ -379,7 +378,7 @@ namespace Godot while (instance[src] != 0 && text[tgt] != 0) { - bool match = false; + bool match; if (case_insensitive) { @@ -455,7 +454,10 @@ namespace Godot return false; // Don't start with number plz } - bool valid_char = (instance[i] >= '0' && instance[i] <= '9') || (instance[i] >= 'a' && instance[i] <= 'z') || (instance[i] >= 'A' && instance[i] <= 'Z') || instance[i] == '_'; + bool valid_char = instance[i] >= '0' && + instance[i] <= '9' || instance[i] >= 'a' && + instance[i] <= 'z' || instance[i] >= 'A' && + instance[i] <= 'Z' || instance[i] == '_'; if (!valid_char) return false; @@ -478,7 +480,7 @@ namespace Godot // </summary> public static bool IsValidIpAddress(this string instance) { - string[] ip = instance.split("."); + string[] ip = instance.Split("."); if (ip.Length != 4) return false; @@ -489,7 +491,7 @@ namespace Godot if (!n.IsValidInteger()) return false; - int val = n.to_int(); + int val = n.ToInt(); if (val < 0 || val > 255) return false; } @@ -502,7 +504,7 @@ namespace Godot // </summary> public static string JsonEscape(this string instance) { - StringBuilder sb = new StringBuilder(string.Copy(instance)); + var sb = new StringBuilder(string.Copy(instance)); sb.Replace("\\", "\\\\"); sb.Replace("\b", "\\b"); @@ -551,7 +553,7 @@ namespace Godot case '\0': return instance[0] == 0; case '*': - return ExprMatch(expr + 1, instance, caseSensitive) || (instance[0] != 0 && ExprMatch(expr, instance + 1, caseSensitive)); + return ExprMatch(expr + 1, instance, caseSensitive) || instance[0] != 0 && ExprMatch(expr, instance + 1, caseSensitive); case '?': return instance[0] != 0 && instance[0] != '.' && ExprMatch(expr + 1, instance + 1, caseSensitive); default: @@ -571,7 +573,7 @@ namespace Godot // <summary> // Do a simple case insensitive expression match, using ? and * wildcards (see [method expr_match]). // </summary> - public static bool matchn(this string instance, string expr) + public static bool Matchn(this string instance, string expr) { return instance.ExprMatch(expr, false); } @@ -610,13 +612,13 @@ namespace Godot { if (to[to_idx] == 0 && instance[instance_idx] == 0) return 0; // We're equal - else if (instance[instance_idx] == 0) + if (instance[instance_idx] == 0) return -1; // If this is empty, and the other one is not, then we're less... I think? - else if (to[to_idx] == 0) + if (to[to_idx] == 0) return 1; // Otherwise the other one is smaller.. - else if (char.ToUpper(instance[instance_idx]) < char.ToUpper(to[to_idx])) // More than + if (char.ToUpper(instance[instance_idx]) < char.ToUpper(to[to_idx])) // More than return -1; - else if (char.ToUpper(instance[instance_idx]) > char.ToUpper(to[to_idx])) // Less than + if (char.ToUpper(instance[instance_idx]) > char.ToUpper(to[to_idx])) // Less than return 1; instance_idx++; @@ -724,8 +726,7 @@ namespace Godot { if (instance.Length > 0 && instance[instance.Length - 1] == '/') return instance + file; - else - return instance + "/" + file; + return instance + "/" + file; } // <summary> @@ -771,7 +772,7 @@ namespace Godot if (pos < 0) return string.Empty; - return instance.Substring(pos, (instance.Length - pos)); + return instance.Substring(pos, instance.Length - pos); } public static byte[] Sha256Buffer(this string instance) @@ -824,23 +825,23 @@ namespace Godot } } - return (2.0f * inter) / sum; + return 2.0f * inter / sum; } // <summary> // Split the string by a divisor string, return an array of the substrings. Example "One,Two,Three" will return ["One","Two","Three"] if split by ",". // </summary> - public static string[] split(this string instance, string divisor, bool allow_empty = true) + public static string[] Split(this string instance, string divisor, bool allow_empty = true) { - return instance.Split(new string[] { divisor }, StringSplitOptions.RemoveEmptyEntries); + return instance.Split(new[] { divisor }, StringSplitOptions.RemoveEmptyEntries); } // <summary> // Split the string in floats by using a divisor string, return an array of the substrings. Example "1,2.5,3" will return [1,2.5,3] if split by ",". // </summary> - public static float[] split_floats(this string instance, string divisor, bool allow_empty = true) + public static float[] SplitFloats(this string instance, string divisor, bool allow_empty = true) { - List<float> ret = new List<float>(); + var ret = new List<float>(); int from = 0; int len = instance.Length; @@ -849,7 +850,7 @@ namespace Godot int end = instance.Find(divisor, from); if (end < 0) end = len; - if (allow_empty || (end > from)) + if (allow_empty || end > from) ret.Add(float.Parse(instance.Substring(from))); if (end == len) break; @@ -872,25 +873,22 @@ namespace Godot // <summary> // Return a copy of the string stripped of any non-printable character at the beginning and the end. The optional arguments are used to toggle stripping on the left and right edges respectively. // </summary> - public static string strip_edges(this string instance, bool left = true, bool right = true) + public static string StripEdges(this string instance, bool left = true, bool right = true) { if (left) { if (right) return instance.Trim(non_printable); - else - return instance.TrimStart(non_printable); - } - else - { - return instance.TrimEnd(non_printable); + return instance.TrimStart(non_printable); } + + return instance.TrimEnd(non_printable); } // <summary> // Return part of the string from the position [code]from[/code], with length [code]len[/code]. // </summary> - public static string substr(this string instance, int from, int len) + public static string Substr(this string instance, int from, int len) { return instance.Substring(from, len); } @@ -898,7 +896,7 @@ namespace Godot // <summary> // Convert the String (which is a character array) to PoolByteArray (which is an array of bytes). The conversion is speeded up in comparison to to_utf8() with the assumption that all the characters the String contains are only ASCII characters. // </summary> - public static byte[] to_ascii(this string instance) + public static byte[] ToAscii(this string instance) { return Encoding.ASCII.GetBytes(instance); } @@ -906,7 +904,7 @@ namespace Godot // <summary> // Convert a string, containing a decimal number, into a [code]float[/code]. // </summary> - public static float to_float(this string instance) + public static float ToFloat(this string instance) { return float.Parse(instance); } @@ -914,7 +912,7 @@ namespace Godot // <summary> // Convert a string, containing an integer number, into an [code]int[/code]. // </summary> - public static int to_int(this string instance) + public static int ToInt(this string instance) { return int.Parse(instance); } @@ -922,7 +920,7 @@ namespace Godot // <summary> // Return the string converted to lowercase. // </summary> - public static string to_lower(this string instance) + public static string ToLower(this string instance) { return instance.ToLower(); } @@ -930,7 +928,7 @@ namespace Godot // <summary> // Return the string converted to uppercase. // </summary> - public static string to_upper(this string instance) + public static string ToUpper(this string instance) { return instance.ToUpper(); } @@ -938,7 +936,7 @@ namespace Godot // <summary> // Convert the String (which is an array of characters) to PoolByteArray (which is an array of bytes). The conversion is a bit slower than to_ascii(), but supports all UTF-8 characters. Therefore, you should prefer this function over to_ascii(). // </summary> - public static byte[] to_utf8(this string instance) + public static byte[] ToUtf8(this string instance) { return Encoding.UTF8.GetBytes(instance); } @@ -946,7 +944,7 @@ namespace Godot // <summary> // Return a copy of the string with special characters escaped using the XML standard. // </summary> - public static string xml_escape(this string instance) + public static string XmlEscape(this string instance) { return SecurityElement.Escape(instance); } @@ -954,7 +952,7 @@ namespace Godot // <summary> // Return a copy of the string with escaped characters replaced by their meanings according to the XML standard. // </summary> - public static string xml_unescape(this string instance) + public static string XmlUnescape(this string instance) { return SecurityElement.FromString(instance).Text; } diff --git a/modules/mono/glue/cs_files/Transform.cs b/modules/mono/glue/cs_files/Transform.cs index 5214100d36..d1b247a552 100644 --- a/modules/mono/glue/cs_files/Transform.cs +++ b/modules/mono/glue/cs_files/Transform.cs @@ -1,5 +1,10 @@ using System; using System.Runtime.InteropServices; +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif namespace Godot { @@ -23,8 +28,8 @@ namespace Godot public Transform LookingAt(Vector3 target, Vector3 up) { - Transform t = this; - t.set_look_at(origin, target, up); + var t = this; + t.SetLookAt(origin, target, up); return t; } @@ -33,7 +38,7 @@ namespace Godot return new Transform(basis.Orthonormalized(), origin); } - public Transform Rotated(Vector3 axis, float phi) + public Transform Rotated(Vector3 axis, real_t phi) { return new Transform(new Basis(axis, phi), new Vector3()) * this; } @@ -43,7 +48,7 @@ namespace Godot return new Transform(basis.Scaled(scale), origin * scale); } - public void set_look_at(Vector3 eye, Vector3 target, Vector3 up) + public void SetLookAt(Vector3 eye, Vector3 target, Vector3 up) { // Make rotation matrix // Z vector @@ -92,21 +97,22 @@ namespace Godot return new Vector3 ( - (basis[0, 0] * vInv.x) + (basis[1, 0] * vInv.y) + (basis[2, 0] * vInv.z), - (basis[0, 1] * vInv.x) + (basis[1, 1] * vInv.y) + (basis[2, 1] * vInv.z), - (basis[0, 2] * vInv.x) + (basis[1, 2] * vInv.y) + (basis[2, 2] * vInv.z) + basis[0, 0] * vInv.x + basis[1, 0] * vInv.y + basis[2, 0] * vInv.z, + basis[0, 1] * vInv.x + basis[1, 1] * vInv.y + basis[2, 1] * vInv.z, + basis[0, 2] * vInv.x + basis[1, 2] * vInv.y + basis[2, 2] * vInv.z ); } - + + // Constructors public Transform(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis, Vector3 origin) { - this.basis = Basis.CreateFromAxes(xAxis, yAxis, zAxis); + basis = Basis.CreateFromAxes(xAxis, yAxis, zAxis); this.origin = origin; } public Transform(Quat quat, Vector3 origin) { - this.basis = new Basis(quat); + basis = new Basis(quat); this.origin = origin; } @@ -157,8 +163,8 @@ namespace Godot { return String.Format("{0} - {1}", new object[] { - this.basis.ToString(), - this.origin.ToString() + basis.ToString(), + origin.ToString() }); } @@ -166,8 +172,8 @@ namespace Godot { return String.Format("{0} - {1}", new object[] { - this.basis.ToString(format), - this.origin.ToString(format) + basis.ToString(format), + origin.ToString(format) }); } } diff --git a/modules/mono/glue/cs_files/Transform2D.cs b/modules/mono/glue/cs_files/Transform2D.cs index fe7c5b5706..ff5259178b 100644 --- a/modules/mono/glue/cs_files/Transform2D.cs +++ b/modules/mono/glue/cs_files/Transform2D.cs @@ -1,5 +1,10 @@ using System; using System.Runtime.InteropServices; +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif namespace Godot { @@ -27,7 +32,7 @@ namespace Godot get { return o; } } - public float Rotation + public real_t Rotation { get { return Mathf.Atan2(y.x, o.y); } } @@ -73,7 +78,7 @@ namespace Godot } - public float this[int index, int axis] + public real_t this[int index, int axis] { get { @@ -105,9 +110,9 @@ namespace Godot public Transform2D AffineInverse() { - Transform2D inv = this; + var inv = this; - float det = this[0, 0] * this[1, 1] - this[1, 0] * this[0, 1]; + real_t det = this[0, 0] * this[1, 1] - this[1, 0] * this[0, 1]; if (det == 0) { @@ -119,9 +124,9 @@ namespace Godot ); } - float idet = 1.0f / det; + real_t idet = 1.0f / det; - float temp = this[0, 0]; + real_t temp = this[0, 0]; this[0, 0] = this[1, 1]; this[1, 1] = temp; @@ -143,24 +148,24 @@ namespace Godot return new Vector2(x.Dot(v), y.Dot(v)); } - public Transform2D InterpolateWith(Transform2D m, float c) + public Transform2D InterpolateWith(Transform2D m, real_t c) { - float r1 = Rotation; - float r2 = m.Rotation; + real_t r1 = Rotation; + real_t r2 = m.Rotation; Vector2 s1 = Scale; Vector2 s2 = m.Scale; // Slerp rotation - Vector2 v1 = new Vector2(Mathf.Cos(r1), Mathf.Sin(r1)); - Vector2 v2 = new Vector2(Mathf.Cos(r2), Mathf.Sin(r2)); + var v1 = new Vector2(Mathf.Cos(r1), Mathf.Sin(r1)); + var v2 = new Vector2(Mathf.Cos(r2), Mathf.Sin(r2)); - float dot = v1.Dot(v2); + real_t dot = v1.Dot(v2); // Clamp dot to [-1, 1] - dot = (dot < -1.0f) ? -1.0f : ((dot > 1.0f) ? 1.0f : dot); + dot = dot < -1.0f ? -1.0f : (dot > 1.0f ? 1.0f : dot); - Vector2 v = new Vector2(); + Vector2 v; if (dot > 0.9995f) { @@ -169,7 +174,7 @@ namespace Godot } else { - float angle = c * Mathf.Acos(dot); + real_t angle = c * Mathf.Acos(dot); Vector2 v3 = (v2 - v1 * dot).Normalized(); v = v1 * Mathf.Cos(angle) + v3 * Mathf.Sin(angle); } @@ -179,7 +184,7 @@ namespace Godot Vector2 p2 = m.Origin; // Construct matrix - Transform2D res = new Transform2D(Mathf.Atan2(v.y, v.x), p1.LinearInterpolate(p2, c)); + var res = new Transform2D(Mathf.Atan2(v.y, v.x), p1.LinearInterpolate(p2, c)); Vector2 scale = s1.LinearInterpolate(s2, c); res.x *= scale; res.y *= scale; @@ -189,10 +194,10 @@ namespace Godot public Transform2D Inverse() { - Transform2D inv = this; + var inv = this; // Swap - float temp = inv.x.y; + real_t temp = inv.x.y; inv.x.y = inv.y.x; inv.y.x = temp; @@ -203,13 +208,13 @@ namespace Godot public Transform2D Orthonormalized() { - Transform2D on = this; + var on = this; Vector2 onX = on.x; Vector2 onY = on.y; onX.Normalize(); - onY = onY - onX * (onX.Dot(onY)); + onY = onY - onX * onX.Dot(onY); onY.Normalize(); on.x = onX; @@ -218,33 +223,33 @@ namespace Godot return on; } - public Transform2D Rotated(float phi) + public Transform2D Rotated(real_t phi) { return this * new Transform2D(phi, new Vector2()); } public Transform2D Scaled(Vector2 scale) { - Transform2D copy = this; + var copy = this; copy.x *= scale; copy.y *= scale; copy.o *= scale; return copy; } - private float Tdotx(Vector2 with) + private real_t Tdotx(Vector2 with) { return this[0, 0] * with[0] + this[1, 0] * with[1]; } - private float Tdoty(Vector2 with) + private real_t Tdoty(Vector2 with) { return this[0, 1] * with[0] + this[1, 1] * with[1]; } public Transform2D Translated(Vector2 offset) { - Transform2D copy = this; + var copy = this; copy.o += copy.BasisXform(offset); return copy; } @@ -259,24 +264,26 @@ namespace Godot Vector2 vInv = v - o; return new Vector2(x.Dot(vInv), y.Dot(vInv)); } - + + // Constructors public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 origin) { - this.x = xAxis; - this.y = yAxis; - this.o = origin; + x = xAxis; + y = yAxis; + o = origin; } - public Transform2D(float xx, float xy, float yx, float yy, float ox, float oy) + + public Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy) { - this.x = new Vector2(xx, xy); - this.y = new Vector2(yx, yy); - this.o = new Vector2(ox, oy); + x = new Vector2(xx, xy); + y = new Vector2(yx, yy); + o = new Vector2(ox, oy); } - public Transform2D(float rot, Vector2 pos) + public Transform2D(real_t rot, Vector2 pos) { - float cr = Mathf.Cos(rot); - float sr = Mathf.Sin(rot); + real_t cr = Mathf.Cos(rot); + real_t sr = Mathf.Sin(rot); x.x = cr; y.y = cr; x.y = -sr; @@ -288,7 +295,7 @@ namespace Godot { left.o = left.Xform(right.o); - float x0, x1, y0, y1; + real_t x0, x1, y0, y1; x0 = left.Tdotx(right.x); x1 = left.Tdoty(right.x); @@ -337,9 +344,9 @@ namespace Godot { return String.Format("({0}, {1}, {2})", new object[] { - this.x.ToString(), - this.y.ToString(), - this.o.ToString() + x.ToString(), + y.ToString(), + o.ToString() }); } @@ -347,9 +354,9 @@ namespace Godot { return String.Format("({0}, {1}, {2})", new object[] { - this.x.ToString(format), - this.y.ToString(format), - this.o.ToString(format) + x.ToString(format), + y.ToString(format), + o.ToString(format) }); } } diff --git a/modules/mono/glue/cs_files/VERSION.txt b/modules/mono/glue/cs_files/VERSION.txt new file mode 100755 index 0000000000..0cfbf08886 --- /dev/null +++ b/modules/mono/glue/cs_files/VERSION.txt @@ -0,0 +1 @@ +2 diff --git a/modules/mono/glue/cs_files/Vector2.cs b/modules/mono/glue/cs_files/Vector2.cs index 238775bda2..9bc40cf8df 100644 --- a/modules/mono/glue/cs_files/Vector2.cs +++ b/modules/mono/glue/cs_files/Vector2.cs @@ -1,22 +1,26 @@ -using System; -using System.Runtime.InteropServices; - // file: core/math/math_2d.h // commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451 // file: core/math/math_2d.cpp // commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451 // file: core/variant_call.cpp // commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685 +using System; +using System.Runtime.InteropServices; +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif namespace Godot { [StructLayout(LayoutKind.Sequential)] public struct Vector2 : IEquatable<Vector2> { - public float x; - public float y; + public real_t x; + public real_t y; - public float this[int index] + public real_t this[int index] { get { @@ -48,7 +52,7 @@ namespace Godot internal void Normalize() { - float length = x * x + y * y; + real_t length = x * x + y * y; if (length != 0f) { @@ -58,7 +62,7 @@ namespace Godot } } - private float Cross(Vector2 b) + private real_t Cross(Vector2 b) { return x * b.y - y * b.x; } @@ -68,22 +72,22 @@ namespace Godot return new Vector2(Mathf.Abs(x), Mathf.Abs(y)); } - public float Angle() + public real_t Angle() { return Mathf.Atan2(y, x); } - public float AngleTo(Vector2 to) + public real_t AngleTo(Vector2 to) { return Mathf.Atan2(Cross(to), Dot(to)); } - public float AngleToPoint(Vector2 to) + public real_t AngleToPoint(Vector2 to) { return Mathf.Atan2(x - to.x, y - to.y); } - public float Aspect() + public real_t Aspect() { return x / y; } @@ -93,10 +97,15 @@ namespace Godot return -Reflect(n); } - public Vector2 Clamped(float length) + public Vector2 Ceil() { - Vector2 v = this; - float l = this.Length(); + return new Vector2(Mathf.Ceil(x), Mathf.Ceil(y)); + } + + public Vector2 Clamped(real_t length) + { + var v = this; + real_t l = Length(); if (l > 0 && length < l) { @@ -107,33 +116,33 @@ namespace Godot return v; } - public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, float t) + public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t t) { - Vector2 p0 = preA; - Vector2 p1 = this; - Vector2 p2 = b; - Vector2 p3 = postB; + var p0 = preA; + var p1 = this; + var p2 = b; + var p3 = postB; - float t2 = t * t; - float t3 = t2 * t; + real_t t2 = t * t; + real_t t3 = t2 * t; - return 0.5f * ((p1 * 2.0f) + + return 0.5f * (p1 * 2.0f + (-p0 + p2) * t + (2.0f * p0 - 5.0f * p1 + 4 * p2 - p3) * t2 + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3); } - public float DistanceSquaredTo(Vector2 to) + public real_t DistanceSquaredTo(Vector2 to) { return (x - to.x) * (x - to.x) + (y - to.y) * (y - to.y); } - public float DistanceTo(Vector2 to) + public real_t DistanceTo(Vector2 to) { return Mathf.Sqrt((x - to.x) * (x - to.x) + (y - to.y) * (y - to.y)); } - public float Dot(Vector2 with) + public real_t Dot(Vector2 with) { return x * with.x + y * with.y; } @@ -148,29 +157,29 @@ namespace Godot return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon; } - public float Length() + public real_t Length() { return Mathf.Sqrt(x * x + y * y); } - public float LengthSquared() + public real_t LengthSquared() { return x * x + y * y; } - public Vector2 LinearInterpolate(Vector2 b, float t) + public Vector2 LinearInterpolate(Vector2 b, real_t t) { - Vector2 res = this; + var res = this; - res.x += (t * (b.x - x)); - res.y += (t * (b.y - y)); + res.x += t * (b.x - x); + res.y += t * (b.y - y); return res; } public Vector2 Normalized() { - Vector2 result = this; + var result = this; result.Normalize(); return result; } @@ -180,12 +189,28 @@ namespace Godot return 2.0f * n * Dot(n) - this; } - public Vector2 Rotated(float phi) + public Vector2 Rotated(real_t phi) { - float rads = Angle() + phi; + real_t rads = Angle() + phi; return new Vector2(Mathf.Cos(rads), Mathf.Sin(rads)) * Length(); } + public Vector2 Round() + { + return new Vector2(Mathf.Round(x), Mathf.Round(y)); + } + + public void Set(real_t x, real_t y) + { + this.x = x; + this.y = y; + } + public void Set(Vector2 v) + { + x = v.x; + y = v.y; + } + public Vector2 Slide(Vector2 n) { return this - n * Dot(n); @@ -200,12 +225,36 @@ namespace Godot { return new Vector2(y, -x); } - - public Vector2(float x, float y) + + private static readonly Vector2 zero = new Vector2 (0, 0); + private static readonly Vector2 one = new Vector2 (1, 1); + private static readonly Vector2 negOne = new Vector2 (-1, -1); + + private static readonly Vector2 up = new Vector2 (0, 1); + private static readonly Vector2 down = new Vector2 (0, -1); + private static readonly Vector2 right = new Vector2 (1, 0); + private static readonly Vector2 left = new Vector2 (-1, 0); + + public static Vector2 Zero { get { return zero; } } + public static Vector2 One { get { return one; } } + public static Vector2 NegOne { get { return negOne; } } + + public static Vector2 Up { get { return up; } } + public static Vector2 Down { get { return down; } } + public static Vector2 Right { get { return right; } } + public static Vector2 Left { get { return left; } } + + // Constructors + public Vector2(real_t x, real_t y) { this.x = x; this.y = y; } + public Vector2(Vector2 v) + { + x = v.x; + y = v.y; + } public static Vector2 operator +(Vector2 left, Vector2 right) { @@ -228,14 +277,14 @@ namespace Godot return vec; } - public static Vector2 operator *(Vector2 vec, float scale) + public static Vector2 operator *(Vector2 vec, real_t scale) { vec.x *= scale; vec.y *= scale; return vec; } - public static Vector2 operator *(float scale, Vector2 vec) + public static Vector2 operator *(real_t scale, Vector2 vec) { vec.x *= scale; vec.y *= scale; @@ -249,7 +298,7 @@ namespace Godot return left; } - public static Vector2 operator /(Vector2 vec, float scale) + public static Vector2 operator /(Vector2 vec, real_t scale) { vec.x /= scale; vec.y /= scale; @@ -279,10 +328,8 @@ namespace Godot { return left.y < right.y; } - else - { - return left.x < right.x; - } + + return left.x < right.x; } public static bool operator >(Vector2 left, Vector2 right) @@ -291,10 +338,8 @@ namespace Godot { return left.y > right.y; } - else - { - return left.x > right.x; - } + + return left.x > right.x; } public static bool operator <=(Vector2 left, Vector2 right) @@ -303,10 +348,8 @@ namespace Godot { return left.y <= right.y; } - else - { - return left.x <= right.x; - } + + return left.x <= right.x; } public static bool operator >=(Vector2 left, Vector2 right) @@ -315,10 +358,8 @@ namespace Godot { return left.y >= right.y; } - else - { - return left.x >= right.x; - } + + return left.x >= right.x; } public override bool Equals(object obj) @@ -345,8 +386,8 @@ namespace Godot { return String.Format("({0}, {1})", new object[] { - this.x.ToString(), - this.y.ToString() + x.ToString(), + y.ToString() }); } @@ -354,8 +395,8 @@ namespace Godot { return String.Format("({0}, {1})", new object[] { - this.x.ToString(format), - this.y.ToString(format) + x.ToString(format), + y.ToString(format) }); } } diff --git a/modules/mono/glue/cs_files/Vector3.cs b/modules/mono/glue/cs_files/Vector3.cs index 190caa4b53..57e4494f7e 100644 --- a/modules/mono/glue/cs_files/Vector3.cs +++ b/modules/mono/glue/cs_files/Vector3.cs @@ -1,12 +1,16 @@ -using System; -using System.Runtime.InteropServices; - // file: core/math/vector3.h // commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0 // file: core/math/vector3.cpp // commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451 // file: core/variant_call.cpp // commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685 +using System; +using System.Runtime.InteropServices; +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif namespace Godot { @@ -20,11 +24,11 @@ namespace Godot Z } - public float x; - public float y; - public float z; + public real_t x; + public real_t y; + public real_t z; - public float this[int index] + public real_t this[int index] { get { @@ -61,7 +65,7 @@ namespace Godot internal void Normalize() { - float length = this.Length(); + real_t length = Length(); if (length == 0f) { @@ -80,7 +84,7 @@ namespace Godot return new Vector3(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z)); } - public float AngleTo(Vector3 to) + public real_t AngleTo(Vector3 to) { return Mathf.Atan2(Cross(to).Length(), Dot(to)); } @@ -99,40 +103,40 @@ namespace Godot { return new Vector3 ( - (y * b.z) - (z * b.y), - (z * b.x) - (x * b.z), - (x * b.y) - (y * b.x) + y * b.z - z * b.y, + z * b.x - x * b.z, + x * b.y - y * b.x ); } - public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, float t) + public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t t) { - Vector3 p0 = preA; - Vector3 p1 = this; - Vector3 p2 = b; - Vector3 p3 = postB; + var p0 = preA; + var p1 = this; + var p2 = b; + var p3 = postB; - float t2 = t * t; - float t3 = t2 * t; + real_t t2 = t * t; + real_t t3 = t2 * t; return 0.5f * ( - (p1 * 2.0f) + (-p0 + p2) * t + + p1 * 2.0f + (-p0 + p2) * t + (2.0f * p0 - 5.0f * p1 + 4f * p2 - p3) * t2 + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3 ); } - public float DistanceSquaredTo(Vector3 b) + public real_t DistanceSquaredTo(Vector3 b) { return (b - this).LengthSquared(); } - public float DistanceTo(Vector3 b) + public real_t DistanceTo(Vector3 b) { return (b - this).Length(); } - public float Dot(Vector3 b) + public real_t Dot(Vector3 b) { return x * b.x + y * b.y + z * b.z; } @@ -152,31 +156,31 @@ namespace Godot return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon; } - public float Length() + public real_t Length() { - float x2 = x * x; - float y2 = y * y; - float z2 = z * z; + real_t x2 = x * x; + real_t y2 = y * y; + real_t z2 = z * z; return Mathf.Sqrt(x2 + y2 + z2); } - public float LengthSquared() + public real_t LengthSquared() { - float x2 = x * x; - float y2 = y * y; - float z2 = z * z; + real_t x2 = x * x; + real_t y2 = y * y; + real_t z2 = z * z; return x2 + y2 + z2; } - public Vector3 LinearInterpolate(Vector3 b, float t) + public Vector3 LinearInterpolate(Vector3 b, real_t t) { return new Vector3 ( - x + (t * (b.x - x)), - y + (t * (b.y - y)), - z + (t * (b.z - z)) + x + t * (b.x - x), + y + t * (b.y - y), + z + t * (b.z - z) ); } @@ -192,7 +196,7 @@ namespace Godot public Vector3 Normalized() { - Vector3 v = this; + var v = this; v.Normalize(); return v; } @@ -215,11 +219,29 @@ namespace Godot return 2.0f * n * Dot(n) - this; } - public Vector3 Rotated(Vector3 axis, float phi) + public Vector3 Round() + { + return new Vector3(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z)); + } + + public Vector3 Rotated(Vector3 axis, real_t phi) { return new Basis(axis, phi).Xform(this); } + public void Set(real_t x, real_t y, real_t z) + { + this.x = x; + this.y = y; + this.z = z; + } + public void Set(Vector3 v) + { + x = v.x; + y = v.y; + z = v.z; + } + public Vector3 Slide(Vector3 n) { return this - n * Dot(n); @@ -243,13 +265,42 @@ namespace Godot 0f, 0f, z ); } - - public Vector3(float x, float y, float z) + + private static readonly Vector3 zero = new Vector3 (0, 0, 0); + private static readonly Vector3 one = new Vector3 (1, 1, 1); + private static readonly Vector3 negOne = new Vector3 (-1, -1, -1); + + private static readonly Vector3 up = new Vector3 (0, 1, 0); + private static readonly Vector3 down = new Vector3 (0, -1, 0); + private static readonly Vector3 right = new Vector3 (1, 0, 0); + private static readonly Vector3 left = new Vector3 (-1, 0, 0); + private static readonly Vector3 forward = new Vector3 (0, 0, -1); + private static readonly Vector3 back = new Vector3 (0, 0, 1); + + public static Vector3 Zero { get { return zero; } } + public static Vector3 One { get { return one; } } + public static Vector3 NegOne { get { return negOne; } } + + public static Vector3 Up { get { return up; } } + public static Vector3 Down { get { return down; } } + public static Vector3 Right { get { return right; } } + public static Vector3 Left { get { return left; } } + public static Vector3 Forward { get { return forward; } } + public static Vector3 Back { get { return back; } } + + // Constructors + public Vector3(real_t x, real_t y, real_t z) { this.x = x; this.y = y; this.z = z; } + public Vector3(Vector3 v) + { + x = v.x; + y = v.y; + z = v.z; + } public static Vector3 operator +(Vector3 left, Vector3 right) { @@ -275,7 +326,7 @@ namespace Godot return vec; } - public static Vector3 operator *(Vector3 vec, float scale) + public static Vector3 operator *(Vector3 vec, real_t scale) { vec.x *= scale; vec.y *= scale; @@ -283,7 +334,7 @@ namespace Godot return vec; } - public static Vector3 operator *(float scale, Vector3 vec) + public static Vector3 operator *(real_t scale, Vector3 vec) { vec.x *= scale; vec.y *= scale; @@ -299,7 +350,7 @@ namespace Godot return left; } - public static Vector3 operator /(Vector3 vec, float scale) + public static Vector3 operator /(Vector3 vec, real_t scale) { vec.x /= scale; vec.y /= scale; @@ -331,8 +382,7 @@ namespace Godot { if (left.y == right.y) return left.z < right.z; - else - return left.y < right.y; + return left.y < right.y; } return left.x < right.x; @@ -344,8 +394,7 @@ namespace Godot { if (left.y == right.y) return left.z > right.z; - else - return left.y > right.y; + return left.y > right.y; } return left.x > right.x; @@ -357,8 +406,7 @@ namespace Godot { if (left.y == right.y) return left.z <= right.z; - else - return left.y < right.y; + return left.y < right.y; } return left.x < right.x; @@ -370,8 +418,7 @@ namespace Godot { if (left.y == right.y) return left.z >= right.z; - else - return left.y > right.y; + return left.y > right.y; } return left.x > right.x; @@ -401,9 +448,9 @@ namespace Godot { return String.Format("({0}, {1}, {2})", new object[] { - this.x.ToString(), - this.y.ToString(), - this.z.ToString() + x.ToString(), + y.ToString(), + z.ToString() }); } @@ -411,9 +458,9 @@ namespace Godot { return String.Format("({0}, {1}, {2})", new object[] { - this.x.ToString(format), - this.y.ToString(format), - this.z.ToString(format) + x.ToString(format), + y.ToString(format), + z.ToString(format) }); } } diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h index 32988c5afa..cedc8e9992 100644 --- a/modules/mono/glue/glue_header.h +++ b/modules/mono/glue/glue_header.h @@ -28,6 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "builtin_types_glue.h" + #include "../csharp_script.h" #include "../mono_gd/gd_mono_class.h" #include "../mono_gd/gd_mono_internals.h" @@ -91,12 +93,6 @@ MonoString *godot_icall_NodePath_operator_String(NodePath *p_np) { return GDMonoMarshal::mono_string_from_godot(p_np->operator String()); } -MonoArray *godot_icall_String_md5_buffer(MonoString *p_str) { - Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_buffer(); - // TODO Check possible Array/Vector<uint8_t> problem? - return GDMonoMarshal::Array_to_mono_array(Variant(ret)); -} - // -- RID -- RID *godot_icall_RID_Ctor(Object *p_from) { @@ -115,6 +111,12 @@ void godot_icall_RID_Dtor(RID *p_ptr) { // -- String -- +MonoArray *godot_icall_String_md5_buffer(MonoString *p_str) { + Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_buffer(); + // TODO Check possible Array/Vector<uint8_t> problem? + return GDMonoMarshal::Array_to_mono_array(Variant(ret)); +} + MonoString *godot_icall_String_md5_text(MonoString *p_str) { String ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_text(); return GDMonoMarshal::mono_string_from_godot(ret); @@ -303,3 +305,7 @@ MonoObject *godot_icall_Godot_weakref(Object *p_obj) { return GDMonoUtils::create_managed_for_godot_object(CACHED_CLASS(WeakRef), Reference::get_class_static(), Object::cast_to<Object>(wref.ptr())); } + +void godot_register_header_icalls() { + godot_register_builtin_type_icalls(); +} diff --git a/modules/mono/godotsharp_defs.h b/modules/mono/godotsharp_defs.h index 4c26c3e6bd..f604464e8f 100644 --- a/modules/mono/godotsharp_defs.h +++ b/modules/mono/godotsharp_defs.h @@ -39,4 +39,7 @@ #define EDITOR_API_ASSEMBLY_NAME "GodotSharpEditor" #define EDITOR_TOOLS_ASSEMBLY_NAME "GodotSharpTools" +#define BINDINGS_CLASS_NATIVECALLS "NativeCalls" +#define BINDINGS_CLASS_NATIVECALLS_EDITOR "EditorNativeCalls" + #endif // GODOTSHARP_DEFS_H diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 6c07c90f79..0646580eaa 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -42,11 +42,15 @@ #include "project_settings.h" #include "../csharp_script.h" +#include "../godotsharp_dirs.h" #include "../utils/path_utils.h" +#include "gd_mono_class.h" +#include "gd_mono_marshal.h" #include "gd_mono_utils.h" #ifdef TOOLS_ENABLED #include "../editor/godotsharp_editor.h" +#include "main/main.h" #endif void gdmono_unhandled_exception_hook(MonoObject *exc, void *user_data) { @@ -70,7 +74,31 @@ void gdmono_MonoPrintCallback(const char *string, mono_bool is_stdout) { GDMono *GDMono::singleton = NULL; +namespace { + +void setup_runtime_main_args() { + CharString execpath = OS::get_singleton()->get_executable_path().utf8(); + + List<String> cmdline_args = OS::get_singleton()->get_cmdline_args(); + + List<CharString> cmdline_args_utf8; + Vector<char *> main_args; + main_args.resize(cmdline_args.size() + 1); + + main_args[0] = execpath.ptrw(); + + int i = 1; + for (List<String>::Element *E = cmdline_args.front(); E; E = E->next()) { + CharString &stored = cmdline_args_utf8.push_back(E->get().utf8())->get(); + main_args[i] = stored.ptrw(); + i++; + } + + mono_runtime_set_main_args(main_args.size(), main_args.ptrw()); +} + #ifdef DEBUG_ENABLED + static bool _wait_for_debugger_msecs(uint32_t p_msecs) { do { @@ -92,24 +120,7 @@ static bool _wait_for_debugger_msecs(uint32_t p_msecs) { return mono_is_debugger_attached(); } -#endif - -#ifdef TOOLS_ENABLED -// temporary workaround. should be provided from Main::setup/setup2 instead -bool _is_project_manager_requested() { - - List<String> cmdline_args = OS::get_singleton()->get_cmdline_args(); - for (List<String>::Element *E = cmdline_args.front(); E; E = E->next()) { - const String &arg = E->get(); - if (arg == "-p" || arg == "--project-manager") - return true; - } - - return false; -} -#endif -#ifdef DEBUG_ENABLED void gdmono_debug_init() { mono_debug_init(MONO_DEBUG_FORMAT_MONO); @@ -121,7 +132,7 @@ void gdmono_debug_init() { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() || ProjectSettings::get_singleton()->get_resource_path().empty() || - _is_project_manager_requested()) { + Main::is_project_manager()) { return; } #endif @@ -136,8 +147,11 @@ void gdmono_debug_init() { }; mono_jit_parse_options(2, (char **)options); } + #endif +} // namespace + void GDMono::initialize() { ERR_FAIL_NULL(Engine::get_singleton()); @@ -190,6 +204,8 @@ void GDMono::initialize() { GDMonoUtils::set_main_thread(GDMonoUtils::get_current_thread()); + setup_runtime_main_args(); // Required for System.Environment.GetCommandLineArgs + runtime_initialized = true; OS::get_singleton()->print("Mono: Runtime initialized\n"); @@ -222,7 +238,46 @@ void GDMono::initialize() { _register_internal_calls(); // The following assemblies are not required at initialization - _load_all_script_assemblies(); +#ifndef MONO_GLUE_DISABLED + if (_load_api_assemblies()) { + if (!core_api_assembly_out_of_sync && !editor_api_assembly_out_of_sync && GDMonoUtils::mono_cache.godot_api_cache_updated) { + // Everything is fine with the api assemblies, load the project assembly + _load_project_assembly(); + } else { +#ifdef TOOLS_ENABLED + // The assembly was successfuly loaded, but the full api could not be cached. + // This is most likely an outdated assembly loaded because of an invalid version in the metadata, + // so we invalidate the version in the metadata and unload the script domain. + + if (core_api_assembly_out_of_sync) { + ERR_PRINT("The loaded Core API assembly is out of sync"); + metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); + } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) { + ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed"); + metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); + } + + if (editor_api_assembly_out_of_sync) { + ERR_PRINT("The loaded Editor API assembly is out of sync"); + metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true); + } + + OS::get_singleton()->print("Mono: Proceeding to unload scripts domain because of invalid API assemblies\n"); + + Error err = _unload_scripts_domain(); + if (err != OK) { + WARN_PRINT("Mono: Failed to unload scripts domain"); + } +#else + ERR_PRINT("The loaded API assembly is invalid"); + CRASH_NOW(); +#endif + } + } +#else + if (OS::get_singleton()->is_stdout_verbose()) + OS::get_singleton()->print("Mono: Glue disabled, ignoring script assemblies\n"); +#endif mono_install_unhandled_exception_hook(gdmono_unhandled_exception_hook, NULL); @@ -233,7 +288,11 @@ void GDMono::initialize() { namespace GodotSharpBindings { uint64_t get_core_api_hash(); +#ifdef TOOLS_ENABLED uint64_t get_editor_api_hash(); +#endif // TOOLS_ENABLED +uint32_t get_bindings_version(); +uint32_t get_cs_glue_version(); void register_generated_icalls(); } // namespace GodotSharpBindings @@ -285,43 +344,84 @@ GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) { return assemblies[domain_id].getptr(p_name); } -bool GDMono::_load_assembly(const String &p_name, GDMonoAssembly **r_assembly) { +bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) { + + CRASH_COND(!r_assembly); + + MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8()); + bool result = load_assembly(p_name, aname, r_assembly, p_refonly); + mono_assembly_name_free(aname); + mono_free(aname); + + return result; +} + +bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) { CRASH_COND(!r_assembly); if (OS::get_singleton()->is_stdout_verbose()) - OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + "...\n").utf8()); + OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...\n").utf8()); 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); + MonoAssembly *assembly = mono_assembly_load_full(p_aname, NULL, &status, p_refonly); if (!assembly) return false; + ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false); + uint32_t domain_id = mono_domain_get_id(mono_domain_get()); GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name); - ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false); ERR_FAIL_COND_V(stored_assembly == NULL, 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()); + OS::get_singleton()->print(String("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path() + "\n").utf8()); return true; } +APIAssembly::Version APIAssembly::Version::get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, APIAssembly::Type p_api_type) { + APIAssembly::Version api_assembly_version; + + const char *nativecalls_name = p_api_type == APIAssembly::API_CORE ? + BINDINGS_CLASS_NATIVECALLS : + BINDINGS_CLASS_NATIVECALLS_EDITOR; + + GDMonoClass *nativecalls_klass = p_api_assembly->get_class(BINDINGS_NAMESPACE, nativecalls_name); + + if (nativecalls_klass) { + GDMonoField *api_hash_field = nativecalls_klass->get_field("godot_api_hash"); + if (api_hash_field) + api_assembly_version.godot_api_hash = GDMonoMarshal::unbox<uint64_t>(api_hash_field->get_value(NULL)); + + GDMonoField *binds_ver_field = nativecalls_klass->get_field("bindings_version"); + if (binds_ver_field) + api_assembly_version.bindings_version = GDMonoMarshal::unbox<uint32_t>(binds_ver_field->get_value(NULL)); + + GDMonoField *cs_glue_ver_field = nativecalls_klass->get_field("cs_glue_version"); + if (cs_glue_ver_field) + api_assembly_version.cs_glue_version = GDMonoMarshal::unbox<uint32_t>(cs_glue_ver_field->get_value(NULL)); + } + + return api_assembly_version; +} + +String APIAssembly::to_string(APIAssembly::Type p_type) { + return p_type == APIAssembly::API_CORE ? "API_CORE" : "API_EDITOR"; +} + bool GDMono::_load_corlib_assembly() { if (corlib_assembly) return true; - bool success = _load_assembly("mscorlib", &corlib_assembly); + bool success = load_assembly("mscorlib", &corlib_assembly); if (success) GDMonoUtils::update_corlib_cache(); @@ -331,13 +431,25 @@ bool GDMono::_load_corlib_assembly() { bool GDMono::_load_core_api_assembly() { - if (api_assembly) + if (core_api_assembly) return true; - bool success = _load_assembly(API_ASSEMBLY_NAME, &api_assembly); +#ifdef TOOLS_ENABLED + if (metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) + return false; +#endif - if (success) + bool success = load_assembly(API_ASSEMBLY_NAME, &core_api_assembly); + + if (success) { +#ifndef MONO_GLUE_DISABLED + APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(core_api_assembly, APIAssembly::API_CORE); + core_api_assembly_out_of_sync = GodotSharpBindings::get_core_api_hash() != api_assembly_ver.godot_api_hash || + GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version || + GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version; +#endif GDMonoUtils::update_godot_api_cache(); + } return success; } @@ -348,7 +460,23 @@ bool GDMono::_load_editor_api_assembly() { if (editor_api_assembly) return true; - return _load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly); +#ifdef TOOLS_ENABLED + if (metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) + return false; +#endif + + bool success = load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly); + + if (success) { +#ifndef MONO_GLUE_DISABLED + APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(editor_api_assembly, APIAssembly::API_EDITOR); + editor_api_assembly_out_of_sync = GodotSharpBindings::get_editor_api_hash() != api_assembly_ver.godot_api_hash || + GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version || + GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version; +#endif + } + + return success; } #endif @@ -360,7 +488,7 @@ bool GDMono::_load_editor_tools_assembly() { _GDMONO_SCOPE_DOMAIN_(tools_domain) - return _load_assembly(EDITOR_TOOLS_ASSEMBLY_NAME, &editor_tools_assembly); + return load_assembly(EDITOR_TOOLS_ASSEMBLY_NAME, &editor_tools_assembly); } #endif @@ -374,17 +502,20 @@ bool GDMono::_load_project_assembly() { name = "UnnamedProject"; } - bool success = _load_assembly(name, &project_assembly); + bool success = load_assembly(name, &project_assembly); - if (success) + if (success) { mono_assembly_set_main(project_assembly->get_assembly()); + } else { + if (OS::get_singleton()->is_stdout_verbose()) + OS::get_singleton()->printerr("Mono: Failed to load project assembly\n"); + } return success; } -bool GDMono::_load_all_script_assemblies() { +bool GDMono::_load_api_assemblies() { -#ifndef MONO_GLUE_DISABLED if (!_load_core_api_assembly()) { if (OS::get_singleton()->is_stdout_verbose()) OS::get_singleton()->printerr("Mono: Failed to load Core API assembly\n"); @@ -399,20 +530,72 @@ bool GDMono::_load_all_script_assemblies() { #endif } - if (!_load_project_assembly()) { - if (OS::get_singleton()->is_stdout_verbose()) - OS::get_singleton()->printerr("Mono: Failed to load project assembly\n"); - return false; + return true; +} + +#ifdef TOOLS_ENABLED +String GDMono::_get_api_assembly_metadata_path() { + + return GodotSharpDirs::get_res_metadata_dir().plus_file("api_assemblies.cfg"); +} + +void GDMono::metadata_set_api_assembly_invalidated(APIAssembly::Type p_api_type, bool p_invalidated) { + + String section = APIAssembly::to_string(p_api_type); + String path = _get_api_assembly_metadata_path(); + + Ref<ConfigFile> metadata; + metadata.instance(); + metadata->load(path); + + metadata->set_value(section, "invalidated", p_invalidated); + + String assembly_path = GodotSharpDirs::get_res_assemblies_dir() + .plus_file(p_api_type == APIAssembly::API_CORE ? + API_ASSEMBLY_NAME ".dll" : + EDITOR_API_ASSEMBLY_NAME ".dll"); + + ERR_FAIL_COND(!FileAccess::exists(assembly_path)); + + uint64_t modified_time = FileAccess::get_modified_time(assembly_path); + + metadata->set_value(section, "invalidated_asm_modified_time", String::num_uint64(modified_time)); + + String dir = path.get_base_dir(); + if (!DirAccess::exists(dir)) { + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND(!da); + Error err = da->make_dir_recursive(ProjectSettings::get_singleton()->globalize_path(dir)); + ERR_FAIL_COND(err != OK); } - return true; -#else - if (OS::get_singleton()->is_stdout_verbose()) - OS::get_singleton()->print("Mono: Glue disbled, ignoring script assemblies\n"); + Error save_err = metadata->save(path); + ERR_FAIL_COND(save_err != OK); +} - return true; -#endif +bool GDMono::metadata_is_api_assembly_invalidated(APIAssembly::Type p_api_type) { + + String section = APIAssembly::to_string(p_api_type); + + Ref<ConfigFile> metadata; + metadata.instance(); + metadata->load(_get_api_assembly_metadata_path()); + + String assembly_path = GodotSharpDirs::get_res_assemblies_dir() + .plus_file(p_api_type == APIAssembly::API_CORE ? + API_ASSEMBLY_NAME ".dll" : + EDITOR_API_ASSEMBLY_NAME ".dll"); + + if (!FileAccess::exists(assembly_path)) + return false; + + uint64_t modified_time = FileAccess::get_modified_time(assembly_path); + + uint64_t stored_modified_time = metadata->get_value(section, "invalidated_asm_modified_time", 0); + + return metadata->get_value(section, "invalidated", false) && modified_time <= stored_modified_time; } +#endif Error GDMono::_load_scripts_domain() { @@ -455,12 +638,15 @@ Error GDMono::_unload_scripts_domain() { _domain_assemblies_cleanup(mono_domain_get_id(scripts_domain)); - api_assembly = NULL; + core_api_assembly = NULL; project_assembly = NULL; #ifdef TOOLS_ENABLED editor_api_assembly = NULL; #endif + core_api_assembly_out_of_sync = false; + editor_api_assembly_out_of_sync = false; + MonoDomain *domain = scripts_domain; scripts_domain = NULL; @@ -515,16 +701,80 @@ Error GDMono::reload_scripts_domain() { return err; } - if (!_load_all_script_assemblies()) { - if (OS::get_singleton()->is_stdout_verbose()) - OS::get_singleton()->printerr("Mono: Failed to load script assemblies\n"); +#ifndef MONO_GLUE_DISABLED + if (!_load_api_assemblies()) { return ERR_CANT_OPEN; } + if (!core_api_assembly_out_of_sync && !editor_api_assembly_out_of_sync && GDMonoUtils::mono_cache.godot_api_cache_updated) { + // Everything is fine with the api assemblies, load the project assembly + _load_project_assembly(); + } else { + // The assembly was successfuly loaded, but the full api could not be cached. + // This is most likely an outdated assembly loaded because of an invalid version in the metadata, + // so we invalidate the version in the metadata and unload the script domain. + + if (core_api_assembly_out_of_sync) { + metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); + } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) { + ERR_PRINT("Core API assembly is in sync, but the cache update failed"); + metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); + } + + if (editor_api_assembly_out_of_sync) { + metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true); + } + + Error err = _unload_scripts_domain(); + if (err != OK) { + WARN_PRINT("Mono: Failed to unload scripts domain"); + } + + return ERR_CANT_RESOLVE; + } + + if (!_load_project_assembly()) + return ERR_CANT_OPEN; +#else + if (OS::get_singleton()->is_stdout_verbose()) + OS::get_singleton()->print("Mono: Glue disabled, ignoring script assemblies\n"); +#endif + return OK; } #endif +Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) { + + CRASH_COND(p_domain == NULL); + + String domain_name = mono_domain_get_friendly_name(p_domain); + + if (OS::get_singleton()->is_stdout_verbose()) { + OS::get_singleton()->print(String("Mono: Unloading domain `" + domain_name + "`...\n").utf8()); + } + + if (mono_domain_get() != root_domain) + mono_domain_set(root_domain, true); + + mono_gc_collect(mono_gc_max_generation()); + mono_domain_finalize(p_domain, 2000); + mono_gc_collect(mono_gc_max_generation()); + + _domain_assemblies_cleanup(mono_domain_get_id(p_domain)); + + MonoObject *ex = NULL; + mono_domain_try_unload(p_domain, &ex); + + if (ex) { + ERR_PRINTS("Exception thrown when unloading domain `" + domain_name + "`:"); + mono_print_unhandled_exception(ex); + return FAILED; + } + + return OK; +} + GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) { MonoImage *image = mono_class_get_image(p_raw_class); @@ -576,8 +826,11 @@ GDMono::GDMono() { tools_domain = NULL; #endif + core_api_assembly_out_of_sync = false; + editor_api_assembly_out_of_sync = false; + corlib_assembly = NULL; - api_assembly = NULL; + core_api_assembly = NULL; project_assembly = NULL; #ifdef TOOLS_ENABLED editor_api_assembly = NULL; @@ -696,11 +949,13 @@ bool _GodotSharp::is_domain_loaded() { return GDMono::get_singleton()->get_scripts_domain() != NULL; } -#define ENQUEUE_FOR_DISPOSAL(m_queue, m_inst) \ - m_queue.push_back(m_inst); \ - if (queue_empty) { \ - queue_empty = false; \ - call_deferred("_dispose_callback"); \ +#define ENQUEUE_FOR_DISPOSAL(m_queue, m_inst) \ + m_queue.push_back(m_inst); \ + if (queue_empty) { \ + queue_empty = false; \ + if (!is_finalizing_domain()) { /* call_deferred may not be safe here */ \ + call_deferred("_dispose_callback"); \ + } \ } void _GodotSharp::queue_dispose(MonoObject *p_mono_object, Object *p_object) { diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index 67251778c6..5e01152870 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -31,6 +31,8 @@ #ifndef GD_MONO_H #define GD_MONO_H +#include "core/io/config_file.h" + #include "../godotsharp_defs.h" #include "gd_mono_assembly.h" #include "gd_mono_log.h" @@ -39,6 +41,43 @@ #include "../utils/mono_reg_utils.h" #endif +namespace APIAssembly { +enum Type { + API_CORE, + API_EDITOR +}; + +struct Version { + uint64_t godot_api_hash; + uint32_t bindings_version; + uint32_t cs_glue_version; + + bool operator==(const Version &p_other) const { + return godot_api_hash == p_other.godot_api_hash && + bindings_version == p_other.bindings_version && + cs_glue_version == p_other.cs_glue_version; + } + + Version() : + godot_api_hash(0), + bindings_version(0), + cs_glue_version(0) { + } + + Version(uint64_t p_godot_api_hash, + uint32_t p_bindings_version, + uint32_t p_cs_glue_version) : + godot_api_hash(p_godot_api_hash), + bindings_version(p_bindings_version), + cs_glue_version(p_cs_glue_version) { + } + + static Version get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, Type p_api_type); +}; + +String to_string(Type p_type); +} // namespace APIAssembly + #define SCRIPTS_DOMAIN GDMono::get_singleton()->get_scripts_domain() #ifdef TOOLS_ENABLED #define TOOLS_DOMAIN GDMono::get_singleton()->get_tools_domain() @@ -55,8 +94,11 @@ class GDMono { MonoDomain *tools_domain; #endif + bool core_api_assembly_out_of_sync; + bool editor_api_assembly_out_of_sync; + GDMonoAssembly *corlib_assembly; - GDMonoAssembly *api_assembly; + GDMonoAssembly *core_api_assembly; GDMonoAssembly *project_assembly; #ifdef TOOLS_ENABLED GDMonoAssembly *editor_api_assembly; @@ -75,7 +117,11 @@ class GDMono { #endif bool _load_project_assembly(); - bool _load_all_script_assemblies(); + bool _load_api_assemblies(); + +#ifdef TOOLS_ENABLED + String _get_api_assembly_metadata_path(); +#endif void _register_internal_calls(); @@ -94,8 +140,6 @@ class GDMono { void _initialize_and_check_api_hashes(); #endif - bool _load_assembly(const String &p_name, GDMonoAssembly **r_assembly); - GDMonoLog *gdmono_log; #ifdef WINDOWS_ENABLED @@ -113,6 +157,11 @@ public: #endif #endif +#ifdef TOOLS_ENABLED + void metadata_set_api_assembly_invalidated(APIAssembly::Type p_api_type, bool p_invalidated); + bool metadata_is_api_assembly_invalidated(APIAssembly::Type p_api_type); +#endif + static GDMono *get_singleton() { return singleton; } // Do not use these, unless you know what you're doing @@ -128,7 +177,7 @@ public: #endif _FORCE_INLINE_ GDMonoAssembly *get_corlib_assembly() const { return corlib_assembly; } - _FORCE_INLINE_ GDMonoAssembly *get_api_assembly() const { return api_assembly; } + _FORCE_INLINE_ GDMonoAssembly *get_core_api_assembly() const { return core_api_assembly; } _FORCE_INLINE_ GDMonoAssembly *get_project_assembly() const { return project_assembly; } #ifdef TOOLS_ENABLED _FORCE_INLINE_ GDMonoAssembly *get_editor_api_assembly() const { return editor_api_assembly; } @@ -145,6 +194,10 @@ public: Error reload_scripts_domain(); #endif + bool load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly = false); + bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly = false); + Error finalize_and_unload_domain(MonoDomain *p_domain); + void initialize(); GDMono(); diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index ba56ed6ed5..d062d56dcf 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -43,7 +43,23 @@ bool GDMonoAssembly::no_search = false; Vector<String> GDMonoAssembly::search_dirs; -MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_data) { +MonoAssembly *GDMonoAssembly::assembly_search_hook(MonoAssemblyName *aname, void *user_data) { + return GDMonoAssembly::_search_hook(aname, user_data, false); +} + +MonoAssembly *GDMonoAssembly::assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data) { + return GDMonoAssembly::_search_hook(aname, user_data, true); +} + +MonoAssembly *GDMonoAssembly::assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) { + return GDMonoAssembly::_preload_hook(aname, assemblies_path, user_data, false); +} + +MonoAssembly *GDMonoAssembly::assembly_refonly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) { + return GDMonoAssembly::_preload_hook(aname, assemblies_path, user_data, true); +} + +MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_data, bool refonly) { (void)user_data; // UNUSED @@ -60,7 +76,7 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d no_search = true; // Avoid the recursion madness String path; - MonoAssembly *res = NULL; + GDMonoAssembly *res = NULL; for (int i = 0; i < search_dirs.size(); i++) { const String &search_dir = search_dirs[i]; @@ -68,44 +84,49 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d if (has_extension) { path = search_dir.plus_file(name); if (FileAccess::exists(path)) { - res = _load_assembly_from(name.get_basename(), path); - break; + res = _load_assembly_from(name.get_basename(), path, refonly); + if (res != NULL) + break; } } else { path = search_dir.plus_file(name + ".dll"); if (FileAccess::exists(path)) { - res = _load_assembly_from(name, path); - break; + res = _load_assembly_from(name, path, refonly); + if (res != NULL) + break; } path = search_dir.plus_file(name + ".exe"); if (FileAccess::exists(path)) { - res = _load_assembly_from(name, path); - break; + res = _load_assembly_from(name, path, refonly); + if (res != NULL) + break; } } } no_search = false; - return res; + return res ? res->get_assembly() : NULL; } -MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) { +MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly) { (void)user_data; // UNUSED if (search_dirs.empty()) { -#ifdef TOOLS_DOMAIN search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir()); -#endif search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir()); search_dirs.push_back(OS::get_singleton()->get_resource_dir()); search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir()); +#ifdef GD_MONO_EDITOR_ASSEMBLIES_DIR + search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir().plus_file(_MKSTR(GD_MONO_EDITOR_ASSEMBLIES_DIR)).simplify_path()); +#endif const char *rootdir = mono_assembly_getrootdir(); if (rootdir) { search_dirs.push_back(String(rootdir).plus_file("mono").plus_file("4.5")); + search_dirs.push_back(String(rootdir).plus_file("mono").plus_file("4.5").plus_file("Facades")); } if (assemblies_path) { @@ -116,38 +137,74 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse } } + String name = mono_assembly_name_get_name(aname); + bool has_extension = name.ends_with(".dll"); + + if (has_extension ? name == "mscorlib.dll" : name == "mscorlib") { + GDMonoAssembly **stored_assembly = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name); + if (stored_assembly) + return (*stored_assembly)->get_assembly(); + + String path; + GDMonoAssembly *res = NULL; + + for (int i = 0; i < search_dirs.size(); i++) { + const String &search_dir = search_dirs[i]; + + if (has_extension) { + path = search_dir.plus_file(name); + if (FileAccess::exists(path)) { + res = _load_assembly_from(name.get_basename(), path, refonly); + if (res != NULL) + break; + } + } else { + path = search_dir.plus_file(name + ".dll"); + if (FileAccess::exists(path)) { + res = _load_assembly_from(name, path, refonly); + if (res != NULL) + break; + } + } + } + + return res ? res->get_assembly() : NULL; + } + return NULL; } -MonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path) { +GDMonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly) { GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path)); - MonoDomain *domain = mono_domain_get(); - - Error err = assembly->load(domain); + Error err = assembly->load(p_refonly); if (err != OK) { memdelete(assembly); ERR_FAIL_V(NULL); } + MonoDomain *domain = mono_domain_get(); GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, assembly); - return assembly->get_assembly(); + return assembly; } void GDMonoAssembly::initialize() { - // TODO refonly as well? - mono_install_assembly_preload_hook(&GDMonoAssembly::_preload_hook, NULL); - mono_install_assembly_search_hook(&GDMonoAssembly::_search_hook, NULL); + mono_install_assembly_search_hook(&assembly_search_hook, NULL); + mono_install_assembly_refonly_search_hook(&assembly_refonly_search_hook, NULL); + mono_install_assembly_preload_hook(&assembly_preload_hook, NULL); + mono_install_assembly_refonly_preload_hook(&assembly_refonly_preload_hook, NULL); } -Error GDMonoAssembly::load(MonoDomain *p_domain) { +Error GDMonoAssembly::load(bool p_refonly) { ERR_FAIL_COND_V(loaded, ERR_FILE_ALREADY_IN_USE); + refonly = p_refonly; + uint64_t last_modified_time = FileAccess::get_modified_time(path); Vector<uint8_t> data = FileAccess::get_file_as_array(path); @@ -155,14 +212,15 @@ Error GDMonoAssembly::load(MonoDomain *p_domain) { String image_filename(path); - MonoImageOpenStatus status; + MonoImageOpenStatus status = MONO_IMAGE_OK; image = mono_image_open_from_data_with_name( (char *)&data[0], data.size(), - true, &status, false, + true, &status, refonly, image_filename.utf8().get_data()); - ERR_FAIL_COND_V(status != MONO_IMAGE_OK || image == NULL, ERR_FILE_CANT_OPEN); + ERR_FAIL_COND_V(status != MONO_IMAGE_OK, ERR_FILE_CANT_OPEN); + ERR_FAIL_NULL_V(image, ERR_FILE_CANT_OPEN); #ifdef DEBUG_ENABLED String pdb_path(path + ".pdb"); @@ -182,15 +240,10 @@ no_pdb: #endif - assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, false); + assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, refonly); ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN); - 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); - } - loaded = true; modified_time = last_modified_time; @@ -342,12 +395,26 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class) return match; } +GDMonoAssembly *GDMonoAssembly::load_from(const String &p_name, const String &p_path, bool p_refonly) { + + GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name); + if (loaded_asm) + return *loaded_asm; + + no_search = true; + GDMonoAssembly *res = _load_assembly_from(p_name, p_path, p_refonly); + no_search = false; + + return res; +} + GDMonoAssembly::GDMonoAssembly(const String &p_name, const String &p_path) { loaded = false; gdobject_class_cache_updated = false; name = p_name; path = p_path; + refonly = false; modified_time = 0; assembly = NULL; image = NULL; diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h index 8e7aa701bf..5cf744a5a2 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.h +++ b/modules/mono/mono_gd/gd_mono_assembly.h @@ -71,6 +71,7 @@ class GDMonoAssembly { MonoAssembly *assembly; MonoImage *image; + bool refonly; bool loaded; String name; @@ -90,19 +91,25 @@ class GDMonoAssembly { 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 *assembly_search_hook(MonoAssemblyName *aname, void *user_data); + static MonoAssembly *assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data); + static MonoAssembly *assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data); + static MonoAssembly *assembly_refonly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data); - static MonoAssembly *_load_assembly_from(const String &p_name, const String &p_path); + static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data, bool refonly); + static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly); + + static GDMonoAssembly *_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly); friend class GDMono; static void initialize(); public: - Error load(MonoDomain *p_domain); + Error load(bool p_refonly); Error wrapper_for_image(MonoImage *p_image); void unload(); + _FORCE_INLINE_ bool is_refonly() const { return refonly; } _FORCE_INLINE_ bool is_loaded() const { return loaded; } _FORCE_INLINE_ MonoImage *get_image() const { return image; } _FORCE_INLINE_ MonoAssembly *get_assembly() const { return assembly; } @@ -110,11 +117,13 @@ public: _FORCE_INLINE_ String get_path() const { return path; } _FORCE_INLINE_ uint64_t get_modified_time() const { return modified_time; } - GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_class); + GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_name); GDMonoClass *get_class(MonoClass *p_mono_class); GDMonoClass *get_object_derived_class(const StringName &p_class); + static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly); + GDMonoAssembly(const String &p_name, const String &p_path = String()); ~GDMonoAssembly(); }; diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index b826352f02..66339d7ae6 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -404,6 +404,33 @@ const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() { return properties_list; } +const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() { + if (delegates_fetched) + return delegates_list; + + void *iter = NULL; + MonoClass *raw_class = NULL; + while ((raw_class = mono_class_get_nested_types(mono_class, &iter)) != NULL) { + if (mono_class_is_delegate(raw_class)) { + StringName name = mono_class_get_name(raw_class); + + Map<StringName, GDMonoClass *>::Element *match = delegates.find(name); + + if (match) { + delegates_list.push_back(match->get()); + } else { + GDMonoClass *delegate = memnew(GDMonoClass(mono_class_get_namespace(raw_class), mono_class_get_name(raw_class), raw_class, assembly)); + delegates.insert(name, delegate); + delegates_list.push_back(delegate); + } + } + } + + delegates_fetched = true; + + return delegates_list; +} + GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly) { namespace_name = p_namespace; @@ -417,6 +444,7 @@ GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name methods_fetched = false; fields_fetched = false; properties_fetched = false; + delegates_fetched = false; } GDMonoClass::~GDMonoClass() { diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h index f5895be144..417c138594 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -90,6 +90,10 @@ class GDMonoClass { Map<StringName, GDMonoProperty *> properties; Vector<GDMonoProperty *> properties_list; + bool delegates_fetched; + Map<StringName, GDMonoClass *> delegates; + Vector<GDMonoClass *> delegates_list; + friend class GDMonoAssembly; GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly); @@ -125,7 +129,7 @@ public: GDMonoMethod *get_method(MonoMethod *p_raw_method); GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name); GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count); - GDMonoMethod *get_method_with_desc(const String &p_description, bool p_includes_namespace); + GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace); GDMonoField *get_field(const StringName &p_name); const Vector<GDMonoField *> &get_all_fields(); @@ -133,6 +137,8 @@ public: GDMonoProperty *get_property(const StringName &p_name); const Vector<GDMonoProperty *> &get_all_properties(); + const Vector<GDMonoClass *> &get_all_delegates(); + ~GDMonoClass(); }; diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp index 1f8e9a1926..ad52904945 100644 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ b/modules/mono/mono_gd/gd_mono_method.cpp @@ -229,6 +229,23 @@ String GDMonoMethod::get_signature_desc(bool p_namespaces) const { return res; } +void GDMonoMethod::get_parameter_names(Vector<StringName> &names) const { + if (params_count > 0) { + const char **_names = memnew_arr(const char *, params_count); + mono_method_get_param_names(mono_method, _names); + for (int i = 0; i < params_count; ++i) { + names.push_back(StringName(_names[i])); + } + memdelete_arr(_names); + } +} + +void GDMonoMethod::get_parameter_types(Vector<ManagedType> &types) const { + for (int i = 0; i < param_types.size(); ++i) { + types.push_back(param_types[i]); + } +} + GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) { name = p_name; diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h index 14df8dcfb4..a173af83f4 100644 --- a/modules/mono/mono_gd/gd_mono_method.h +++ b/modules/mono/mono_gd/gd_mono_method.h @@ -80,6 +80,9 @@ public: String get_ret_type_full_name() const; String get_signature_desc(bool p_namespaces = false) const; + void get_parameter_names(Vector<StringName> &names) const; + void get_parameter_types(Vector<ManagedType> &types) const; + GDMonoMethod(StringName p_name, MonoMethod *p_method); ~GDMonoMethod(); }; diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp index bc5a1d3a39..0fe527b199 100644 --- a/modules/mono/mono_gd/gd_mono_property.cpp +++ b/modules/mono/mono_gd/gd_mono_property.cpp @@ -139,7 +139,7 @@ bool GDMonoProperty::has_setter() { } void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoObject **r_exc) { - MonoMethod *prop_method = mono_property_get_get_method(mono_property); + MonoMethod *prop_method = mono_property_get_set_method(mono_property); MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1); mono_array_set(params, MonoObject *, 0, p_value); diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 835a4614c1..db136a1313 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -114,6 +114,7 @@ void MonoCache::clear_members() { class_ExportAttribute = NULL; field_ExportAttribute_hint = NULL; field_ExportAttribute_hintString = NULL; + class_SignalAttribute = NULL; class_ToolAttribute = NULL; class_RemoteAttribute = NULL; class_SyncAttribute = NULL; @@ -142,7 +143,7 @@ void MonoCache::cleanup() { godot_api_cache_updated = false; } -#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class)) +#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class)) void update_corlib_cache() { @@ -184,7 +185,7 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color)); CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane)); CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath)); - CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(NodePath)); + CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID)); CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object)); CACHE_CLASS_AND_CHECK(GodotReference, GODOT_API_CLASS(Reference)); CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node)); @@ -201,6 +202,7 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute)); CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint")); CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString")); + CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute)); CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute)); CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute)); CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute)); @@ -243,7 +245,7 @@ void update_godot_api_cache() { mono_runtime_object_init(task_scheduler); mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler); - mono_cache.corlib_cache_updated = true; + mono_cache.godot_api_cache_updated = true; } void clear_cache() { @@ -303,7 +305,7 @@ GDMonoClass *type_get_proxy_class(const StringName &p_type) { if (class_name[0] == '_') class_name = class_name.substr(1, class_name.length()); - GDMonoClass *klass = GDMono::get_singleton()->get_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name); + GDMonoClass *klass = GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name); #ifdef TOOLS_ENABLED if (!klass) { @@ -319,7 +321,7 @@ GDMonoClass *get_class_native_base(GDMonoClass *p_class) { do { const GDMonoAssembly *assembly = klass->get_assembly(); - if (assembly == GDMono::get_singleton()->get_api_assembly()) + if (assembly == GDMono::get_singleton()->get_core_api_assembly()) return klass; #ifdef TOOLS_ENABLED if (assembly == GDMono::get_singleton()->get_editor_api_assembly()) @@ -418,37 +420,56 @@ void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution) { if (!ScriptDebugger::get_singleton()) return; - GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace); - MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr()); + ScriptLanguage::StackInfo separator; + separator.file = ""; + separator.func = "--- " + RTR("End of inner exception stack trace") + " ---"; + separator.line = 0; + + Vector<ScriptLanguage::StackInfo> si; + String exc_msg = ""; + + while (p_exc != NULL) { + GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace); + MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr()); - MonoBoolean need_file_info = true; - void *ctor_args[2] = { p_exc, &need_file_info }; + MonoBoolean need_file_info = true; + void *ctor_args[2] = { p_exc, &need_file_info }; - MonoObject *unexpected_exc = NULL; - CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc); + MonoObject *unexpected_exc = NULL; + CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc); - if (unexpected_exc != NULL) { - mono_print_unhandled_exception(unexpected_exc); + if (unexpected_exc != NULL) { + mono_print_unhandled_exception(unexpected_exc); - if (p_recursion_caution) { - // Called from CSharpLanguage::get_current_stack_info, - // so printing an error here could result in endless recursion - OS::get_singleton()->printerr("Mono: Method GDMonoUtils::print_unhandled_exception failed"); - return; - } else { - ERR_FAIL(); + if (p_recursion_caution) { + // Called from CSharpLanguage::get_current_stack_info, + // so printing an error here could result in endless recursion + OS::get_singleton()->printerr("Mono: Method GDMonoUtils::print_unhandled_exception failed"); + return; + } else { + ERR_FAIL(); + } } - } - Vector<ScriptLanguage::StackInfo> si; - if (stack_trace != NULL && !p_recursion_caution) - si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace); + Vector<ScriptLanguage::StackInfo> _si; + if (stack_trace != NULL && !p_recursion_caution) { + _si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace); + for (int i = _si.size() - 1; i >= 0; i--) + si.insert(0, _si[i]); + } + + exc_msg += (exc_msg.length() > 0 ? " ---> " : "") + GDMonoUtils::get_exception_name_and_message(p_exc); + + GDMonoProperty *p_prop = GDMono::get_singleton()->get_class(mono_object_get_class(p_exc))->get_property("InnerException"); + p_exc = p_prop != NULL ? p_prop->get_value(p_exc) : NULL; + if (p_exc != NULL) + si.insert(0, separator); + } String file = si.size() ? si[0].file : __FILE__; String func = si.size() ? si[0].func : FUNCTION_STR; int line = si.size() ? si[0].line : __LINE__; String error_msg = "Unhandled exception"; - String exc_msg = GDMonoUtils::get_exception_name_and_message(p_exc); ScriptDebugger::get_singleton()->send_error(func, file, line, error_msg, exc_msg, ERR_HANDLER_ERROR, si); #endif diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 2666433170..1a34180d15 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -43,7 +43,7 @@ namespace GDMonoUtils { typedef MonoObject *(*MarshalUtils_DictToArrays)(MonoObject *, MonoArray **, MonoArray **, MonoObject **); typedef MonoObject *(*MarshalUtils_ArraysToDict)(MonoArray *, MonoArray *, MonoObject **); -typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray **, MonoObject **); +typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **); typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **); typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **); typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **); @@ -108,6 +108,7 @@ struct MonoCache { GDMonoClass *class_ExportAttribute; GDMonoField *field_ExportAttribute_hint; GDMonoField *field_ExportAttribute_hintString; + GDMonoClass *class_SignalAttribute; GDMonoClass *class_ToolAttribute; GDMonoClass *class_RemoteAttribute; GDMonoClass *class_SyncAttribute; diff --git a/modules/mono/mono_reg_utils.py b/modules/mono/mono_reg_utils.py index 8ddddb3a24..9c188d07a7 100644 --- a/modules/mono/mono_reg_utils.py +++ b/modules/mono/mono_reg_utils.py @@ -75,7 +75,7 @@ def find_msbuild_tools_path_reg(): vswhere = os.getenv('PROGRAMFILES') vswhere += r'\Microsoft Visual Studio\Installer\vswhere.exe' - vswhere_args = ['-latest', '-requires', 'Microsoft.Component.MSBuild'] + vswhere_args = ['-latest', '-products', '*', '-requires', 'Microsoft.Component.MSBuild'] try: lines = subprocess.check_output([vswhere] + vswhere_args).splitlines() diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp index 2671e9a970..b9d8520ac9 100644 --- a/modules/mono/signal_awaiter_utils.cpp +++ b/modules/mono/signal_awaiter_utils.cpp @@ -102,7 +102,7 @@ Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argc GDMonoUtils::SignalAwaiter_SignalCallback thunk = CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback); MonoObject *ex = NULL; - thunk(get_target(), &signal_args, &ex); + thunk(get_target(), signal_args, &ex); if (ex) { mono_print_unhandled_exception(ex); diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp index 9bb8da8ac0..7b23cd7579 100644 --- a/modules/mono/utils/mono_reg_utils.cpp +++ b/modules/mono/utils/mono_reg_utils.cpp @@ -174,6 +174,8 @@ String find_msbuild_tools_path() { List<String> vswhere_args; vswhere_args.push_back("-latest"); + vswhere_args.push_back("-products"); + vswhere_args.push_back("*"); vswhere_args.push_back("-requires"); vswhere_args.push_back("Microsoft.Component.MSBuild"); |