Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GDScript: Fix some bugs with static variables and functions #77129

Merged
Merged
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
279 changes: 177 additions & 102 deletions modules/gdscript/gdscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -878,44 +878,55 @@ Variant GDScript::callp(const StringName &p_method, const Variant **p_args, int
}

bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
{
const GDScript *top = this;
while (top) {
{
HashMap<StringName, Variant>::ConstIterator E = top->constants.find(p_name);
if (E) {
r_ret = E->value;
return true;
}
if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
r_ret = get_source_code();
return true;
}

const GDScript *top = this;
while (top) {
{
HashMap<StringName, Variant>::ConstIterator E = top->constants.find(p_name);
if (E) {
r_ret = E->value;
return true;
}
}

{
HashMap<StringName, Ref<GDScript>>::ConstIterator E = subclasses.find(p_name);
if (E) {
r_ret = E->value;
{
HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name);
if (E) {
if (E->value.getter) {
Callable::CallError ce;
r_ret = const_cast<GDScript *>(this)->callp(E->value.getter, nullptr, 0, ce);
return true;
}
r_ret = top->static_variables[E->value.index];
return true;
}
}

{
HashMap<StringName, MemberInfo>::ConstIterator E = static_variables_indices.find(p_name);
if (E) {
if (E->value.getter) {
Callable::CallError ce;
r_ret = const_cast<GDScript *>(this)->callp(E->value.getter, nullptr, 0, ce);
return true;
}
r_ret = static_variables[E->value.index];
return true;
{
HashMap<StringName, GDScriptFunction *>::ConstIterator E = top->member_functions.find(p_name);
if (E && E->value->is_static()) {
if (top->rpc_config.has(p_name)) {
r_ret = Callable(memnew(GDScriptRPCCallable(const_cast<GDScript *>(top), E->key)));
} else {
r_ret = Callable(const_cast<GDScript *>(top), E->key);
}
return true;
}
top = top->_base;
}

if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
r_ret = get_source_code();
return true;
{
HashMap<StringName, Ref<GDScript>>::ConstIterator E = top->subclasses.find(p_name);
if (E) {
r_ret = E->value;
return true;
}
}

top = top->_base;
}

return false;
Expand All @@ -925,40 +936,60 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
set_source_code(p_value);
reload();
} else {
const GDScript *top = this;
while (top) {
HashMap<StringName, MemberInfo>::ConstIterator E = static_variables_indices.find(p_name);
if (E) {
const GDScript::MemberInfo *member = &E->value;
Variant value = p_value;
if (member->data_type.has_type && !member->data_type.is_type(value)) {
const Variant *args = &p_value;
Callable::CallError err;
Variant::construct(member->data_type.builtin_type, value, &args, 1, err);
if (err.error != Callable::CallError::CALL_OK || !member->data_type.is_type(value)) {
return false;
}
}
if (member->setter) {
const Variant *args = &value;
Callable::CallError err;
callp(member->setter, &args, 1, err);
return err.error == Callable::CallError::CALL_OK;
} else {
static_variables.write[member->index] = value;
return true;
return true;
}

GDScript *top = this;
while (top) {
HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name);
if (E) {
const MemberInfo *member = &E->value;
Variant value = p_value;
if (member->data_type.has_type && !member->data_type.is_type(value)) {
const Variant *args = &p_value;
Callable::CallError err;
Variant::construct(member->data_type.builtin_type, value, &args, 1, err);
if (err.error != Callable::CallError::CALL_OK || !member->data_type.is_type(value)) {
return false;
}
}
top = top->_base;
if (member->setter) {
const Variant *args = &value;
Callable::CallError err;
callp(member->setter, &args, 1, err);
return err.error == Callable::CallError::CALL_OK;
} else {
top->static_variables.write[member->index] = value;
return true;
}
}

top = top->_base;
}

return true;
return false;
}

void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {
p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));

List<PropertyInfo> property_list;

const GDScript *top = this;
while (top) {
for (const KeyValue<StringName, MemberInfo> &E : top->static_variables_indices) {
PropertyInfo pi = PropertyInfo(E.value.data_type);
pi.name = E.key;
pi.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; // For the script (as a class) it is a non-static property.
property_list.push_back(pi);
}

top = top->_base;
}

for (const List<PropertyInfo>::Element *E = property_list.back(); E; E = E->prev()) {
p_properties->push_back(E->get());
}
}

void GDScript::_bind_methods() {
Expand Down Expand Up @@ -1037,6 +1068,16 @@ StringName GDScript::debug_get_member_by_index(int p_idx) const {
return "<error>";
}

StringName GDScript::debug_get_static_var_by_index(int p_idx) const {
for (const KeyValue<StringName, MemberInfo> &E : static_variables_indices) {
if (E.value.index == p_idx) {
return E.key;
}
}

return "<error>";
}

Ref<GDScript> GDScript::get_base() const {
return base;
}
Expand Down Expand Up @@ -1376,8 +1417,8 @@ void GDScript::clear(GDScript::ClearData *p_clear_data) {
}
clearing = true;

GDScript::ClearData data;
GDScript::ClearData *clear_data = p_clear_data;
ClearData data;
ClearData *clear_data = p_clear_data;
bool is_root = false;

// If `clear_data` is `nullptr`, it means that it's the root.
Expand All @@ -1398,12 +1439,12 @@ void GDScript::clear(GDScript::ClearData *p_clear_data) {
}
member_functions.clear();

for (KeyValue<StringName, GDScript::MemberInfo> &E : member_indices) {
for (KeyValue<StringName, MemberInfo> &E : member_indices) {
clear_data->scripts.insert(E.value.data_type.script_type_ref);
E.value.data_type.script_type_ref = Ref<Script>();
}

for (KeyValue<StringName, GDScript::MemberInfo> &E : static_variables_indices) {
for (KeyValue<StringName, MemberInfo> &E : static_variables_indices) {
clear_data->scripts.insert(E.value.data_type.script_type_ref);
E.value.data_type.script_type_ref = Ref<Script>();
}
Expand Down Expand Up @@ -1486,7 +1527,6 @@ GDScript::~GDScript() {
//////////////////////////////

bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
//member
{
HashMap<StringName, GDScript::MemberInfo>::Iterator E = script->member_indices.find(p_name);
if (E) {
Expand Down Expand Up @@ -1514,80 +1554,115 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {

GDScript *sptr = script.ptr();
while (sptr) {
HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
if (E) {
Variant name = p_name;
const Variant *args[2] = { &name, &p_value };
{
HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = sptr->static_variables_indices.find(p_name);
if (E) {
const GDScript::MemberInfo *member = &E->value;
Variant value = p_value;
if (member->data_type.has_type && !member->data_type.is_type(value)) {
const Variant *args = &p_value;
Callable::CallError err;
Variant::construct(member->data_type.builtin_type, value, &args, 1, err);
if (err.error != Callable::CallError::CALL_OK || !member->data_type.is_type(value)) {
return false;
}
}
if (member->setter) {
const Variant *args = &value;
Callable::CallError err;
callp(member->setter, &args, 1, err);
return err.error == Callable::CallError::CALL_OK;
} else {
sptr->static_variables.write[member->index] = value;
return true;
}
}
}

Callable::CallError err;
Variant ret = E->value->call(this, (const Variant **)args, 2, err);
if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
return true;
{
HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
if (E) {
Variant name = p_name;
const Variant *args[2] = { &name, &p_value };

Callable::CallError err;
Variant ret = E->value->call(this, (const Variant **)args, 2, err);
if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
return true;
}
}
}

sptr = sptr->_base;
}

return false;
}

bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
{
HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = script->member_indices.find(p_name);
if (E) {
if (E->value.getter) {
Callable::CallError err;
r_ret = const_cast<GDScriptInstance *>(this)->callp(E->value.getter, nullptr, 0, err);
if (err.error == Callable::CallError::CALL_OK) {
return true;
}
}
r_ret = members[E->value.index];
return true;
}
}

const GDScript *sptr = script.ptr();
while (sptr) {
{
HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = script->member_indices.find(p_name);
HashMap<StringName, Variant>::ConstIterator E = sptr->constants.find(p_name);
if (E) {
r_ret = E->value;
return true;
}
}

{
HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = sptr->static_variables_indices.find(p_name);
if (E) {
if (E->value.getter) {
Callable::CallError err;
r_ret = const_cast<GDScriptInstance *>(this)->callp(E->value.getter, nullptr, 0, err);
if (err.error == Callable::CallError::CALL_OK) {
return true;
}
Callable::CallError ce;
r_ret = const_cast<GDScript *>(sptr)->callp(E->value.getter, nullptr, 0, ce);
return true;
}
r_ret = members[E->value.index];
return true; //index found
r_ret = sptr->static_variables[E->value.index];
return true;
}
}

{
const GDScript *sl = sptr;
while (sl) {
HashMap<StringName, Variant>::ConstIterator E = sl->constants.find(p_name);
if (E) {
r_ret = E->value;
return true; //index found
}
sl = sl->_base;
HashMap<StringName, Vector<StringName>>::ConstIterator E = sptr->_signals.find(p_name);
if (E) {
r_ret = Signal(this->owner, E->key);
return true;
}
}

{
// Signals.
const GDScript *sl = sptr;
while (sl) {
HashMap<StringName, Vector<StringName>>::ConstIterator E = sl->_signals.find(p_name);
if (E) {
r_ret = Signal(this->owner, E->key);
return true; //index found
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_name);
if (E) {
if (sptr->rpc_config.has(p_name)) {
r_ret = Callable(memnew(GDScriptRPCCallable(this->owner, E->key)));
} else {
r_ret = Callable(this->owner, E->key);
}
sl = sl->_base;
return true;
}
}

{
// Methods.
const GDScript *sl = sptr;
while (sl) {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sl->member_functions.find(p_name);
if (E) {
if (sptr->rpc_config.has(p_name)) {
r_ret = Callable(memnew(GDScriptRPCCallable(this->owner, E->key)));
} else {
r_ret = Callable(this->owner, E->key);
}
return true; //index found
}
sl = sl->_base;
HashMap<StringName, Ref<GDScript>>::ConstIterator E = sptr->subclasses.find(p_name);
if (E) {
r_ret = E->value;
return true;
}
}

Expand Down
1 change: 1 addition & 0 deletions modules/gdscript/gdscript.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ class GDScript : public Script {
const HashMap<StringName, MemberInfo> &debug_get_member_indices() const { return member_indices; }
const HashMap<StringName, GDScriptFunction *> &debug_get_member_functions() const; //this is debug only
StringName debug_get_member_by_index(int p_idx) const;
StringName debug_get_static_var_by_index(int p_idx) const;

Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
virtual bool can_instantiate() const override;
Expand Down
Loading