From e163fe2b2c1ecf9bd357d286f6dae51a209e9e04 Mon Sep 17 00:00:00 2001 From: Daylily-Zeleen Date: Mon, 19 Jan 2026 02:17:43 +0800 Subject: [PATCH] feat: Implement missing godot object' virtual functions. --- .changeset/silver-worms-ask.md | 5 ++ internal/jsb_string_names.def.h | 8 ++ weaver/jsb_script_instance.cpp | 153 ++++++++++++++++++++++++++++++-- 3 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 .changeset/silver-worms-ask.md diff --git a/.changeset/silver-worms-ask.md b/.changeset/silver-worms-ask.md new file mode 100644 index 00000000..c3fc4dd4 --- /dev/null +++ b/.changeset/silver-worms-ask.md @@ -0,0 +1,5 @@ +--- +"@godot-js/editor": minor +--- + +feat: Implement missing godot object' virtual functions. diff --git a/internal/jsb_string_names.def.h b/internal/jsb_string_names.def.h index e4f248d9..f24f186f 100644 --- a/internal/jsb_string_names.def.h +++ b/internal/jsb_string_names.def.h @@ -73,3 +73,11 @@ DEF(properties) DEF(resource) DEF(GodotJSScript) #endif + +// Godot Object virtual methods +DEF(_set) +DEF(_get) +DEF(_get_property_list) +DEF(_validate_property) +DEF(_property_can_revert) +DEF(_property_get_revert) diff --git a/weaver/jsb_script_instance.cpp b/weaver/jsb_script_instance.cpp index 5665924f..184500e6 100644 --- a/weaver/jsb_script_instance.cpp +++ b/weaver/jsb_script_instance.cpp @@ -1,5 +1,7 @@ #include "jsb_script_instance.h" +#include "jsb_script.h" #include "jsb_script_language.h" +#include "modules/gdscript/gdscript_rpc_callable.h" GodotJSScriptInstanceBase::ScriptCallProfilingScope::ScriptCallProfilingScope(const ScriptProfilingInfo& p_info, const StringName& p_method) : info_(p_info), method_(p_method) @@ -60,6 +62,21 @@ bool GodotJSScriptInstance::set(const StringName& p_name, const Variant& p_value { return env_->set_script_property_value(object_id_, it->value, p_value); } + + // TODO: Static variable? + + if (const auto& it = script_->script_class_info_.methods.find(jsb_string_name(_set)); it) + { + Variant name = p_name; + const Variant *args[2] = { &name, &p_value }; + + Callable::CallError err; + Variant ret = env_->call_script_method(class_id_, object_id_, jsb_string_name(_set), (const Variant **)args, 2, err); + if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) { + return true; + } + } + return false; } @@ -78,12 +95,104 @@ bool GodotJSScriptInstance::get(const StringName& p_name, Variant& r_ret) const return env_->get_script_property_value(object_id_, it->value, r_ret); } + // TODO: constant? + // TODO: static variable? + // TODO: Inner class? + + if (const auto& it = script_->script_class_info_.signals.find(p_name); it) + { + r_ret = Signal(owner_, p_name); + return true; + } + + if (const auto& it = script_->script_class_info_.methods.find(p_name); it) + { + if (script_->script_class_info_.rpc_config.has(p_name)) { + r_ret = Callable(memnew(GDScriptRPCCallable(owner_, p_name))); + return true; + } else { + if (!it->value.is_static()) + { + r_ret = Callable(owner_, p_name); + return true; + } else { + // TODO: Warp static method to Callable + } + } + } + + if (const auto& it = script_->script_class_info_.methods.find(jsb_string_name(_get)); it) + { + Variant name = p_name; + const Variant *args[1] = { &name }; + + Callable::CallError err; + Variant ret = env_->call_script_method(class_id_, object_id_, jsb_string_name(_get), (const Variant **)args, 1, err); + if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) + { + r_ret = ret; + return true; + } + } + return false; } void GodotJSScriptInstance::get_property_list(List* p_properties) const { script_->get_script_property_list(p_properties); + + if (const auto& it = script_->script_class_info_.methods.find(jsb_string_name(_get_property_list)); it) + { + Callable::CallError err; + Variant ret = env_->call_script_method(class_id_, object_id_, jsb_string_name(_get_property_list), nullptr, 0, err); + if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) + { + ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries."); + + Array arr = ret; + for (int i = 0; i < arr.size(); i++) + { + Dictionary d = arr[i]; + ERR_CONTINUE(!d.has("name")); + ERR_CONTINUE(!d.has("type")); + + PropertyInfo pinfo; + pinfo.name = d["name"]; + pinfo.type = Variant::Type(d["type"].operator int()); + if (d.has("hint")) + { + pinfo.hint = PropertyHint(d["hint"].operator int()); + } + if (d.has("hint_string")) + { + pinfo.hint_string = d["hint_string"]; + } + if (d.has("usage")) + { + pinfo.usage = d["usage"]; + } + if (d.has("class_name")) + { + pinfo.class_name = d["class_name"]; + } + + ERR_CONTINUE(pinfo.name.is_empty() && (pinfo.usage & PROPERTY_USAGE_STORAGE)); + ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX); + + if (script_->script_class_info_.properties.has(pinfo.name)) + { + continue; + } + + p_properties->push_back(pinfo); + } + } + } + + for (PropertyInfo &prop : *p_properties) { + validate_property(prop); + } } const Variant GodotJSScriptInstance::get_rpc_config() const @@ -105,19 +214,53 @@ Variant::Type GodotJSScriptInstance::get_property_type(const StringName& p_name, void GodotJSScriptInstance::validate_property(PropertyInfo& p_property) const { - //TODO + if (const auto& it = script_->script_class_info_.methods.find(jsb_string_name(_validate_property)); it) + { + Variant property = (Dictionary)p_property; + const Variant *args[1] = { &property }; + + Callable::CallError err; + Variant ret = env_->call_script_method(class_id_, object_id_, jsb_string_name(_validate_property), (const Variant **)args, 1, err); + if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) + { + p_property = PropertyInfo::from_dict(property); + } + } } bool GodotJSScriptInstance::property_can_revert(const StringName& p_name) const { - //TODO - return false; + if (const auto& it = script_->script_class_info_.methods.find(jsb_string_name(_property_can_revert)); it) + { + Variant name = p_name; + const Variant *args[1] = { &name }; + + Callable::CallError err; + Variant ret = env_->call_script_method(class_id_, object_id_, jsb_string_name(_property_can_revert), args, 1, err); + if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) { + return true; + } + } + + return false; } bool GodotJSScriptInstance::property_get_revert(const StringName& p_name, Variant& r_ret) const { - //TODO - return false; + if (const auto& it = script_->script_class_info_.methods.find(jsb_string_name(_property_get_revert)); it) + { + Variant name = p_name; + const Variant *args[1] = { &name }; + + Callable::CallError err; + Variant ret = env_->call_script_method(class_id_, object_id_, jsb_string_name(_property_get_revert), args, 1, err); + if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) { + r_ret = ret; + return true; + } + } + + return false; } void GodotJSScriptInstance::get_method_list(List* p_list) const