1 /*************************************************************************/
2 /*  object.cpp                                                           */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 #include "object.h"
31 #include "core_string_names.h"
32 #include "message_queue.h"
33 #include "object_type_db.h"
34 #include "os/os.h"
35 #include "print_string.h"
36 #include "resource.h"
37 #include "script_language.h"
38 #include "translation.h"
39 
40 #ifdef DEBUG_ENABLED
41 
42 struct _ObjectDebugLock {
43 
44 	Object *obj;
45 
_ObjectDebugLock_ObjectDebugLock46 	_ObjectDebugLock(Object *p_obj) {
47 		obj = p_obj;
48 		obj->_lock_index.ref();
49 	}
~_ObjectDebugLock_ObjectDebugLock50 	~_ObjectDebugLock() {
51 		obj->_lock_index.unref();
52 	}
53 };
54 
55 #define OBJ_DEBUG_LOCK _ObjectDebugLock _debug_lock(this);
56 
57 #else
58 
59 #define OBJ_DEBUG_LOCK
60 
61 #endif
62 
convert_property_list(const List<PropertyInfo> * p_list)63 Array convert_property_list(const List<PropertyInfo> *p_list) {
64 
65 	Array va;
66 	for (const List<PropertyInfo>::Element *E = p_list->front(); E; E = E->next()) {
67 
68 		const PropertyInfo &pi = E->get();
69 		Dictionary d;
70 		d["name"] = pi.name;
71 		d["type"] = pi.type;
72 		d["hint"] = pi.hint;
73 		d["hint_string"] = pi.hint_string;
74 		d["usage"] = pi.usage;
75 		va.push_back(d);
76 	}
77 
78 	return va;
79 }
80 
MethodInfo()81 MethodInfo::MethodInfo() {
82 
83 	id = 0;
84 	flags = METHOD_FLAG_NORMAL;
85 }
86 
MethodInfo(const String & p_name)87 MethodInfo::MethodInfo(const String &p_name) {
88 
89 	id = 0;
90 	name = p_name;
91 	flags = METHOD_FLAG_NORMAL;
92 }
MethodInfo(const String & p_name,const PropertyInfo & p_param1)93 MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1) {
94 
95 	id = 0;
96 	name = p_name;
97 	arguments.push_back(p_param1);
98 	flags = METHOD_FLAG_NORMAL;
99 }
MethodInfo(const String & p_name,const PropertyInfo & p_param1,const PropertyInfo & p_param2)100 MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2) {
101 
102 	id = 0;
103 	name = p_name;
104 	arguments.push_back(p_param1);
105 	arguments.push_back(p_param2);
106 	flags = METHOD_FLAG_NORMAL;
107 }
108 
MethodInfo(const String & p_name,const PropertyInfo & p_param1,const PropertyInfo & p_param2,const PropertyInfo & p_param3)109 MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3) {
110 
111 	id = 0;
112 	name = p_name;
113 	arguments.push_back(p_param1);
114 	arguments.push_back(p_param2);
115 	arguments.push_back(p_param3);
116 	flags = METHOD_FLAG_NORMAL;
117 }
118 
MethodInfo(const String & p_name,const PropertyInfo & p_param1,const PropertyInfo & p_param2,const PropertyInfo & p_param3,const PropertyInfo & p_param4)119 MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4) {
120 
121 	id = 0;
122 	name = p_name;
123 	arguments.push_back(p_param1);
124 	arguments.push_back(p_param2);
125 	arguments.push_back(p_param3);
126 	arguments.push_back(p_param4);
127 	flags = METHOD_FLAG_NORMAL;
128 }
129 
MethodInfo(const String & p_name,const PropertyInfo & p_param1,const PropertyInfo & p_param2,const PropertyInfo & p_param3,const PropertyInfo & p_param4,const PropertyInfo & p_param5)130 MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5) {
131 	id = 0;
132 	name = p_name;
133 	arguments.push_back(p_param1);
134 	arguments.push_back(p_param2);
135 	arguments.push_back(p_param3);
136 	arguments.push_back(p_param4);
137 	arguments.push_back(p_param5);
138 	flags = METHOD_FLAG_NORMAL;
139 }
140 
MethodInfo(Variant::Type ret)141 MethodInfo::MethodInfo(Variant::Type ret) {
142 
143 	id = 0;
144 	flags = METHOD_FLAG_NORMAL;
145 	return_val.type = ret;
146 }
147 
MethodInfo(Variant::Type ret,const String & p_name)148 MethodInfo::MethodInfo(Variant::Type ret, const String &p_name) {
149 
150 	id = 0;
151 	name = p_name;
152 	flags = METHOD_FLAG_NORMAL;
153 	return_val.type = ret;
154 }
MethodInfo(Variant::Type ret,const String & p_name,const PropertyInfo & p_param1)155 MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1) {
156 
157 	id = 0;
158 	name = p_name;
159 	arguments.push_back(p_param1);
160 	flags = METHOD_FLAG_NORMAL;
161 	return_val.type = ret;
162 }
MethodInfo(Variant::Type ret,const String & p_name,const PropertyInfo & p_param1,const PropertyInfo & p_param2)163 MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2) {
164 
165 	id = 0;
166 	name = p_name;
167 	arguments.push_back(p_param1);
168 	arguments.push_back(p_param2);
169 	flags = METHOD_FLAG_NORMAL;
170 	return_val.type = ret;
171 }
172 
MethodInfo(Variant::Type ret,const String & p_name,const PropertyInfo & p_param1,const PropertyInfo & p_param2,const PropertyInfo & p_param3)173 MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3) {
174 
175 	id = 0;
176 	name = p_name;
177 	arguments.push_back(p_param1);
178 	arguments.push_back(p_param2);
179 	arguments.push_back(p_param3);
180 	flags = METHOD_FLAG_NORMAL;
181 	return_val.type = ret;
182 }
183 
MethodInfo(Variant::Type ret,const String & p_name,const PropertyInfo & p_param1,const PropertyInfo & p_param2,const PropertyInfo & p_param3,const PropertyInfo & p_param4)184 MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4) {
185 
186 	id = 0;
187 	name = p_name;
188 	arguments.push_back(p_param1);
189 	arguments.push_back(p_param2);
190 	arguments.push_back(p_param3);
191 	arguments.push_back(p_param4);
192 	flags = METHOD_FLAG_NORMAL;
193 	return_val.type = ret;
194 }
195 
MethodInfo(Variant::Type ret,const String & p_name,const PropertyInfo & p_param1,const PropertyInfo & p_param2,const PropertyInfo & p_param3,const PropertyInfo & p_param4,const PropertyInfo & p_param5)196 MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5) {
197 	id = 0;
198 	name = p_name;
199 	arguments.push_back(p_param1);
200 	arguments.push_back(p_param2);
201 	arguments.push_back(p_param3);
202 	arguments.push_back(p_param4);
203 	arguments.push_back(p_param5);
204 	flags = METHOD_FLAG_NORMAL;
205 	return_val.type = ret;
206 }
207 
operator Variant() const208 Object::Connection::operator Variant() const {
209 
210 	Dictionary d;
211 	d["source"] = source;
212 	d["signal"] = signal;
213 	d["target"] = target;
214 	d["method"] = method;
215 	d["flags"] = flags;
216 	d["binds"] = binds;
217 	return d;
218 }
219 
operator <(const Connection & p_conn) const220 bool Object::Connection::operator<(const Connection &p_conn) const {
221 
222 	if (source == p_conn.source) {
223 
224 		if (signal == p_conn.signal) {
225 
226 			if (target == p_conn.target) {
227 
228 				return method < p_conn.method;
229 			} else {
230 
231 				return target < p_conn.target;
232 			}
233 		} else
234 			return signal < p_conn.signal;
235 	} else {
236 		return source < p_conn.source;
237 	}
238 }
Connection(const Variant & p_variant)239 Object::Connection::Connection(const Variant &p_variant) {
240 
241 	Dictionary d = p_variant;
242 	if (d.has("source"))
243 		source = d["source"];
244 	if (d.has("signal"))
245 		signal = d["signal"];
246 	if (d.has("target"))
247 		target = d["target"];
248 	if (d.has("method"))
249 		method = d["method"];
250 	if (d.has("flags"))
251 		flags = d["flags"];
252 	if (d.has("binds"))
253 		binds = d["binds"];
254 }
255 
_predelete()256 bool Object::_predelete() {
257 
258 	_predelete_ok = 1;
259 	notification(NOTIFICATION_PREDELETE, true);
260 	if (_predelete_ok) {
261 		_type_ptr = NULL; //must restore so destructors can access type ptr correctly
262 	}
263 	return _predelete_ok;
264 }
265 
_postinitialize()266 void Object::_postinitialize() {
267 	_type_ptr = _get_type_namev();
268 	_initialize_typev();
269 	notification(NOTIFICATION_POSTINITIALIZE);
270 }
271 
get_valid_parents_static(List<String> * p_parents)272 void Object::get_valid_parents_static(List<String> *p_parents) {
273 }
_get_valid_parents_static(List<String> * p_parents)274 void Object::_get_valid_parents_static(List<String> *p_parents) {
275 }
276 #if 0
277 //old style set, deprecated
278 
279 void Object::set(const String& p_name, const Variant& p_value) {
280 
281 	_setv(p_name,p_value);
282 
283 	//if (!_use_builtin_script())
284 //		return;
285 
286 	bool success;
287 	ObjectTypeDB::set_property(this,p_name,p_value,success);
288 	if (success) {
289 		return;
290 	}
291 
292 	if (p_name=="__meta__") {
293 		metadata=p_value;
294 	} else if (p_name=="script/script") {
295 		set_script(p_value);
296 	} else if (script_instance) {
297 		script_instance->set(p_name,p_value);
298 	}
299 
300 
301 }
302 #endif
303 
set(const StringName & p_name,const Variant & p_value,bool * r_valid)304 void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid) {
305 
306 #ifdef TOOLS_ENABLED
307 
308 	_edited = true;
309 #endif
310 
311 	if (script_instance) {
312 
313 		if (script_instance->set(p_name, p_value)) {
314 			if (r_valid)
315 				*r_valid = true;
316 			return;
317 		}
318 	}
319 
320 	//try built-in setgetter
321 	{
322 		if (ObjectTypeDB::set_property(this, p_name, p_value, r_valid)) {
323 			//if (r_valid)
324 			//	*r_valid=true;
325 			return;
326 		}
327 	}
328 
329 	if (p_name == CoreStringNames::get_singleton()->_script) {
330 		set_script(p_value);
331 		if (r_valid)
332 			*r_valid = true;
333 		return;
334 
335 	} else if (p_name == CoreStringNames::get_singleton()->_meta) {
336 		//set_meta(p_name,p_value);
337 		metadata = p_value;
338 		if (r_valid)
339 			*r_valid = true;
340 		return;
341 	} else {
342 		//something inside the object... :|
343 		bool success = _setv(p_name, p_value);
344 		if (success) {
345 			if (r_valid)
346 				*r_valid = true;
347 			return;
348 		}
349 		setvar(p_name, p_value, r_valid);
350 	}
351 }
352 
get(const StringName & p_name,bool * r_valid) const353 Variant Object::get(const StringName &p_name, bool *r_valid) const {
354 
355 	Variant ret;
356 
357 	if (script_instance) {
358 
359 		if (script_instance->get(p_name, ret)) {
360 			if (r_valid)
361 				*r_valid = true;
362 			return ret;
363 		}
364 	}
365 
366 	//try built-in setgetter
367 	{
368 		if (ObjectTypeDB::get_property(const_cast<Object *>(this), p_name, ret)) {
369 			if (r_valid)
370 				*r_valid = true;
371 			return ret;
372 		}
373 	}
374 
375 	if (p_name == CoreStringNames::get_singleton()->_script) {
376 		ret = get_script();
377 		if (r_valid)
378 			*r_valid = true;
379 		return ret;
380 
381 	} else if (p_name == CoreStringNames::get_singleton()->_meta) {
382 		ret = metadata;
383 		if (r_valid)
384 			*r_valid = true;
385 		return ret;
386 	} else {
387 		//something inside the object... :|
388 		bool success = _getv(p_name, ret);
389 		if (success) {
390 			if (r_valid)
391 				*r_valid = true;
392 			return ret;
393 		}
394 		//if nothing else, use getvar
395 		return getvar(p_name, r_valid);
396 	}
397 }
398 
399 #if 0
400 //old style get, deprecated
401 Variant Object::get(const String& p_name) const {
402 
403 	Variant ret=_getv(p_name);
404 	if (ret.get_type()!=Variant::NIL)
405 		return ret;
406 
407 	bool success;
408 	ObjectTypeDB::get_property(const_cast<Object*>(this),p_name,ret,success);
409 	if (success) {
410 		return ret;
411 	}
412 
413 	if (p_name=="__meta__")
414 		return metadata;
415 	else if (p_name=="script/script")
416 		return script;
417 
418 	if (script_instance) {
419 		return script_instance->get(p_name);
420 	}
421 
422 	return Variant();
423 
424 }
425 #endif
426 
get_property_list(List<PropertyInfo> * p_list,bool p_reversed) const427 void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) const {
428 
429 	if (script_instance && p_reversed) {
430 		p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
431 		script_instance->get_property_list(p_list);
432 	}
433 
434 	_get_property_listv(p_list, p_reversed);
435 
436 	if (!_use_builtin_script())
437 		return;
438 
439 	if (!is_type("Script")) // can still be set, but this is for userfriendlyness
440 		p_list->push_back(PropertyInfo(Variant::OBJECT, "script/script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NONZERO));
441 	if (!metadata.empty())
442 		p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_STORE_IF_NONZERO));
443 	if (script_instance && !p_reversed) {
444 		p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
445 		script_instance->get_property_list(p_list);
446 	}
447 }
448 
_validate_property(PropertyInfo & property) const449 void Object::_validate_property(PropertyInfo &property) const {
450 }
451 
get_method_list(List<MethodInfo> * p_list) const452 void Object::get_method_list(List<MethodInfo> *p_list) const {
453 
454 	ObjectTypeDB::get_method_list(get_type_name(), p_list);
455 	if (script_instance) {
456 		script_instance->get_method_list(p_list);
457 	}
458 }
459 
_call_bind(const Variant ** p_args,int p_argcount,Variant::CallError & r_error)460 Variant Object::_call_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
461 
462 	if (p_argcount < 1) {
463 		r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
464 		r_error.argument = 0;
465 		return Variant();
466 	}
467 
468 	if (p_args[0]->get_type() != Variant::STRING) {
469 		r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
470 		r_error.argument = 0;
471 		r_error.expected = Variant::STRING;
472 		return Variant();
473 	}
474 
475 	StringName method = *p_args[0];
476 
477 	return call(method, &p_args[1], p_argcount - 1, r_error);
478 }
479 
_call_deferred_bind(const Variant ** p_args,int p_argcount,Variant::CallError & r_error)480 Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
481 
482 	if (p_argcount < 1) {
483 		r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
484 		r_error.argument = 0;
485 		return Variant();
486 	}
487 
488 	if (p_args[0]->get_type() != Variant::STRING) {
489 		r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
490 		r_error.argument = 0;
491 		r_error.expected = Variant::STRING;
492 		return Variant();
493 	}
494 
495 	r_error.error = Variant::CallError::CALL_OK;
496 
497 	StringName method = *p_args[0];
498 
499 	MessageQueue::get_singleton()->push_call(get_instance_ID(), method, &p_args[1], p_argcount - 1);
500 
501 	return Variant();
502 }
503 
504 #if 0
505 Variant Object::_call_bind(const StringName& p_name, const Variant& p_arg1, const Variant& p_arg2, const Variant& p_arg3, const Variant& p_arg4) {
506 
507 	ERR_FAIL_COND_V(p_argcount<1,Variant());
508 
509 	return call(p_name, p_arg1, p_arg2, p_arg3, p_arg4);
510 };
511 
512 
513 
514 
515 void Object::_call_deferred_bind(const StringName& p_name, const Variant& p_arg1, const Variant& p_arg2, const Variant& p_arg3, const Variant& p_arg4) {
516 
517 	call_deferred(p_name, p_arg1, p_arg2, p_arg3, p_arg4);
518 };
519 #endif
520 #ifdef DEBUG_ENABLED
_test_call_error(const StringName & p_func,const Variant::CallError & error)521 static bool _test_call_error(const StringName &p_func, const Variant::CallError &error) {
522 
523 	switch (error.error) {
524 
525 		case Variant::CallError::CALL_OK:
526 			return true;
527 		case Variant::CallError::CALL_ERROR_INVALID_METHOD:
528 			return false;
529 		case Variant::CallError::CALL_ERROR_INVALID_ARGUMENT: {
530 
531 			ERR_EXPLAIN("Error Calling Function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(error.expected));
532 			ERR_FAIL_V(true);
533 		} break;
534 		case Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: {
535 
536 			ERR_EXPLAIN("Error Calling Function: " + String(p_func) + " - Too many arguments, expected " + itos(error.argument));
537 			ERR_FAIL_V(true);
538 
539 		} break;
540 		case Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: {
541 
542 			ERR_EXPLAIN("Error Calling Function: " + String(p_func) + " - Too few arguments, expected " + itos(error.argument));
543 			ERR_FAIL_V(true);
544 
545 		} break;
546 		case Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
547 		} //?
548 	}
549 
550 	return true;
551 }
552 #else
553 
554 #define _test_call_error(m_str, m_err) ((m_err.error == Variant::CallError::CALL_ERROR_INVALID_METHOD) ? false : true)
555 
556 #endif
557 
call_multilevel(const StringName & p_method,const Variant ** p_args,int p_argcount)558 void Object::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
559 
560 	if (p_method == CoreStringNames::get_singleton()->_free) {
561 #ifdef DEBUG_ENABLED
562 		if (cast_to<Reference>()) {
563 			ERR_EXPLAIN("Can't 'free' a reference.");
564 			ERR_FAIL();
565 			return;
566 		}
567 
568 		if (_lock_index.get() > 1) {
569 			ERR_EXPLAIN("Object is locked and can't be freed.");
570 			ERR_FAIL();
571 			return;
572 		}
573 #endif
574 
575 		//must be here, must be before everything,
576 		memdelete(this);
577 		return;
578 	}
579 
580 	//Variant ret;
581 	OBJ_DEBUG_LOCK
582 
583 	Variant::CallError error;
584 
585 	if (script_instance) {
586 		script_instance->call_multilevel(p_method, p_args, p_argcount);
587 		//_test_call_error(p_method,error);
588 	}
589 
590 	MethodBind *method = ObjectTypeDB::get_method(get_type_name(), p_method);
591 
592 	if (method) {
593 
594 		method->call(this, p_args, p_argcount, error);
595 		_test_call_error(p_method, error);
596 	}
597 }
598 
call_multilevel_reversed(const StringName & p_method,const Variant ** p_args,int p_argcount)599 void Object::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
600 
601 	MethodBind *method = ObjectTypeDB::get_method(get_type_name(), p_method);
602 
603 	Variant::CallError error;
604 	OBJ_DEBUG_LOCK
605 
606 	if (method) {
607 
608 		method->call(this, p_args, p_argcount, error);
609 		_test_call_error(p_method, error);
610 	}
611 
612 	//Variant ret;
613 
614 	if (script_instance) {
615 		script_instance->call_multilevel_reversed(p_method, p_args, p_argcount);
616 		//_test_call_error(p_method,error);
617 	}
618 }
619 
has_method(const StringName & p_method) const620 bool Object::has_method(const StringName &p_method) const {
621 
622 	if (p_method == CoreStringNames::get_singleton()->_free) {
623 		return true;
624 	}
625 
626 	if (script_instance && script_instance->has_method(p_method)) {
627 		return true;
628 	}
629 
630 	MethodBind *method = ObjectTypeDB::get_method(get_type_name(), p_method);
631 
632 	if (method) {
633 		return true;
634 	}
635 
636 	return false;
637 }
638 
getvar(const Variant & p_key,bool * r_valid) const639 Variant Object::getvar(const Variant &p_key, bool *r_valid) const {
640 
641 	if (r_valid)
642 		*r_valid = false;
643 	return Variant();
644 }
setvar(const Variant & p_key,const Variant & p_value,bool * r_valid)645 void Object::setvar(const Variant &p_key, const Variant &p_value, bool *r_valid) {
646 
647 	if (r_valid)
648 		*r_valid = false;
649 }
650 
callv(const StringName & p_method,const Array & p_args)651 Variant Object::callv(const StringName &p_method, const Array &p_args) {
652 
653 	if (p_args.size() == 0) {
654 		return call(p_method);
655 	}
656 
657 	Vector<Variant> args;
658 	args.resize(p_args.size());
659 	Vector<const Variant *> argptrs;
660 	argptrs.resize(p_args.size());
661 
662 	for (int i = 0; i < p_args.size(); i++) {
663 		args[i] = p_args[i];
664 		argptrs[i] = &args[i];
665 	}
666 
667 	Variant::CallError ce;
668 	return call(p_method, argptrs.ptr(), p_args.size(), ce);
669 }
670 
call(const StringName & p_name,VARIANT_ARG_DECLARE)671 Variant Object::call(const StringName &p_name, VARIANT_ARG_DECLARE) {
672 #if 0
673 	if (p_name==CoreStringNames::get_singleton()->_free) {
674 #ifdef DEBUG_ENABLED
675 		if (cast_to<Reference>()) {
676 			ERR_EXPLAIN("Can't 'free' a reference.");
677 			ERR_FAIL_V(Variant());
678 		}
679 #endif
680 		//must be here, must be before everything,
681 		memdelete(this);
682 		return Variant();
683 	}
684 
685 	VARIANT_ARGPTRS;
686 
687 	int argc=0;
688 	for(int i=0;i<VARIANT_ARG_MAX;i++) {
689 		if (argptr[i]->get_type()==Variant::NIL)
690 			break;
691 		argc++;
692 	}
693 
694 	Variant::CallError error;
695 
696 	Variant ret;
697 
698 	if (script_instance) {
699 		ret = script_instance->call(p_name,argptr,argc,error);
700 		if (_test_call_error(p_name,error))
701 			return ret;
702 	}
703 
704 	MethodBind *method=ObjectTypeDB::get_method(get_type_name(),p_name);
705 
706 	if (method) {
707 
708 
709 		Variant ret = method->call(this,argptr,argc,error);
710 		if (_test_call_error(p_name,error))
711 			return ret;
712 
713 		return ret;
714 	} else {
715 
716 	}
717 
718 	return Variant();
719 #else
720 
721 	VARIANT_ARGPTRS;
722 
723 	int argc = 0;
724 	for (int i = 0; i < VARIANT_ARG_MAX; i++) {
725 		if (argptr[i]->get_type() == Variant::NIL)
726 			break;
727 		argc++;
728 	}
729 
730 	Variant::CallError error;
731 
732 	Variant ret = call(p_name, argptr, argc, error);
733 	return ret;
734 
735 #endif
736 }
737 
call_multilevel(const StringName & p_name,VARIANT_ARG_DECLARE)738 void Object::call_multilevel(const StringName &p_name, VARIANT_ARG_DECLARE) {
739 #if 0
740 	if (p_name==CoreStringNames::get_singleton()->_free) {
741 #ifdef DEBUG_ENABLED
742 		if (cast_to<Reference>()) {
743 			ERR_EXPLAIN("Can't 'free' a reference.");
744 			ERR_FAIL();
745 			return;
746 		}
747 #endif
748 		//must be here, must be before everything,
749 		memdelete(this);
750 		return;
751 	}
752 
753 	VARIANT_ARGPTRS;
754 
755 	int argc=0;
756 	for(int i=0;i<VARIANT_ARG_MAX;i++) {
757 		if (argptr[i]->get_type()==Variant::NIL)
758 			break;
759 		argc++;
760 	}
761 
762 	Variant::CallError error;
763 
764 	if (script_instance) {
765 		script_instance->call(p_name,argptr,argc,error);
766 		_test_call_error(p_name,error);
767 
768 	}
769 
770 	MethodBind *method=ObjectTypeDB::get_method(get_type_name(),p_name);
771 
772 	if (method) {
773 
774 		method->call(this,argptr,argc,error);
775 		_test_call_error(p_name,error);
776 
777 	}
778 
779 #else
780 
781 	VARIANT_ARGPTRS;
782 
783 	int argc = 0;
784 	for (int i = 0; i < VARIANT_ARG_MAX; i++) {
785 		if (argptr[i]->get_type() == Variant::NIL)
786 			break;
787 		argc++;
788 	}
789 
790 	//Variant::CallError error;
791 	call_multilevel(p_name, argptr, argc);
792 
793 #endif
794 }
795 
call(const StringName & p_method,const Variant ** p_args,int p_argcount,Variant::CallError & r_error)796 Variant Object::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
797 
798 	r_error.error = Variant::CallError::CALL_OK;
799 
800 	if (p_method == CoreStringNames::get_singleton()->_free) {
801 //free must be here, before anything, always ready
802 #ifdef DEBUG_ENABLED
803 		if (p_argcount != 0) {
804 			r_error.argument = 0;
805 			r_error.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
806 			return Variant();
807 		}
808 		if (cast_to<Reference>()) {
809 			r_error.argument = 0;
810 			r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
811 			ERR_EXPLAIN("Can't 'free' a reference.");
812 			ERR_FAIL_V(Variant());
813 		}
814 
815 		if (_lock_index.get() > 1) {
816 			r_error.argument = 0;
817 			r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
818 			ERR_EXPLAIN("Object is locked and can't be freed.");
819 			ERR_FAIL_V(Variant());
820 		}
821 
822 #endif
823 		//must be here, must be before everything,
824 		memdelete(this);
825 		r_error.error = Variant::CallError::CALL_OK;
826 		return Variant();
827 	}
828 
829 	Variant ret;
830 	OBJ_DEBUG_LOCK
831 	if (script_instance) {
832 		ret = script_instance->call(p_method, p_args, p_argcount, r_error);
833 		//force jumptable
834 		switch (r_error.error) {
835 
836 			case Variant::CallError::CALL_OK:
837 				return ret;
838 			case Variant::CallError::CALL_ERROR_INVALID_METHOD:
839 				break;
840 			case Variant::CallError::CALL_ERROR_INVALID_ARGUMENT:
841 			case Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
842 			case Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
843 				return ret;
844 			case Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
845 			}
846 		}
847 	}
848 
849 	MethodBind *method = ObjectTypeDB::get_method(get_type_name(), p_method);
850 
851 	if (method) {
852 
853 		ret = method->call(this, p_args, p_argcount, r_error);
854 	} else {
855 		r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
856 	}
857 
858 	return ret;
859 }
860 
notification(int p_notification,bool p_reversed)861 void Object::notification(int p_notification, bool p_reversed) {
862 
863 	_notificationv(p_notification, p_reversed);
864 
865 	if (script_instance) {
866 		script_instance->notification(p_notification);
867 	}
868 }
869 
_changed_callback(Object * p_changed,const char * p_prop)870 void Object::_changed_callback(Object *p_changed, const char *p_prop) {
871 }
872 
add_change_receptor(Object * p_receptor)873 void Object::add_change_receptor(Object *p_receptor) {
874 
875 	change_receptors.insert(p_receptor);
876 }
877 
remove_change_receptor(Object * p_receptor)878 void Object::remove_change_receptor(Object *p_receptor) {
879 
880 	change_receptors.erase(p_receptor);
881 }
882 
property_list_changed_notify()883 void Object::property_list_changed_notify() {
884 
885 	_change_notify();
886 }
887 
cancel_delete()888 void Object::cancel_delete() {
889 
890 	_predelete_ok = true;
891 }
892 
set_script(const RefPtr & p_script)893 void Object::set_script(const RefPtr &p_script) {
894 
895 	if (script == p_script)
896 		return;
897 
898 	if (script_instance) {
899 		memdelete(script_instance);
900 		script_instance = NULL;
901 	}
902 
903 	script = p_script;
904 	Ref<Script> s(script);
905 
906 	if (!s.is_null() && s->can_instance()) {
907 		OBJ_DEBUG_LOCK
908 		script_instance = s->instance_create(this);
909 	}
910 
911 	_change_notify("script/script");
912 	emit_signal(CoreStringNames::get_singleton()->script_changed);
913 }
914 
set_script_instance(ScriptInstance * p_instance)915 void Object::set_script_instance(ScriptInstance *p_instance) {
916 
917 	if (script_instance == p_instance)
918 		return;
919 
920 	if (script_instance)
921 		memdelete(script_instance);
922 
923 	script_instance = p_instance;
924 
925 	if (p_instance)
926 		script = p_instance->get_script().get_ref_ptr();
927 	else
928 		script = RefPtr();
929 }
930 
get_script() const931 RefPtr Object::get_script() const {
932 
933 	return script;
934 }
935 
has_meta(const String & p_name) const936 bool Object::has_meta(const String &p_name) const {
937 
938 	return metadata.has(p_name);
939 }
940 
set_meta(const String & p_name,const Variant & p_value)941 void Object::set_meta(const String &p_name, const Variant &p_value) {
942 
943 	if (p_value.get_type() == Variant::NIL) {
944 		metadata.erase(p_name);
945 		return;
946 	};
947 
948 	metadata[p_name] = p_value;
949 }
950 
get_meta(const String & p_name) const951 Variant Object::get_meta(const String &p_name) const {
952 
953 	ERR_FAIL_COND_V(!metadata.has(p_name), Variant());
954 	return metadata[p_name];
955 }
956 
_get_property_list_bind() const957 Array Object::_get_property_list_bind() const {
958 
959 	List<PropertyInfo> lpi;
960 	get_property_list(&lpi);
961 	return convert_property_list(&lpi);
962 }
963 
_get_dict_from_method(const MethodInfo & mi)964 static Dictionary _get_dict_from_method(const MethodInfo &mi) {
965 
966 	Dictionary d;
967 	d["name"] = mi.name;
968 	d["args"] = convert_property_list(&mi.arguments);
969 	Array da;
970 	for (int i = 0; i < mi.default_arguments.size(); i++)
971 		da.push_back(mi.default_arguments[i]);
972 	d["default_args"] = da;
973 	d["flags"] = mi.flags;
974 	d["id"] = mi.id;
975 	Dictionary r;
976 	r["type"] = mi.return_val.type;
977 	r["hint"] = mi.return_val.hint;
978 	r["hint_string"] = mi.return_val.hint_string;
979 	d["return_type"] = r;
980 	return d;
981 }
982 
_get_method_list_bind() const983 Array Object::_get_method_list_bind() const {
984 
985 	List<MethodInfo> ml;
986 	get_method_list(&ml);
987 	Array ret;
988 
989 	for (List<MethodInfo>::Element *E = ml.front(); E; E = E->next()) {
990 
991 		Dictionary d = _get_dict_from_method(E->get());
992 		//va.push_back(d);
993 		ret.push_back(d);
994 	}
995 
996 	return ret;
997 }
998 
_get_meta_list_bind() const999 DVector<String> Object::_get_meta_list_bind() const {
1000 
1001 	DVector<String> _metaret;
1002 
1003 	List<Variant> keys;
1004 	metadata.get_key_list(&keys);
1005 	for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
1006 
1007 		_metaret.push_back(E->get());
1008 	}
1009 
1010 	return _metaret;
1011 }
get_meta_list(List<String> * p_list) const1012 void Object::get_meta_list(List<String> *p_list) const {
1013 
1014 	List<Variant> keys;
1015 	metadata.get_key_list(&keys);
1016 	for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
1017 
1018 		p_list->push_back(E->get());
1019 	}
1020 }
1021 
add_user_signal(const MethodInfo & p_signal)1022 void Object::add_user_signal(const MethodInfo &p_signal) {
1023 
1024 	ERR_FAIL_COND(p_signal.name == "");
1025 	ERR_FAIL_COND(ObjectTypeDB::has_signal(get_type_name(), p_signal.name));
1026 	ERR_FAIL_COND(signal_map.has(p_signal.name));
1027 	Signal s;
1028 	s.user = p_signal;
1029 	signal_map[p_signal.name] = s;
1030 }
1031 
_has_user_signal(const StringName & p_name) const1032 bool Object::_has_user_signal(const StringName &p_name) const {
1033 
1034 	if (!signal_map.has(p_name))
1035 		return false;
1036 	return signal_map[p_name].user.name.length() > 0;
1037 }
1038 
1039 struct _ObjectSignalDisconnectData {
1040 
1041 	StringName signal;
1042 	Object *target;
1043 	StringName method;
1044 };
1045 
1046 #if 0
1047 void Object::_emit_signal(const StringName& p_name,const Array& p_pargs){
1048 
1049 	Variant args[VARIANT_ARG_MAX];
1050 
1051 	int count = p_pargs.size();
1052 
1053 	for(int i=0;i<count;i++) {
1054 		args[i]=p_pargs[i];
1055 	}
1056 
1057 	emit_signal(p_name,VARIANT_ARGS_FROM_ARRAY(args));
1058 }
1059 
1060 #endif
1061 
_emit_signal(const Variant ** p_args,int p_argcount,Variant::CallError & r_error)1062 Variant Object::_emit_signal(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
1063 
1064 	r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
1065 
1066 	ERR_FAIL_COND_V(p_argcount < 1, Variant());
1067 	if (p_args[0]->get_type() != Variant::STRING) {
1068 		r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
1069 		r_error.argument = 0;
1070 		r_error.expected = Variant::STRING;
1071 		ERR_FAIL_COND_V(p_args[0]->get_type() != Variant::STRING, Variant());
1072 	}
1073 
1074 	r_error.error = Variant::CallError::CALL_OK;
1075 
1076 	StringName signal = *p_args[0];
1077 
1078 	const Variant **args = NULL;
1079 
1080 	int argc = p_argcount - 1;
1081 	if (argc) {
1082 		args = &p_args[1];
1083 	}
1084 
1085 	emit_signal(signal, args, argc);
1086 
1087 	return Variant();
1088 }
1089 
emit_signal(const StringName & p_name,const Variant ** p_args,int p_argcount)1090 void Object::emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount) {
1091 
1092 	if (_block_signals)
1093 		return; //no emit, signals blocked
1094 
1095 	Signal *s = signal_map.getptr(p_name);
1096 	if (!s) {
1097 #ifdef DEBUG_ENABLED
1098 		bool signal_is_valid = ObjectTypeDB::has_signal(get_type_name(), p_name);
1099 		//check in script
1100 		if (!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name)) {
1101 			ERR_EXPLAIN("Can't emit non-existing signal " + String("\"") + p_name + "\".");
1102 			ERR_FAIL();
1103 		}
1104 #endif
1105 		//not connected? just return
1106 		return;
1107 	}
1108 
1109 	List<_ObjectSignalDisconnectData> disconnect_data;
1110 
1111 	//copy on write will ensure that disconnecting the signal or even deleting the object will not affect the signal calling.
1112 	//this happens automatically and will not change the performance of calling.
1113 	//awesome, isn't it?
1114 	VMap<Signal::Target, Signal::Slot> slot_map = s->slot_map;
1115 
1116 	int ssize = slot_map.size();
1117 
1118 	OBJ_DEBUG_LOCK
1119 
1120 	Vector<const Variant *> bind_mem;
1121 
1122 	for (int i = 0; i < ssize; i++) {
1123 
1124 		const Connection &c = slot_map.getv(i).conn;
1125 
1126 		Object *target;
1127 #ifdef DEBUG_ENABLED
1128 		target = ObjectDB::get_instance(slot_map.getk(i)._id);
1129 		ERR_CONTINUE(!target);
1130 #else
1131 		target = c.target;
1132 #endif
1133 
1134 		const Variant **args = p_args;
1135 		int argc = p_argcount;
1136 
1137 		if (c.binds.size()) {
1138 			//handle binds
1139 			bind_mem.resize(p_argcount + c.binds.size());
1140 
1141 			for (int j = 0; j < p_argcount; j++) {
1142 				bind_mem[j] = p_args[j];
1143 			}
1144 			for (int j = 0; j < c.binds.size(); j++) {
1145 				bind_mem[p_argcount + j] = &c.binds[j];
1146 			}
1147 
1148 			args = bind_mem.ptr();
1149 			argc = bind_mem.size();
1150 		}
1151 
1152 		if (c.flags & CONNECT_DEFERRED) {
1153 			MessageQueue::get_singleton()->push_call(target->get_instance_ID(), c.method, args, argc, true);
1154 		} else {
1155 			Variant::CallError ce;
1156 			target->call(c.method, args, argc, ce);
1157 			if (ce.error != Variant::CallError::CALL_OK) {
1158 
1159 				if (ce.error == Variant::CallError::CALL_ERROR_INVALID_METHOD && !ObjectTypeDB::type_exists(target->get_type_name())) {
1160 					//most likely object is not initialized yet, do not throw error.
1161 				} else {
1162 					ERR_PRINTS("Error calling method from signal '" + String(p_name) + "': " + Variant::get_call_error_text(target, c.method, args, argc, ce));
1163 				}
1164 			}
1165 		}
1166 
1167 		if (c.flags & CONNECT_ONESHOT) {
1168 			_ObjectSignalDisconnectData dd;
1169 			dd.signal = p_name;
1170 			dd.target = target;
1171 			dd.method = c.method;
1172 			disconnect_data.push_back(dd);
1173 		}
1174 	}
1175 
1176 	while (!disconnect_data.empty()) {
1177 
1178 		const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get();
1179 		disconnect(dd.signal, dd.target, dd.method);
1180 		disconnect_data.pop_front();
1181 	}
1182 }
1183 
emit_signal(const StringName & p_name,VARIANT_ARG_DECLARE)1184 void Object::emit_signal(const StringName &p_name, VARIANT_ARG_DECLARE) {
1185 
1186 	VARIANT_ARGPTRS;
1187 
1188 	int argc = 0;
1189 
1190 	for (int i = 0; i < VARIANT_ARG_MAX; i++) {
1191 		if (argptr[i]->get_type() == Variant::NIL)
1192 			break;
1193 		argc++;
1194 	}
1195 
1196 	emit_signal(p_name, argptr, argc);
1197 }
1198 
_add_user_signal(const String & p_name,const Array & p_args)1199 void Object::_add_user_signal(const String &p_name, const Array &p_args) {
1200 
1201 	// this version of add_user_signal is meant to be used from scripts or external apis
1202 	// without access to ADD_SIGNAL in bind_methods
1203 	// added events are per instance, as opposed to the other ones, which are global
1204 
1205 	MethodInfo mi;
1206 	mi.name = p_name;
1207 
1208 	for (int i = 0; i < p_args.size(); i++) {
1209 
1210 		Dictionary d = p_args[i];
1211 		PropertyInfo param;
1212 
1213 		if (d.has("name"))
1214 			param.name = d["name"];
1215 		if (d.has("type"))
1216 			param.type = (Variant::Type)(int)d["type"];
1217 
1218 		mi.arguments.push_back(param);
1219 	}
1220 
1221 	add_user_signal(mi);
1222 }
1223 #if 0
1224 void Object::_emit_signal(const StringName& p_name,const Array& p_pargs){
1225 
1226 	Variant args[VARIANT_ARG_MAX];
1227 
1228 	int count = p_pargs.size();
1229 
1230 	for(int i=0;i<count;i++) {
1231 		args[i]=p_pargs[i];
1232 	}
1233 
1234 	emit_signal(p_name,VARIANT_ARGS_FROM_ARRAY(args));
1235 }
1236 
1237 #endif
_get_signal_list() const1238 Array Object::_get_signal_list() const {
1239 
1240 	List<MethodInfo> signal_list;
1241 	get_signal_list(&signal_list);
1242 
1243 	Array ret;
1244 	for (List<MethodInfo>::Element *E = signal_list.front(); E; E = E->next()) {
1245 
1246 		ret.push_back(_get_dict_from_method(E->get()));
1247 	}
1248 
1249 	return ret;
1250 }
_get_signal_connection_list(const String & p_signal) const1251 Array Object::_get_signal_connection_list(const String &p_signal) const {
1252 
1253 	List<Connection> conns;
1254 	get_all_signal_connections(&conns);
1255 
1256 	Array ret;
1257 
1258 	for (List<Connection>::Element *E = conns.front(); E; E = E->next()) {
1259 
1260 		Connection &c = E->get();
1261 		if (c.signal == p_signal) {
1262 			Dictionary rc;
1263 			rc["signal"] = c.signal;
1264 			rc["method"] = c.method;
1265 			rc["source"] = c.source;
1266 			rc["target"] = c.target;
1267 			rc["binds"] = c.binds;
1268 			rc["flags"] = c.flags;
1269 			ret.push_back(rc);
1270 		}
1271 	}
1272 
1273 	return ret;
1274 }
1275 
get_signal_list(List<MethodInfo> * p_signals) const1276 void Object::get_signal_list(List<MethodInfo> *p_signals) const {
1277 
1278 	if (!script.is_null()) {
1279 		Ref<Script>(script)->get_script_signal_list(p_signals);
1280 	}
1281 
1282 	ObjectTypeDB::get_signal_list(get_type_name(), p_signals);
1283 	//find maybe usersignals?
1284 	const StringName *S = NULL;
1285 
1286 	while ((S = signal_map.next(S))) {
1287 
1288 		if (signal_map[*S].user.name != "") {
1289 			//user signal
1290 			p_signals->push_back(signal_map[*S].user);
1291 		}
1292 	}
1293 }
1294 
get_all_signal_connections(List<Connection> * p_connections) const1295 void Object::get_all_signal_connections(List<Connection> *p_connections) const {
1296 
1297 	const StringName *S = NULL;
1298 
1299 	while ((S = signal_map.next(S))) {
1300 
1301 		const Signal *s = &signal_map[*S];
1302 
1303 		for (int i = 0; i < s->slot_map.size(); i++) {
1304 
1305 			p_connections->push_back(s->slot_map.getv(i).conn);
1306 		}
1307 	}
1308 }
1309 
get_signal_connection_list(const StringName & p_signal,List<Connection> * p_connections) const1310 void Object::get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const {
1311 
1312 	const Signal *s = signal_map.getptr(p_signal);
1313 	if (!s)
1314 		return; //nothing
1315 
1316 	for (int i = 0; i < s->slot_map.size(); i++)
1317 		p_connections->push_back(s->slot_map.getv(i).conn);
1318 }
1319 
has_persistent_signal_connections() const1320 bool Object::has_persistent_signal_connections() const {
1321 
1322 	const StringName *S = NULL;
1323 
1324 	while ((S = signal_map.next(S))) {
1325 
1326 		const Signal *s = &signal_map[*S];
1327 
1328 		for (int i = 0; i < s->slot_map.size(); i++) {
1329 
1330 			if (s->slot_map.getv(i).conn.flags & CONNECT_PERSIST)
1331 				return true;
1332 		}
1333 	}
1334 
1335 	return false;
1336 }
1337 
get_signals_connected_to_this(List<Connection> * p_connections) const1338 void Object::get_signals_connected_to_this(List<Connection> *p_connections) const {
1339 
1340 	for (const List<Connection>::Element *E = connections.front(); E; E = E->next()) {
1341 		p_connections->push_back(E->get());
1342 	}
1343 }
1344 
connect(const StringName & p_signal,Object * p_to_object,const StringName & p_to_method,const Vector<Variant> & p_binds,uint32_t p_flags)1345 Error Object::connect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, const Vector<Variant> &p_binds, uint32_t p_flags) {
1346 
1347 	ERR_FAIL_NULL_V(p_to_object, ERR_INVALID_PARAMETER);
1348 
1349 	Signal *s = signal_map.getptr(p_signal);
1350 	if (!s) {
1351 		bool signal_is_valid = ObjectTypeDB::has_signal(get_type_name(), p_signal);
1352 		//check in script
1353 		if (!signal_is_valid && !script.is_null() && Ref<Script>(script)->has_script_signal(p_signal))
1354 			signal_is_valid = true;
1355 
1356 		if (!signal_is_valid) {
1357 			ERR_EXPLAIN("In Object of type '" + String(get_type()) + "': Attempt to connect nonexistent signal '" + p_signal + "' to method '" + p_to_object->get_type() + "." + p_to_method + "'");
1358 			ERR_FAIL_COND_V(!signal_is_valid, ERR_INVALID_PARAMETER);
1359 		}
1360 		signal_map[p_signal] = Signal();
1361 		s = &signal_map[p_signal];
1362 	}
1363 
1364 	Signal::Target target(p_to_object->get_instance_ID(), p_to_method);
1365 	if (s->slot_map.has(target)) {
1366 		ERR_EXPLAIN("Signal '" + p_signal + "' is already connected to given method '" + p_to_method + "' in that object.");
1367 		ERR_FAIL_COND_V(s->slot_map.has(target), ERR_INVALID_PARAMETER);
1368 	}
1369 
1370 	Signal::Slot slot;
1371 
1372 	Connection conn;
1373 	conn.source = this;
1374 	conn.target = p_to_object;
1375 	conn.method = p_to_method;
1376 	conn.signal = p_signal;
1377 	conn.flags = p_flags;
1378 	conn.binds = p_binds;
1379 	slot.conn = conn;
1380 	slot.cE = p_to_object->connections.push_back(conn);
1381 	s->slot_map[target] = slot;
1382 
1383 	return OK;
1384 }
1385 
is_connected(const StringName & p_signal,Object * p_to_object,const StringName & p_to_method) const1386 bool Object::is_connected(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) const {
1387 
1388 	ERR_FAIL_NULL_V(p_to_object, false);
1389 	const Signal *s = signal_map.getptr(p_signal);
1390 	if (!s) {
1391 		bool signal_is_valid = ObjectTypeDB::has_signal(get_type_name(), p_signal);
1392 		if (signal_is_valid)
1393 			return false;
1394 
1395 		if (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal))
1396 			return false;
1397 
1398 		ERR_EXPLAIN("Nonexistent signal: " + p_signal);
1399 		ERR_FAIL_COND_V(!s, false);
1400 	}
1401 
1402 	Signal::Target target(p_to_object->get_instance_ID(), p_to_method);
1403 
1404 	return s->slot_map.has(target);
1405 	//const Map<Signal::Target,Signal::Slot>::Element *E = s->slot_map.find(target);
1406 	//return (E!=NULL);
1407 }
1408 
disconnect(const StringName & p_signal,Object * p_to_object,const StringName & p_to_method)1409 void Object::disconnect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) {
1410 
1411 	ERR_FAIL_NULL(p_to_object);
1412 	Signal *s = signal_map.getptr(p_signal);
1413 	if (!s) {
1414 		ERR_EXPLAIN("Nonexistent signal: " + p_signal);
1415 		ERR_FAIL_COND(!s);
1416 	}
1417 	if (s->lock > 0) {
1418 		ERR_EXPLAIN("Attempt to disconnect signal '" + p_signal + "' while emitting (locks: " + itos(s->lock) + ")");
1419 		ERR_FAIL_COND(s->lock > 0);
1420 	}
1421 
1422 	Signal::Target target(p_to_object->get_instance_ID(), p_to_method);
1423 
1424 	if (!s->slot_map.has(target)) {
1425 		ERR_EXPLAIN("Disconnecting nonexistent signal '" + p_signal + "', slot: " + itos(target._id) + ":" + target.method);
1426 		ERR_FAIL();
1427 	}
1428 
1429 	p_to_object->connections.erase(s->slot_map[target].cE);
1430 	s->slot_map.erase(target);
1431 
1432 	if (s->slot_map.empty() && ObjectTypeDB::has_signal(get_type_name(), p_signal)) {
1433 		//not user signal, delete
1434 		signal_map.erase(p_signal);
1435 	}
1436 }
1437 
_set_bind(const String & p_set,const Variant & p_value)1438 void Object::_set_bind(const String &p_set, const Variant &p_value) {
1439 
1440 	set(p_set, p_value);
1441 }
1442 
_get_bind(const String & p_name) const1443 Variant Object::_get_bind(const String &p_name) const {
1444 
1445 	return get(p_name);
1446 }
1447 
initialize_type()1448 void Object::initialize_type() {
1449 
1450 	static bool initialized = false;
1451 	if (initialized)
1452 		return;
1453 	ObjectTypeDB::_add_type<Object>();
1454 	_bind_methods();
1455 	initialized = true;
1456 }
1457 
XL_MESSAGE(const StringName & p_message) const1458 StringName Object::XL_MESSAGE(const StringName &p_message) const {
1459 
1460 	if (!_can_translate || !TranslationServer::get_singleton())
1461 		return p_message;
1462 
1463 	return TranslationServer::get_singleton()->translate(p_message);
1464 }
1465 
tr(const StringName & p_message) const1466 StringName Object::tr(const StringName &p_message) const {
1467 
1468 	return XL_MESSAGE(p_message);
1469 }
1470 
_clear_internal_resource_paths(const Variant & p_var)1471 void Object::_clear_internal_resource_paths(const Variant &p_var) {
1472 
1473 	switch (p_var.get_type()) {
1474 
1475 		case Variant::OBJECT: {
1476 
1477 			RES r = p_var;
1478 			if (!r.is_valid())
1479 				return;
1480 
1481 			if (!r->get_path().begins_with("res://") || r->get_path().find("::") == -1)
1482 				return; //not an internal resource
1483 
1484 			Object *object = p_var;
1485 			if (!object)
1486 				return;
1487 
1488 			r->set_path("");
1489 			r->clear_internal_resource_paths();
1490 		} break;
1491 		case Variant::ARRAY: {
1492 
1493 			Array a = p_var;
1494 			for (int i = 0; i < a.size(); i++) {
1495 				_clear_internal_resource_paths(a[i]);
1496 			}
1497 
1498 		} break;
1499 		case Variant::DICTIONARY: {
1500 
1501 			Dictionary d = p_var;
1502 			List<Variant> keys;
1503 			d.get_key_list(&keys);
1504 
1505 			for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
1506 
1507 				_clear_internal_resource_paths(E->get());
1508 				_clear_internal_resource_paths(d[E->get()]);
1509 			}
1510 		} break;
1511 	}
1512 }
1513 
clear_internal_resource_paths()1514 void Object::clear_internal_resource_paths() {
1515 
1516 	List<PropertyInfo> pinfo;
1517 
1518 	get_property_list(&pinfo);
1519 
1520 	for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
1521 
1522 		_clear_internal_resource_paths(get(E->get().name));
1523 	}
1524 }
1525 
_bind_methods()1526 void Object::_bind_methods() {
1527 
1528 	ObjectTypeDB::bind_method(_MD("get_type"), &Object::get_type);
1529 	ObjectTypeDB::bind_method(_MD("is_type", "type"), &Object::is_type);
1530 	ObjectTypeDB::bind_method(_MD("set", "property", "value"), &Object::_set_bind);
1531 	ObjectTypeDB::bind_method(_MD("get", "property"), &Object::_get_bind);
1532 	ObjectTypeDB::bind_method(_MD("get_property_list"), &Object::_get_property_list_bind);
1533 	ObjectTypeDB::bind_method(_MD("get_method_list"), &Object::_get_method_list_bind);
1534 	ObjectTypeDB::bind_method(_MD("notification", "what", "reversed"), &Object::notification, DEFVAL(false));
1535 	ObjectTypeDB::bind_method(_MD("get_instance_ID"), &Object::get_instance_ID);
1536 
1537 	ObjectTypeDB::bind_method(_MD("set_script", "script:Script"), &Object::set_script);
1538 	ObjectTypeDB::bind_method(_MD("get_script:Script"), &Object::get_script);
1539 
1540 	ObjectTypeDB::bind_method(_MD("set_meta", "name", "value"), &Object::set_meta);
1541 	ObjectTypeDB::bind_method(_MD("get_meta:Variant", "name", "value"), &Object::get_meta);
1542 	ObjectTypeDB::bind_method(_MD("has_meta", "name"), &Object::has_meta);
1543 	ObjectTypeDB::bind_method(_MD("get_meta_list"), &Object::_get_meta_list_bind);
1544 
1545 	//todo reimplement this per language so all 5 arguments can be called
1546 
1547 	//	ObjectTypeDB::bind_method(_MD("call","method","arg1","arg2","arg3","arg4"),&Object::_call_bind,DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()));
1548 	//	ObjectTypeDB::bind_method(_MD("call_deferred","method","arg1","arg2","arg3","arg4"),&Object::_call_deferred_bind,DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()));
1549 
1550 	ObjectTypeDB::bind_method(_MD("add_user_signal", "signal", "arguments"), &Object::_add_user_signal, DEFVAL(Array()));
1551 	ObjectTypeDB::bind_method(_MD("has_user_signal", "signal"), &Object::_has_user_signal);
1552 	//	ObjectTypeDB::bind_method(_MD("emit_signal","signal","arguments"),&Object::_emit_signal,DEFVAL(Array()));
1553 
1554 	{
1555 		MethodInfo mi;
1556 		mi.name = "emit_signal";
1557 		mi.arguments.push_back(PropertyInfo(Variant::STRING, "signal"));
1558 		Vector<Variant> defargs;
1559 		for (int i = 0; i < VARIANT_ARG_MAX; i++) {
1560 			mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i)));
1561 			defargs.push_back(Variant());
1562 		}
1563 
1564 		ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT, "emit_signal", &Object::_emit_signal, mi, defargs);
1565 	}
1566 
1567 	{
1568 		MethodInfo mi;
1569 		mi.name = "call";
1570 		mi.arguments.push_back(PropertyInfo(Variant::STRING, "method"));
1571 		Vector<Variant> defargs;
1572 		for (int i = 0; i < 10; i++) {
1573 			mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i)));
1574 			defargs.push_back(Variant());
1575 		}
1576 
1577 		ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT, "call", &Object::_call_bind, mi, defargs);
1578 	}
1579 
1580 	{
1581 		MethodInfo mi;
1582 		mi.name = "call_deferred";
1583 		mi.arguments.push_back(PropertyInfo(Variant::STRING, "method"));
1584 		Vector<Variant> defargs;
1585 		for (int i = 0; i < VARIANT_ARG_MAX; i++) {
1586 			mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i)));
1587 			defargs.push_back(Variant());
1588 		}
1589 
1590 		ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT, "call_deferred", &Object::_call_deferred_bind, mi, defargs);
1591 	}
1592 
1593 	ObjectTypeDB::bind_method(_MD("callv:Variant", "method", "arg_array"), &Object::callv);
1594 
1595 	ObjectTypeDB::bind_method(_MD("has_method", "method"), &Object::has_method);
1596 
1597 	ObjectTypeDB::bind_method(_MD("get_signal_list"), &Object::_get_signal_list);
1598 	ObjectTypeDB::bind_method(_MD("get_signal_connection_list", "signal"), &Object::_get_signal_connection_list);
1599 
1600 	ObjectTypeDB::bind_method(_MD("connect", "signal", "target:Object", "method", "binds", "flags"), &Object::connect, DEFVAL(Array()), DEFVAL(0));
1601 	ObjectTypeDB::bind_method(_MD("disconnect", "signal", "target:Object", "method"), &Object::disconnect);
1602 	ObjectTypeDB::bind_method(_MD("is_connected", "signal", "target:Object", "method"), &Object::is_connected);
1603 
1604 	ObjectTypeDB::bind_method(_MD("set_block_signals", "enable"), &Object::set_block_signals);
1605 	ObjectTypeDB::bind_method(_MD("is_blocking_signals"), &Object::is_blocking_signals);
1606 	ObjectTypeDB::bind_method(_MD("set_message_translation", "enable"), &Object::set_message_translation);
1607 	ObjectTypeDB::bind_method(_MD("can_translate_messages"), &Object::can_translate_messages);
1608 	ObjectTypeDB::bind_method(_MD("property_list_changed_notify"), &Object::property_list_changed_notify);
1609 
1610 	ObjectTypeDB::bind_method(_MD("XL_MESSAGE", "message"), &Object::XL_MESSAGE);
1611 	ObjectTypeDB::bind_method(_MD("tr", "message"), &Object::tr);
1612 
1613 	ObjectTypeDB::bind_method(_MD("is_queued_for_deletion"), &Object::is_queued_for_deletion);
1614 
1615 	ObjectTypeDB::add_virtual_method("Object", MethodInfo("free"), false);
1616 
1617 	ADD_SIGNAL(MethodInfo("script_changed"));
1618 
1619 	BIND_VMETHOD(MethodInfo("_notification", PropertyInfo(Variant::INT, "what")));
1620 	BIND_VMETHOD(MethodInfo("_set", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value")));
1621 #ifdef TOOLS_ENABLED
1622 	MethodInfo miget("_get", PropertyInfo(Variant::STRING, "property"));
1623 	miget.return_val.name = "var";
1624 	BIND_VMETHOD(miget);
1625 
1626 	MethodInfo plget("_get_property_list");
1627 
1628 	plget.return_val.type = Variant::ARRAY;
1629 	BIND_VMETHOD(plget);
1630 
1631 #endif
1632 	BIND_VMETHOD(MethodInfo("_init"));
1633 
1634 	BIND_CONSTANT(NOTIFICATION_POSTINITIALIZE);
1635 	BIND_CONSTANT(NOTIFICATION_PREDELETE);
1636 
1637 	BIND_CONSTANT(CONNECT_DEFERRED);
1638 	BIND_CONSTANT(CONNECT_PERSIST);
1639 	BIND_CONSTANT(CONNECT_ONESHOT);
1640 }
1641 
call_deferred(const StringName & p_method,VARIANT_ARG_DECLARE)1642 void Object::call_deferred(const StringName &p_method, VARIANT_ARG_DECLARE) {
1643 
1644 	MessageQueue::get_singleton()->push_call(this, p_method, VARIANT_ARG_PASS);
1645 }
1646 
set_block_signals(bool p_block)1647 void Object::set_block_signals(bool p_block) {
1648 
1649 	_block_signals = p_block;
1650 }
1651 
is_blocking_signals() const1652 bool Object::is_blocking_signals() const {
1653 
1654 	return _block_signals;
1655 }
1656 
get_translatable_strings(List<String> * p_strings) const1657 void Object::get_translatable_strings(List<String> *p_strings) const {
1658 
1659 	List<PropertyInfo> plist;
1660 	get_property_list(&plist);
1661 
1662 	for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
1663 
1664 		if (!(E->get().usage & PROPERTY_USAGE_INTERNATIONALIZED))
1665 			continue;
1666 
1667 		String text = get(E->get().name);
1668 
1669 		if (text == "")
1670 			continue;
1671 
1672 		p_strings->push_back(text);
1673 	}
1674 }
1675 
get_static_property_type(const StringName & p_property,bool * r_valid) const1676 Variant::Type Object::get_static_property_type(const StringName &p_property, bool *r_valid) const {
1677 
1678 	bool valid;
1679 	Variant::Type t = ObjectTypeDB::get_property_type(get_type_name(), p_property, &valid);
1680 	if (valid) {
1681 		if (r_valid)
1682 			*r_valid = true;
1683 		return t;
1684 	}
1685 
1686 	if (get_script_instance()) {
1687 		return get_script_instance()->get_property_type(p_property, r_valid);
1688 	}
1689 	if (r_valid)
1690 		*r_valid = false;
1691 
1692 	return Variant::NIL;
1693 }
1694 
is_queued_for_deletion() const1695 bool Object::is_queued_for_deletion() const {
1696 	return _is_queued_for_deletion;
1697 }
1698 
1699 #ifdef TOOLS_ENABLED
set_edited(bool p_edited)1700 void Object::set_edited(bool p_edited) {
1701 
1702 	_edited = p_edited;
1703 	_edited_version++;
1704 }
1705 
is_edited() const1706 bool Object::is_edited() const {
1707 
1708 	return _edited;
1709 }
1710 
get_edited_version() const1711 uint32_t Object::get_edited_version() const {
1712 
1713 	return _edited_version;
1714 }
1715 #endif
1716 
Object()1717 Object::Object() {
1718 
1719 	_type_ptr = NULL;
1720 	_block_signals = false;
1721 	_predelete_ok = 0;
1722 	_instance_ID = 0;
1723 	_instance_ID = ObjectDB::add_instance(this);
1724 	_can_translate = true;
1725 	_is_queued_for_deletion = false;
1726 	script_instance = NULL;
1727 #ifdef TOOLS_ENABLED
1728 
1729 	_edited = false;
1730 	_edited_version = 0;
1731 #endif
1732 
1733 #ifdef DEBUG_ENABLED
1734 	_lock_index.init(1);
1735 #endif
1736 }
1737 
~Object()1738 Object::~Object() {
1739 
1740 	if (script_instance)
1741 		memdelete(script_instance);
1742 	script_instance = NULL;
1743 
1744 	List<Connection> sconnections;
1745 	const StringName *S = NULL;
1746 
1747 	while ((S = signal_map.next(S))) {
1748 
1749 		Signal *s = &signal_map[*S];
1750 
1751 		ERR_EXPLAIN("Attempt to delete an object in the middle of a signal emission from it");
1752 		ERR_CONTINUE(s->lock > 0);
1753 
1754 		for (int i = 0; i < s->slot_map.size(); i++) {
1755 
1756 			sconnections.push_back(s->slot_map.getv(i).conn);
1757 		}
1758 	}
1759 
1760 	for (List<Connection>::Element *E = sconnections.front(); E; E = E->next()) {
1761 
1762 		Connection &c = E->get();
1763 		ERR_CONTINUE(c.source != this); //bug?
1764 
1765 		this->disconnect(c.signal, c.target, c.method);
1766 	}
1767 
1768 	while (connections.size()) {
1769 
1770 		Connection c = connections.front()->get();
1771 		c.source->disconnect(c.signal, c.target, c.method);
1772 	}
1773 
1774 	ObjectDB::remove_instance(this);
1775 	_instance_ID = 0;
1776 	_predelete_ok = 2;
1777 }
1778 
predelete_handler(Object * p_object)1779 bool predelete_handler(Object *p_object) {
1780 
1781 	return p_object->_predelete();
1782 }
1783 
postinitialize_handler(Object * p_object)1784 void postinitialize_handler(Object *p_object) {
1785 
1786 	p_object->_postinitialize();
1787 }
1788 
1789 HashMap<uint32_t, Object *> ObjectDB::instances;
1790 uint32_t ObjectDB::instance_counter = 1;
1791 HashMap<Object *, ObjectID, ObjectDB::ObjectPtrHash> ObjectDB::instance_checks;
add_instance(Object * p_object)1792 uint32_t ObjectDB::add_instance(Object *p_object) {
1793 
1794 	GLOBAL_LOCK_FUNCTION;
1795 	ERR_FAIL_COND_V(p_object->get_instance_ID() != 0, 0);
1796 	instances[++instance_counter] = p_object;
1797 #ifdef DEBUG_ENABLED
1798 	instance_checks[p_object] = instance_counter;
1799 #endif
1800 	return instance_counter;
1801 }
1802 
remove_instance(Object * p_object)1803 void ObjectDB::remove_instance(Object *p_object) {
1804 
1805 	GLOBAL_LOCK_FUNCTION;
1806 	instances.erase(p_object->get_instance_ID());
1807 #ifdef DEBUG_ENABLED
1808 	instance_checks.erase(p_object);
1809 #endif
1810 }
get_instance(uint32_t p_instance_ID)1811 Object *ObjectDB::get_instance(uint32_t p_instance_ID) {
1812 
1813 	GLOBAL_LOCK_FUNCTION;
1814 	Object **obj = instances.getptr(p_instance_ID);
1815 	if (!obj)
1816 		return NULL;
1817 	return *obj;
1818 }
1819 
debug_objects(DebugFunc p_func)1820 void ObjectDB::debug_objects(DebugFunc p_func) {
1821 
1822 	GLOBAL_LOCK_FUNCTION;
1823 
1824 	const uint32_t *K = NULL;
1825 	while ((K = instances.next(K))) {
1826 
1827 		p_func(instances[*K]);
1828 	}
1829 }
1830 
get_argument_options(const StringName & p_function,int p_idx,List<String> * r_options) const1831 void Object::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
1832 }
1833 
get_object_count()1834 int ObjectDB::get_object_count() {
1835 
1836 	GLOBAL_LOCK_FUNCTION;
1837 	return instances.size();
1838 }
1839 
cleanup()1840 void ObjectDB::cleanup() {
1841 
1842 	GLOBAL_LOCK_FUNCTION;
1843 	if (instances.size()) {
1844 
1845 		WARN_PRINT("ObjectDB Instances still exist!");
1846 		if (OS::get_singleton()->is_stdout_verbose()) {
1847 			const uint32_t *K = NULL;
1848 			while ((K = instances.next(K))) {
1849 
1850 				String node_name;
1851 				if (instances[*K]->is_type("Node"))
1852 					node_name = " - Node Name: " + String(instances[*K]->call("get_name"));
1853 				if (instances[*K]->is_type("Resource"))
1854 					node_name = " - Resource Name: " + String(instances[*K]->call("get_name")) + " Path: " + String(instances[*K]->call("get_path"));
1855 				print_line("Leaked Instance: " + String(instances[*K]->get_type()) + ":" + itos(*K) + node_name);
1856 			}
1857 		}
1858 	}
1859 	instances.clear();
1860 	instance_checks.clear();
1861 }
1862