From 390d4a938539219ebbd151776d12cab3900d807f Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 17 Jan 2024 22:46:48 +0100 Subject: [PATCH] New and improved workaround for the missing ClassDB::add_virtual_method --- bt/tasks/bt_task.cpp | 21 ++++++------------- editor/limbo_ai_editor_plugin.cpp | 11 ---------- editor/limbo_ai_editor_plugin.h | 4 ---- util/limbo_compat.h | 34 +++++++++++++++++++++++++++++-- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/bt/tasks/bt_task.cpp b/bt/tasks/bt_task.cpp index e563ba9..7675447 100644 --- a/bt/tasks/bt_task.cpp +++ b/bt/tasks/bt_task.cpp @@ -100,7 +100,9 @@ String BTTask::get_task_name() { } return _generate_name(); #elif LIMBOAI_GDEXTENSION - return call(LimboStringNames::get_singleton()->_generate_name); + String s; + VCALL_OR_NATIVE_V(_generate_name, String, s); + return s; #endif } return data.custom_name; @@ -226,13 +228,7 @@ BT::Status BTTask::execute(double p_delta) { data.elapsed += p_delta; } -#ifdef LIMBOAI_MODULE - if (!GDVIRTUAL_CALL(_tick, p_delta, data.status)) { - data.status = _tick(p_delta); - } -#elif LIMBOAI_GDEXTENSION - data.status = (Status)(int)call(LimboStringNames::get_singleton()->_tick, p_delta); -#endif + VCALL_OR_NATIVE_ARGS_V(_tick, Status, data.status, p_delta); if (data.status != RUNNING) { VCALL_OR_NATIVE(_exit); @@ -337,6 +333,7 @@ PackedStringArray BTTask::get_configuration_warnings() { PackedStringArray warnings; VCALL_V(_get_configuration_warnings, warnings); // Get script warnings. ret.append_array(warnings); + ret.append_array(_get_configuration_warnings()); return ret; } @@ -403,13 +400,7 @@ void BTTask::_bind_methods() { GDVIRTUAL_BIND(_generate_name); GDVIRTUAL_BIND(_get_configuration_warnings); #elif LIMBOAI_GDEXTENSION - // TODO: Until virtual functions are implemented in godot-cpp, we do this. Replace this code when possible. - ClassDB::bind_method(D_METHOD("_setup"), &BTTask::_setup); - ClassDB::bind_method(D_METHOD("_enter"), &BTTask::_enter); - ClassDB::bind_method(D_METHOD("_exit"), &BTTask::_exit); - ClassDB::bind_method(D_METHOD("_tick", "p_delta"), &BTTask::_tick); - ClassDB::bind_method(D_METHOD("_generate_name"), &BTTask::_generate_name); - ClassDB::bind_method(D_METHOD("_get_configuration_warnings"), &BTTask::_get_configuration_warnings); + // TODO: Registering virtual functions is not available in godot-cpp... #endif } diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index a185e0d..08e30ac 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -1005,17 +1005,6 @@ void LimboAIEditor::_update_banners() { banners->call_deferred(LW_NAME(add_child), banner); } } - -#ifdef LIMBOAI_GDEXTENSION - if (!limitations_banner_shown && GLOBAL_GET("debug/gdscript/warnings/native_method_override") == Variant(2)) { - ActionBanner *banner = memnew(ActionBanner); - banner->set_text(vformat(TTR("In Project Settings, \"debug/gdscript/warnings/native_method_override\" is set to \"Error\""))); - banner->add_action(TTR("Instructions..."), callable_mp(LimboUtility::get_singleton(), &LimboUtility::open_doc_gdextension_limitations)); - banner->add_action(TTR("Dismiss"), callable_mp(banner, &ActionBanner::close)); - banners->call_deferred(LW_NAME(add_child), banner); - limitations_banner_shown = true; - } -#endif // LIMBOAI_GDEXTENSION } void LimboAIEditor::_do_update_theme_item_cache() { diff --git a/editor/limbo_ai_editor_plugin.h b/editor/limbo_ai_editor_plugin.h index 01a6ed1..42305f3 100644 --- a/editor/limbo_ai_editor_plugin.h +++ b/editor/limbo_ai_editor_plugin.h @@ -110,10 +110,6 @@ private: Ref behavior_tree_icon; } theme_cache; -#ifdef LIMBOAI_GDEXTENSION - bool limitations_banner_shown = false; -#endif // LIMBOAI_GDEXTENSION - EditorPlugin *plugin; Vector> history; int idx_history; diff --git a/util/limbo_compat.h b/util/limbo_compat.h index 81191e9..c6ae3ef 100644 --- a/util/limbo_compat.h +++ b/util/limbo_compat.h @@ -60,6 +60,7 @@ #define VCALL(m_name, ...) (GDVIRTUAL_CALL(m_name, __VA_ARGS__)) #define VCALL_ARGS(method, ...) (call(LW_NAME(method), __VA_ARGS__)) #define VCALL_V(m_name, r_ret) (GDVIRTUAL_CALL(m_name, r_ret)) + #define VCALL_OR_NATIVE(m_name) \ if (!GDVIRTUAL_CALL(m_name)) { \ m_name(); \ @@ -70,6 +71,16 @@ m_name(__VA_ARGS__); \ } +#define VCALL_OR_NATIVE_V(m_name, m_ret_type, r_ret) \ + if (!GDVIRTUAL_CALL(m_name, r_ret)) { \ + r_ret = VariantCaster::cast(m_name()); \ + } + +#define VCALL_OR_NATIVE_ARGS_V(m_name, m_ret_type, r_ret, ...) \ + if (!GDVIRTUAL_CALL(m_name, __VA_ARGS__, r_ret)) { \ + r_ret = VariantCaster::cast(m_name(__VA_ARGS__)); \ + } + // * Enum #define LW_KEY(key) (Key::key) @@ -125,11 +136,30 @@ using namespace godot; Variant::evaluate(m_op, m_lvalue, m_rvalue, r_ret, r_valid); \ } +// * Virtual calls: +// * This is a workaround for missing ClassDB::add_virtual_method(). +// ! When using these macros, DON'T BIND the native virtual methods! + #define VCALL(m_name) (call(LW_NAME(m_name))) #define VCALL_ARGS(m_name, ...) (call(LW_NAME(m_name), __VA_ARGS__)) #define VCALL_V(m_name, r_ret) (r_ret = call(LW_NAME(m_name))) -#define VCALL_OR_NATIVE(m_name) (call(LW_NAME(m_name))) -#define VCALL_OR_NATIVE_ARGS(m_name, ...) (call(LW_NAME(m_name), __VA_ARGS__)) + +#define VCALL_OR_NATIVE(m_name) \ + if (has_method(LW_NAME(m_name))) { \ + call(LW_NAME(m_name)); \ + } else { \ + m_name(); \ + } + +#define VCALL_OR_NATIVE_ARGS(m_name, ...) \ + if (has_method(LW_NAME(m_name))) { \ + call(LW_NAME(m_name), __VA_ARGS__); \ + } else { \ + m_name(__VA_ARGS__); \ + } + +#define VCALL_OR_NATIVE_V(m_name, m_ret_type, r_ret) r_ret = (has_method(LW_NAME(m_name)) ? VariantCaster::cast(call(LW_NAME(m_name))) : VariantCaster::cast(m_name())) +#define VCALL_OR_NATIVE_ARGS_V(m_name, m_ret_type, r_ret, ...) r_ret = (has_method(LW_NAME(m_name)) ? VariantCaster::cast(call(LW_NAME(m_name), __VA_ARGS__)) : VariantCaster::cast(m_name(__VA_ARGS__))) // * Enum