diff options
Diffstat (limited to 'modules/gdscript/gdscript.cpp')
-rw-r--r-- | modules/gdscript/gdscript.cpp | 122 |
1 files changed, 103 insertions, 19 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 8e74de4242..0c58b41fcb 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -49,11 +49,12 @@ #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/core_constants.h" -#include "core/core_string_names.h" #include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" #include "core/os/os.h" +#include "scene/scene_string_names.h" + #ifdef TOOLS_ENABLED #include "editor/editor_paths.h" #endif @@ -395,6 +396,8 @@ bool GDScript::get_property_default_value(const StringName &p_property, Variant } ScriptInstance *GDScript::instance_create(Object *p_this) { + ERR_FAIL_COND_V_MSG(!valid, nullptr, "Script is invalid!"); + GDScript *top = this; while (top->_base) { top = top->_base; @@ -678,6 +681,27 @@ Error GDScript::_static_init() { #ifdef TOOLS_ENABLED +void GDScript::_static_default_init() { + for (const KeyValue<StringName, MemberInfo> &E : static_variables_indices) { + const GDScriptDataType &type = E.value.data_type; + // Only initialize builtin types, which are not expected to be `null`. + if (!type.has_type || type.kind != GDScriptDataType::BUILTIN) { + continue; + } + if (type.builtin_type == Variant::ARRAY && type.has_container_element_type(0)) { + Array default_value; + const GDScriptDataType &element_type = type.get_container_element_type(0); + default_value.set_typed(element_type.builtin_type, element_type.native_type, element_type.script_type); + static_variables.write[E.value.index] = default_value; + } else { + Variant default_value; + Callable::CallError err; + Variant::construct(type.builtin_type, default_value, nullptr, 0, err); + static_variables.write[E.value.index] = default_value; + } + } +} + void GDScript::_save_old_static_data() { old_static_variables_indices = static_variables_indices; old_static_variables = static_variables; @@ -739,10 +763,18 @@ Error GDScript::reload(bool p_keep_state) { if (source_path.is_empty()) { source_path = get_path(); } - Ref<GDScript> cached_script = GDScriptCache::get_cached_script(source_path); - if (!source_path.is_empty() && cached_script.is_null()) { - MutexLock lock(GDScriptCache::singleton->mutex); - GDScriptCache::singleton->shallow_gdscript_cache[source_path] = Ref<GDScript>(this); + if (!source_path.is_empty()) { + if (GDScriptCache::get_cached_script(source_path).is_null()) { + MutexLock lock(GDScriptCache::singleton->mutex); + GDScriptCache::singleton->shallow_gdscript_cache[source_path] = Ref<GDScript>(this); + } + if (GDScriptCache::has_parser(source_path)) { + Error err = OK; + Ref<GDScriptParserRef> parser_ref = GDScriptCache::get_parser(source_path, GDScriptParserRef::EMPTY, err); + if (parser_ref.is_valid() && parser_ref->get_source_hash() != source.hash()) { + GDScriptCache::remove_parser(source_path); + } + } } } @@ -833,6 +865,9 @@ Error GDScript::reload(bool p_keep_state) { #ifdef TOOLS_ENABLED if (can_run && p_keep_state) { _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 @@ -869,6 +904,11 @@ void GDScript::unload_static() const { } 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; while (top) { HashMap<StringName, GDScriptFunction *>::Iterator E = top->member_functions.find(p_method); @@ -891,6 +931,10 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const { return true; } + if (unlikely(!valid)) { + return false; + } + const GDScript *top = this; while (top) { { @@ -947,6 +991,10 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) { return true; } + if (unlikely(!valid)) { + return false; + } + GDScript *top = this; while (top) { HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name); @@ -981,6 +1029,10 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) { 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)); + if (unlikely(!valid)) { + return; + } + List<const GDScript *> classes; const GDScript *top = this; while (top) { @@ -1597,6 +1649,10 @@ GDScript::~GDScript() { ////////////////////////////// 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); if (E) { @@ -1670,6 +1726,10 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { } 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); if (E) { @@ -1790,6 +1850,10 @@ void GDScriptInstance::validate_property(PropertyInfo &p_property) const { } void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { + if (unlikely(!script->valid)) { + return; + } + // exported members, not done yet! const GDScript *sptr = script.ptr(); @@ -1868,6 +1932,10 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const } bool GDScriptInstance::property_can_revert(const StringName &p_name) const { + if (unlikely(!script->valid)) { + return false; + } + Variant name = p_name; const Variant *args[1] = { &name }; @@ -1888,6 +1956,10 @@ bool GDScriptInstance::property_can_revert(const StringName &p_name) const { } bool GDScriptInstance::property_get_revert(const StringName &p_name, Variant &r_ret) const { + if (unlikely(!script->valid)) { + return false; + } + Variant name = p_name; const Variant *args[1] = { &name }; @@ -1950,19 +2022,27 @@ int GDScriptInstance::get_method_argument_count(const StringName &p_method, bool return 0; } +void GDScriptInstance::_call_implicit_ready_recursively(GDScript *p_script) { + // Call base class first. + if (p_script->_base) { + _call_implicit_ready_recursively(p_script->_base); + } + if (p_script->implicit_ready) { + Callable::CallError 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) { - GDScript *sptr = script.ptr(); - if (unlikely(p_method == SNAME("_ready"))) { - // Call implicit ready first, including for the super classes. - while (sptr) { - if (sptr->implicit_ready) { - sptr->implicit_ready->call(this, nullptr, 0, r_error); - } - sptr = sptr->_base; - } + if (unlikely(!script->valid)) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; + return Variant(); + } - // Reset this back for the regular call. - sptr = script.ptr(); + GDScript *sptr = script.ptr(); + if (unlikely(p_method == SceneStringName(_ready))) { + // Call implicit ready first, including for the super classes recursively. + _call_implicit_ready_recursively(sptr); } while (sptr) { HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method); @@ -1976,6 +2056,10 @@ Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_ar } void GDScriptInstance::notification(int p_notification, bool p_reversed) { + if (unlikely(!script->valid)) { + return; + } + //notification is not virtual, it gets called at ALL levels just like in C. Variant value = p_notification; const Variant *args[1] = { &value }; @@ -2003,15 +2087,15 @@ void GDScriptInstance::notification(int p_notification, bool p_reversed) { } String GDScriptInstance::to_string(bool *r_valid) { - if (has_method(CoreStringNames::get_singleton()->_to_string)) { + if (has_method(CoreStringName(_to_string))) { Callable::CallError ce; - Variant ret = callp(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce); + Variant ret = callp(CoreStringName(_to_string), nullptr, 0, ce); if (ce.error == Callable::CallError::CALL_OK) { if (ret.get_type() != Variant::STRING) { if (r_valid) { *r_valid = false; } - ERR_FAIL_V_MSG(String(), "Wrong type for " + CoreStringNames::get_singleton()->_to_string + ", must be a String."); + ERR_FAIL_V_MSG(String(), "Wrong type for " + CoreStringName(_to_string) + ", must be a String."); } if (r_valid) { *r_valid = true; |