1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

GDScript: partially allow some functions on invalid scripts

+ always default initialize static variables
+ dont invalidate script when dependant scripts don't compile/resolve
This commit is contained in:
rune-scape
2024-06-02 02:07:47 -07:00
committed by rune-scape
parent 505da68b26
commit 7f7114c008
5 changed files with 101 additions and 136 deletions

View File

@@ -115,7 +115,7 @@ Variant GDScriptNativeClass::callp(const StringName &p_method, const Variant **p
} }
GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) { GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) {
if (p_script->initializer) { if (likely(p_script->valid) && p_script->initializer) {
return p_script->initializer; return p_script->initializer;
} else { } else {
GDScript *base_src = p_script->_base; GDScript *base_src = p_script->_base;
@@ -136,7 +136,11 @@ void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance
} }
} }
ERR_FAIL_NULL(p_script->implicit_initializer); ERR_FAIL_NULL(p_script->implicit_initializer);
if (likely(valid)) {
p_script->implicit_initializer->call(p_instance, nullptr, 0, r_error); p_script->implicit_initializer->call(p_instance, nullptr, 0, r_error);
} else {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
}
} }
GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) { GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) {
@@ -662,7 +666,7 @@ String GDScript::_get_debug_path() const {
} }
Error GDScript::_static_init() { Error GDScript::_static_init() {
if (static_initializer) { if (likely(valid) && static_initializer) {
Callable::CallError call_err; Callable::CallError call_err;
static_initializer->call(nullptr, nullptr, 0, call_err); static_initializer->call(nullptr, nullptr, 0, call_err);
if (call_err.error != Callable::CallError::CALL_OK) { if (call_err.error != Callable::CallError::CALL_OK) {
@@ -679,8 +683,6 @@ Error GDScript::_static_init() {
return err; return err;
} }
#ifdef TOOLS_ENABLED
void GDScript::_static_default_init() { void GDScript::_static_default_init() {
for (const KeyValue<StringName, MemberInfo> &E : static_variables_indices) { for (const KeyValue<StringName, MemberInfo> &E : static_variables_indices) {
const GDScriptDataType &type = E.value.data_type; const GDScriptDataType &type = E.value.data_type;
@@ -702,6 +704,8 @@ void GDScript::_static_default_init() {
} }
} }
#ifdef TOOLS_ENABLED
void GDScript::_save_old_static_data() { void GDScript::_save_old_static_data() {
old_static_variables_indices = static_variables_indices; old_static_variables_indices = static_variables_indices;
old_static_variables = static_variables; old_static_variables = static_variables;
@@ -865,9 +869,6 @@ Error GDScript::reload(bool p_keep_state) {
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if (can_run && p_keep_state) { if (can_run && p_keep_state) {
_restore_old_static_data(); _restore_old_static_data();
} else if (!can_run) {
// Initialize static variables with sane default values even if the constructor isn't called.
_static_default_init();
} }
#endif #endif
@@ -904,19 +905,16 @@ void GDScript::unload_static() const {
} }
Variant GDScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { Variant GDScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (unlikely(!valid)) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return Variant();
}
GDScript *top = this; GDScript *top = this;
while (top) { while (top) {
if (likely(top->valid)) {
HashMap<StringName, GDScriptFunction *>::Iterator E = top->member_functions.find(p_method); HashMap<StringName, GDScriptFunction *>::Iterator E = top->member_functions.find(p_method);
if (E) { if (E) {
ERR_FAIL_COND_V_MSG(!E->value->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script."); ERR_FAIL_COND_V_MSG(!E->value->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script.");
return E->value->call(nullptr, p_args, p_argcount, r_error); return E->value->call(nullptr, p_args, p_argcount, r_error);
} }
}
top = top->_base; top = top->_base;
} }
@@ -931,10 +929,6 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
return true; return true;
} }
if (unlikely(!valid)) {
return false;
}
const GDScript *top = this; const GDScript *top = this;
while (top) { while (top) {
{ {
@@ -948,7 +942,7 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
{ {
HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name); HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name);
if (E) { if (E) {
if (E->value.getter) { if (likely(top->valid) && E->value.getter) {
Callable::CallError ce; Callable::CallError ce;
r_ret = const_cast<GDScript *>(this)->callp(E->value.getter, nullptr, 0, ce); r_ret = const_cast<GDScript *>(this)->callp(E->value.getter, nullptr, 0, ce);
return true; return true;
@@ -958,7 +952,7 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
} }
} }
{ if (likely(top->valid)) {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = top->member_functions.find(p_name); HashMap<StringName, GDScriptFunction *>::ConstIterator E = top->member_functions.find(p_name);
if (E && E->value->is_static()) { if (E && E->value->is_static()) {
if (top->rpc_config.has(p_name)) { if (top->rpc_config.has(p_name)) {
@@ -991,10 +985,6 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
return true; return true;
} }
if (unlikely(!valid)) {
return false;
}
GDScript *top = this; GDScript *top = this;
while (top) { while (top) {
HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name); HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name);
@@ -1009,7 +999,7 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
return false; return false;
} }
} }
if (member->setter) { if (likely(top->valid) && member->setter) {
const Variant *args = &value; const Variant *args = &value;
Callable::CallError err; Callable::CallError err;
callp(member->setter, &args, 1, err); callp(member->setter, &args, 1, err);
@@ -1029,10 +1019,6 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const { 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)); p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
if (unlikely(!valid)) {
return;
}
List<const GDScript *> classes; List<const GDScript *> classes;
const GDScript *top = this; const GDScript *top = this;
while (top) { while (top) {
@@ -1649,10 +1635,6 @@ GDScript::~GDScript() {
////////////////////////////// //////////////////////////////
bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
if (unlikely(!script->valid)) {
return false;
}
{ {
HashMap<StringName, GDScript::MemberInfo>::Iterator E = script->member_indices.find(p_name); HashMap<StringName, GDScript::MemberInfo>::Iterator E = script->member_indices.find(p_name);
if (E) { if (E) {
@@ -1666,7 +1648,7 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
return false; return false;
} }
} }
if (member->setter) { if (likely(script->valid) && member->setter) {
const Variant *args = &value; const Variant *args = &value;
Callable::CallError err; Callable::CallError err;
callp(member->setter, &args, 1, err); callp(member->setter, &args, 1, err);
@@ -1693,7 +1675,7 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
return false; return false;
} }
} }
if (member->setter) { if (likely(sptr->valid) && member->setter) {
const Variant *args = &value; const Variant *args = &value;
Callable::CallError err; Callable::CallError err;
callp(member->setter, &args, 1, err); callp(member->setter, &args, 1, err);
@@ -1705,7 +1687,7 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
} }
} }
{ if (likely(sptr->valid)) {
HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set); HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
if (E) { if (E) {
Variant name = p_name; Variant name = p_name;
@@ -1726,14 +1708,10 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
} }
bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
if (unlikely(!script->valid)) {
return false;
}
{ {
HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = script->member_indices.find(p_name); HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = script->member_indices.find(p_name);
if (E) { if (E) {
if (E->value.getter) { if (likely(script->valid) && E->value.getter) {
Callable::CallError err; Callable::CallError err;
r_ret = const_cast<GDScriptInstance *>(this)->callp(E->value.getter, nullptr, 0, err); r_ret = const_cast<GDScriptInstance *>(this)->callp(E->value.getter, nullptr, 0, err);
if (err.error == Callable::CallError::CALL_OK) { if (err.error == Callable::CallError::CALL_OK) {
@@ -1758,7 +1736,7 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
{ {
HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = sptr->static_variables_indices.find(p_name); HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = sptr->static_variables_indices.find(p_name);
if (E) { if (E) {
if (E->value.getter) { if (likely(sptr->valid) && E->value.getter) {
Callable::CallError ce; Callable::CallError ce;
r_ret = const_cast<GDScript *>(sptr)->callp(E->value.getter, nullptr, 0, ce); r_ret = const_cast<GDScript *>(sptr)->callp(E->value.getter, nullptr, 0, ce);
return true; return true;
@@ -1776,7 +1754,7 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
} }
} }
{ if (likely(sptr->valid)) {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_name); HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_name);
if (E) { if (E) {
if (sptr->rpc_config.has(p_name)) { if (sptr->rpc_config.has(p_name)) {
@@ -1796,7 +1774,7 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
} }
} }
{ if (likely(sptr->valid)) {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get); HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get);
if (E) { if (E) {
Variant name = p_name; Variant name = p_name;
@@ -1836,6 +1814,7 @@ void GDScriptInstance::validate_property(PropertyInfo &p_property) const {
const GDScript *sptr = script.ptr(); const GDScript *sptr = script.ptr();
while (sptr) { while (sptr) {
if (likely(sptr->valid)) {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._validate_property); HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._validate_property);
if (E) { if (E) {
Callable::CallError err; Callable::CallError err;
@@ -1845,21 +1824,19 @@ void GDScriptInstance::validate_property(PropertyInfo &p_property) const {
return; return;
} }
} }
}
sptr = sptr->_base; sptr = sptr->_base;
} }
} }
void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
if (unlikely(!script->valid)) {
return;
}
// exported members, not done yet! // exported members, not done yet!
const GDScript *sptr = script.ptr(); const GDScript *sptr = script.ptr();
List<PropertyInfo> props; List<PropertyInfo> props;
while (sptr) { while (sptr) {
if (likely(sptr->valid)) {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list); HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list);
if (E) { if (E) {
Callable::CallError err; Callable::CallError err;
@@ -1896,6 +1873,7 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
} }
} }
} }
}
//instance a fake script for editing the values //instance a fake script for editing the values
@@ -1932,15 +1910,12 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
} }
bool GDScriptInstance::property_can_revert(const StringName &p_name) const { bool GDScriptInstance::property_can_revert(const StringName &p_name) const {
if (unlikely(!script->valid)) {
return false;
}
Variant name = p_name; Variant name = p_name;
const Variant *args[1] = { &name }; const Variant *args[1] = { &name };
const GDScript *sptr = script.ptr(); const GDScript *sptr = script.ptr();
while (sptr) { while (sptr) {
if (likely(sptr->valid)) {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_can_revert); HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_can_revert);
if (E) { if (E) {
Callable::CallError err; Callable::CallError err;
@@ -1949,6 +1924,7 @@ bool GDScriptInstance::property_can_revert(const StringName &p_name) const {
return true; return true;
} }
} }
}
sptr = sptr->_base; sptr = sptr->_base;
} }
@@ -1956,15 +1932,12 @@ bool GDScriptInstance::property_can_revert(const StringName &p_name) const {
} }
bool GDScriptInstance::property_get_revert(const StringName &p_name, Variant &r_ret) const { bool GDScriptInstance::property_get_revert(const StringName &p_name, Variant &r_ret) const {
if (unlikely(!script->valid)) {
return false;
}
Variant name = p_name; Variant name = p_name;
const Variant *args[1] = { &name }; const Variant *args[1] = { &name };
const GDScript *sptr = script.ptr(); const GDScript *sptr = script.ptr();
while (sptr) { while (sptr) {
if (likely(sptr->valid)) {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_get_revert); HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_get_revert);
if (E) { if (E) {
Callable::CallError err; Callable::CallError err;
@@ -1974,6 +1947,7 @@ bool GDScriptInstance::property_get_revert(const StringName &p_name, Variant &r_
return true; return true;
} }
} }
}
sptr = sptr->_base; sptr = sptr->_base;
} }
@@ -2027,30 +2001,28 @@ void GDScriptInstance::_call_implicit_ready_recursively(GDScript *p_script) {
if (p_script->_base) { if (p_script->_base) {
_call_implicit_ready_recursively(p_script->_base); _call_implicit_ready_recursively(p_script->_base);
} }
if (p_script->implicit_ready) { if (likely(p_script->valid) && p_script->implicit_ready) {
Callable::CallError err; Callable::CallError err;
p_script->implicit_ready->call(this, nullptr, 0, err); p_script->implicit_ready->call(this, nullptr, 0, err);
} }
} }
Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (unlikely(!script->valid)) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return Variant();
}
GDScript *sptr = script.ptr(); GDScript *sptr = script.ptr();
if (unlikely(p_method == SceneStringName(_ready))) { if (unlikely(p_method == SceneStringName(_ready))) {
// Call implicit ready first, including for the super classes recursively. // Call implicit ready first, including for the super classes recursively.
_call_implicit_ready_recursively(sptr); _call_implicit_ready_recursively(sptr);
} }
while (sptr) { while (sptr) {
if (likely(sptr->valid)) {
HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method); HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method);
if (E) { if (E) {
return E->value->call(this, p_args, p_argcount, r_error); return E->value->call(this, p_args, p_argcount, r_error);
} }
}
sptr = sptr->_base; sptr = sptr->_base;
} }
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return Variant(); return Variant();
} }
@@ -2075,6 +2047,7 @@ void GDScriptInstance::notification(int p_notification, bool p_reversed) {
sptr = sptr->_base; sptr = sptr->_base;
} }
for (GDScript *sc : pl) { for (GDScript *sc : pl) {
if (likely(sc->valid)) {
HashMap<StringName, GDScriptFunction *>::Iterator E = sc->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification); HashMap<StringName, GDScriptFunction *>::Iterator E = sc->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification);
if (E) { if (E) {
Callable::CallError err; Callable::CallError err;
@@ -2084,6 +2057,7 @@ void GDScriptInstance::notification(int p_notification, bool p_reversed) {
} }
} }
} }
}
} }
String GDScriptInstance::to_string(bool *r_valid) { String GDScriptInstance::to_string(bool *r_valid) {

View File

@@ -169,9 +169,7 @@ private:
GDScriptFunction *static_initializer = nullptr; GDScriptFunction *static_initializer = nullptr;
Error _static_init(); Error _static_init();
#ifdef TOOLS_ENABLED
void _static_default_init(); // Initialize static variables with default values based on their types. void _static_default_init(); // Initialize static variables with default values based on their types.
#endif
int subclass_count = 0; int subclass_count = 0;
RBSet<Object *> instances; RBSet<Object *> instances;

View File

@@ -91,12 +91,8 @@ Error GDScriptParserRef::raise_status(Status p_new_status) {
result = get_analyzer()->resolve_interface(); result = get_analyzer()->resolve_interface();
} break; } break;
case INTERFACE_SOLVED: { case INTERFACE_SOLVED: {
status = BODY_SOLVED;
result = get_analyzer()->resolve_body();
} break;
case BODY_SOLVED: {
status = FULLY_SOLVED; status = FULLY_SOLVED;
result = get_analyzer()->resolve_dependencies(); result = get_analyzer()->resolve_body();
} break; } break;
case FULLY_SOLVED: { case FULLY_SOLVED: {
return result; return result;

View File

@@ -48,7 +48,6 @@ public:
PARSED, PARSED,
INHERITANCE_SOLVED, INHERITANCE_SOLVED,
INTERFACE_SOLVED, INTERFACE_SOLVED,
BODY_SOLVED,
FULLY_SOLVED, FULLY_SOLVED,
}; };

View File

@@ -3006,6 +3006,8 @@ Error GDScriptCompiler::_compile_class(GDScript *p_script, const GDScriptParser:
has_static_data = has_static_data || inner_class->has_static_data; has_static_data = has_static_data || inner_class->has_static_data;
} }
p_script->_static_default_init();
p_script->valid = true; p_script->valid = true;
return OK; return OK;
} }
@@ -3228,11 +3230,7 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri
GDScriptCache::add_static_script(p_script); GDScriptCache::add_static_script(p_script);
} }
err = GDScriptCache::finish_compiling(main_script->path); return GDScriptCache::finish_compiling(main_script->path);
if (err) {
main_script->valid = false;
}
return err;
} }
String GDScriptCompiler::get_error() const { String GDScriptCompiler::get_error() const {