summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/gdscript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gdscript.cpp')
-rw-r--r--modules/gdscript/gdscript.cpp122
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;