diff options
Diffstat (limited to 'modules/gdscript/gdscript.cpp')
-rw-r--r-- | modules/gdscript/gdscript.cpp | 322 |
1 files changed, 243 insertions, 79 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index b90fab8221..a72bb7ba49 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,6 +30,8 @@ #include "gdscript.h" +#include <stdint.h> + #include "core/core_string_names.h" #include "core/engine.h" #include "core/global_constants.h" @@ -82,7 +84,7 @@ Object *GDScriptNativeClass::instance() { return ClassDB::instance(name); } -GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error) { +GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error) { /* STEP 1, CREATE */ @@ -91,6 +93,7 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco instance->members.resize(member_indices.size()); instance->script = Ref<GDScript>(this); instance->owner = p_owner; + instance->owner_id = p_owner->get_instance_id(); #ifdef DEBUG_ENABLED //needed for hot reloading for (Map<StringName, MemberInfo>::Element *E = member_indices.front(); E; E = E->next()) { @@ -113,7 +116,7 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco initializer->call(instance, p_args, p_argcount, r_error); - if (r_error.error != Variant::CallError::CALL_OK) { + if (r_error.error != Callable::CallError::CALL_OK) { instance->script = Ref<GDScript>(); instance->owner->set_script_instance(NULL); #ifndef NO_THREADS @@ -124,23 +127,23 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco GDScriptLanguage::singleton->lock->unlock(); #endif - ERR_FAIL_COND_V(r_error.error != Variant::CallError::CALL_OK, NULL); //error constructing + ERR_FAIL_COND_V(r_error.error != Callable::CallError::CALL_OK, NULL); //error constructing } //@TODO make thread safe return instance; } -Variant GDScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { +Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { /* STEP 1, CREATE */ if (!valid) { - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; return Variant(); } - r_error.error = Variant::CallError::CALL_OK; + r_error.error = Callable::CallError::CALL_OK; REF ref; Object *owner = NULL; @@ -320,13 +323,13 @@ ScriptInstance *GDScript::instance_create(Object *p_this) { if (!ClassDB::is_parent_class(p_this->get_class_name(), top->native->get_name())) { if (ScriptDebugger::get_singleton()) { - GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 0, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'"); + GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'"); } ERR_FAIL_V_MSG(NULL, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type '" + p_this->get_class() + "'" + "."); } } - Variant::CallError unchecked_error; + Callable::CallError unchecked_error; return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error); } @@ -610,6 +613,53 @@ Error GDScript::reload(bool p_keep_state) { _set_subclass_path(E->get(), path); } + // Copy the base rpc methods so we don't mask their IDs. + rpc_functions.clear(); + rpc_variables.clear(); + if (base.is_valid()) { + rpc_functions = base->rpc_functions; + rpc_variables = base->rpc_variables; + } + + GDScript *cscript = this; + Map<StringName, Ref<GDScript> >::Element *sub_E = subclasses.front(); + while (cscript) { + // RPC Methods + for (Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.front(); E; E = E->next()) { + if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) { + ScriptNetData nd; + nd.name = E->key(); + nd.mode = E->get()->get_rpc_mode(); + if (-1 == rpc_functions.find(nd)) { + rpc_functions.push_back(nd); + } + } + } + // RSet + for (Map<StringName, MemberInfo>::Element *E = cscript->member_indices.front(); E; E = E->next()) { + if (E->get().rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) { + ScriptNetData nd; + nd.name = E->key(); + nd.mode = E->get().rpc_mode; + if (-1 == rpc_variables.find(nd)) { + rpc_variables.push_back(nd); + } + } + } + + if (cscript != this) + sub_E = sub_E->next(); + + if (sub_E) + cscript = sub_E->get().ptr(); + else + cscript = NULL; + } + + // Sort so we are 100% that they are always the same. + rpc_functions.sort_custom<SortNetData>(); + rpc_variables.sort_custom<SortNetData>(); + return OK; } @@ -635,7 +685,61 @@ void GDScript::get_members(Set<StringName> *p_members) { } } -Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { +Vector<ScriptNetData> GDScript::get_rpc_methods() const { + return rpc_functions; +} + +uint16_t GDScript::get_rpc_method_id(const StringName &p_method) const { + for (int i = 0; i < rpc_functions.size(); i++) { + if (rpc_functions[i].name == p_method) { + return i; + } + } + return UINT16_MAX; +} + +StringName GDScript::get_rpc_method(const uint16_t p_rpc_method_id) const { + ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName()); + return rpc_functions[p_rpc_method_id].name; +} + +MultiplayerAPI::RPCMode GDScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { + ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED); + return rpc_functions[p_rpc_method_id].mode; +} + +MultiplayerAPI::RPCMode GDScript::get_rpc_mode(const StringName &p_method) const { + return get_rpc_mode_by_id(get_rpc_method_id(p_method)); +} + +Vector<ScriptNetData> GDScript::get_rset_properties() const { + return rpc_variables; +} + +uint16_t GDScript::get_rset_property_id(const StringName &p_variable) const { + for (int i = 0; i < rpc_variables.size(); i++) { + if (rpc_variables[i].name == p_variable) { + return i; + } + } + return UINT16_MAX; +} + +StringName GDScript::get_rset_property(const uint16_t p_rset_member_id) const { + ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), StringName()); + return rpc_variables[p_rset_member_id].name; +} + +MultiplayerAPI::RPCMode GDScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const { + ERR_FAIL_COND_V(p_rset_member_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED); + return rpc_functions[p_rset_member_id].mode; +} + +MultiplayerAPI::RPCMode GDScript::get_rset_mode(const StringName &p_variable) const { + return get_rset_mode_by_id(get_rset_property_id(p_variable)); +} + +Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { GDScript *top = this; while (top) { @@ -798,7 +902,7 @@ Error GDScript::load_byte_code(const String &p_path) { Error GDScript::load_source_code(const String &p_path) { - PoolVector<uint8_t> sourcef; + Vector<uint8_t> sourcef; Error err; FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { @@ -808,15 +912,15 @@ Error GDScript::load_source_code(const String &p_path) { int len = f->get_len(); sourcef.resize(len + 1); - PoolVector<uint8_t>::Write w = sourcef.write(); - int r = f->get_buffer(w.ptr(), len); + uint8_t *w = sourcef.ptrw(); + int r = f->get_buffer(w, len); f->close(); memdelete(f); ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); w[len] = 0; String s; - if (s.parse_utf8((const char *)w.ptr())) { + if (s.parse_utf8((const char *)w)) { ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded. Please ensure that scripts are saved in valid UTF-8 unicode."); } @@ -891,7 +995,6 @@ void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const { GDScript::GDScript() : script_list(this) { - _static_ref = this; valid = false; subclass_count = 0; initializer = NULL; @@ -915,14 +1018,43 @@ GDScript::GDScript() : #endif } +void GDScript::_save_orphaned_subclasses() { + struct ClassRefWithName { + ObjectID id; + String fully_qualified_name; + }; + Vector<ClassRefWithName> weak_subclasses; + // collect subclasses ObjectID and name + for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) { + E->get()->_owner = NULL; //bye, you are no longer owned cause I died + ClassRefWithName subclass; + subclass.id = E->get()->get_instance_id(); + subclass.fully_qualified_name = E->get()->fully_qualified_name; + weak_subclasses.push_back(subclass); + } + + // clear subclasses to allow unused subclasses to be deleted + subclasses.clear(); + // subclasses are also held by constants, clear those as well + constants.clear(); + + // keep orphan subclass only for subclasses that are still in use + for (int i = 0; i < weak_subclasses.size(); i++) { + ClassRefWithName subclass = weak_subclasses[i]; + Object *obj = ObjectDB::get_instance(subclass.id); + if (!obj) + continue; + // subclass is not released + GDScriptLanguage::get_singleton()->add_orphan_subclass(subclass.fully_qualified_name, subclass.id); + } +} + GDScript::~GDScript() { for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) { memdelete(E->get()); } - for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) { - E->get()->_owner = NULL; //bye, you are no longer owned cause I died - } + _save_orphaned_subclasses(); #ifdef DEBUG_ENABLED if (GDScriptLanguage::get_singleton()->lock) { @@ -946,18 +1078,29 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { { const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); if (E) { - if (E->get().setter) { + const GDScript::MemberInfo *member = &E->get(); + if (member->setter) { const Variant *val = &p_value; - Variant::CallError err; - call(E->get().setter, &val, 1, err); - if (err.error == Variant::CallError::CALL_OK) { + Callable::CallError err; + call(member->setter, &val, 1, err); + if (err.error == Callable::CallError::CALL_OK) { return true; //function exists, call was successful } } else { - if (!E->get().data_type.is_type(p_value)) { - return false; // Type mismatch + if (!member->data_type.is_type(p_value)) { + // Try conversion + Callable::CallError ce; + const Variant *value = &p_value; + Variant converted = Variant::construct(member->data_type.builtin_type, &value, 1, ce); + if (ce.error == Callable::CallError::CALL_OK) { + members.write[member->index] = converted; + return true; + } else { + return false; + } + } else { + members.write[member->index] = p_value; } - members.write[E->get().index] = p_value; } return true; } @@ -972,9 +1115,9 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { Variant name = p_name; const Variant *args[2] = { &name, &p_value }; - Variant::CallError err; + Callable::CallError err; Variant ret = E->get()->call(this, (const Variant **)args, 2, err); - if (err.error == Variant::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) + if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) return true; } sptr = sptr->_base; @@ -992,9 +1135,9 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); if (E) { if (E->get().getter) { - Variant::CallError err; + Callable::CallError err; r_ret = const_cast<GDScriptInstance *>(this)->call(E->get().getter, NULL, 0, err); - if (err.error == Variant::CallError::CALL_OK) { + if (err.error == Callable::CallError::CALL_OK) { return true; } } @@ -1023,9 +1166,9 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { Variant name = p_name; const Variant *args[1] = { &name }; - Variant::CallError err; + Callable::CallError err; Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), (const Variant **)args, 1, err); - if (err.error == Variant::CallError::CALL_OK && ret.get_type() != Variant::NIL) { + if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) { r_ret = ret; return true; } @@ -1066,9 +1209,9 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list); if (E) { - Variant::CallError err; + Callable::CallError err; Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), NULL, 0, err); - if (err.error == Variant::CallError::CALL_OK) { + if (err.error == Callable::CallError::CALL_OK) { ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries."); @@ -1153,9 +1296,7 @@ bool GDScriptInstance::has_method(const StringName &p_method) const { return false; } -Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - - //printf("calling %ls:%i method %ls\n", script->get_path().c_str(), -1, String(p_method).c_str()); +Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { GDScript *sptr = script.ptr(); while (sptr) { @@ -1165,14 +1306,14 @@ Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_arg } sptr = sptr->_base; } - r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; return Variant(); } void GDScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { GDScript *sptr = script.ptr(); - Variant::CallError ce; + Callable::CallError ce; while (sptr) { Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method); @@ -1188,7 +1329,7 @@ void GDScriptInstance::_ml_call_reversed(GDScript *sptr, const StringName &p_met if (sptr->_base) _ml_call_reversed(sptr->_base, p_method, p_args, p_argcount); - Variant::CallError ce; + Callable::CallError ce; Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method); if (E) { @@ -1213,9 +1354,9 @@ void GDScriptInstance::notification(int p_notification) { while (sptr) { Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification); if (E) { - Variant::CallError err; + Callable::CallError err; E->get()->call(this, args, 1, err); - if (err.error != Variant::CallError::CALL_OK) { + if (err.error != Callable::CallError::CALL_OK) { //print error about notification call } } @@ -1225,9 +1366,9 @@ void GDScriptInstance::notification(int p_notification) { String GDScriptInstance::to_string(bool *r_valid) { if (has_method(CoreStringNames::get_singleton()->_to_string)) { - Variant::CallError ce; + Callable::CallError ce; Variant ret = call(CoreStringNames::get_singleton()->_to_string, NULL, 0, ce); - if (ce.error == Variant::CallError::CALL_OK) { + if (ce.error == Callable::CallError::CALL_OK) { if (ret.get_type() != Variant::STRING) { if (r_valid) *r_valid = false; @@ -1253,40 +1394,44 @@ ScriptLanguage *GDScriptInstance::get_language() { return GDScriptLanguage::get_singleton(); } -MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_method) const { +Vector<ScriptNetData> GDScriptInstance::get_rpc_methods() const { + return script->get_rpc_methods(); +} - const GDScript *cscript = script.ptr(); +uint16_t GDScriptInstance::get_rpc_method_id(const StringName &p_method) const { + return script->get_rpc_method_id(p_method); +} - while (cscript) { - const Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.find(p_method); - if (E) { +StringName GDScriptInstance::get_rpc_method(const uint16_t p_rpc_method_id) const { + return script->get_rpc_method(p_rpc_method_id); +} - if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) { - return E->get()->get_rpc_mode(); - } - } - cscript = cscript->_base; - } +MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { + return script->get_rpc_mode_by_id(p_rpc_method_id); +} - return MultiplayerAPI::RPC_MODE_DISABLED; +MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_method) const { + return script->get_rpc_mode(p_method); } -MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_variable) const { +Vector<ScriptNetData> GDScriptInstance::get_rset_properties() const { + return script->get_rset_properties(); +} - const GDScript *cscript = script.ptr(); +uint16_t GDScriptInstance::get_rset_property_id(const StringName &p_variable) const { + return script->get_rset_property_id(p_variable); +} - while (cscript) { - const Map<StringName, GDScript::MemberInfo>::Element *E = cscript->member_indices.find(p_variable); - if (E) { +StringName GDScriptInstance::get_rset_property(const uint16_t p_rset_member_id) const { + return script->get_rset_property(p_rset_member_id); +} - if (E->get().rpc_mode) { - return E->get().rpc_mode; - } - } - cscript = cscript->_base; - } +MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode_by_id(const uint16_t p_rset_member_id) const { + return script->get_rset_mode_by_id(p_rset_member_id); +} - return MultiplayerAPI::RPC_MODE_DISABLED; +MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_variable) const { + return script->get_rset_mode(p_variable); } void GDScriptInstance::reload_members() { @@ -1647,7 +1792,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so obj->get_script_instance()->get_property_state(state); map[obj->get_instance_id()] = state; - obj->set_script(RefPtr()); + obj->set_script(Variant()); } } @@ -1663,7 +1808,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so map.insert(obj->get_instance_id(), List<Pair<StringName, Variant> >()); List<Pair<StringName, Variant> > &state = map[obj->get_instance_id()]; obj->get_script_instance()->get_property_state(state); - obj->set_script(RefPtr()); + obj->set_script(Variant()); } else { // no instance found. Let's remove it so we don't loop forever E->get()->placeholders.erase(E->get()->placeholders.front()->get()); @@ -1694,9 +1839,9 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so if (!p_soft_reload) { //clear it just in case (may be a pending reload state) - obj->set_script(RefPtr()); + obj->set_script(Variant()); } - obj->set_script(scr.get_ref_ptr()); + obj->set_script(scr); ScriptInstance *script_instance = obj->get_script_instance(); @@ -1812,10 +1957,8 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "match", "while", "remote", - "sync", "master", "puppet", - "slave", "remotesync", "mastersync", "puppetsync", @@ -1842,7 +1985,7 @@ bool GDScriptLanguage::handles_global_class_type(const String &p_type) const { String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { - PoolVector<uint8_t> sourcef; + Vector<uint8_t> sourcef; Error err; FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { @@ -1952,11 +2095,11 @@ String GDScriptWarning::get_message() const { } break; case UNUSED_VARIABLE: { CHECK_SYMBOLS(1); - return "The local variable '" + symbols[0] + "' is declared but never used in the block."; + return "The local variable '" + symbols[0] + "' is declared but never used in the block. If this is intended, prefix it with an underscore: '_" + symbols[0] + "'"; } break; case SHADOWED_VARIABLE: { CHECK_SYMBOLS(2); - return "The local variable '" + symbols[0] + "' is shadowing an already defined variable at line " + symbols[1] + "."; + return "The local variable '" + symbols[0] + "' is shadowing an already-defined variable at line " + symbols[1] + "."; } break; case UNUSED_CLASS_VARIABLE: { CHECK_SYMBOLS(1); @@ -1964,7 +2107,7 @@ String GDScriptWarning::get_message() const { } break; case UNUSED_ARGUMENT: { CHECK_SYMBOLS(2); - return "The argument '" + symbols[1] + "' is never used in the function '" + symbols[0] + "'."; + return "The argument '" + symbols[1] + "' is never used in the function '" + symbols[0] + "'. If this is intended, prefix it with an underscore: '_" + symbols[1] + "'"; } break; case UNREACHABLE_CODE: { CHECK_SYMBOLS(1); @@ -2042,6 +2185,9 @@ String GDScriptWarning::get_message() const { CHECK_SYMBOLS(2); return "The '" + symbols[0] + "' keyword is deprecated and will be removed in a future release, please replace its uses by '" + symbols[1] + "'."; } break; + case STANDALONE_TERNARY: { + return "Standalone ternary conditional operator: the return value is being discarded."; + } case WARNING_MAX: break; // Can't happen, but silences warning } ERR_FAIL_V_MSG(String(), "Invalid GDScript warning code: " + get_name_from_code(code) + "."); @@ -2083,6 +2229,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) { "UNSAFE_CAST", "UNSAFE_CALL_ARGUMENT", "DEPRECATED_KEYWORD", + "STANDALONE_TERNARY", NULL }; @@ -2145,7 +2292,8 @@ GDScriptLanguage::GDScriptLanguage() { GLOBAL_DEF("debug/gdscript/completion/autocomplete_setters_and_getters", false); for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) { String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower(); - GLOBAL_DEF("debug/gdscript/warnings/" + warning, !warning.begins_with("unsafe_")); + bool default_enabled = !warning.begins_with("unsafe_") && i != GDScriptWarning::UNUSED_CLASS_VARIABLE; + GLOBAL_DEF("debug/gdscript/warnings/" + warning, default_enabled); } #endif // DEBUG_ENABLED } @@ -2162,6 +2310,22 @@ GDScriptLanguage::~GDScriptLanguage() { singleton = NULL; } +void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass) { + orphan_subclasses[p_qualified_name] = p_subclass; +} + +Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_name) { + Map<String, ObjectID>::Element *orphan_subclass_element = orphan_subclasses.find(p_qualified_name); + if (!orphan_subclass_element) + return Ref<GDScript>(); + ObjectID orphan_subclass = orphan_subclass_element->get(); + Object *obj = ObjectDB::get_instance(orphan_subclass); + orphan_subclasses.erase(orphan_subclass_element); + if (!obj) + return Ref<GDScript>(); + return Ref<GDScript>(Object::cast_to<GDScript>(obj)); +} + /*************** RESOURCE ***************/ RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error) { |