diff options
Diffstat (limited to 'modules/mono/csharp_script.cpp')
-rw-r--r-- | modules/mono/csharp_script.cpp | 360 |
1 files changed, 224 insertions, 136 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 1901b2cae8..d2a861dbe8 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -49,6 +49,8 @@ #include "mono_gd/gd_mono_class.h" #include "mono_gd/gd_mono_marshal.h" #include "signal_awaiter_utils.h" +#include "utils/macros.h" +#include "utils/thread_local.h" #define CACHED_STRING_NAME(m_var) (CSharpLanguage::get_singleton()->get_string_names().m_var) @@ -118,6 +120,8 @@ void CSharpLanguage::init() { #ifdef TOOLS_ENABLED EditorNode::add_init_callback(&gdsharp_editor_init_callback); + + GLOBAL_DEF("mono/export/include_scripts_content", false); #endif } @@ -280,34 +284,42 @@ 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" "using System;\n" "\n" - "public class %CLASS_NAME% : %BASE_CLASS_NAME%\n" + "public class %CLASS% : %BASE%\n" "{\n" - " // Member variables here, example:\n" + " // Declare member variables here. Examples:\n" " // private int a = 2;\n" - " // private string b = \"textvar\";\n" + " // private string b = \"text\";\n" "\n" + " // Called when the node enters the scene tree for the first time.\n" " public override void _Ready()\n" " {\n" - " // Called every time the node is added to the scene.\n" - " // Initialization here\n" " \n" " }\n" "\n" - "// public override void _Process(float delta)\n" - "// {\n" - "// // Called every frame. Delta is time since last frame.\n" - "// // Update game logic here.\n" - "// \n" - "// }\n" + "// // Called every frame. 'delta' is the elapsed time since the previous frame.\n" + "// public override void _Process(float delta)\n" + "// {\n" + "// \n" + "// }\n" "}\n"; - script_template = script_template.replace("%BASE_CLASS_NAME%", p_base_class_name) - .replace("%CLASS_NAME%", p_class_name); + String base_class_name = get_base_class_name(p_base_class_name, p_class_name); + script_template = script_template.replace("%BASE%", base_class_name) + .replace("%CLASS%", p_class_name); Ref<CSharpScript> script; script.instance(); @@ -325,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); @@ -422,7 +446,7 @@ String CSharpLanguage::make_function(const String &p_class, const String &p_name s += variant_type_to_managed_name(arg.get_slice(":", 1)) + " " + escape_csharp_keyword(arg.get_slice(":", 0)); } - s += ")\n{\n // Replace with function body\n}\n"; + s += ")\n{\n // Replace with function body.\n}\n"; return s; #else @@ -452,9 +476,9 @@ 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 + _TLS_RECURSION_GUARD_V_(Vector<StackInfo>()); - 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()); @@ -476,15 +500,15 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() #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 + _TLS_RECURSION_GUARD_V_(Vector<StackInfo>()); - MonoObject *exc = NULL; + MonoException *exc = NULL; GDMonoUtils::StackTrace_GetFrames st_get_frames = CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames); - MonoArray *frames = st_get_frames(p_stack_trace, &exc); + MonoArray *frames = st_get_frames(p_stack_trace, (MonoObject **)&exc); if (exc) { - GDMonoUtils::print_unhandled_exception(exc, true /* fail silently to avoid endless recursion */); + GDMonoUtils::debug_print_unhandled_exception(exc); return Vector<StackInfo>(); } @@ -499,16 +523,16 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec si.resize(frame_count); for (int i = 0; i < frame_count; i++) { - StackInfo &sif = si[i]; + StackInfo &sif = si.write[i]; MonoObject *frame = mono_array_get(frames, MonoObject *, i); MonoString *file_name; int file_line_num; MonoString *method_decl; - get_sf_info(frame, &file_name, &file_line_num, &method_decl, &exc); + get_sf_info(frame, &file_name, &file_line_num, &method_decl, (MonoObject **)&exc); if (exc) { - GDMonoUtils::print_unhandled_exception(exc, true /* fail silently to avoid endless recursion */); + GDMonoUtils::debug_print_unhandled_exception(exc); return Vector<StackInfo>(); } @@ -537,12 +561,12 @@ void CSharpLanguage::frame() { ERR_FAIL_NULL(thunk); - MonoObject *ex; - thunk(task_scheduler, &ex); + MonoException *exc = NULL; + thunk(task_scheduler, (MonoObject **)&exc); - if (ex) { - mono_print_unhandled_exception(ex); - ERR_FAIL(); + if (exc) { + GDMonoUtils::debug_unhandled_exception(exc); + _UNREACHABLE_(); } } } @@ -614,33 +638,41 @@ void CSharpLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft #ifdef TOOLS_ENABLED void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { - if (gdmono->is_runtime_initialized()) { + if (!gdmono->is_runtime_initialized()) + return; - GDMonoAssembly *proj_assembly = gdmono->get_project_assembly(); + GDMonoAssembly *proj_assembly = gdmono->get_project_assembly(); - String name = ProjectSettings::get_singleton()->get("application/config/name"); - if (name.empty()) { - name = "UnnamedProject"; - } + String name = ProjectSettings::get_singleton()->get("application/config/name"); + if (name.empty()) { + name = "UnnamedProject"; + } - if (proj_assembly) { - String proj_asm_path = proj_assembly->get_path(); + name += ".dll"; - if (!FileAccess::exists(proj_assembly->get_path())) { - // Maybe it wasn't loaded from the default path, so check this as well - proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name); - if (!FileAccess::exists(proj_asm_path)) - return; // No assembly to load - } + if (proj_assembly) { + String proj_asm_path = proj_assembly->get_path(); - if (FileAccess::get_modified_time(proj_asm_path) <= proj_assembly->get_modified_time()) - return; // Already up to date - } else { - if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name))) + if (!FileAccess::exists(proj_assembly->get_path())) { + // Maybe it wasn't loaded from the default path, so check this as well + proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name); + if (!FileAccess::exists(proj_asm_path)) return; // No assembly to load } + + if (FileAccess::get_modified_time(proj_asm_path) <= proj_assembly->get_modified_time()) + return; // Already up to date + } else { + if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name))) + return; // No assembly to load } + if (!gdmono->get_core_api_assembly() && gdmono->metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) + return; // The core API assembly to load is invalidated + + if (!gdmono->get_editor_api_assembly() && gdmono->metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) + return; // The editor API assembly to load is invalidated + #ifndef NO_THREADS lock->lock(); #endif @@ -704,6 +736,9 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { obj->get_script_instance()->get_property_state(state); map[obj->get_instance_id()] = state; obj->set_script(RefPtr()); + } else { + // no instance found. Let's remove it so we don't loop forever + E->get()->placeholders.erase(E->get()->placeholders.front()->get()); } } @@ -715,16 +750,31 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { } } - if (gdmono->reload_scripts_domain() != OK) + if (gdmono->reload_scripts_domain() != OK) { + // Failed to reload the scripts domain + // Make sure to add the scripts back to their owners before returning + for (Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) { + Ref<CSharpScript> scr = E->key(); + for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get().front(); F; F = F->next()) { + Object *obj = ObjectDB::get_instance(F->key()); + if (!obj) + continue; + obj->set_script(scr.get_ref_ptr()); + // Save reload state for next time if not saved + if (!scr->pending_reload_state.has(obj->get_instance_id())) { + scr->pending_reload_state[obj->get_instance_id()] = F->get(); + } + } + } return; + } 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->signals_invalidated = true; scr->reload(p_soft_reload); - scr->update_signals(); scr->update_exports(); //restore state if saved @@ -747,6 +797,14 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { continue; } + if (scr->valid && scr->is_tool() && obj->get_script_instance()->is_placeholder()) { + // Script instance was a placeholder, but now the script was built successfully and is a tool script. + // We have to replace the placeholder with an actual C# script instance. + scr->placeholders.erase(static_cast<PlaceHolderScriptInstance *>(obj->get_script_instance())); + ScriptInstance *script_instance = scr->instance_create(obj); + obj->set_script_instance(script_instance); // Not necessary as it's already done in instance_create, but just in case... + } + for (List<Pair<StringName, Variant> >::Element *G = F->get().front(); G; G = G->next()) { obj->get_script_instance()->set(G->get().first, G->get().second); } @@ -758,7 +816,7 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { } if (Engine::get_singleton()->is_editor_hint()) { - EditorNode::get_singleton()->get_property_editor()->update_tree(); + EditorNode::get_singleton()->get_inspector()->update_tree(); NodeDock::singleton->update_lists(); } } @@ -1117,11 +1175,11 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const { GDMonoProperty *property = top->get_property(p_name); if (property) { - MonoObject *exc = NULL; + MonoException *exc = NULL; MonoObject *value = property->get_value(mono_object, &exc); if (exc) { r_ret = Variant(); - GDMonoUtils::print_unhandled_exception(exc); + GDMonoUtils::set_pending_exception(exc); } else { r_ret = GDMonoMarshal::mono_object_to_variant(value); } @@ -1353,21 +1411,27 @@ bool CSharpInstance::refcount_decremented() { return ref_dying; } -ScriptInstance::RPCMode CSharpInstance::_member_get_rpc_mode(GDMonoClassMember *p_member) const { +MultiplayerAPI::RPCMode CSharpInstance::_member_get_rpc_mode(GDMonoClassMember *p_member) const { if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute))) - return RPC_MODE_REMOTE; + return MultiplayerAPI::RPC_MODE_REMOTE; if (p_member->has_attribute(CACHED_CLASS(SyncAttribute))) - return RPC_MODE_SYNC; + return MultiplayerAPI::RPC_MODE_SYNC; if (p_member->has_attribute(CACHED_CLASS(MasterAttribute))) - return RPC_MODE_MASTER; + return MultiplayerAPI::RPC_MODE_MASTER; if (p_member->has_attribute(CACHED_CLASS(SlaveAttribute))) - return RPC_MODE_SLAVE; + return MultiplayerAPI::RPC_MODE_SLAVE; + if (p_member->has_attribute(CACHED_CLASS(RemoteSyncAttribute))) + return MultiplayerAPI::RPC_MODE_REMOTESYNC; + if (p_member->has_attribute(CACHED_CLASS(MasterSyncAttribute))) + return MultiplayerAPI::RPC_MODE_MASTERSYNC; + if (p_member->has_attribute(CACHED_CLASS(SlaveSyncAttribute))) + return MultiplayerAPI::RPC_MODE_SLAVESYNC; - return RPC_MODE_DISABLED; + return MultiplayerAPI::RPC_MODE_DISABLED; } -ScriptInstance::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const { +MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const { GDMonoClass *top = script->script_class; @@ -1380,10 +1444,10 @@ ScriptInstance::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) top = top->get_parent_class(); } - return RPC_MODE_DISABLED; + return MultiplayerAPI::RPC_MODE_DISABLED; } -ScriptInstance::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const { +MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const { GDMonoClass *top = script->script_class; @@ -1401,7 +1465,7 @@ ScriptInstance::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variab top = top->get_parent_class(); } - return RPC_MODE_DISABLED; + return MultiplayerAPI::RPC_MODE_DISABLED; } void CSharpInstance::notification(int p_notification) { @@ -1504,8 +1568,12 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List bool CSharpScript::_update_exports() { #ifdef TOOLS_ENABLED - if (!valid) + if (!valid) { + for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->set_build_failed(true); + } return false; + } bool changed = false; @@ -1527,12 +1595,12 @@ bool CSharpScript::_update_exports() { CACHED_FIELD(GodotObject, ptr)->set_value_raw(tmp_object, tmp_object); // FIXME WTF is this workaround GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0); - MonoObject *ex = NULL; - ctor->invoke(tmp_object, NULL, &ex); + MonoException *exc = NULL; + ctor->invoke(tmp_object, NULL, &exc); - if (ex) { + if (exc) { ERR_PRINT("Exception thrown from constructor of temporary MonoObject:"); - mono_print_unhandled_exception(ex); + GDMonoUtils::debug_print_unhandled_exception(exc); tmp_object = NULL; ERR_FAIL_V(false); } @@ -1581,11 +1649,11 @@ bool CSharpScript::_update_exports() { exported_members_cache.push_front(prop_info); if (tmp_object) { - MonoObject *exc = NULL; + MonoException *exc = NULL; MonoObject *ret = property->get_value(tmp_object, &exc); if (exc) { exported_members_defval_cache[name] = Variant(); - GDMonoUtils::print_unhandled_exception(exc); + GDMonoUtils::debug_print_unhandled_exception(exc); } else { exported_members_defval_cache[name] = GDMonoMarshal::mono_object_to_variant(ret); } @@ -1607,6 +1675,7 @@ bool CSharpScript::_update_exports() { _update_exports_values(values, propnames); for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->set_build_failed(false); E->get()->update(propnames, values); } } @@ -1616,45 +1685,38 @@ bool CSharpScript::_update_exports() { return false; } -bool CSharpScript::_update_signals() { -#ifdef TOOLS_ENABLED - if (!valid) - return false; - - bool changed = false; - - if (signals_invalidated) { - signals_invalidated = false; +void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class) { - GDMonoClass *top = script_class; + // no need to load the script's signals more than once + if (!signals_invalidated) { + return; + } - _signals.clear(); - changed = true; // TODO Do a real check for change + // make sure this classes signals are empty when loading for the first time + _signals.clear(); - 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 *top = p_class; + while (top && top != p_native_class) { + const Vector<GDMonoClass *> &delegates = top->get_all_delegates(); + for (int i = delegates.size() - 1; i >= 0; --i) { + Vector<Argument> parameters; - GDMonoClass *delegate = delegates[i]; + GDMonoClass *delegate = delegates[i]; - if (_get_signal(top, delegate, parameters)) { - _signals[delegate->get_name()] = parameters; - } + if (_get_signal(top, delegate, parameters)) { + _signals[delegate->get_name()] = parameters; } - - top = top->get_parent_class(); } + + top = top->get_parent_class(); } - return changed; -#endif - return false; + signals_invalidated = false; } 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); + MonoType *raw_type = p_delegate->get_mono_type(); if (mono_type_get_type(raw_type) == MONO_TYPE_CLASS) { // Arguments are accessibles as arguments of .Invoke method @@ -1724,7 +1786,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute)); - PropertyHint hint; + PropertyHint hint = PROPERTY_HINT_NONE; String hint_string; if (variant_type == Variant::NIL) { @@ -1772,6 +1834,12 @@ void CSharpScript::_clear() { Variant CSharpScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + if (unlikely(GDMono::get_singleton() == NULL)) { + // Probably not the best error but eh. + r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL; + return Variant(); + } + GDMonoClass *top = script_class; while (top && top != native) { @@ -1882,6 +1950,8 @@ Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class) { top = top->get_parent_class(); } + script->load_script_signals(script->script_class, script->native); + return script; } @@ -1902,7 +1972,11 @@ bool CSharpScript::can_instance() const { } #endif - return valid || (!tool && !ScriptServer::is_scripting_enabled()); +#ifdef TOOLS_ENABLED + return valid && (tool || ScriptServer::is_scripting_enabled()); +#else + return valid; +#endif } StringName CSharpScript::get_instance_base_type() const { @@ -1952,7 +2026,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg // Construct GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount); - ctor->invoke(mono_object, p_args, NULL); + ctor->invoke(mono_object, p_args); // Tie managed to unmanaged instance->gchandle = MonoGCHandle::create_strong(mono_object); @@ -2000,22 +2074,23 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Variant::Call ScriptInstance *CSharpScript::instance_create(Object *p_this) { - if (!valid) - return 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; +#ifdef DEBUG_ENABLED + CRASH_COND(!valid); #endif + + if (!script_class) { + if (GDMono::get_singleton()->get_project_assembly() == NULL) { + // The project assembly is not loaded + ERR_EXPLAIN("Cannot instance script because the project assembly is not loaded. Script: " + get_path()); + ERR_FAIL_V(NULL); + } else { + // The project assembly is loaded, but the class could not found + ERR_EXPLAIN("Cannot instance script because the class '" + name + "' could not be found. Script: " + get_path()); + ERR_FAIL_V(NULL); + } } - update_signals(); + ERR_FAIL_COND_V(!valid, NULL); if (native) { String native_name = native->get_name(); @@ -2032,6 +2107,18 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) { return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error); } +PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_this) { + +#ifdef TOOLS_ENABLED + PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this)); + placeholders.insert(si); + _update_exports(); + return si; +#else + return NULL; +#endif +} + bool CSharpScript::instance_has(const Object *p_this) const { #ifndef NO_THREADS @@ -2069,6 +2156,9 @@ void CSharpScript::set_source_code(const String &p_code) { bool CSharpScript::has_method(const StringName &p_method) const { + if (!script_class) + return false; + return script_class->has_fetched_method_unknown_params(p_method); } @@ -2091,20 +2181,13 @@ Error CSharpScript::reload(bool p_keep_state) { if (project_assembly) { script_class = project_assembly->get_object_derived_class(name); - if (!script_class) { - ERR_PRINTS("Cannot find class " + name + " for script " + get_path()); - } -#ifdef DEBUG_ENABLED - else if (OS::get_singleton()->is_stdout_verbose()) { - OS::get_singleton()->print(String("Found class " + script_class->get_namespace() + "." + - script_class->get_name() + " for script " + get_path() + "\n") - .utf8()); - } -#endif - valid = script_class != NULL; if (script_class) { +#ifdef DEBUG_ENABLED + print_verbose("Found class " + script_class->get_namespace() + "." + script_class->get_name() + " for script " + get_path()); +#endif + tool = script_class->has_attribute(CACHED_CLASS(ToolAttribute)); native = GDMonoUtils::get_class_native_base(script_class); @@ -2142,6 +2225,8 @@ Error CSharpScript::reload(bool p_keep_state) { top->fetch_methods_with_godot_api_checks(native); top = top->get_parent_class(); } + + load_script_signals(script_class, native); } return OK; @@ -2201,12 +2286,6 @@ void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const { } } -void CSharpScript::update_signals() { -#ifdef TOOLS_ENABLED - _update_signals(); -#endif -} - Ref<Script> CSharpScript::get_base_script() const { // TODO search in metadata file once we have it, not important any way? @@ -2271,9 +2350,10 @@ CSharpScript::CSharpScript() : #ifdef TOOLS_ENABLED source_changed_cache = false; exports_invalidated = true; - signals_invalidated = true; #endif + signals_invalidated = true; + _resource_path_changed(); #ifdef DEBUG_ENABLED @@ -2336,7 +2416,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()); @@ -2345,14 +2427,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; |