Skip to content

Commit 64cbcb3

Browse files
# Fix/implement some essential script instance behaviors:
1. Fix parsing script class: only detecting doc, property and signal in current class (without base class). 2. Implement essential godot object' virtual functions. 3. Fix `GodotJSScript::has_script_signal`.
1 parent a8e2567 commit 64cbcb3

5 files changed

Lines changed: 222 additions & 19 deletions

File tree

.changeset/tired-bats-wear.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@godot-js/editor": minor
3+
---
4+
5+
# Fix/implement some essential script instance behaviors:
6+
7+
1. Fix parsing script class: only detecting doc, property and signal in current class (without base class).
8+
2. Implement essential godot object' virtual functions.
9+
3. Fix `GodotJSScript::has_script_signal`.

bridge/jsb_class_info.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ namespace jsb
9999
#ifdef TOOLS_ENABLED
100100
// class doc
101101
v8::Local<v8::Map> doc_map;
102-
if (v8::Local<v8::Value> val; prototype->Get(p_context, jsb_symbol(environment, MemberDocMap)).ToLocal(&val) && val->IsMap())
102+
if (v8::Local<v8::Value> val; prototype->HasOwnProperty(p_context, jsb_symbol(environment, MemberDocMap)).ToChecked() && prototype->Get(p_context, jsb_symbol(environment, MemberDocMap)).ToLocal(&val) && val->IsMap())
103103
{
104104
doc_map = val.As<v8::Map>();
105105
}
@@ -209,7 +209,7 @@ namespace jsb
209209
// signals (@signal_)
210210
{
211211
v8::Local<v8::Value> val_test;
212-
if (prototype->Get(p_context, jsb_symbol(environment, ClassSignals)).ToLocal(&val_test) && val_test->IsArray())
212+
if (prototype->HasOwnProperty(p_context, jsb_symbol(environment, ClassSignals)).ToChecked() && prototype->Get(p_context, jsb_symbol(environment, ClassSignals)).ToLocal(&val_test) && val_test->IsArray())
213213
{
214214
v8::Local<v8::Array> collection = val_test.As<v8::Array>();
215215
const uint32_t len = collection->Length();
@@ -238,7 +238,7 @@ namespace jsb
238238
// detect all exported properties (which annotated with @export_)
239239
{
240240
v8::Local<v8::Value> val_test;
241-
if (prototype->Get(p_context, jsb_symbol(environment, ClassProperties)).ToLocal(&val_test) && val_test->IsArray())
241+
if (prototype->HasOwnProperty(p_context, jsb_symbol(environment, ClassProperties)).ToChecked() && prototype->Get(p_context, jsb_symbol(environment, ClassProperties)).ToLocal(&val_test) && val_test->IsArray())
242242
{
243243
const v8::Local<v8::Array> collection = val_test.As<v8::Array>();
244244
const uint32_t len = collection->Length();

internal/jsb_string_names.def.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,11 @@ DEF(properties)
7676
DEF(resource)
7777
DEF(GodotJSScript)
7878
#endif
79+
80+
// Godot Object virtual methods
81+
DEF(_set)
82+
DEF(_get)
83+
DEF(_get_property_list)
84+
DEF(_validate_property)
85+
DEF(_property_can_revert)
86+
DEF(_property_get_revert)

weaver/jsb_script.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,20 @@ ScriptLanguage* GodotJSScript::get_language() const
376376

377377
bool GodotJSScript::has_script_signal(const StringName& p_signal) const
378378
{
379-
return is_valid() ? script_class_info_.signals.has(p_signal) : false;
379+
if (is_valid())
380+
{
381+
if(script_class_info_.signals.has(p_signal))
382+
{
383+
return true;
384+
}
385+
386+
if (base.is_valid())
387+
{
388+
return base->has_script_signal(p_signal);
389+
}
390+
}
391+
392+
return false;
380393
}
381394

382395
void GodotJSScript::get_script_signal_list(List<MethodInfo>* r_signals) const

weaver/jsb_script_instance.cpp

Lines changed: 188 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "jsb_script_instance.h"
2+
#include "jsb_script.h"
23
#include "jsb_script_language.h"
4+
#include "modules/gdscript/gdscript_rpc_callable.h"
35

46
GodotJSScriptInstanceBase::ScriptCallProfilingScope::ScriptCallProfilingScope(const ScriptProfilingInfo& p_info, const StringName& p_method)
57
: info_(p_info), method_(p_method)
@@ -56,10 +58,31 @@ void GodotJSScriptInstance::cache_property(const StringName& name, const Variant
5658

5759
bool GodotJSScriptInstance::set(const StringName& p_name, const Variant& p_value)
5860
{
59-
if (const auto& it = script_->script_class_info_.properties.find(p_name); it)
61+
GodotJSScript* sptr = script_.ptr();
62+
while (sptr)
6063
{
61-
return env_->set_script_property_value(object_id_, it->value, p_value);
64+
if (const auto& it = sptr->script_class_info_.properties.find(p_name); it)
65+
{
66+
return env_->set_script_property_value(object_id_, it->value, p_value);
67+
}
68+
69+
// TODO: Static variable?
70+
71+
if (const auto& it = sptr->script_class_info_.methods.find(jsb_string_name(_set)); it)
72+
{
73+
Variant name = p_name;
74+
const Variant *args[2] = { &name, &p_value };
75+
76+
Callable::CallError err;
77+
Variant ret = env_->call_script_method(class_id_, object_id_, jsb_string_name(_set), (const Variant **)args, 2, err);
78+
if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
79+
return true;
80+
}
81+
}
82+
83+
sptr = sptr->base.ptr();
6284
}
85+
6386
return false;
6487
}
6588

@@ -73,17 +96,110 @@ bool GodotJSScriptInstance::get(const StringName& p_name, Variant& r_ret) const
7396
return true;
7497
}
7598

76-
if (const auto& it = script_->script_class_info_.properties.find(p_name); it)
99+
GodotJSScript* sptr = script_.ptr();
100+
while (sptr)
77101
{
78-
return env_->get_script_property_value(object_id_, it->value, r_ret);
102+
if (const auto& it = sptr->script_class_info_.properties.find(p_name); it)
103+
{
104+
return env_->get_script_property_value(object_id_, it->value, r_ret);
105+
}
106+
107+
// TODO: constant?
108+
// TODO: static variable?
109+
// TODO: Inner class?
110+
111+
if (const auto& it = sptr->script_class_info_.signals.find(p_name); it)
112+
{
113+
r_ret = Signal(owner_, p_name);
114+
return true;
115+
}
116+
117+
if (const auto& it = sptr->script_class_info_.methods.find(p_name); it)
118+
{
119+
if (sptr->script_class_info_.rpc_config.has(p_name)) {
120+
r_ret = Callable(memnew(GDScriptRPCCallable(owner_, p_name)));
121+
return true;
122+
} else {
123+
if (!it->value.is_static())
124+
{
125+
r_ret = Callable(owner_, p_name);
126+
return true;
127+
} else {
128+
// TODO: Warp static method to Callable
129+
}
130+
}
131+
}
132+
133+
if (const auto& it = sptr->script_class_info_.methods.find(jsb_string_name(_get)); it)
134+
{
135+
Variant name = p_name;
136+
const Variant *args[1] = { &name };
137+
138+
Callable::CallError err;
139+
Variant ret = env_->call_script_method(class_id_, object_id_, jsb_string_name(_get), (const Variant **)args, 1, err);
140+
if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL)
141+
{
142+
r_ret = ret;
143+
return true;
144+
}
145+
}
146+
147+
sptr = sptr->base.ptr();
79148
}
80149

81150
return false;
82151
}
83152

84153
void GodotJSScriptInstance::get_property_list(List<PropertyInfo>* p_properties) const
85154
{
86-
script_->get_script_property_list(p_properties);
155+
GodotJSScript* sptr = script_.ptr();
156+
HashSet<String> properties;
157+
158+
while (sptr)
159+
{
160+
if (const auto& it = sptr->script_class_info_.methods.find(jsb_string_name(_get_property_list)); it)
161+
{
162+
Callable::CallError err;
163+
Variant ret = env_->call_script_method(class_id_, object_id_, jsb_string_name(_get_property_list), nullptr, 0, err);
164+
if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL)
165+
{
166+
ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries.");
167+
168+
Array arr = ret;
169+
for (int i = 0; i < arr.size(); i++)
170+
{
171+
Dictionary d = arr[i];
172+
ERR_CONTINUE(!d.has("name"));
173+
ERR_CONTINUE(!d.has("type"));
174+
175+
PropertyInfo pinfo = PropertyInfo::from_dict(d);
176+
177+
ERR_CONTINUE(pinfo.name.is_empty() && (pinfo.usage & PROPERTY_USAGE_STORAGE));
178+
ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX);
179+
180+
ERR_CONTINUE_MSG(properties.has(pinfo.name), vformat("Duplicate property \"%s\" in script: %s", pinfo.name, script_->get_path()));
181+
182+
p_properties->push_back(pinfo);
183+
properties.insert(pinfo.name);
184+
}
185+
}
186+
}
187+
188+
#ifdef TOOLS_ENABLED
189+
p_properties->push_back(sptr->get_class_category());
190+
#endif
191+
for (const auto& it : sptr->script_class_info_.properties)
192+
{
193+
ERR_CONTINUE_MSG(properties.has(it.value.name), vformat("Duplicate property \"%s\" in script: %s", it.value.name, script_->get_path()));
194+
p_properties->push_back((PropertyInfo) it.value);
195+
}
196+
197+
sptr = sptr->base.ptr();
198+
}
199+
200+
for (PropertyInfo &prop : *p_properties) {
201+
validate_property(prop);
202+
}
87203
}
88204

