diff options
Diffstat (limited to 'modules/mono/csharp_script.cpp')
-rw-r--r-- | modules/mono/csharp_script.cpp | 110 |
1 files changed, 71 insertions, 39 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index e54e5ac0bb..5235c6d176 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -104,7 +104,7 @@ Error CSharpLanguage::execute_file(const String &p_path) { return OK; } -extern void *godotsharp_pinvoke_funcs[186]; +extern void *godotsharp_pinvoke_funcs[185]; [[maybe_unused]] volatile void **do_not_strip_godotsharp_pinvoke_funcs; #ifdef TOOLS_ENABLED extern void *godotsharp_editor_pinvoke_funcs[30]; @@ -1452,6 +1452,8 @@ void CSharpLanguage::tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_int CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(p_unmanaged, script.ptr(), gchandle); p_unmanaged->set_script_and_instance(script, csharp_instance); + + csharp_instance->connect_event_signals(); } void CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged) { @@ -1480,6 +1482,8 @@ void CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gc // instances is a set, so it's safe to insert multiple times (e.g.: from _internal_new_managed) instance->script->instances.insert(instance->owner); } + + instance->connect_event_signals(); } CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) { @@ -1774,13 +1778,22 @@ void CSharpInstance::mono_object_disposed_baseref(GCHandleIntPtr p_gchandle_to_f } } -void CSharpInstance::connect_event_signal(const StringName &p_event_signal) { - // TODO: Use pooling for ManagedCallable instances. - EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, p_event_signal)); +void CSharpInstance::connect_event_signals() { + CSharpScript *top = script.ptr(); + while (top != nullptr) { + for (CSharpScript::EventSignalInfo &signal : top->get_script_event_signals()) { + String signal_name = signal.name; - Callable callable(event_signal_callable); - connected_event_signals.push_back(callable); - owner->connect(p_event_signal, callable); + // TODO: Use pooling for ManagedCallable instances. + EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name)); + + Callable callable(event_signal_callable); + connected_event_signals.push_back(callable); + owner->connect(signal_name, callable); + } + + top = top->base_script.ptr(); + } } void CSharpInstance::disconnect_event_signals() { @@ -2169,20 +2182,56 @@ void CSharpScript::reload_registered_script(Ref<CSharpScript> p_script) { // Extract information about the script using the mono class. void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) { bool tool = false; + Dictionary rpc_functions_dict; // Destructor won't be called from C#, and I don't want to include the GDNative header // only for this, so need to call the destructor manually before passing this to C#. rpc_functions_dict.~Dictionary(); + Dictionary signals_dict; + // Destructor won't be called from C#, and I don't want to include the GDNative header + // only for this, so need to call the destructor manually before passing this to C#. + signals_dict.~Dictionary(); + Ref<CSharpScript> base_script; GDMonoCache::managed_callbacks.ScriptManagerBridge_UpdateScriptClassInfo( - p_script.ptr(), &tool, &rpc_functions_dict, &base_script); + p_script.ptr(), &tool, &rpc_functions_dict, &signals_dict, &base_script); p_script->tool = tool; p_script->rpc_config.clear(); p_script->rpc_config = rpc_functions_dict; + // Event signals + + // Performance is not critical here as this will be replaced with source generators. + + p_script->event_signals.clear(); + + // Sigh... can't we just have capacity? + p_script->event_signals.resize(signals_dict.size()); + int push_index = 0; + + for (const Variant *s = signals_dict.next(nullptr); s != nullptr; s = signals_dict.next(s)) { + StringName name = *s; + + MethodInfo mi; + mi.name = name; + + Array params = signals_dict[*s]; + + for (int i = 0; i < params.size(); i++) { + Dictionary param = params[i]; + + Variant::Type param_type = (Variant::Type)(int)param["type"]; + PropertyInfo arg_info = PropertyInfo(param_type, (String)param["name"]); + arg_info.usage = (uint32_t)param["usage"]; + mi.arguments.push_back(arg_info); + } + + p_script->event_signals.set(push_index++, EventSignalInfo{ name, mi }); + } + p_script->base_script = base_script; } @@ -2467,9 +2516,13 @@ bool CSharpScript::has_script_signal(const StringName &p_signal) const { return false; } - String signal = p_signal; + for (const EventSignalInfo &signal : event_signals) { + if (signal.name == p_signal) { + return true; + } + } - return GDMonoCache::managed_callbacks.ScriptManagerBridge_HasScriptSignal(this, &signal); + return false; } void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const { @@ -2477,38 +2530,17 @@ void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const { return; } - // Performance is not critical here as this will be replaced with source generators. - - if (!GDMonoCache::godot_api_cache_updated) { - return; + for (const EventSignalInfo &signal : get_script_event_signals()) { + r_signals->push_back(signal.method_info); } +} - Dictionary signals_dict; - // Destructor won't be called from C#, and I don't want to include the GDNative header - // only for this, so need to call the destructor manually before passing this to C#. - signals_dict.~Dictionary(); - - GDMonoCache::managed_callbacks.ScriptManagerBridge_GetScriptSignalList(this, &signals_dict); - - for (const Variant *s = signals_dict.next(nullptr); s != nullptr; s = signals_dict.next(s)) { - MethodInfo mi; - mi.name = *s; - - Array params = signals_dict[*s]; - - for (int i = 0; i < params.size(); i++) { - Dictionary param = params[i]; - - Variant::Type param_type = (Variant::Type)(int)param["type"]; - PropertyInfo arg_info = PropertyInfo(param_type, (String)param["name"]); - if (param_type == Variant::NIL && (bool)param["nil_is_variant"]) { - arg_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; - } - mi.arguments.push_back(arg_info); - } - - r_signals->push_back(mi); +Vector<CSharpScript::EventSignalInfo> CSharpScript::get_script_event_signals() const { + if (!valid) { + return Vector<EventSignalInfo>(); } + + return event_signals; } bool CSharpScript::inherits_script(const Ref<Script> &p_script) const { |