summaryrefslogtreecommitdiff
path: root/core/object.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/object.cpp')
-rw-r--r--core/object.cpp135
1 files changed, 111 insertions, 24 deletions
diff --git a/core/object.cpp b/core/object.cpp
index aaa37e6cf2..76226d113a 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -450,16 +450,41 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
*r_valid = true;
return;
#endif
- } else {
- //something inside the object... :|
- bool success = _setv(p_name, p_value);
- if (success) {
+ }
+
+ //something inside the object... :|
+ bool success = _setv(p_name, p_value);
+ if (success) {
+ if (r_valid)
+ *r_valid = true;
+ return;
+ }
+
+ {
+ bool valid;
+ setvar(p_name, p_value, &valid);
+ if (valid) {
+ if (r_valid)
+ *r_valid = true;
+ return;
+ }
+ }
+
+#ifdef TOOLS_ENABLED
+ if (script_instance) {
+ bool valid;
+ script_instance->property_set_fallback(p_name, p_value, &valid);
+ if (valid) {
if (r_valid)
*r_valid = true;
return;
}
- setvar(p_name, p_value, r_valid);
}
+#endif
+
+ if (r_valid)
+ *r_valid = false;
+ return;
}
Variant Object::get(const StringName &p_name, bool *r_valid) const {
@@ -513,8 +538,33 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
*r_valid = true;
return ret;
}
+
//if nothing else, use getvar
- return getvar(p_name, r_valid);
+ {
+ bool valid;
+ ret = getvar(p_name, &valid);
+ if (valid) {
+ if (r_valid)
+ *r_valid = true;
+ return ret;
+ }
+ }
+
+#ifdef TOOLS_ENABLED
+ if (script_instance) {
+ bool valid;
+ ret = script_instance->property_get_fallback(p_name, &valid);
+ if (valid) {
+ if (r_valid)
+ *r_valid = true;
+ return ret;
+ }
+ }
+#endif
+
+ if (r_valid)
+ *r_valid = false;
+ return Variant();
}
}
@@ -601,8 +651,12 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
_get_property_listv(p_list, p_reversed);
- if (!is_class("Script")) // can still be set, but this is for userfriendlyness
+ if (!is_class("Script")) { // can still be set, but this is for userfriendlyness
+#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));
+ }
#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));
@@ -814,8 +868,8 @@ Variant Object::callv(const StringName &p_method, const Array &p_args) {
argptrs.resize(p_args.size());
for (int i = 0; i < p_args.size(); i++) {
- args[i] = p_args[i];
- argptrs[i] = &args[i];
+ args.write[i] = p_args[i];
+ argptrs.write[i] = &args[i];
}
Variant::CallError ce;
@@ -975,9 +1029,14 @@ void Object::set_script(const RefPtr &p_script) {
script = p_script;
Ref<Script> s(script);
- if (!s.is_null() && s->can_instance()) {
- OBJ_DEBUG_LOCK
- script_instance = s->instance_create(this);
+ if (!s.is_null()) {
+ if (s->can_instance()) {
+ OBJ_DEBUG_LOCK
+ script_instance = s->instance_create(this);
+ } else if (Engine::get_singleton()->is_editor_hint()) {
+ OBJ_DEBUG_LOCK
+ script_instance = s->placeholder_instance_create(this);
+ }
}
_change_notify("script");
@@ -1178,10 +1237,10 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int
bind_mem.resize(p_argcount + c.binds.size());
for (int j = 0; j < p_argcount; j++) {
- bind_mem[j] = p_args[j];
+ bind_mem.write[j] = p_args[j];
}
for (int j = 0; j < c.binds.size(); j++) {
- bind_mem[p_argcount + j] = &c.binds[j];
+ bind_mem.write[p_argcount + j] = &c.binds[j];
}
args = (const Variant **)bind_mem.ptr();
@@ -1205,7 +1264,15 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int
}
}
- if (c.flags & CONNECT_ONESHOT) {
+ 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
+ disconnect = false;
+ }
+#endif
+ if (disconnect) {
+
_ObjectSignalDisconnectData dd;
dd.signal = p_name;
dd.target = target;
@@ -1409,8 +1476,13 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str
Signal::Target target(p_to_object->get_instance_id(), p_to_method);
if (s->slot_map.has(target)) {
- 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);
+ if (p_flags & CONNECT_REFERENCE_COUNTED) {
+ 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);
+ }
}
Signal::Slot slot;
@@ -1424,6 +1496,10 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str
conn.binds = p_binds;
slot.conn = conn;
slot.cE = p_to_object->connections.push_back(conn);
+ if (p_flags & CONNECT_REFERENCE_COUNTED) {
+ slot.reference_count = 1;
+ }
+
s->slot_map[target] = slot;
return OK;
@@ -1454,6 +1530,10 @@ bool Object::is_connected(const StringName &p_signal, Object *p_to_object, const
void Object::disconnect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) {
+ _disconnect(p_signal, p_to_object, p_to_method);
+}
+void Object::_disconnect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, bool p_force) {
+
ERR_FAIL_NULL(p_to_object);
Signal *s = signal_map.getptr(p_signal);
if (!s) {
@@ -1472,7 +1552,16 @@ void Object::disconnect(const StringName &p_signal, Object *p_to_object, const S
ERR_FAIL();
}
- p_to_object->connections.erase(s->slot_map[target].cE);
+ Signal::Slot *slot = &s->slot_map[target];
+
+ if (!p_force) {
+ slot->reference_count--; // by default is zero, if it was not referenced it will go below it
+ if (slot->reference_count >= 0) {
+ return;
+ }
+ }
+
+ p_to_object->connections.erase(slot->cE);
s->slot_map.erase(target);
if (s->slot_map.empty() && ClassDB::has_signal(get_class_name(), p_signal)) {
@@ -1677,6 +1766,7 @@ void Object::_bind_methods() {
#ifdef TOOLS_ENABLED
MethodInfo miget("_get", PropertyInfo(Variant::STRING, "property"));
miget.return_val.name = "Variant";
+ miget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
BIND_VMETHOD(miget);
MethodInfo plget("_get_property_list");
@@ -1693,6 +1783,7 @@ void Object::_bind_methods() {
BIND_ENUM_CONSTANT(CONNECT_DEFERRED);
BIND_ENUM_CONSTANT(CONNECT_PERSIST);
BIND_ENUM_CONSTANT(CONNECT_ONESHOT);
+ BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);
}
void Object::call_deferred(const StringName &p_method, VARIANT_ARG_DECLARE) {
@@ -1880,13 +1971,13 @@ Object::~Object() {
Connection &c = E->get();
ERR_CONTINUE(c.source != this); //bug?
- this->disconnect(c.signal, c.target, c.method);
+ this->_disconnect(c.signal, c.target, c.method, true);
}
while (connections.size()) {
Connection c = connections.front()->get();
- c.source->disconnect(c.signal, c.target, c.method);
+ c.source->_disconnect(c.signal, c.target, c.method, true);
}
ObjectDB::remove_instance(this);
@@ -1919,9 +2010,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) {
rw_lock->write_lock();
instances[++instance_counter] = p_object;
-#ifdef DEBUG_ENABLED
instance_checks[p_object] = instance_counter;
-#endif
rw_lock->write_unlock();
return instance_counter;
@@ -1932,9 +2021,7 @@ void ObjectDB::remove_instance(Object *p_object) {
rw_lock->write_lock();
instances.erase(p_object->get_instance_id());
-#ifdef DEBUG_ENABLED
instance_checks.erase(p_object);
-#endif
rw_lock->write_unlock();
}