89205
const Variant GodotJSScriptInstance::get_rpc_config() const
@@ -93,31 +209,88 @@ const Variant GodotJSScriptInstance::get_rpc_config() const
93209

94210
Variant::Type GodotJSScriptInstance::get_property_type(const StringName& p_name, bool* r_is_valid) const
95211
{
96-
const jsb::ScriptClassInfoPtr class_info = get_script_class();
97-
if (const HashMap<StringName, jsb::ScriptPropertyInfo>::ConstIterator it = class_info->properties.find(p_name))
98-
{
99-
if (r_is_valid) *r_is_valid = true;
100-
return it->value.type;
212+
GodotJSScript* sptr = script_.ptr();
213+
while (sptr) {
214+
if (const HashMap<StringName, jsb::ScriptPropertyInfo>::ConstIterator it = sptr->script_class_info_.properties.find(p_name))
215+
{
216+
if (r_is_valid) *r_is_valid = true;
217+
return it->value.type;
218+
}
219+
220+
sptr = sptr->base.ptr();
101221
}
222+
102223
if (r_is_valid) *r_is_valid = false;
103224
return Variant::NIL;
104225
}
105226

106227
void GodotJSScriptInstance::validate_property(PropertyInfo& p_property) const
107228
{
108-
//TODO
229+
GodotJSScript* sptr = script_.ptr();
230+
while(sptr)
231+
{
232+
if (const auto& it = sptr->script_class_info_.methods.find(jsb_string_name(_validate_property)); it)
233+
{
234+
Variant property = (Dictionary)p_property;
235+
const Variant *args[1] = { &property };
236+
237+
Callable::CallError err;
238+
Variant ret = env_->call_script_method(class_id_, object_id_, jsb_string_name(_validate_property), (const Variant **)args, 1, err);
239+
if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL)
240+
{
241+
p_property = PropertyInfo::from_dict(property);
242+
}
243+
}
244+
245+
sptr = sptr->base.ptr();
246+
}
109247
}
110248

