1/**************************************************************************/
2/* object.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
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
31#include "object.h"
32
33#include "core/core_string_names.h"
34#include "core/io/resource.h"
35#include "core/object/class_db.h"
36#include "core/object/message_queue.h"
37#include "core/object/script_language.h"
38#include "core/os/os.h"
39#include "core/string/print_string.h"
40#include "core/string/translation.h"
41#include "core/templates/local_vector.h"
42#include "core/variant/typed_array.h"
43
44#ifdef DEBUG_ENABLED
45
46struct _ObjectDebugLock {
47 Object *obj;
48
49 _ObjectDebugLock(Object *p_obj) {
50 obj = p_obj;
51 obj->_lock_index.ref();
52 }
53 ~_ObjectDebugLock() {
54 obj->_lock_index.unref();
55 }
56};
57
58#define OBJ_DEBUG_LOCK _ObjectDebugLock _debug_lock(this);
59
60#else
61
62#define OBJ_DEBUG_LOCK
63
64#endif
65
66PropertyInfo::operator Dictionary() const {
67 Dictionary d;
68 d["name"] = name;
69 d["class_name"] = class_name;
70 d["type"] = type;
71 d["hint"] = hint;
72 d["hint_string"] = hint_string;
73 d["usage"] = usage;
74 return d;
75}
76
77PropertyInfo PropertyInfo::from_dict(const Dictionary &p_dict) {
78 PropertyInfo pi;
79
80 if (p_dict.has("type")) {
81 pi.type = Variant::Type(int(p_dict["type"]));
82 }
83
84 if (p_dict.has("name")) {
85 pi.name = p_dict["name"];
86 }
87
88 if (p_dict.has("class_name")) {
89 pi.class_name = p_dict["class_name"];
90 }
91
92 if (p_dict.has("hint")) {
93 pi.hint = PropertyHint(int(p_dict["hint"]));
94 }
95
96 if (p_dict.has("hint_string")) {
97 pi.hint_string = p_dict["hint_string"];
98 }
99
100 if (p_dict.has("usage")) {
101 pi.usage = p_dict["usage"];
102 }
103
104 return pi;
105}
106
107TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list) {
108 TypedArray<Dictionary> va;
109 for (const List<PropertyInfo>::Element *E = p_list->front(); E; E = E->next()) {
110 va.push_back(Dictionary(E->get()));
111 }
112
113 return va;
114}
115
116MethodInfo::operator Dictionary() const {
117 Dictionary d;
118 d["name"] = name;
119 d["args"] = convert_property_list(&arguments);
120 Array da;
121 for (int i = 0; i < default_arguments.size(); i++) {
122 da.push_back(default_arguments[i]);
123 }
124 d["default_args"] = da;
125 d["flags"] = flags;
126 d["id"] = id;
127 Dictionary r = return_val;
128 d["return"] = r;
129 return d;
130}
131
132MethodInfo MethodInfo::from_dict(const Dictionary &p_dict) {
133 MethodInfo mi;
134
135 if (p_dict.has("name")) {
136 mi.name = p_dict["name"];
137 }
138 Array args;
139 if (p_dict.has("args")) {
140 args = p_dict["args"];
141 }
142
143 for (int i = 0; i < args.size(); i++) {
144 Dictionary d = args[i];
145 mi.arguments.push_back(PropertyInfo::from_dict(d));
146 }
147 Array defargs;
148 if (p_dict.has("default_args")) {
149 defargs = p_dict["default_args"];
150 }
151 for (int i = 0; i < defargs.size(); i++) {
152 mi.default_arguments.push_back(defargs[i]);
153 }
154
155 if (p_dict.has("return")) {
156 mi.return_val = PropertyInfo::from_dict(p_dict["return"]);
157 }
158
159 if (p_dict.has("flags")) {
160 mi.flags = p_dict["flags"];
161 }
162
163 return mi;
164}
165
166Object::Connection::operator Variant() const {
167 Dictionary d;
168 d["signal"] = signal;
169 d["callable"] = callable;
170 d["flags"] = flags;
171 return d;
172}
173
174bool Object::Connection::operator<(const Connection &p_conn) const {
175 if (signal == p_conn.signal) {
176 return callable < p_conn.callable;
177 } else {
178 return signal < p_conn.signal;
179 }
180}
181
182Object::Connection::Connection(const Variant &p_variant) {
183 Dictionary d = p_variant;
184 if (d.has("signal")) {
185 signal = d["signal"];
186 }
187 if (d.has("callable")) {
188 callable = d["callable"];
189 }
190 if (d.has("flags")) {
191 flags = d["flags"];
192 }
193}
194
195bool Object::_predelete() {
196 _predelete_ok = 1;
197 notification(NOTIFICATION_PREDELETE, true);
198 if (_predelete_ok) {
199 _class_name_ptr = nullptr; // Must restore, so constructors/destructors have proper class name access at each stage.
200 }
201 return _predelete_ok;
202}
203
204void Object::cancel_free() {
205 _predelete_ok = false;
206}
207
208void Object::_postinitialize() {
209 _class_name_ptr = _get_class_namev(); // Set the direct pointer, which is much faster to obtain, but can only happen after postinitialize.
210 _initialize_classv();
211 _class_name_ptr = nullptr; // May have been called from a constructor.
212 notification(NOTIFICATION_POSTINITIALIZE);
213}
214
215void Object::get_valid_parents_static(List<String> *p_parents) {
216}
217
218void Object::_get_valid_parents_static(List<String> *p_parents) {
219}
220
221void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid) {
222#ifdef TOOLS_ENABLED
223
224 _edited = true;
225#endif
226
227 if (script_instance) {
228 if (script_instance->set(p_name, p_value)) {
229 if (r_valid) {
230 *r_valid = true;
231 }
232 return;
233 }
234 }
235
236 if (_extension && _extension->set) {
237// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
238#if defined(__GNUC__) && !defined(__clang__)
239#pragma GCC diagnostic push
240#pragma GCC diagnostic ignored "-Wignored-qualifiers"
241#endif
242 if (_extension->set(_extension_instance, (const GDExtensionStringNamePtr)&p_name, (const GDExtensionVariantPtr)&p_value)) {
243 if (r_valid) {
244 *r_valid = true;
245 }
246 return;
247 }
248#if defined(__GNUC__) && !defined(__clang__)
249#pragma GCC diagnostic pop
250#endif
251 }
252
253 // Try built-in setter.
254 {
255 if (ClassDB::set_property(this, p_name, p_value, r_valid)) {
256 return;
257 }
258 }
259
260 if (p_name == CoreStringNames::get_singleton()->_script) {
261 set_script(p_value);
262 if (r_valid) {
263 *r_valid = true;
264 }
265 return;
266
267 } else {
268 Variant **V = metadata_properties.getptr(p_name);
269 if (V) {
270 **V = p_value;
271 if (r_valid) {
272 *r_valid = true;
273 }
274 return;
275 } else if (p_name.operator String().begins_with("metadata/")) {
276 // Must exist, otherwise duplicate() will not work.
277 set_meta(p_name.operator String().replace_first("metadata/", ""), p_value);
278 if (r_valid) {
279 *r_valid = true;
280 }
281 return;
282 }
283 }
284
285#ifdef TOOLS_ENABLED
286 if (script_instance) {
287 bool valid;
288 script_instance->property_set_fallback(p_name, p_value, &valid);
289 if (valid) {
290 if (r_valid) {
291 *r_valid = true;
292 }
293 return;
294 }
295 }
296#endif
297
298 // Something inside the object... :|
299 bool success = _setv(p_name, p_value);
300 if (success) {
301 if (r_valid) {
302 *r_valid = true;
303 }
304 return;
305 }
306
307 if (r_valid) {
308 *r_valid = false;
309 }
310}
311
312Variant Object::get(const StringName &p_name, bool *r_valid) const {
313 Variant ret;
314
315 if (script_instance) {
316 if (script_instance->get(p_name, ret)) {
317 if (r_valid) {
318 *r_valid = true;
319 }
320 return ret;
321 }
322 }
323 if (_extension && _extension->get) {
324// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
325#if defined(__GNUC__) && !defined(__clang__)
326#pragma GCC diagnostic push
327#pragma GCC diagnostic ignored "-Wignored-qualifiers"
328#endif
329
330 if (_extension->get(_extension_instance, (const GDExtensionStringNamePtr)&p_name, (GDExtensionVariantPtr)&ret)) {
331 if (r_valid) {
332 *r_valid = true;
333 }
334 return ret;
335 }
336#if defined(__GNUC__) && !defined(__clang__)
337#pragma GCC diagnostic pop
338#endif
339 }
340
341 // Try built-in getter.
342 {
343 if (ClassDB::get_property(const_cast<Object *>(this), p_name, ret)) {
344 if (r_valid) {
345 *r_valid = true;
346 }
347 return ret;
348 }
349 }
350
351 if (p_name == CoreStringNames::get_singleton()->_script) {
352 ret = get_script();
353 if (r_valid) {
354 *r_valid = true;
355 }
356 return ret;
357 }
358
359 const Variant *const *V = metadata_properties.getptr(p_name);
360
361 if (V) {
362 ret = **V;
363 if (r_valid) {
364 *r_valid = true;
365 }
366 return ret;
367
368 } else {
369#ifdef TOOLS_ENABLED
370 if (script_instance) {
371 bool valid;
372 ret = script_instance->property_get_fallback(p_name, &valid);
373 if (valid) {
374 if (r_valid) {
375 *r_valid = true;
376 }
377 return ret;
378 }
379 }
380#endif
381 // Something inside the object... :|
382 bool success = _getv(p_name, ret);
383 if (success) {
384 if (r_valid) {
385 *r_valid = true;
386 }
387 return ret;
388 }
389
390 if (r_valid) {
391 *r_valid = false;
392 }
393 return Variant();
394 }
395}
396
397void Object::set_indexed(const Vector<StringName> &p_names, const Variant &p_value, bool *r_valid) {
398 if (p_names.is_empty()) {
399 if (r_valid) {
400 *r_valid = false;
401 }
402 return;
403 }
404 if (p_names.size() == 1) {
405 set(p_names[0], p_value, r_valid);
406 return;
407 }
408
409 bool valid = false;
410 if (!r_valid) {
411 r_valid = &valid;
412 }
413
414 List<Variant> value_stack;
415
416 value_stack.push_back(get(p_names[0], r_valid));
417
418 if (!*r_valid) {
419 value_stack.clear();
420 return;
421 }
422
423 for (int i = 1; i < p_names.size() - 1; i++) {
424 value_stack.push_back(value_stack.back()->get().get_named(p_names[i], valid));
425 if (r_valid) {
426 *r_valid = valid;
427 }
428
429 if (!valid) {
430 value_stack.clear();
431 return;
432 }
433 }
434
435 value_stack.push_back(p_value); // p_names[p_names.size() - 1]
436
437 for (int i = p_names.size() - 1; i > 0; i--) {
438 value_stack.back()->prev()->get().set_named(p_names[i], value_stack.back()->get(), valid);
439 value_stack.pop_back();
440
441 if (r_valid) {
442 *r_valid = valid;
443 }
444 if (!valid) {
445 value_stack.clear();
446 return;
447 }
448 }
449
450 set(p_names[0], value_stack.back()->get(), r_valid);
451 value_stack.pop_back();
452
453 ERR_FAIL_COND(!value_stack.is_empty());
454}
455
456Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) const {
457 if (p_names.is_empty()) {
458 if (r_valid) {
459 *r_valid = false;
460 }
461 return Variant();
462 }
463 bool valid = false;
464
465 Variant current_value = get(p_names[0], &valid);
466 for (int i = 1; i < p_names.size(); i++) {
467 current_value = current_value.get_named(p_names[i], valid);
468
469 if (!valid) {
470 break;
471 }
472 }
473 if (r_valid) {
474 *r_valid = valid;
475 }
476
477 return current_value;
478}
479
480void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) const {
481 if (script_instance && p_reversed) {
482 script_instance->get_property_list(p_list);
483 }
484
485 if (_extension) {
486 const ObjectGDExtension *current_extension = _extension;
487 while (current_extension) {
488 p_list->push_back(PropertyInfo(Variant::NIL, current_extension->class_name, PROPERTY_HINT_NONE, current_extension->class_name, PROPERTY_USAGE_CATEGORY));
489
490 ClassDB::get_property_list(current_extension->class_name, p_list, true, this);
491
492 if (current_extension->get_property_list) {
493 uint32_t pcount;
494 const GDExtensionPropertyInfo *pinfo = current_extension->get_property_list(_extension_instance, &pcount);
495 for (uint32_t i = 0; i < pcount; i++) {
496 p_list->push_back(PropertyInfo(pinfo[i]));
497 }
498 if (current_extension->free_property_list) {
499 current_extension->free_property_list(_extension_instance, pinfo);
500 }
501 }
502
503 current_extension = current_extension->parent;
504 }
505 }
506
507 _get_property_listv(p_list, p_reversed);
508
509 if (!is_class("Script")) { // can still be set, but this is for user-friendliness
510 p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NEVER_DUPLICATE));
511 }
512
513 if (script_instance && !p_reversed) {
514 script_instance->get_property_list(p_list);
515 }
516
517 for (const KeyValue<StringName, Variant> &K : metadata) {
518 PropertyInfo pi = PropertyInfo(K.value.get_type(), "metadata/" + K.key.operator String());
519 if (K.value.get_type() == Variant::OBJECT) {
520 pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
521 pi.hint_string = "Resource";
522 }
523 p_list->push_back(pi);
524 }
525}
526
527void Object::validate_property(PropertyInfo &p_property) const {
528 _validate_propertyv(p_property);
529
530 if (_extension && _extension->validate_property) {
531 // GDExtension uses a StringName rather than a String for property name.
532 StringName prop_name = p_property.name;
533 GDExtensionPropertyInfo gdext_prop = {
534 (GDExtensionVariantType)p_property.type,
535 &prop_name,
536 &p_property.class_name,
537 (uint32_t)p_property.hint,
538 &p_property.hint_string,
539 p_property.usage,
540 };
541 if (_extension->validate_property(_extension_instance, &gdext_prop)) {
542 p_property.type = (Variant::Type)gdext_prop.type;
543 p_property.name = *reinterpret_cast<StringName *>(gdext_prop.name);
544 p_property.class_name = *reinterpret_cast<StringName *>(gdext_prop.class_name);
545 p_property.hint = (PropertyHint)gdext_prop.hint;
546 p_property.hint_string = *reinterpret_cast<String *>(gdext_prop.hint_string);
547 p_property.usage = gdext_prop.usage;
548 };
549 }
550
551 if (script_instance) { // Call it last to allow user altering already validated properties.
552 script_instance->validate_property(p_property);
553 }
554}
555
556bool Object::property_can_revert(const StringName &p_name) const {
557 if (script_instance) {
558 if (script_instance->property_can_revert(p_name)) {
559 return true;
560 }
561 }
562
563// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
564#if defined(__GNUC__) && !defined(__clang__)
565#pragma GCC diagnostic push
566#pragma GCC diagnostic ignored "-Wignored-qualifiers"
567#endif
568 if (_extension && _extension->property_can_revert) {
569 if (_extension->property_can_revert(_extension_instance, (const GDExtensionStringNamePtr)&p_name)) {
570 return true;
571 }
572 }
573#if defined(__GNUC__) && !defined(__clang__)
574#pragma GCC diagnostic pop
575#endif
576
577 return _property_can_revertv(p_name);
578}
579
580Variant Object::property_get_revert(const StringName &p_name) const {
581 Variant ret;
582
583 if (script_instance) {
584 if (script_instance->property_get_revert(p_name, ret)) {
585 return ret;
586 }
587 }
588
589// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
590#if defined(__GNUC__) && !defined(__clang__)
591#pragma GCC diagnostic push
592#pragma GCC diagnostic ignored "-Wignored-qualifiers"
593#endif
594 if (_extension && _extension->property_get_revert) {
595 if (_extension->property_get_revert(_extension_instance, (const GDExtensionStringNamePtr)&p_name, (GDExtensionVariantPtr)&ret)) {
596 return ret;
597 }
598 }
599#if defined(__GNUC__) && !defined(__clang__)
600#pragma GCC diagnostic pop
601#endif
602
603 if (_property_get_revertv(p_name, ret)) {
604 return ret;
605 }
606 return Variant();
607}
608
609void Object::get_method_list(List<MethodInfo> *p_list) const {
610 ClassDB::get_method_list(get_class_name(), p_list);
611 if (script_instance) {
612 script_instance->get_method_list(p_list);
613 }
614}
615
616Variant Object::_call_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
617 if (p_argcount < 1) {
618 r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
619 r_error.argument = 0;
620 return Variant();
621 }
622
623 if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) {
624 r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
625 r_error.argument = 0;
626 r_error.expected = Variant::STRING_NAME;
627 return Variant();
628 }
629
630 StringName method = *p_args[0];
631
632 return callp(method, &p_args[1], p_argcount - 1, r_error);
633}
634
635Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
636 if (p_argcount < 1) {
637 r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
638 r_error.argument = 0;
639 return Variant();
640 }
641
642 if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) {
643 r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
644 r_error.argument = 0;
645 r_error.expected = Variant::STRING_NAME;
646 return Variant();
647 }
648
649 r_error.error = Callable::CallError::CALL_OK;
650
651 StringName method = *p_args[0];
652
653 MessageQueue::get_singleton()->push_callp(get_instance_id(), method, &p_args[1], p_argcount - 1, true);
654
655 return Variant();
656}
657
658bool Object::has_method(const StringName &p_method) const {
659 if (p_method == CoreStringNames::get_singleton()->_free) {
660 return true;
661 }
662
663 if (script_instance && script_instance->has_method(p_method)) {
664 return true;
665 }
666
667 MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
668
669 return method != nullptr;
670}
671
672Variant Object::getvar(const Variant &p_key, bool *r_valid) const {
673 if (r_valid) {
674 *r_valid = false;
675 }
676
677 if (p_key.get_type() == Variant::STRING_NAME || p_key.get_type() == Variant::STRING) {
678 return get(p_key, r_valid);
679 }
680 return Variant();
681}
682
683void Object::setvar(const Variant &p_key, const Variant &p_value, bool *r_valid) {
684 if (r_valid) {
685 *r_valid = false;
686 }
687 if (p_key.get_type() == Variant::STRING_NAME || p_key.get_type() == Variant::STRING) {
688 return set(p_key, p_value, r_valid);
689 }
690}
691
692Variant Object::callv(const StringName &p_method, const Array &p_args) {
693 const Variant **argptrs = nullptr;
694
695 if (p_args.size() > 0) {
696 argptrs = (const Variant **)alloca(sizeof(Variant *) * p_args.size());
697 for (int i = 0; i < p_args.size(); i++) {
698 argptrs[i] = &p_args[i];
699 }
700 }
701
702 Callable::CallError ce;
703 Variant ret = callp(p_method, argptrs, p_args.size(), ce);
704 if (ce.error != Callable::CallError::CALL_OK) {
705 ERR_FAIL_V_MSG(Variant(), "Error calling method from 'callv': " + Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce) + ".");
706 }
707 return ret;
708}
709
710Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
711 r_error.error = Callable::CallError::CALL_OK;
712
713 if (p_method == CoreStringNames::get_singleton()->_free) {
714//free must be here, before anything, always ready
715#ifdef DEBUG_ENABLED
716 if (p_argcount != 0) {
717 r_error.argument = 0;
718 r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
719 return Variant();
720 }
721 if (Object::cast_to<RefCounted>(this)) {
722 r_error.argument = 0;
723 r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
724 ERR_FAIL_V_MSG(Variant(), "Can't 'free' a reference.");
725 }
726
727 if (_lock_index.get() > 1) {
728 r_error.argument = 0;
729 r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
730 ERR_FAIL_V_MSG(Variant(), "Object is locked and can't be freed.");
731 }
732
733#endif
734 //must be here, must be before everything,
735 memdelete(this);
736 r_error.error = Callable::CallError::CALL_OK;
737 return Variant();
738 }
739
740 Variant ret;
741 OBJ_DEBUG_LOCK
742
743 if (script_instance) {
744 ret = script_instance->callp(p_method, p_args, p_argcount, r_error);
745 //force jumptable
746 switch (r_error.error) {
747 case Callable::CallError::CALL_OK:
748 return ret;
749 case Callable::CallError::CALL_ERROR_INVALID_METHOD:
750 break;
751 case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
752 case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
753 case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
754 case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
755 return ret;
756 case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
757 }
758 }
759 }
760
761 //extension does not need this, because all methods are registered in MethodBind
762
763 MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
764
765 if (method) {
766 ret = method->call(this, p_args, p_argcount, r_error);
767 } else {
768 r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
769 }
770
771 return ret;
772}
773
774Variant Object::call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
775 r_error.error = Callable::CallError::CALL_OK;
776
777 if (p_method == CoreStringNames::get_singleton()->_free) {
778 // Free is not const, so fail.
779 r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST;
780 return Variant();
781 }
782
783 Variant ret;
784 OBJ_DEBUG_LOCK
785
786 if (script_instance) {
787 ret = script_instance->call_const(p_method, p_args, p_argcount, r_error);
788 //force jumptable
789 switch (r_error.error) {
790 case Callable::CallError::CALL_OK:
791 return ret;
792 case Callable::CallError::CALL_ERROR_INVALID_METHOD:
793 break;
794 case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
795 break;
796 case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
797 case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
798 case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
799 return ret;
800 case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
801 }
802 }
803 }
804
805 //extension does not need this, because all methods are registered in MethodBind
806
807 MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
808
809 if (method) {
810 if (!method->is_const()) {
811 r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST;
812 return ret;
813 }
814 ret = method->call(this, p_args, p_argcount, r_error);
815 } else {
816 r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
817 }
818
819 return ret;
820}
821
822void Object::notification(int p_notification, bool p_reversed) {
823 if (p_reversed) {
824 if (script_instance) {
825 script_instance->notification(p_notification, p_reversed);
826 }
827 } else {
828 _notificationv(p_notification, p_reversed);
829 }
830
831 if (_extension) {
832 if (_extension->notification2) {
833 _extension->notification2(_extension_instance, p_notification, static_cast<GDExtensionBool>(p_reversed));
834#ifndef DISABLE_DEPRECATED
835 } else if (_extension->notification) {
836 _extension->notification(_extension_instance, p_notification);
837#endif // DISABLE_DEPRECATED
838 }
839 }
840
841 if (p_reversed) {
842 _notificationv(p_notification, p_reversed);
843 } else {
844 if (script_instance) {
845 script_instance->notification(p_notification, p_reversed);
846 }
847 }
848}
849
850String Object::to_string() {
851 if (script_instance) {
852 bool valid;
853 String ret = script_instance->to_string(&valid);
854 if (valid) {
855 return ret;
856 }
857 }
858 if (_extension && _extension->to_string) {
859 String ret;
860 GDExtensionBool is_valid;
861 _extension->to_string(_extension_instance, &is_valid, &ret);
862 return ret;
863 }
864 return "<" + get_class() + "#" + itos(get_instance_id()) + ">";
865}
866
867void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) {
868 //this function is not meant to be used in any of these ways
869 ERR_FAIL_COND(p_script.is_null());
870 ERR_FAIL_NULL(p_instance);
871 ERR_FAIL_COND(script_instance != nullptr || !script.is_null());
872
873 script = p_script;
874 script_instance = p_instance;
875}
876
877void Object::set_script(const Variant &p_script) {
878 if (script == p_script) {
879 return;
880 }
881
882 Ref<Script> s = p_script;
883 ERR_FAIL_COND_MSG(s.is_null() && !p_script.is_null(), "Invalid parameter, it should be a reference to a valid script (or null).");
884
885 script = p_script;
886
887 if (script_instance) {
888 memdelete(script_instance);
889 script_instance = nullptr;
890 }
891
892 if (!s.is_null()) {
893 if (s->can_instantiate()) {
894 OBJ_DEBUG_LOCK
895 script_instance = s->instance_create(this);
896 } else if (Engine::get_singleton()->is_editor_hint()) {
897 OBJ_DEBUG_LOCK
898 script_instance = s->placeholder_instance_create(this);
899 }
900 }
901
902 notify_property_list_changed(); //scripts may add variables, so refresh is desired
903 emit_signal(CoreStringNames::get_singleton()->script_changed);
904}
905
906void Object::set_script_instance(ScriptInstance *p_instance) {
907 if (script_instance == p_instance) {
908 return;
909 }
910
911 if (script_instance) {
912 memdelete(script_instance);
913 }
914
915 script_instance = p_instance;
916
917 if (p_instance) {
918 script = p_instance->get_script();
919 } else {
920 script = Variant();
921 }
922}
923
924Variant Object::get_script() const {
925 return script;
926}
927
928bool Object::has_meta(const StringName &p_name) const {
929 return metadata.has(p_name);
930}
931
932void Object::set_meta(const StringName &p_name, const Variant &p_value) {
933 if (p_value.get_type() == Variant::NIL) {
934 if (metadata.has(p_name)) {
935 metadata.erase(p_name);
936
937 const String &sname = p_name;
938 metadata_properties.erase("metadata/" + sname);
939 if (!sname.begins_with("_")) {
940 // Metadata starting with _ don't show up in the inspector, so no need to update.
941 notify_property_list_changed();
942 }
943 }
944 return;
945 }
946
947 HashMap<StringName, Variant>::Iterator E = metadata.find(p_name);
948 if (E) {
949 E->value = p_value;
950 } else {
951 ERR_FAIL_COND_MSG(!p_name.operator String().is_valid_identifier(), "Invalid metadata identifier: '" + p_name + "'.");
952 Variant *V = &metadata.insert(p_name, p_value)->value;
953
954 const String &sname = p_name;
955 metadata_properties["metadata/" + sname] = V;
956 if (!sname.begins_with("_")) {
957 notify_property_list_changed();
958 }
959 }
960}
961
962Variant Object::get_meta(const StringName &p_name, const Variant &p_default) const {
963 if (!metadata.has(p_name)) {
964 if (p_default != Variant()) {
965 return p_default;
966 } else {
967 ERR_FAIL_V_MSG(Variant(), "The object does not have any 'meta' values with the key '" + p_name + "'.");
968 }
969 }
970 return metadata[p_name];
971}
972
973void Object::remove_meta(const StringName &p_name) {
974 set_meta(p_name, Variant());
975}
976
977TypedArray<Dictionary> Object::_get_property_list_bind() const {
978 List<PropertyInfo> lpi;
979 get_property_list(&lpi);
980 return convert_property_list(&lpi);
981}
982
983TypedArray<Dictionary> Object::_get_method_list_bind() const {
984 List<MethodInfo> ml;
985 get_method_list(&ml);
986 TypedArray<Dictionary> ret;
987
988 for (List<MethodInfo>::Element *E = ml.front(); E; E = E->next()) {
989 Dictionary d = E->get();
990 //va.push_back(d);
991 ret.push_back(d);
992 }
993
994 return ret;
995}
996
997TypedArray<StringName> Object::_get_meta_list_bind() const {
998 TypedArray<StringName> _metaret;
999
1000 for (const KeyValue<StringName, Variant> &K : metadata) {
1001 _metaret.push_back(K.key);
1002 }
1003
1004 return _metaret;
1005}
1006
1007void Object::get_meta_list(List<StringName> *p_list) const {
1008 for (const KeyValue<StringName, Variant> &K : metadata) {
1009 p_list->push_back(K.key);
1010 }
1011}
1012
1013void Object::add_user_signal(const MethodInfo &p_signal) {
1014 ERR_FAIL_COND_MSG(p_signal.name.is_empty(), "Signal name cannot be empty.");
1015 ERR_FAIL_COND_MSG(ClassDB::has_signal(get_class_name(), p_signal.name), "User signal's name conflicts with a built-in signal of '" + get_class_name() + "'.");
1016 ERR_FAIL_COND_MSG(signal_map.has(p_signal.name), "Trying to add already existing signal '" + p_signal.name + "'.");
1017 SignalData s;
1018 s.user = p_signal;
1019 signal_map[p_signal.name] = s;
1020}
1021
1022bool Object::_has_user_signal(const StringName &p_name) const {
1023 if (!signal_map.has(p_name)) {
1024 return false;
1025 }
1026 return signal_map[p_name].user.name.length() > 0;
1027}
1028
1029struct _ObjectSignalDisconnectData {
1030 StringName signal;
1031 Callable callable;
1032};
1033
1034Error Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
1035 r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
1036
1037 ERR_FAIL_COND_V(p_argcount < 1, Error::ERR_INVALID_PARAMETER);
1038 if (p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING) {
1039 r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
1040 r_error.argument = 0;
1041 r_error.expected = Variant::STRING_NAME;
1042 ERR_FAIL_COND_V(p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING, Error::ERR_INVALID_PARAMETER);
1043 }
1044
1045 r_error.error = Callable::CallError::CALL_OK;
1046
1047 StringName signal = *p_args[0];
1048
1049 const Variant **args = nullptr;
1050
1051 int argc = p_argcount - 1;
1052 if (argc) {
1053 args = &p_args[1];
1054 }
1055
1056 return emit_signalp(signal, args, argc);
1057}
1058
1059Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount) {
1060 if (_block_signals) {
1061 return ERR_CANT_ACQUIRE_RESOURCE; //no emit, signals blocked
1062 }
1063
1064 SignalData *s = signal_map.getptr(p_name);
1065 if (!s) {
1066#ifdef DEBUG_ENABLED
1067 bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_name);
1068 //check in script
1069 ERR_FAIL_COND_V_MSG(!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name), ERR_UNAVAILABLE, "Can't emit non-existing signal " + String("\"") + p_name + "\".");
1070#endif
1071 //not connected? just return
1072 return ERR_UNAVAILABLE;
1073 }
1074
1075 // If this is a ref-counted object, prevent it from being destroyed during signal emission,
1076 // which is needed in certain edge cases; e.g., https://github.com/godotengine/godot/issues/73889.
1077 Ref<RefCounted> rc = Ref<RefCounted>(Object::cast_to<RefCounted>(this));
1078
1079 List<_ObjectSignalDisconnectData> disconnect_data;
1080
1081 // Ensure that disconnecting the signal or even deleting the object
1082 // will not affect the signal calling.
1083 LocalVector<Connection> slot_conns;
1084 slot_conns.resize(s->slot_map.size());
1085 {
1086 uint32_t idx = 0;
1087 for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
1088 slot_conns[idx++] = slot_kv.value.conn;
1089 }
1090 DEV_ASSERT(idx == s->slot_map.size());
1091 }
1092
1093 OBJ_DEBUG_LOCK
1094
1095 Error err = OK;
1096
1097 for (const Connection &c : slot_conns) {
1098 Object *target = c.callable.get_object();
1099 if (!target) {
1100 // Target might have been deleted during signal callback, this is expected and OK.
1101 continue;
1102 }
1103
1104 const Variant **args = p_args;
1105 int argc = p_argcount;
1106
1107 if (c.flags & CONNECT_DEFERRED) {
1108 MessageQueue::get_singleton()->push_callablep(c.callable, args, argc, true);
1109 } else {
1110 Callable::CallError ce;
1111 _emitting = true;
1112 Variant ret;
1113 c.callable.callp(args, argc, ret, ce);
1114 _emitting = false;
1115
1116 if (ce.error != Callable::CallError::CALL_OK) {
1117#ifdef DEBUG_ENABLED
1118 if (c.flags & CONNECT_PERSIST && Engine::get_singleton()->is_editor_hint() && (script.is_null() || !Ref<Script>(script)->is_tool())) {
1119 continue;
1120 }
1121#endif
1122 if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD && !ClassDB::class_exists(target->get_class_name())) {
1123 //most likely object is not initialized yet, do not throw error.
1124 } else {
1125 ERR_PRINT("Error calling from signal '" + String(p_name) + "' to callable: " + Variant::get_callable_error_text(c.callable, args, argc, ce) + ".");
1126 err = ERR_METHOD_NOT_FOUND;
1127 }
1128 }
1129 }
1130
1131 bool disconnect = c.flags & CONNECT_ONE_SHOT;
1132#ifdef TOOLS_ENABLED
1133 if (disconnect && (c.flags & CONNECT_PERSIST) && Engine::get_singleton()->is_editor_hint()) {
1134 //this signal was connected from the editor, and is being edited. just don't disconnect for now
1135 disconnect = false;
1136 }
1137#endif
1138 if (disconnect) {
1139 _ObjectSignalDisconnectData dd;
1140 dd.signal = p_name;
1141 dd.callable = c.callable;
1142 disconnect_data.push_back(dd);
1143 }
1144 }
1145
1146 while (!disconnect_data.is_empty()) {
1147 const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get();
1148
1149 _disconnect(dd.signal, dd.callable);
1150 disconnect_data.pop_front();
1151 }
1152
1153 return err;
1154}
1155
1156void Object::_add_user_signal(const String &p_name, const Array &p_args) {
1157 // this version of add_user_signal is meant to be used from scripts or external apis
1158 // without access to ADD_SIGNAL in bind_methods
1159 // added events are per instance, as opposed to the other ones, which are global
1160
1161 MethodInfo mi;
1162 mi.name = p_name;
1163
1164 for (int i = 0; i < p_args.size(); i++) {
1165 Dictionary d = p_args[i];
1166 PropertyInfo param;
1167
1168 if (d.has("name")) {
1169 param.name = d["name"];
1170 }
1171 if (d.has("type")) {
1172 param.type = (Variant::Type)(int)d["type"];
1173 }
1174
1175 mi.arguments.push_back(param);
1176 }
1177
1178 add_user_signal(mi);
1179}
1180
1181TypedArray<Dictionary> Object::_get_signal_list() const {
1182 List<MethodInfo> signal_list;
1183 get_signal_list(&signal_list);
1184
1185 TypedArray<Dictionary> ret;
1186 for (const MethodInfo &E : signal_list) {
1187 ret.push_back(Dictionary(E));
1188 }
1189
1190 return ret;
1191}
1192
1193TypedArray<Dictionary> Object::_get_signal_connection_list(const StringName &p_signal) const {
1194 List<Connection> conns;
1195 get_all_signal_connections(&conns);
1196
1197 TypedArray<Dictionary> ret;
1198
1199 for (const Connection &c : conns) {
1200 if (c.signal.get_name() == p_signal) {
1201 ret.push_back(c);
1202 }
1203 }
1204
1205 return ret;
1206}
1207
1208TypedArray<Dictionary> Object::_get_incoming_connections() const {
1209 TypedArray<Dictionary> ret;
1210 int connections_amount = connections.size();
1211 for (int idx_conn = 0; idx_conn < connections_amount; idx_conn++) {
1212 ret.push_back(connections[idx_conn]);
1213 }
1214
1215 return ret;
1216}
1217
1218bool Object::has_signal(const StringName &p_name) const {
1219 if (!script.is_null()) {
1220 Ref<Script> scr = script;
1221 if (scr.is_valid() && scr->has_script_signal(p_name)) {
1222 return true;
1223 }
1224 }
1225
1226 if (ClassDB::has_signal(get_class_name(), p_name)) {
1227 return true;
1228 }
1229
1230 if (_has_user_signal(p_name)) {
1231 return true;
1232 }
1233
1234 return false;
1235}
1236
1237void Object::get_signal_list(List<MethodInfo> *p_signals) const {
1238 if (!script.is_null()) {
1239 Ref<Script> scr = script;
1240 if (scr.is_valid()) {
1241 scr->get_script_signal_list(p_signals);
1242 }
1243 }
1244
1245 ClassDB::get_signal_list(get_class_name(), p_signals);
1246 //find maybe usersignals?
1247
1248 for (const KeyValue<StringName, SignalData> &E : signal_map) {
1249 if (!E.value.user.name.is_empty()) {
1250 //user signal
1251 p_signals->push_back(E.value.user);
1252 }
1253 }
1254}
1255
1256void Object::get_all_signal_connections(List<Connection> *p_connections) const {
1257 for (const KeyValue<StringName, SignalData> &E : signal_map) {
1258 const SignalData *s = &E.value;
1259
1260 for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
1261 p_connections->push_back(slot_kv.value.conn);
1262 }
1263 }
1264}
1265
1266void Object::get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const {
1267 const SignalData *s = signal_map.getptr(p_signal);
1268 if (!s) {
1269 return; //nothing
1270 }
1271
1272 for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
1273 p_connections->push_back(slot_kv.value.conn);
1274 }
1275}
1276
1277int Object::get_persistent_signal_connection_count() const {
1278 int count = 0;
1279
1280 for (const KeyValue<StringName, SignalData> &E : signal_map) {
1281 const SignalData *s = &E.value;
1282
1283 for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
1284 if (slot_kv.value.conn.flags & CONNECT_PERSIST) {
1285 count += 1;
1286 }
1287 }
1288 }
1289
1290 return count;
1291}
1292
1293void Object::get_signals_connected_to_this(List<Connection> *p_connections) const {
1294 for (const Connection &E : connections) {
1295 p_connections->push_back(E);
1296 }
1297}
1298
1299Error Object::connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags) {
1300 ERR_FAIL_COND_V_MSG(p_callable.is_null(), ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "': the provided callable is null.");
1301
1302 Object *target_object = p_callable.get_object();
1303 ERR_FAIL_NULL_V_MSG(target_object, ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "' to callable '" + p_callable + "': the callable object is null.");
1304
1305 SignalData *s = signal_map.getptr(p_signal);
1306 if (!s) {
1307 bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
1308 //check in script
1309 if (!signal_is_valid && !script.is_null()) {
1310 if (Ref<Script>(script)->has_script_signal(p_signal)) {
1311 signal_is_valid = true;
1312 }
1313#ifdef TOOLS_ENABLED
1314 else {
1315 //allow connecting signals anyway if script is invalid, see issue #17070
1316 if (!Ref<Script>(script)->is_valid()) {
1317 signal_is_valid = true;
1318 }
1319 }
1320#endif
1321 }
1322
1323 ERR_FAIL_COND_V_MSG(!signal_is_valid, ERR_INVALID_PARAMETER, "In Object of type '" + String(get_class()) + "': Attempt to connect nonexistent signal '" + p_signal + "' to callable '" + p_callable + "'.");
1324
1325 signal_map[p_signal] = SignalData();
1326 s = &signal_map[p_signal];
1327 }
1328
1329 Callable target = p_callable;
1330
1331 //compare with the base callable, so binds can be ignored
1332 if (s->slot_map.has(*target.get_base_comparator())) {
1333 if (p_flags & CONNECT_REFERENCE_COUNTED) {
1334 s->slot_map[*target.get_base_comparator()].reference_count++;
1335 return OK;
1336 } else {
1337 ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Signal '" + p_signal + "' is already connected to given callable '" + p_callable + "' in that object.");
1338 }
1339 }
1340
1341 SignalData::Slot slot;
1342
1343 Connection conn;
1344 conn.callable = target;
1345 conn.signal = ::Signal(this, p_signal);
1346 conn.flags = p_flags;
1347 slot.conn = conn;
1348 slot.cE = target_object->connections.push_back(conn);
1349 if (p_flags & CONNECT_REFERENCE_COUNTED) {
1350 slot.reference_count = 1;
1351 }
1352
1353 //use callable version as key, so binds can be ignored
1354 s->slot_map[*target.get_base_comparator()] = slot;
1355
1356 return OK;
1357}
1358
1359bool Object::is_connected(const StringName &p_signal, const Callable &p_callable) const {
1360 ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot determine if connected to '" + p_signal + "': the provided callable is null.");
1361 const SignalData *s = signal_map.getptr(p_signal);
1362 if (!s) {
1363 bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
1364 if (signal_is_valid) {
1365 return false;
1366 }
1367
1368 if (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)) {
1369 return false;
1370 }
1371
1372 ERR_FAIL_V_MSG(false, "Nonexistent signal: " + p_signal + ".");
1373 }
1374
1375 Callable target = p_callable;
1376
1377 return s->slot_map.has(*target.get_base_comparator());
1378}
1379
1380void Object::disconnect(const StringName &p_signal, const Callable &p_callable) {
1381 _disconnect(p_signal, p_callable);
1382}
1383
1384bool Object::_disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force) {
1385 ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot disconnect from '" + p_signal + "': the provided callable is null.");
1386
1387 Object *target_object = p_callable.get_object();
1388 ERR_FAIL_NULL_V_MSG(target_object, false, "Cannot disconnect '" + p_signal + "' from callable '" + p_callable + "': the callable object is null.");
1389
1390 SignalData *s = signal_map.getptr(p_signal);
1391 if (!s) {
1392 bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal) ||
1393 (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal));
1394 ERR_FAIL_COND_V_MSG(signal_is_valid, false, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. Signal: '" + p_signal + "', callable: '" + p_callable + "'.");
1395 }
1396 ERR_FAIL_NULL_V_MSG(s, false, vformat("Disconnecting nonexistent signal '%s' in %s.", p_signal, to_string()));
1397
1398 ERR_FAIL_COND_V_MSG(!s->slot_map.has(*p_callable.get_base_comparator()), false, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. Signal: '" + p_signal + "', callable: '" + p_callable + "'.");
1399
1400 SignalData::Slot *slot = &s->slot_map[*p_callable.get_base_comparator()];
1401
1402 if (!p_force) {
1403 slot->reference_count--; // by default is zero, if it was not referenced it will go below it
1404 if (slot->reference_count > 0) {
1405 return false;
1406 }
1407 }
1408
1409 target_object->connections.erase(slot->cE);
1410 s->slot_map.erase(*p_callable.get_base_comparator());
1411
1412 if (s->slot_map.is_empty() && ClassDB::has_signal(get_class_name(), p_signal)) {
1413 //not user signal, delete
1414 signal_map.erase(p_signal);
1415 }
1416
1417 return true;
1418}
1419
1420void Object::_set_bind(const StringName &p_set, const Variant &p_value) {
1421 set(p_set, p_value);
1422}
1423
1424Variant Object::_get_bind(const StringName &p_name) const {
1425 return get(p_name);
1426}
1427
1428void Object::_set_indexed_bind(const NodePath &p_name, const Variant &p_value) {
1429 set_indexed(p_name.get_as_property_path().get_subnames(), p_value);
1430}
1431
1432Variant Object::_get_indexed_bind(const NodePath &p_name) const {
1433 return get_indexed(p_name.get_as_property_path().get_subnames());
1434}
1435
1436void Object::initialize_class() {
1437 static bool initialized = false;
1438 if (initialized) {
1439 return;
1440 }
1441 ClassDB::_add_class<Object>();
1442 _bind_methods();
1443 initialized = true;
1444}
1445
1446String Object::tr(const StringName &p_message, const StringName &p_context) const {
1447 if (!_can_translate || !TranslationServer::get_singleton()) {
1448 return p_message;
1449 }
1450
1451 if (Engine::get_singleton()->is_editor_hint()) {
1452 return TranslationServer::get_singleton()->tool_translate(p_message, p_context);
1453 } else {
1454 return TranslationServer::get_singleton()->translate(p_message, p_context);
1455 }
1456}
1457
1458String Object::tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
1459 if (!_can_translate || !TranslationServer::get_singleton()) {
1460 // Return message based on English plural rule if translation is not possible.
1461 if (p_n == 1) {
1462 return p_message;
1463 }
1464 return p_message_plural;
1465 }
1466
1467 if (Engine::get_singleton()->is_editor_hint()) {
1468 return TranslationServer::get_singleton()->tool_translate_plural(p_message, p_message_plural, p_n, p_context);
1469 } else {
1470 return TranslationServer::get_singleton()->translate_plural(p_message, p_message_plural, p_n, p_context);
1471 }
1472}
1473
1474void Object::_clear_internal_resource_paths(const Variant &p_var) {
1475 switch (p_var.get_type()) {
1476 case Variant::OBJECT: {
1477 Ref<Resource> r = p_var;
1478 if (!r.is_valid()) {
1479 return;
1480 }
1481
1482 if (!r->is_built_in()) {
1483 return; //not an internal resource
1484 }
1485
1486 Object *object = p_var;
1487 if (!object) {
1488 return;
1489 }
1490
1491 r->set_path("");
1492 r->clear_internal_resource_paths();
1493 } break;
1494 case Variant::ARRAY: {
1495 Array a = p_var;
1496 for (int i = 0; i < a.size(); i++) {
1497 _clear_internal_resource_paths(a[i]);
1498 }
1499
1500 } break;
1501 case Variant::DICTIONARY: {
1502 Dictionary d = p_var;
1503 List<Variant> keys;
1504 d.get_key_list(&keys);
1505
1506 for (const Variant &E : keys) {
1507 _clear_internal_resource_paths(E);
1508 _clear_internal_resource_paths(d[E]);
1509 }
1510 } break;
1511 default: {
1512 }
1513 }
1514}
1515
1516#ifdef TOOLS_ENABLED
1517void Object::editor_set_section_unfold(const String &p_section, bool p_unfolded) {
1518 set_edited(true);
1519 if (p_unfolded) {
1520 editor_section_folding.insert(p_section);
1521 } else {
1522 editor_section_folding.erase(p_section);
1523 }
1524}
1525
1526bool Object::editor_is_section_unfolded(const String &p_section) {
1527 return editor_section_folding.has(p_section);
1528}
1529
1530#endif
1531
1532void Object::clear_internal_resource_paths() {
1533 List<PropertyInfo> pinfo;
1534
1535 get_property_list(&pinfo);
1536
1537 for (const PropertyInfo &E : pinfo) {
1538 _clear_internal_resource_paths(get(E.name));
1539 }
1540}
1541
1542void Object::notify_property_list_changed() {
1543 emit_signal(CoreStringNames::get_singleton()->property_list_changed);
1544}
1545
1546void Object::_bind_methods() {
1547 ClassDB::bind_method(D_METHOD("get_class"), &Object::get_class);
1548 ClassDB::bind_method(D_METHOD("is_class", "class"), &Object::is_class);
1549 ClassDB::bind_method(D_METHOD("set", "property", "value"), &Object::_set_bind);
1550 ClassDB::bind_method(D_METHOD("get", "property"), &Object::_get_bind);
1551 ClassDB::bind_method(D_METHOD("set_indexed", "property_path", "value"), &Object::_set_indexed_bind);
1552 ClassDB::bind_method(D_METHOD("get_indexed", "property_path"), &Object::_get_indexed_bind);
1553 ClassDB::bind_method(D_METHOD("get_property_list"), &Object::_get_property_list_bind);
1554 ClassDB::bind_method(D_METHOD("get_method_list"), &Object::_get_method_list_bind);
1555 ClassDB::bind_method(D_METHOD("property_can_revert", "property"), &Object::property_can_revert);
1556 ClassDB::bind_method(D_METHOD("property_get_revert", "property"), &Object::property_get_revert);
1557 ClassDB::bind_method(D_METHOD("notification", "what", "reversed"), &Object::notification, DEFVAL(false));
1558 ClassDB::bind_method(D_METHOD("to_string"), &Object::to_string);
1559 ClassDB::bind_method(D_METHOD("get_instance_id"), &Object::get_instance_id);
1560
1561 ClassDB::bind_method(D_METHOD("set_script", "script"), &Object::set_script);
1562 ClassDB::bind_method(D_METHOD("get_script"), &Object::get_script);
1563
1564 ClassDB::bind_method(D_METHOD("set_meta", "name", "value"), &Object::set_meta);
1565 ClassDB::bind_method(D_METHOD("remove_meta", "name"), &Object::remove_meta);
1566 ClassDB::bind_method(D_METHOD("get_meta", "name", "default"), &Object::get_meta, DEFVAL(Variant()));
1567 ClassDB::bind_method(D_METHOD("has_meta", "name"), &Object::has_meta);
1568 ClassDB::bind_method(D_METHOD("get_meta_list"), &Object::_get_meta_list_bind);
1569
1570 ClassDB::bind_method(D_METHOD("add_user_signal", "signal", "arguments"), &Object::_add_user_signal, DEFVAL(Array()));
1571 ClassDB::bind_method(D_METHOD("has_user_signal", "signal"), &Object::_has_user_signal);
1572
1573 {
1574 MethodInfo mi;
1575 mi.name = "emit_signal";
1576 mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "signal"));
1577
1578 ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "emit_signal", &Object::_emit_signal, mi, varray(), false);
1579 }
1580
1581 {
1582 MethodInfo mi;
1583 mi.name = "call";
1584 mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
1585
1586 ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call", &Object::_call_bind, mi);
1587 }
1588
1589 {
1590 MethodInfo mi;
1591 mi.name = "call_deferred";
1592 mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
1593
1594 ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_deferred", &Object::_call_deferred_bind, mi, varray(), false);
1595 }
1596
1597 ClassDB::bind_method(D_METHOD("set_deferred", "property", "value"), &Object::set_deferred);
1598
1599 ClassDB::bind_method(D_METHOD("callv", "method", "arg_array"), &Object::callv);
1600
1601 ClassDB::bind_method(D_METHOD("has_method", "method"), &Object::has_method);
1602
1603 ClassDB::bind_method(D_METHOD("has_signal", "signal"), &Object::has_signal);
1604 ClassDB::bind_method(D_METHOD("get_signal_list"), &Object::_get_signal_list);
1605 ClassDB::bind_method(D_METHOD("get_signal_connection_list", "signal"), &Object::_get_signal_connection_list);
1606 ClassDB::bind_method(D_METHOD("get_incoming_connections"), &Object::_get_incoming_connections);
1607
1608 ClassDB::bind_method(D_METHOD("connect", "signal", "callable", "flags"), &Object::connect, DEFVAL(0));
1609 ClassDB::bind_method(D_METHOD("disconnect", "signal", "callable"), &Object::disconnect);
1610 ClassDB::bind_method(D_METHOD("is_connected", "signal", "callable"), &Object::is_connected);
1611
1612 ClassDB::bind_method(D_METHOD("set_block_signals", "enable"), &Object::set_block_signals);
1613 ClassDB::bind_method(D_METHOD("is_blocking_signals"), &Object::is_blocking_signals);
1614 ClassDB::bind_method(D_METHOD("notify_property_list_changed"), &Object::notify_property_list_changed);
1615
1616 ClassDB::bind_method(D_METHOD("set_message_translation", "enable"), &Object::set_message_translation);
1617 ClassDB::bind_method(D_METHOD("can_translate_messages"), &Object::can_translate_messages);
1618 ClassDB::bind_method(D_METHOD("tr", "message", "context"), &Object::tr, DEFVAL(""));
1619 ClassDB::bind_method(D_METHOD("tr_n", "message", "plural_message", "n", "context"), &Object::tr_n, DEFVAL(""));
1620
1621 ClassDB::bind_method(D_METHOD("is_queued_for_deletion"), &Object::is_queued_for_deletion);
1622 ClassDB::bind_method(D_METHOD("cancel_free"), &Object::cancel_free);
1623
1624 ClassDB::add_virtual_method("Object", MethodInfo("free"), false);
1625
1626 ADD_SIGNAL(MethodInfo("script_changed"));
1627 ADD_SIGNAL(MethodInfo("property_list_changed"));
1628
1629#define BIND_OBJ_CORE_METHOD(m_method) \
1630 ::ClassDB::add_virtual_method(get_class_static(), m_method, true, Vector<String>(), true);
1631
1632 MethodInfo notification_mi("_notification", PropertyInfo(Variant::INT, "what"));
1633 notification_mi.arguments_metadata.push_back(GodotTypeInfo::Metadata::METADATA_INT_IS_INT32);
1634 BIND_OBJ_CORE_METHOD(notification_mi);
1635 BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_set", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value")));
1636#ifdef TOOLS_ENABLED
1637 MethodInfo miget("_get", PropertyInfo(Variant::STRING_NAME, "property"));
1638 miget.return_val.name = "Variant";
1639 miget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
1640 BIND_OBJ_CORE_METHOD(miget);
1641
1642 MethodInfo plget("_get_property_list");
1643 plget.return_val.type = Variant::ARRAY;
1644 plget.return_val.hint = PROPERTY_HINT_ARRAY_TYPE;
1645 plget.return_val.hint_string = "Dictionary";
1646 BIND_OBJ_CORE_METHOD(plget);
1647
1648 BIND_OBJ_CORE_METHOD(MethodInfo(Variant::NIL, "_validate_property", PropertyInfo(Variant::DICTIONARY, "property")));
1649
1650 BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_property_can_revert", PropertyInfo(Variant::STRING_NAME, "property")));
1651 MethodInfo mipgr("_property_get_revert", PropertyInfo(Variant::STRING_NAME, "property"));
1652 mipgr.return_val.name = "Variant";
1653 mipgr.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
1654 BIND_OBJ_CORE_METHOD(mipgr);
1655
1656#endif
1657 BIND_OBJ_CORE_METHOD(MethodInfo("_init"));
1658 BIND_OBJ_CORE_METHOD(MethodInfo(Variant::STRING, "_to_string"));
1659
1660 BIND_CONSTANT(NOTIFICATION_POSTINITIALIZE);
1661 BIND_CONSTANT(NOTIFICATION_PREDELETE);
1662
1663 BIND_ENUM_CONSTANT(CONNECT_DEFERRED);
1664 BIND_ENUM_CONSTANT(CONNECT_PERSIST);
1665 BIND_ENUM_CONSTANT(CONNECT_ONE_SHOT);
1666 BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);
1667}
1668
1669void Object::set_deferred(const StringName &p_property, const Variant &p_value) {
1670 MessageQueue::get_singleton()->push_set(this, p_property, p_value);
1671}
1672
1673void Object::set_block_signals(bool p_block) {
1674 _block_signals = p_block;
1675}
1676
1677bool Object::is_blocking_signals() const {
1678 return _block_signals;
1679}
1680
1681Variant::Type Object::get_static_property_type(const StringName &p_property, bool *r_valid) const {
1682 bool valid;
1683 Variant::Type t = ClassDB::get_property_type(get_class_name(), p_property, &valid);
1684 if (valid) {
1685 if (r_valid) {
1686 *r_valid = true;
1687 }
1688 return t;
1689 }
1690
1691 if (get_script_instance()) {
1692 return get_script_instance()->get_property_type(p_property, r_valid);
1693 }
1694 if (r_valid) {
1695 *r_valid = false;
1696 }
1697
1698 return Variant::NIL;
1699}
1700
1701Variant::Type Object::get_static_property_type_indexed(const Vector<StringName> &p_path, bool *r_valid) const {
1702 if (p_path.size() == 0) {
1703 if (r_valid) {
1704 *r_valid = false;
1705 }
1706
1707 return Variant::NIL;
1708 }
1709
1710 bool valid = false;
1711 Variant::Type t = get_static_property_type(p_path[0], &valid);
1712 if (!valid) {
1713 if (r_valid) {
1714 *r_valid = false;
1715 }
1716
1717 return Variant::NIL;
1718 }
1719
1720 Callable::CallError ce;
1721 Variant check;
1722 Variant::construct(t, check, nullptr, 0, ce);
1723
1724 for (int i = 1; i < p_path.size(); i++) {
1725 if (check.get_type() == Variant::OBJECT || check.get_type() == Variant::DICTIONARY || check.get_type() == Variant::ARRAY) {
1726 // We cannot be sure about the type of properties this type can have
1727 if (r_valid) {
1728 *r_valid = false;
1729 }
1730 return Variant::NIL;
1731 }
1732
1733 check = check.get_named(p_path[i], valid);
1734
1735 if (!valid) {
1736 if (r_valid) {
1737 *r_valid = false;
1738 }
1739 return Variant::NIL;
1740 }
1741 }
1742
1743 if (r_valid) {
1744 *r_valid = true;
1745 }
1746
1747 return check.get_type();
1748}
1749
1750bool Object::is_queued_for_deletion() const {
1751 return _is_queued_for_deletion;
1752}
1753
1754#ifdef TOOLS_ENABLED
1755void Object::set_edited(bool p_edited) {
1756 _edited = p_edited;
1757 _edited_version++;
1758}
1759
1760bool Object::is_edited() const {
1761 return _edited;
1762}
1763
1764uint32_t Object::get_edited_version() const {
1765 return _edited_version;
1766}
1767#endif
1768
1769StringName Object::get_class_name_for_extension(const GDExtension *p_library) const {
1770 // Only return the class name per the extension if it matches the given p_library.
1771 if (_extension && _extension->library == p_library) {
1772 return _extension->class_name;
1773 }
1774
1775 // Extensions only have wrapper classes for classes exposed in ClassDB.
1776 const StringName *class_name = _get_class_namev();
1777 if (ClassDB::is_class_exposed(*class_name)) {
1778 return *class_name;
1779 }
1780
1781 // Find the nearest parent class that's exposed.
1782 StringName parent_class = ClassDB::get_parent_class(*class_name);
1783 while (parent_class != StringName()) {
1784 if (ClassDB::is_class_exposed(parent_class)) {
1785 return parent_class;
1786 }
1787 parent_class = ClassDB::get_parent_class(parent_class);
1788 }
1789
1790 return SNAME("Object");
1791}
1792
1793void Object::set_instance_binding(void *p_token, void *p_binding, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
1794 // This is only meant to be used on creation by the binder.
1795 ERR_FAIL_COND(_instance_bindings != nullptr);
1796 _instance_bindings = (InstanceBinding *)memalloc(sizeof(InstanceBinding));
1797 _instance_bindings[0].binding = p_binding;
1798 _instance_bindings[0].free_callback = p_callbacks->free_callback;
1799 _instance_bindings[0].reference_callback = p_callbacks->reference_callback;
1800 _instance_bindings[0].token = p_token;
1801 _instance_binding_count = 1;
1802}
1803
1804void *Object::get_instance_binding(void *p_token, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
1805 void *binding = nullptr;
1806 _instance_binding_mutex.lock();
1807 for (uint32_t i = 0; i < _instance_binding_count; i++) {
1808 if (_instance_bindings[i].token == p_token) {
1809 binding = _instance_bindings[i].binding;
1810 break;
1811 }
1812 }
1813 if (unlikely(!binding && p_callbacks)) {
1814 uint32_t current_size = next_power_of_2(_instance_binding_count);
1815 uint32_t new_size = next_power_of_2(_instance_binding_count + 1);
1816
1817 if (current_size == 0 || new_size > current_size) {
1818 _instance_bindings = (InstanceBinding *)memrealloc(_instance_bindings, new_size * sizeof(InstanceBinding));
1819 }
1820
1821 _instance_bindings[_instance_binding_count].free_callback = p_callbacks->free_callback;
1822 _instance_bindings[_instance_binding_count].reference_callback = p_callbacks->reference_callback;
1823 _instance_bindings[_instance_binding_count].token = p_token;
1824
1825 binding = p_callbacks->create_callback(p_token, this);
1826 _instance_bindings[_instance_binding_count].binding = binding;
1827
1828 _instance_binding_count++;
1829 }
1830
1831 _instance_binding_mutex.unlock();
1832
1833 return binding;
1834}
1835
1836bool Object::has_instance_binding(void *p_token) {
1837 bool found = false;
1838 _instance_binding_mutex.lock();
1839 for (uint32_t i = 0; i < _instance_binding_count; i++) {
1840 if (_instance_bindings[i].token == p_token) {
1841 found = true;
1842 break;
1843 }
1844 }
1845
1846 _instance_binding_mutex.unlock();
1847
1848 return found;
1849}
1850
1851void Object::_construct_object(bool p_reference) {
1852 type_is_reference = p_reference;
1853 _instance_id = ObjectDB::add_instance(this);
1854
1855#ifdef DEBUG_ENABLED
1856 _lock_index.init(1);
1857#endif
1858}
1859
1860Object::Object(bool p_reference) {
1861 _construct_object(p_reference);
1862}
1863
1864Object::Object() {
1865 _construct_object(false);
1866}
1867
1868void Object::detach_from_objectdb() {
1869 if (_instance_id != ObjectID()) {
1870 ObjectDB::remove_instance(this);
1871 _instance_id = ObjectID();
1872 }
1873}
1874
1875Object::~Object() {
1876 if (script_instance) {
1877 memdelete(script_instance);
1878 }
1879 script_instance = nullptr;
1880
1881 if (_extension && _extension->free_instance) {
1882 _extension->free_instance(_extension->class_userdata, _extension_instance);
1883 _extension = nullptr;
1884 _extension_instance = nullptr;
1885 }
1886
1887 if (_emitting) {
1888 //@todo this may need to actually reach the debugger prioritarily somehow because it may crash before
1889 ERR_PRINT("Object " + to_string() + " was freed or unreferenced while a signal is being emitted from it. Try connecting to the signal using 'CONNECT_DEFERRED' flag, or use queue_free() to free the object (if this object is a Node) to avoid this error and potential crashes.");
1890 }
1891
1892 // Drop all connections to the signals of this object.
1893 while (signal_map.size()) {
1894 // Avoid regular iteration so erasing is safe.
1895 KeyValue<StringName, SignalData> &E = *signal_map.begin();
1896 SignalData *s = &E.value;
1897
1898 for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
1899 Object *target = slot_kv.value.conn.callable.get_object();
1900 if (likely(target)) {
1901 target->connections.erase(slot_kv.value.cE);
1902 }
1903 }
1904
1905 signal_map.erase(E.key);
1906 }
1907
1908 // Disconnect signals that connect to this object.
1909 while (connections.size()) {
1910 Connection c = connections.front()->get();
1911 bool disconnected = c.signal.get_object()->_disconnect(c.signal.get_name(), c.callable, true);
1912 if (unlikely(!disconnected)) {
1913 // If the disconnect has failed, abandon the connection to avoid getting trapped in an infinite loop here.
1914 connections.pop_front();
1915 }
1916 }
1917
1918 if (_instance_id != ObjectID()) {
1919 ObjectDB::remove_instance(this);
1920 _instance_id = ObjectID();
1921 }
1922 _predelete_ok = 2;
1923
1924 if (_instance_bindings != nullptr) {
1925 for (uint32_t i = 0; i < _instance_binding_count; i++) {
1926 if (_instance_bindings[i].free_callback) {
1927 _instance_bindings[i].free_callback(_instance_bindings[i].token, this, _instance_bindings[i].binding);
1928 }
1929 }
1930 memfree(_instance_bindings);
1931 }
1932}
1933
1934bool predelete_handler(Object *p_object) {
1935 return p_object->_predelete();
1936}
1937
1938void postinitialize_handler(Object *p_object) {
1939 p_object->_postinitialize();
1940}
1941
1942void ObjectDB::debug_objects(DebugFunc p_func) {
1943 spin_lock.lock();
1944
1945 for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) {
1946 if (object_slots[i].validator) {
1947 p_func(object_slots[i].object);
1948 count--;
1949 }
1950 }
1951 spin_lock.unlock();
1952}
1953
1954void Object::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
1955 if (p_idx == 0) {
1956 if (p_function == "connect" || p_function == "is_connected" || p_function == "disconnect" || p_function == "emit_signal" || p_function == "has_signal") {
1957 List<MethodInfo> signals;
1958 get_signal_list(&signals);
1959 for (const MethodInfo &E : signals) {
1960 r_options->push_back(E.name.quote());
1961 }
1962 } else if (p_function == "call" || p_function == "call_deferred" || p_function == "callv" || p_function == "has_method") {
1963 List<MethodInfo> methods;
1964 get_method_list(&methods);
1965 for (const MethodInfo &E : methods) {
1966 if (E.name.begins_with("_") && !(E.flags & METHOD_FLAG_VIRTUAL)) {
1967 continue;
1968 }
1969 r_options->push_back(E.name.quote());
1970 }
1971 } else if (p_function == "set" || p_function == "set_deferred" || p_function == "get") {
1972 List<PropertyInfo> properties;
1973 get_property_list(&properties);
1974 for (const PropertyInfo &E : properties) {
1975 if (E.usage & PROPERTY_USAGE_DEFAULT && !(E.usage & PROPERTY_USAGE_INTERNAL)) {
1976 r_options->push_back(E.name.quote());
1977 }
1978 }
1979 } else if (p_function == "set_meta" || p_function == "get_meta" || p_function == "has_meta" || p_function == "remove_meta") {
1980 for (const KeyValue<StringName, Variant> &K : metadata) {
1981 r_options->push_back(String(K.key).quote());
1982 }
1983 }
1984 } else if (p_idx == 2) {
1985 if (p_function == "connect") {
1986 // Ideally, the constants should be inferred by the parameter.
1987 // But a parameter's PropertyInfo does not store the enum they come from, so this will do for now.
1988 List<StringName> constants;
1989 ClassDB::get_enum_constants("Object", "ConnectFlags", &constants);
1990 for (const StringName &E : constants) {
1991 r_options->push_back(String(E));
1992 }
1993 }
1994 }
1995}
1996
1997SpinLock ObjectDB::spin_lock;
1998uint32_t ObjectDB::slot_count = 0;
1999uint32_t ObjectDB::slot_max = 0;
2000ObjectDB::ObjectSlot *ObjectDB::object_slots = nullptr;
2001uint64_t ObjectDB::validator_counter = 0;
2002
2003int ObjectDB::get_object_count() {
2004 return slot_count;
2005}
2006
2007ObjectID ObjectDB::add_instance(Object *p_object) {
2008 spin_lock.lock();
2009 if (unlikely(slot_count == slot_max)) {
2010 CRASH_COND(slot_count == (1 << OBJECTDB_SLOT_MAX_COUNT_BITS));
2011
2012 uint32_t new_slot_max = slot_max > 0 ? slot_max * 2 : 1;
2013 object_slots = (ObjectSlot *)memrealloc(object_slots, sizeof(ObjectSlot) * new_slot_max);
2014 for (uint32_t i = slot_max; i < new_slot_max; i++) {
2015 object_slots[i].object = nullptr;
2016 object_slots[i].is_ref_counted = false;
2017 object_slots[i].next_free = i;
2018 object_slots[i].validator = 0;
2019 }
2020 slot_max = new_slot_max;
2021 }
2022
2023 uint32_t slot = object_slots[slot_count].next_free;
2024 if (object_slots[slot].object != nullptr) {
2025 spin_lock.unlock();
2026 ERR_FAIL_COND_V(object_slots[slot].object != nullptr, ObjectID());
2027 }
2028 object_slots[slot].object = p_object;
2029 object_slots[slot].is_ref_counted = p_object->is_ref_counted();
2030 validator_counter = (validator_counter + 1) & OBJECTDB_VALIDATOR_MASK;
2031 if (unlikely(validator_counter == 0)) {
2032 validator_counter = 1;
2033 }
2034 object_slots[slot].validator = validator_counter;
2035
2036 uint64_t id = validator_counter;
2037 id <<= OBJECTDB_SLOT_MAX_COUNT_BITS;
2038 id |= uint64_t(slot);
2039
2040 if (p_object->is_ref_counted()) {
2041 id |= OBJECTDB_REFERENCE_BIT;
2042 }
2043
2044 slot_count++;
2045
2046 spin_lock.unlock();
2047
2048 return ObjectID(id);
2049}
2050
2051void ObjectDB::remove_instance(Object *p_object) {
2052 uint64_t t = p_object->get_instance_id();
2053 uint32_t slot = t & OBJECTDB_SLOT_MAX_COUNT_MASK; //slot is always valid on valid object
2054
2055 spin_lock.lock();
2056
2057#ifdef DEBUG_ENABLED
2058
2059 if (object_slots[slot].object != p_object) {
2060 spin_lock.unlock();
2061 ERR_FAIL_COND(object_slots[slot].object != p_object);
2062 }
2063 {
2064 uint64_t validator = (t >> OBJECTDB_SLOT_MAX_COUNT_BITS) & OBJECTDB_VALIDATOR_MASK;
2065 if (object_slots[slot].validator != validator) {
2066 spin_lock.unlock();
2067 ERR_FAIL_COND(object_slots[slot].validator != validator);
2068 }
2069 }
2070
2071#endif
2072 //decrease slot count
2073 slot_count--;
2074 //set the free slot properly
2075 object_slots[slot_count].next_free = slot;
2076 //invalidate, so checks against it fail
2077 object_slots[slot].validator = 0;
2078 object_slots[slot].is_ref_counted = false;
2079 object_slots[slot].object = nullptr;
2080
2081 spin_lock.unlock();
2082}
2083
2084void ObjectDB::setup() {
2085 //nothing to do now
2086}
2087
2088void ObjectDB::cleanup() {
2089 if (slot_count > 0) {
2090 spin_lock.lock();
2091
2092 WARN_PRINT("ObjectDB instances leaked at exit (run with --verbose for details).");
2093 if (OS::get_singleton()->is_stdout_verbose()) {
2094 // Ensure calling the native classes because if a leaked instance has a script
2095 // that overrides any of those methods, it'd not be OK to call them at this point,
2096 // now the scripting languages have already been terminated.
2097 MethodBind *node_get_name = ClassDB::get_method("Node", "get_name");
2098 MethodBind *resource_get_path = ClassDB::get_method("Resource", "get_path");
2099 Callable::CallError call_error;
2100
2101 for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) {
2102 if (object_slots[i].validator) {
2103 Object *obj = object_slots[i].object;
2104
2105 String extra_info;
2106 if (obj->is_class("Node")) {
2107 extra_info = " - Node name: " + String(node_get_name->call(obj, nullptr, 0, call_error));
2108 }
2109 if (obj->is_class("Resource")) {
2110 extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error));
2111 }
2112
2113 uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[i].is_ref_counted ? OBJECTDB_REFERENCE_BIT : 0);
2114 print_line("Leaked instance: " + String(obj->get_class()) + ":" + itos(id) + extra_info);
2115
2116 count--;
2117 }
2118 }
2119 print_line("Hint: Leaked instances typically happen when nodes are removed from the scene tree (with `remove_child()`) but not freed (with `free()` or `queue_free()`).");
2120 }
2121 spin_lock.unlock();
2122 }
2123
2124 if (object_slots) {
2125 memfree(object_slots);
2126 }
2127}
2128