diff options
Diffstat (limited to 'core/object.cpp')
-rw-r--r-- | core/object.cpp | 307 |
1 files changed, 147 insertions, 160 deletions
diff --git a/core/object.cpp b/core/object.cpp index 96914fe141..6facf38733 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -277,8 +277,8 @@ MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyIn MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name) : name(p_name), - flags(METHOD_FLAG_NORMAL), return_val(p_ret), + flags(METHOD_FLAG_NORMAL), id(0) { } @@ -440,16 +440,6 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid if (r_valid) *r_valid = true; return; -#ifdef TOOLS_ENABLED - } else if (p_name == CoreStringNames::get_singleton()->_sections_unfolded) { - Array arr = p_value; - for (int i = 0; i < arr.size(); i++) { - editor_section_folding.insert(arr[i]); - } - if (r_valid) - *r_valid = true; - return; -#endif } //something inside the object... :| @@ -484,7 +474,6 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid if (r_valid) *r_valid = false; - return; } Variant Object::get(const StringName &p_name, bool *r_valid) const { @@ -520,16 +509,7 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const { if (r_valid) *r_valid = true; return ret; -#ifdef TOOLS_ENABLED - } else if (p_name == CoreStringNames::get_singleton()->_sections_unfolded) { - Array array; - for (Set<String>::Element *E = editor_section_folding.front(); E; E = E->next()) { - array.push_back(E->get()); - } - if (r_valid) - *r_valid = true; - return array; -#endif + } else { //something inside the object... :| bool success = _getv(p_name, ret); @@ -627,18 +607,16 @@ Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) co } bool valid = false; - Variant current_value = get(p_names[0]); + Variant current_value = get(p_names[0], &valid); for (int i = 1; i < p_names.size(); i++) { current_value = current_value.get_named(p_names[i], &valid); - if (!valid) { - if (r_valid) - *r_valid = false; - return Variant(); - } + if (!valid) + break; } if (r_valid) - *r_valid = true; + *r_valid = valid; + return current_value; } @@ -655,15 +633,11 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons #ifdef TOOLS_ENABLED p_list->push_back(PropertyInfo(Variant::NIL, "Script", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP)); #endif - p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NONZERO)); + p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT)); } -#ifdef TOOLS_ENABLED - if (editor_section_folding.size()) { - p_list->push_back(PropertyInfo(Variant::ARRAY, CoreStringNames::get_singleton()->_sections_unfolded, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + if (!metadata.empty()) { + p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); } -#endif - if (!metadata.empty()) - p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_STORE_IF_NONZERO)); if (script_instance && !p_reversed) { p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); script_instance->get_property_list(p_list); @@ -726,40 +700,35 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Vari } #ifdef DEBUG_ENABLED -static bool _test_call_error(const StringName &p_func, const Variant::CallError &error) { +static void _test_call_error(const StringName &p_func, const Variant::CallError &error) { switch (error.error) { case Variant::CallError::CALL_OK: - return true; case Variant::CallError::CALL_ERROR_INVALID_METHOD: - return false; + break; case Variant::CallError::CALL_ERROR_INVALID_ARGUMENT: { - ERR_EXPLAIN("Error Calling Function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(error.expected)); - ERR_FAIL_V(true); - } break; + ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(error.expected) + "."); + break; + } case Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { - ERR_EXPLAIN("Error Calling Function: " + String(p_func) + " - Too many arguments, expected " + itos(error.argument)); - ERR_FAIL_V(true); - - } break; + ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too many arguments, expected " + itos(error.argument) + "."); + break; + } case Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: { - ERR_EXPLAIN("Error Calling Function: " + String(p_func) + " - Too few arguments, expected " + itos(error.argument)); - ERR_FAIL_V(true); - - } break; - case Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL: { - } //? + ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too few arguments, expected " + itos(error.argument) + "."); + break; + } + case Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL: + break; } - - return true; } #else -#define _test_call_error(m_str, m_err) ((m_err.error == Variant::CallError::CALL_ERROR_INVALID_METHOD) ? false : true) +#define _test_call_error(m_str, m_err) #endif @@ -767,17 +736,9 @@ void Object::call_multilevel(const StringName &p_method, const Variant **p_args, if (p_method == CoreStringNames::get_singleton()->_free) { #ifdef DEBUG_ENABLED - if (Object::cast_to<Reference>(this)) { - ERR_EXPLAIN("Can't 'free' a reference."); - ERR_FAIL(); - return; - } + ERR_FAIL_COND_MSG(Object::cast_to<Reference>(this), "Can't 'free' a reference."); - if (_lock_index.get() > 1) { - ERR_EXPLAIN("Object is locked and can't be freed."); - ERR_FAIL(); - return; - } + ERR_FAIL_COND_MSG(_lock_index.get() > 1, "Object is locked and can't be freed."); #endif //must be here, must be before everything, @@ -837,11 +798,7 @@ bool Object::has_method(const StringName &p_method) const { MethodBind *method = ClassDB::get_method(get_class_name(), p_method); - if (method) { - return true; - } - - return false; + return method != NULL; } Variant Object::getvar(const Variant &p_key, bool *r_valid) const { @@ -857,23 +814,21 @@ void Object::setvar(const Variant &p_key, const Variant &p_value, bool *r_valid) } Variant Object::callv(const StringName &p_method, const Array &p_args) { + const Variant **argptrs = NULL; - if (p_args.size() == 0) { - return call(p_method); - } - - Vector<Variant> args; - args.resize(p_args.size()); - Vector<const Variant *> argptrs; - argptrs.resize(p_args.size()); - - for (int i = 0; i < p_args.size(); i++) { - args.write[i] = p_args[i]; - argptrs.write[i] = &args[i]; + if (p_args.size() > 0) { + argptrs = (const Variant **)alloca(sizeof(Variant *) * p_args.size()); + for (int i = 0; i < p_args.size(); i++) { + argptrs[i] = &p_args[i]; + } } Variant::CallError ce; - return call(p_method, (const Variant **)argptrs.ptr(), p_args.size(), ce); + Variant ret = call(p_method, argptrs, p_args.size(), ce); + if (ce.error != Variant::CallError::CALL_OK) { + ERR_FAIL_V_MSG(Variant(), "Error calling method from 'callv': " + Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce) + "."); + } + return ret; } Variant Object::call(const StringName &p_name, VARIANT_ARG_DECLARE) { @@ -923,15 +878,13 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a if (Object::cast_to<Reference>(this)) { r_error.argument = 0; r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; - ERR_EXPLAIN("Can't 'free' a reference."); - ERR_FAIL_V(Variant()); + ERR_FAIL_V_MSG(Variant(), "Can't 'free' a reference."); } if (_lock_index.get() > 1) { r_error.argument = 0; r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; - ERR_EXPLAIN("Object is locked and can't be freed."); - ERR_FAIL_V(Variant()); + ERR_FAIL_V_MSG(Variant(), "Object is locked and can't be freed."); } #endif @@ -982,6 +935,16 @@ void Object::notification(int p_notification, bool p_reversed) { } } +String Object::to_string() { + if (script_instance) { + bool valid; + String ret = script_instance->to_string(&valid); + if (valid) + return ret; + } + return "[" + get_class() + ":" + itos(get_instance_id()) + "]"; +} + void Object::_changed_callback(Object *p_changed, const char *p_prop) { } @@ -1039,7 +1002,7 @@ void Object::set_script(const RefPtr &p_script) { } } - _change_notify("script"); + _change_notify(); //scripts may add variables, so refresh is desired emit_signal(CoreStringNames::get_singleton()->script_changed); } @@ -1085,6 +1048,10 @@ Variant Object::get_meta(const String &p_name) const { return metadata[p_name]; } +void Object::remove_meta(const String &p_name) { + metadata.erase(p_name); +} + Array Object::_get_property_list_bind() const { List<PropertyInfo> lpi; @@ -1133,9 +1100,9 @@ void Object::get_meta_list(List<String> *p_list) const { void Object::add_user_signal(const MethodInfo &p_signal) { - ERR_FAIL_COND(p_signal.name == ""); - ERR_FAIL_COND(ClassDB::has_signal(get_class_name(), p_signal.name)); - ERR_FAIL_COND(signal_map.has(p_signal.name)); + ERR_FAIL_COND_MSG(p_signal.name == "", "Signal name cannot be empty."); + ERR_FAIL_COND_MSG(ClassDB::has_signal(get_class_name(), p_signal.name), "User signal's name conflicts with a built-in signal of '" + get_class_name() + "'."); + ERR_FAIL_COND_MSG(signal_map.has(p_signal.name), "Trying to add already existing signal '" + p_signal.name + "'."); Signal s; s.user = p_signal; signal_map[p_signal.name] = s; @@ -1193,10 +1160,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int #ifdef DEBUG_ENABLED bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_name); //check in script - if (!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name)) { - ERR_EXPLAIN("Can't emit non-existing signal " + String("\"") + p_name + "\"."); - ERR_FAIL_V(ERR_UNAVAILABLE); - } + ERR_FAIL_COND_V_MSG(!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name), ERR_UNAVAILABLE, "Can't emit non-existing signal " + String("\"") + p_name + "\"."); #endif //not connected? just return return ERR_UNAVAILABLE; @@ -1254,11 +1218,14 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int target->call(c.method, args, argc, ce); if (ce.error != Variant::CallError::CALL_OK) { - +#ifdef DEBUG_ENABLED + if (c.flags & CONNECT_PERSIST && Engine::get_singleton()->is_editor_hint() && (script.is_null() || !Ref<Script>(script)->is_tool())) + continue; +#endif if (ce.error == Variant::CallError::CALL_ERROR_INVALID_METHOD && !ClassDB::class_exists(target->get_class_name())) { //most likely object is not initialized yet, do not throw error. } else { - ERR_PRINTS("Error calling method from signal '" + String(p_name) + "': " + Variant::get_call_error_text(target, c.method, args, argc, ce)); + ERR_PRINTS("Error calling method from signal '" + String(p_name) + "': " + Variant::get_call_error_text(target, c.method, args, argc, ce) + "."); err = ERR_METHOD_NOT_FOUND; } } @@ -1267,7 +1234,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int bool disconnect = c.flags & CONNECT_ONESHOT; #ifdef TOOLS_ENABLED if (disconnect && (c.flags & CONNECT_PERSIST) && Engine::get_singleton()->is_editor_hint()) { - //this signal was connected from the editor, and is being edited. just dont disconnect for now + //this signal was connected from the editor, and is being edited. just don't disconnect for now disconnect = false; } #endif @@ -1389,7 +1356,10 @@ Array Object::_get_incoming_connections() const { void Object::get_signal_list(List<MethodInfo> *p_signals) const { if (!script.is_null()) { - Ref<Script>(script)->get_script_signal_list(p_signals); + Ref<Script> scr = script; + if (scr.is_valid()) { + scr->get_script_signal_list(p_signals); + } } ClassDB::get_signal_list(get_class_name(), p_signals); @@ -1430,8 +1400,9 @@ void Object::get_signal_connection_list(const StringName &p_signal, List<Connect p_connections->push_back(s->slot_map.getv(i).conn); } -bool Object::has_persistent_signal_connections() const { +int Object::get_persistent_signal_connection_count() const { + int count = 0; const StringName *S = NULL; while ((S = signal_map.next(S))) { @@ -1439,13 +1410,13 @@ bool Object::has_persistent_signal_connections() const { const Signal *s = &signal_map[*S]; for (int i = 0; i < s->slot_map.size(); i++) { - - if (s->slot_map.getv(i).conn.flags & CONNECT_PERSIST) - return true; + if (s->slot_map.getv(i).conn.flags & CONNECT_PERSIST) { + count += 1; + } } } - return false; + return count; } void Object::get_signals_connected_to_this(List<Connection> *p_connections) const { @@ -1463,13 +1434,23 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str if (!s) { bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal); //check in script - if (!signal_is_valid && !script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)) - signal_is_valid = true; + if (!signal_is_valid && !script.is_null()) { - if (!signal_is_valid) { - ERR_EXPLAIN("In Object of type '" + String(get_class()) + "': Attempt to connect nonexistent signal '" + p_signal + "' to method '" + p_to_object->get_class() + "." + p_to_method + "'"); - ERR_FAIL_COND_V(!signal_is_valid, ERR_INVALID_PARAMETER); + if (Ref<Script>(script)->has_script_signal(p_signal)) { + signal_is_valid = true; + } +#ifdef TOOLS_ENABLED + else { + //allow connecting signals anyway if script is invalid, see issue #17070 + if (!Ref<Script>(script)->is_valid()) { + signal_is_valid = true; + } + } +#endif } + + ERR_FAIL_COND_V_MSG(!signal_is_valid, ERR_INVALID_PARAMETER, "In Object of type '" + String(get_class()) + "': Attempt to connect nonexistent signal '" + p_signal + "' to method '" + p_to_object->get_class() + "." + p_to_method + "'."); + signal_map[p_signal] = Signal(); s = &signal_map[p_signal]; } @@ -1480,8 +1461,7 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str s->slot_map[target].reference_count++; return OK; } else { - ERR_EXPLAIN("Signal '" + p_signal + "' is already connected to given method '" + p_to_method + "' in that object."); - ERR_FAIL_COND_V(s->slot_map.has(target), ERR_INVALID_PARAMETER); + ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Signal '" + p_signal + "' is already connected to given method '" + p_to_method + "' in that object."); } } @@ -1517,8 +1497,7 @@ bool Object::is_connected(const StringName &p_signal, Object *p_to_object, const if (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)) return false; - ERR_EXPLAIN("Nonexistent signal: " + p_signal); - ERR_FAIL_COND_V(!s, false); + ERR_FAIL_V_MSG(false, "Nonexistent signal: " + p_signal + "."); } Signal::Target target(p_to_object->get_instance_id(), p_to_method); @@ -1536,21 +1515,13 @@ void Object::_disconnect(const StringName &p_signal, Object *p_to_object, const ERR_FAIL_NULL(p_to_object); Signal *s = signal_map.getptr(p_signal); - if (!s) { - ERR_EXPLAIN("Nonexistent signal: " + p_signal); - ERR_FAIL_COND(!s); - } - if (s->lock > 0) { - ERR_EXPLAIN("Attempt to disconnect signal '" + p_signal + "' while emitting (locks: " + itos(s->lock) + ")"); - ERR_FAIL_COND(s->lock > 0); - } + ERR_FAIL_COND_MSG(!s, "Nonexistent signal: " + p_signal + "."); + + ERR_FAIL_COND_MSG(s->lock > 0, "Attempt to disconnect signal '" + p_signal + "' while emitting (locks: " + itos(s->lock) + ")."); Signal::Target target(p_to_object->get_instance_id(), p_to_method); - if (!s->slot_map.has(target)) { - ERR_EXPLAIN("Disconnecting nonexistent signal '" + p_signal + "', slot: " + itos(target._id) + ":" + target.method); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!s->slot_map.has(target), "Disconnecting nonexistent signal '" + p_signal + "', slot: " + itos(target._id) + ":" + target.method + "."); Signal::Slot *slot = &s->slot_map[target]; @@ -1648,7 +1619,8 @@ void Object::_clear_internal_resource_paths(const Variant &p_var) { _clear_internal_resource_paths(d[E->get()]); } } break; - default: {} + default: { + } } } @@ -1684,7 +1656,7 @@ void Object::clear_internal_resource_paths() { void Object::_bind_methods() { ClassDB::bind_method(D_METHOD("get_class"), &Object::get_class); - ClassDB::bind_method(D_METHOD("is_class", "type"), &Object::is_class); + ClassDB::bind_method(D_METHOD("is_class", "class"), &Object::is_class); ClassDB::bind_method(D_METHOD("set", "property", "value"), &Object::_set_bind); ClassDB::bind_method(D_METHOD("get", "property"), &Object::_get_bind); ClassDB::bind_method(D_METHOD("set_indexed", "property", "value"), &Object::_set_indexed_bind); @@ -1692,24 +1664,20 @@ void Object::_bind_methods() { ClassDB::bind_method(D_METHOD("get_property_list"), &Object::_get_property_list_bind); ClassDB::bind_method(D_METHOD("get_method_list"), &Object::_get_method_list_bind); ClassDB::bind_method(D_METHOD("notification", "what", "reversed"), &Object::notification, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("to_string"), &Object::to_string); ClassDB::bind_method(D_METHOD("get_instance_id"), &Object::get_instance_id); ClassDB::bind_method(D_METHOD("set_script", "script"), &Object::set_script); ClassDB::bind_method(D_METHOD("get_script"), &Object::get_script); ClassDB::bind_method(D_METHOD("set_meta", "name", "value"), &Object::set_meta); + ClassDB::bind_method(D_METHOD("remove_meta", "name"), &Object::remove_meta); ClassDB::bind_method(D_METHOD("get_meta", "name"), &Object::get_meta); ClassDB::bind_method(D_METHOD("has_meta", "name"), &Object::has_meta); ClassDB::bind_method(D_METHOD("get_meta_list"), &Object::_get_meta_list_bind); - //todo reimplement this per language so all 5 arguments can be called - - //ClassDB::bind_method(D_METHOD("call","method","arg1","arg2","arg3","arg4"),&Object::_call_bind,DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant())); - //ClassDB::bind_method(D_METHOD("call_deferred","method","arg1","arg2","arg3","arg4"),&Object::_call_deferred_bind,DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant())); - ClassDB::bind_method(D_METHOD("add_user_signal", "signal", "arguments"), &Object::_add_user_signal, DEFVAL(Array())); ClassDB::bind_method(D_METHOD("has_user_signal", "signal"), &Object::_has_user_signal); - //ClassDB::bind_method(D_METHOD("emit_signal","signal","arguments"),&Object::_emit_signal,DEFVAL(Array())); { MethodInfo mi; @@ -1735,6 +1703,8 @@ void Object::_bind_methods() { ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_deferred", &Object::_call_deferred_bind, mi); } + ClassDB::bind_method(D_METHOD("set_deferred", "property", "value"), &Object::set_deferred); + ClassDB::bind_method(D_METHOD("callv", "method", "arg_array"), &Object::callv); ClassDB::bind_method(D_METHOD("has_method", "method"), &Object::has_method); @@ -1776,6 +1746,7 @@ void Object::_bind_methods() { #endif BIND_VMETHOD(MethodInfo("_init")); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_to_string")); BIND_CONSTANT(NOTIFICATION_POSTINITIALIZE); BIND_CONSTANT(NOTIFICATION_PREDELETE); @@ -1791,6 +1762,10 @@ void Object::call_deferred(const StringName &p_method, VARIANT_ARG_DECLARE) { MessageQueue::get_singleton()->push_call(this, p_method, VARIANT_ARG_PASS); } +void Object::set_deferred(const StringName &p_property, const Variant &p_value) { + MessageQueue::get_singleton()->push_set(this, p_property, p_value); +} + void Object::set_block_signals(bool p_block) { _block_signals = p_block; @@ -1926,13 +1901,25 @@ void *Object::get_script_instance_binding(int p_script_language_index) { return _script_instance_bindings[p_script_language_index]; } +bool Object::has_script_instance_binding(int p_script_language_index) { + + return _script_instance_bindings[p_script_language_index] != NULL; +} + +void Object::set_script_instance_binding(int p_script_language_index, void *p_data) { +#ifdef DEBUG_ENABLED + CRASH_COND(_script_instance_bindings[p_script_language_index] != NULL); +#endif + _script_instance_bindings[p_script_language_index] = p_data; +} + Object::Object() { _class_ptr = NULL; _block_signals = false; _predelete_ok = 0; - _instance_ID = 0; - _instance_ID = ObjectDB::add_instance(this); + _instance_id = 0; + _instance_id = ObjectDB::add_instance(this); _can_translate = true; _is_queued_for_deletion = false; instance_binding_count = 0; @@ -1955,30 +1942,27 @@ Object::~Object() { memdelete(script_instance); script_instance = NULL; - List<Connection> sconnections; const StringName *S = NULL; - while ((S = signal_map.next(S))) { + while ((S = signal_map.next(NULL))) { Signal *s = &signal_map[*S]; - ERR_EXPLAIN("Attempt to delete an object in the middle of a signal emission from it"); - ERR_CONTINUE(s->lock > 0); + ERR_CONTINUE_MSG(s->lock > 0, "Attempt to delete an object in the middle of a signal emission from it."); - for (int i = 0; i < s->slot_map.size(); i++) { + //brute force disconnect for performance + int slot_count = s->slot_map.size(); + const VMap<Signal::Target, Signal::Slot>::Pair *slot_list = s->slot_map.get_array(); - sconnections.push_back(s->slot_map.getv(i).conn); - } - } + for (int i = 0; i < slot_count; i++) { - for (List<Connection>::Element *E = sconnections.front(); E; E = E->next()) { - - Connection &c = E->get(); - ERR_CONTINUE(c.source != this); //bug? + slot_list[i].value.conn.target->connections.erase(slot_list[i].value.cE); + } - this->_disconnect(c.signal, c.target, c.method, true); + signal_map.erase(*S); } + //signals from nodes that connect to this node while (connections.size()) { Connection c = connections.front()->get(); @@ -1986,12 +1970,14 @@ Object::~Object() { } ObjectDB::remove_instance(this); - _instance_ID = 0; + _instance_id = 0; _predelete_ok = 2; - for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { - if (_script_instance_bindings[i]) { - ScriptServer::get_language(i)->free_instance_binding_data(_script_instance_bindings[i]); + if (!ScriptServer::are_languages_finished()) { + for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { + if (_script_instance_bindings[i]) { + ScriptServer::get_language(i)->free_instance_binding_data(_script_instance_bindings[i]); + } } } } @@ -2014,11 +2000,13 @@ ObjectID ObjectDB::add_instance(Object *p_object) { ERR_FAIL_COND_V(p_object->get_instance_id() != 0, 0); rw_lock->write_lock(); - instances[++instance_counter] = p_object; - instance_checks[p_object] = instance_counter; + ObjectID instance_id = ++instance_counter; + instances[instance_id] = p_object; + instance_checks[p_object] = instance_id; + rw_lock->write_unlock(); - return instance_counter; + return instance_id; } void ObjectDB::remove_instance(Object *p_object) { @@ -2030,10 +2018,10 @@ void ObjectDB::remove_instance(Object *p_object) { rw_lock->write_unlock(); } -Object *ObjectDB::get_instance(ObjectID p_instance_ID) { +Object *ObjectDB::get_instance(ObjectID p_instance_id) { rw_lock->read_lock(); - Object **obj = instances.getptr(p_instance_ID); + Object **obj = instances.getptr(p_instance_id); rw_lock->read_unlock(); if (!obj) @@ -2095,6 +2083,5 @@ void ObjectDB::cleanup() { instances.clear(); instance_checks.clear(); rw_lock->write_unlock(); - memdelete(rw_lock); } |