111249
bool GodotJSScriptInstance::property_can_revert(const StringName& p_name) const
112250
{
113-
//TODO
114-
return false;
251+
GodotJSScript* sptr = script_.ptr();
252+
while(sptr)
253+
{
254+
if (const auto& it = sptr->script_class_info_.methods.find(jsb_string_name(_property_can_revert)); it)
255+
{
256+
Variant name = p_name;
257+
const Variant *args[1] = { &name };
258+
259+
Callable::CallError err;
260+
Variant ret = env_->call_script_method(class_id_, object_id_, jsb_string_name(_property_can_revert), args, 1, err);
261+
if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
262+
return true;
263+
}
264+
}
265+
266+
sptr = sptr->base.ptr();
267+
}
268+
269+
return false;
115270
}
116271

117272
bool GodotJSScriptInstance::property_get_revert(const StringName& p_name, Variant& r_ret) const
118273
{
119-
//TODO
120-
return false;
274+
GodotJSScript* sptr = script_.ptr();
275+
while(sptr)
276+
{
277+
if (const auto& it = sptr->script_class_info_.methods.find(jsb_string_name(_property_get_revert)); it)
278+
{
279+
Variant name = p_name;
280+
const Variant *args[1] = { &name };
281+
282+
Callable::CallError err;
283+
Variant ret = env_->call_script_method(class_id_, object_id_, jsb_string_name(_property_get_revert), args, 1, err);
284+
if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
285+
r_ret = ret;
286+
return true;
287+
}
288+
}
289+
290+
sptr = sptr->base.ptr();
291+
}
292+
293+
return false;
121294
}
122295

123296
void GodotJSScriptInstance::get_method_list(List<MethodInfo>* p_list) const

0 commit comments

Comments
 (0)