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