Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/silver-worms-ask.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@godot-js/editor": minor
---

feat: Implement missing godot object' virtual functions.
8 changes: 8 additions & 0 deletions internal/jsb_string_names.def.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
153 changes: 148 additions & 5 deletions weaver/jsb_script_instance.cpp
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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;
}

Expand All @@ -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<PropertyInfo>* 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
Expand All @@ -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<MethodInfo>* p_list) const
Expand Down
Loading