New and improved workaround for the missing ClassDB::add_virtual_method

This commit is contained in:
Serhii Snitsaruk 2024-01-17 22:46:48 +01:00
parent caa1508fea
commit 390d4a9385
4 changed files with 38 additions and 32 deletions

View File

@ -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
}

View File

@ -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() {

View File

@ -110,10 +110,6 @@ private:
Ref<Texture2D> behavior_tree_icon;
} theme_cache;
#ifdef LIMBOAI_GDEXTENSION
bool limitations_banner_shown = false;
#endif // LIMBOAI_GDEXTENSION
EditorPlugin *plugin;
Vector<Ref<BehaviorTree>> history;
int idx_history;

View File

@ -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<m_ret_type>::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<m_ret_type>::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<m_ret_type>::cast(call(LW_NAME(m_name))) : VariantCaster<m_ret_type>::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<m_ret_type>::cast(call(LW_NAME(m_name), __VA_ARGS__)) : VariantCaster<m_ret_type>::cast(m_name(__VA_ARGS__)))
// * Enum