Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/object/object.cpp
20843 views
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/extension/gdextension_manager.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_server.h"
41
#include "core/variant/typed_array.h"
42
43
#ifdef DEBUG_ENABLED
44
45
struct _ObjectDebugLock {
46
ObjectID obj_id;
47
48
_ObjectDebugLock(Object *p_obj) {
49
obj_id = p_obj->get_instance_id();
50
p_obj->_lock_index.ref();
51
}
52
~_ObjectDebugLock() {
53
Object *obj_ptr = ObjectDB::get_instance(obj_id);
54
if (likely(obj_ptr)) {
55
obj_ptr->_lock_index.unref();
56
}
57
}
58
};
59
60
#define OBJ_DEBUG_LOCK _ObjectDebugLock _debug_lock(this);
61
62
#else
63
64
#define OBJ_DEBUG_LOCK
65
66
#endif
67
68
struct _ObjectSignalLock {
69
Mutex *mutex;
70
_ObjectSignalLock(const Object *const p_obj) {
71
mutex = p_obj->signal_mutex;
72
if (mutex) {
73
mutex->lock();
74
}
75
}
76
~_ObjectSignalLock() {
77
if (mutex) {
78
mutex->unlock();
79
}
80
}
81
};
82
83
#define OBJ_SIGNAL_LOCK _ObjectSignalLock _signal_lock(this);
84
85
PropertyInfo::operator Dictionary() const {
86
Dictionary d;
87
d["name"] = name;
88
d["class_name"] = class_name;
89
d["type"] = type;
90
d["hint"] = hint;
91
d["hint_string"] = hint_string;
92
d["usage"] = usage;
93
return d;
94
}
95
96
PropertyInfo PropertyInfo::from_dict(const Dictionary &p_dict) {
97
PropertyInfo pi;
98
99
if (p_dict.has("type")) {
100
pi.type = Variant::Type(int(p_dict["type"]));
101
}
102
103
if (p_dict.has("name")) {
104
pi.name = p_dict["name"];
105
}
106
107
if (p_dict.has("class_name")) {
108
pi.class_name = p_dict["class_name"];
109
}
110
111
if (p_dict.has("hint")) {
112
pi.hint = PropertyHint(int(p_dict["hint"]));
113
}
114
115
if (p_dict.has("hint_string")) {
116
pi.hint_string = p_dict["hint_string"];
117
}
118
119
if (p_dict.has("usage")) {
120
pi.usage = p_dict["usage"];
121
}
122
123
return pi;
124
}
125
126
TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list) {
127
TypedArray<Dictionary> va;
128
for (const List<PropertyInfo>::Element *E = p_list->front(); E; E = E->next()) {
129
va.push_back(Dictionary(E->get()));
130
}
131
132
return va;
133
}
134
135
TypedArray<Dictionary> convert_property_list(const Vector<PropertyInfo> &p_vector) {
136
TypedArray<Dictionary> va;
137
for (const PropertyInfo &E : p_vector) {
138
va.push_back(Dictionary(E));
139
}
140
141
return va;
142
}
143
144
MethodInfo::operator Dictionary() const {
145
Dictionary d;
146
d["name"] = name;
147
d["args"] = convert_property_list(arguments);
148
Array da;
149
for (int i = 0; i < default_arguments.size(); i++) {
150
da.push_back(default_arguments[i]);
151
}
152
d["default_args"] = da;
153
d["flags"] = flags;
154
d["id"] = id;
155
Dictionary r = return_val;
156
d["return"] = r;
157
return d;
158
}
159
160
MethodInfo MethodInfo::from_dict(const Dictionary &p_dict) {
161
MethodInfo mi;
162
163
if (p_dict.has("name")) {
164
mi.name = p_dict["name"];
165
}
166
Array args;
167
if (p_dict.has("args")) {
168
args = p_dict["args"];
169
}
170
171
for (const Variant &arg : args) {
172
Dictionary d = arg;
173
mi.arguments.push_back(PropertyInfo::from_dict(d));
174
}
175
Array defargs;
176
if (p_dict.has("default_args")) {
177
defargs = p_dict["default_args"];
178
}
179
for (const Variant &defarg : defargs) {
180
mi.default_arguments.push_back(defarg);
181
}
182
183
if (p_dict.has("return")) {
184
mi.return_val = PropertyInfo::from_dict(p_dict["return"]);
185
}
186
187
if (p_dict.has("flags")) {
188
mi.flags = p_dict["flags"];
189
}
190
191
return mi;
192
}
193
194
uint32_t MethodInfo::get_compatibility_hash() const {
195
bool has_return = (return_val.type != Variant::NIL) || (return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT);
196
197
uint32_t hash = hash_murmur3_one_32(has_return);
198
hash = hash_murmur3_one_32(arguments.size(), hash);
199
200
if (has_return) {
201
hash = hash_murmur3_one_32(return_val.type, hash);
202
if (return_val.class_name != StringName()) {
203
hash = hash_murmur3_one_32(return_val.class_name.hash(), hash);
204
}
205
}
206
207
for (const PropertyInfo &arg : arguments) {
208
hash = hash_murmur3_one_32(arg.type, hash);
209
if (arg.class_name != StringName()) {
210
hash = hash_murmur3_one_32(arg.class_name.hash(), hash);
211
}
212
}
213
214
hash = hash_murmur3_one_32(default_arguments.size(), hash);
215
for (const Variant &v : default_arguments) {
216
hash = hash_murmur3_one_32(v.hash(), hash);
217
}
218
219
hash = hash_murmur3_one_32(flags & METHOD_FLAG_CONST ? 1 : 0, hash);
220
hash = hash_murmur3_one_32(flags & METHOD_FLAG_VARARG ? 1 : 0, hash);
221
222
return hash_fmix32(hash);
223
}
224
225
Object::Connection::operator Variant() const {
226
Dictionary d;
227
d["signal"] = signal;
228
d["callable"] = callable;
229
d["flags"] = flags;
230
return d;
231
}
232
233
void ObjectGDExtension::create_gdtype() {
234
ERR_FAIL_COND(gdtype);
235
236
gdtype = memnew(GDType(ClassDB::get_gdtype(parent_class_name), class_name));
237
}
238
239
void ObjectGDExtension::destroy_gdtype() {
240
ERR_FAIL_COND(!gdtype);
241
242
memdelete(const_cast<GDType *>(gdtype));
243
gdtype = nullptr;
244
}
245
246
ObjectGDExtension::~ObjectGDExtension() {
247
if (gdtype) {
248
memdelete(const_cast<GDType *>(gdtype));
249
}
250
}
251
252
bool Object::Connection::operator<(const Connection &p_conn) const {
253
if (signal == p_conn.signal) {
254
return callable < p_conn.callable;
255
} else {
256
return signal < p_conn.signal;
257
}
258
}
259
260
Object::Connection::Connection(const Variant &p_variant) {
261
Dictionary d = p_variant;
262
if (d.has("signal")) {
263
signal = d["signal"];
264
}
265
if (d.has("callable")) {
266
callable = d["callable"];
267
}
268
if (d.has("flags")) {
269
flags = d["flags"];
270
}
271
}
272
273
bool Object::_predelete() {
274
_predelete_ok = true;
275
notification(NOTIFICATION_PREDELETE, true);
276
if (!_predelete_ok) {
277
return false;
278
}
279
280
_gdtype_ptr = nullptr; // Must restore, so constructors/destructors have proper class name access at each stage.
281
notification(NOTIFICATION_PREDELETE_CLEANUP, true);
282
283
// Destruction order starts with the most derived class, and progresses towards the base Object class:
284
// Script subclasses -> GDExtension subclasses -> C++ subclasses -> Object
285
if (script_instance) {
286
memdelete(script_instance);
287
}
288
script_instance = nullptr;
289
290
if (_extension) {
291
#ifdef TOOLS_ENABLED
292
if (_extension->untrack_instance) {
293
_extension->untrack_instance(_extension->tracking_userdata, this);
294
}
295
#endif
296
if (_extension->free_instance) {
297
_extension->free_instance(_extension->class_userdata, _extension_instance);
298
}
299
_extension = nullptr;
300
_extension_instance = nullptr;
301
// _gdtype_ptr = nullptr; // The pointer already set to nullptr above, no need to do it again.
302
}
303
#ifdef TOOLS_ENABLED
304
else if (_instance_bindings != nullptr) {
305
Engine *engine = Engine::get_singleton();
306
GDExtensionManager *gdextension_manager = GDExtensionManager::get_singleton();
307
if (engine && gdextension_manager && engine->is_extension_reloading_enabled()) {
308
for (uint32_t i = 0; i < _instance_binding_count; i++) {
309
gdextension_manager->untrack_instance_binding(_instance_bindings[i].token, this);
310
}
311
}
312
}
313
#endif
314
315
return true;
316
}
317
318
void Object::cancel_free() {
319
_predelete_ok = false;
320
}
321
322
void Object::_initialize() {
323
// Cache the class name in the object for quick reference.
324
_gdtype_ptr = &_get_typev();
325
_initialize_classv();
326
}
327
328
void Object::_postinitialize() {
329
if (_uses_signal_mutex()) {
330
signal_mutex = memnew(Mutex);
331
}
332
notification(NOTIFICATION_POSTINITIALIZE);
333
}
334
335
void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid) {
336
#ifdef TOOLS_ENABLED
337
338
_edited = true;
339
#endif
340
341
if (script_instance) {
342
if (script_instance->set(p_name, p_value)) {
343
if (r_valid) {
344
*r_valid = true;
345
}
346
return;
347
}
348
}
349
350
if (_extension && _extension->set) {
351
if (_extension->set(_extension_instance, (GDExtensionConstStringNamePtr)&p_name, (GDExtensionConstVariantPtr)&p_value)) {
352
if (r_valid) {
353
*r_valid = true;
354
}
355
return;
356
}
357
}
358
359
// Try built-in setter.
360
{
361
if (ClassDB::set_property(this, p_name, p_value, r_valid)) {
362
return;
363
}
364
}
365
366
if (p_name == CoreStringName(script)) {
367
set_script(p_value);
368
if (r_valid) {
369
*r_valid = true;
370
}
371
return;
372
373
} else {
374
Variant **V = metadata_properties.getptr(p_name);
375
if (V) {
376
**V = p_value;
377
if (r_valid) {
378
*r_valid = true;
379
}
380
return;
381
} else if (p_name.operator String().begins_with("metadata/")) {
382
// Must exist, otherwise duplicate() will not work.
383
set_meta(p_name.operator String().replace_first("metadata/", ""), p_value);
384
if (r_valid) {
385
*r_valid = true;
386
}
387
return;
388
}
389
}
390
391
#ifdef TOOLS_ENABLED
392
if (script_instance) {
393
bool valid;
394
script_instance->property_set_fallback(p_name, p_value, &valid);
395
if (valid) {
396
if (r_valid) {
397
*r_valid = true;
398
}
399
return;
400
}
401
}
402
#endif
403
404
// Something inside the object... :|
405
bool success = _setv(p_name, p_value);
406
if (success) {
407
if (r_valid) {
408
*r_valid = true;
409
}
410
return;
411
}
412
413
if (r_valid) {
414
*r_valid = false;
415
}
416
}
417
418
Variant Object::get(const StringName &p_name, bool *r_valid) const {
419
Variant ret;
420
421
if (script_instance) {
422
if (script_instance->get(p_name, ret)) {
423
if (r_valid) {
424
*r_valid = true;
425
}
426
return ret;
427
}
428
}
429
if (_extension && _extension->get) {
430
if (_extension->get(_extension_instance, (GDExtensionConstStringNamePtr)&p_name, (GDExtensionVariantPtr)&ret)) {
431
if (r_valid) {
432
*r_valid = true;
433
}
434
return ret;
435
}
436
}
437
438
// Try built-in getter.
439
{
440
if (ClassDB::get_property(const_cast<Object *>(this), p_name, ret)) {
441
if (r_valid) {
442
*r_valid = true;
443
}
444
return ret;
445
}
446
}
447
448
if (p_name == CoreStringName(script)) {
449
ret = get_script();
450
if (r_valid) {
451
*r_valid = true;
452
}
453
return ret;
454
}
455
456
const Variant *const *V = metadata_properties.getptr(p_name);
457
458
if (V) {
459
ret = **V;
460
if (r_valid) {
461
*r_valid = true;
462
}
463
return ret;
464
465
} else {
466
#ifdef TOOLS_ENABLED
467
if (script_instance) {
468
bool valid;
469
ret = script_instance->property_get_fallback(p_name, &valid);
470
if (valid) {
471
if (r_valid) {
472
*r_valid = true;
473
}
474
return ret;
475
}
476
}
477
#endif
478
// Something inside the object... :|
479
bool success = _getv(p_name, ret);
480
if (success) {
481
if (r_valid) {
482
*r_valid = true;
483
}
484
return ret;
485
}
486
487
if (r_valid) {
488
*r_valid = false;
489
}
490
return Variant();
491
}
492
}
493
494
void Object::set_indexed(const Vector<StringName> &p_names, const Variant &p_value, bool *r_valid) {
495
if (p_names.is_empty()) {
496
if (r_valid) {
497
*r_valid = false;
498
}
499
return;
500
}
501
if (p_names.size() == 1) {
502
set(p_names[0], p_value, r_valid);
503
return;
504
}
505
506
bool valid = false;
507
if (!r_valid) {
508
r_valid = &valid;
509
}
510
511
List<Variant> value_stack;
512
513
value_stack.push_back(get(p_names[0], r_valid));
514
515
if (!*r_valid) {
516
value_stack.clear();
517
return;
518
}
519
520
for (int i = 1; i < p_names.size() - 1; i++) {
521
value_stack.push_back(value_stack.back()->get().get_named(p_names[i], valid));
522
if (r_valid) {
523
*r_valid = valid;
524
}
525
526
if (!valid) {
527
value_stack.clear();
528
return;
529
}
530
}
531
532
value_stack.push_back(p_value); // p_names[p_names.size() - 1]
533
534
for (int i = p_names.size() - 1; i > 0; i--) {
535
value_stack.back()->prev()->get().set_named(p_names[i], value_stack.back()->get(), valid);
536
value_stack.pop_back();
537
538
if (r_valid) {
539
*r_valid = valid;
540
}
541
if (!valid) {
542
value_stack.clear();
543
return;
544
}
545
}
546
547
set(p_names[0], value_stack.back()->get(), r_valid);
548
value_stack.pop_back();
549
550
ERR_FAIL_COND(!value_stack.is_empty());
551
}
552
553
Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) const {
554
if (p_names.is_empty()) {
555
if (r_valid) {
556
*r_valid = false;
557
}
558
return Variant();
559
}
560
bool valid = false;
561
562
Variant current_value = get(p_names[0], &valid);
563
for (int i = 1; i < p_names.size(); i++) {
564
current_value = current_value.get_named(p_names[i], valid);
565
566
if (!valid) {
567
break;
568
}
569
}
570
if (r_valid) {
571
*r_valid = valid;
572
}
573
574
return current_value;
575
}
576
577
void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) const {
578
if (script_instance && p_reversed) {
579
script_instance->get_property_list(p_list);
580
}
581
582
if (_extension) {
583
const ObjectGDExtension *current_extension = _extension;
584
while (current_extension) {
585
p_list->push_back(PropertyInfo(Variant::NIL, current_extension->class_name, PROPERTY_HINT_NONE, current_extension->class_name, PROPERTY_USAGE_CATEGORY));
586
587
ClassDB::get_property_list(current_extension->class_name, p_list, true, this);
588
589
if (current_extension->get_property_list) {
590
#ifdef TOOLS_ENABLED
591
// If this is a placeholder, we can't call into the GDExtension on the parent class,
592
// because we don't have a real instance of the class to give it.
593
if (likely(!_extension->is_placeholder)) {
594
#endif
595
uint32_t pcount;
596
const GDExtensionPropertyInfo *pinfo = current_extension->get_property_list(_extension_instance, &pcount);
597
for (uint32_t i = 0; i < pcount; i++) {
598
p_list->push_back(PropertyInfo(pinfo[i]));
599
}
600
if (current_extension->free_property_list2) {
601
current_extension->free_property_list2(_extension_instance, pinfo, pcount);
602
}
603
#ifndef DISABLE_DEPRECATED
604
else if (current_extension->free_property_list) {
605
current_extension->free_property_list(_extension_instance, pinfo);
606
}
607
#endif // DISABLE_DEPRECATED
608
#ifdef TOOLS_ENABLED
609
}
610
#endif
611
}
612
613
current_extension = current_extension->parent;
614
}
615
}
616
617
_get_property_listv(p_list, p_reversed);
618
619
const uint32_t base_script_usage = is_class(Script::get_class_static()) ? PROPERTY_USAGE_NO_EDITOR : PROPERTY_USAGE_DEFAULT;
620
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, Script::get_class_static(), base_script_usage | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_NEVER_DUPLICATE));
621
622
if (script_instance && !p_reversed) {
623
script_instance->get_property_list(p_list);
624
}
625
626
for (const KeyValue<StringName, Variant> &K : metadata) {
627
PropertyInfo pi = PropertyInfo(K.value.get_type(), "metadata/" + K.key.operator String());
628
if (K.value.get_type() == Variant::OBJECT) {
629
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
630
Object *obj = K.value;
631
if (Object::cast_to<Script>(obj)) {
632
pi.hint_string = Script::get_class_static();
633
pi.usage |= PROPERTY_USAGE_NEVER_DUPLICATE;
634
} else {
635
pi.hint_string = Resource::get_class_static();
636
}
637
}
638
p_list->push_back(pi);
639
}
640
}
641
642
void Object::validate_property(PropertyInfo &p_property) const {
643
_validate_propertyv(p_property);
644
645
if (_extension && _extension->validate_property) {
646
// GDExtension uses a StringName rather than a String for property name.
647
StringName prop_name = p_property.name;
648
GDExtensionPropertyInfo gdext_prop = {
649
(GDExtensionVariantType)p_property.type,
650
&prop_name,
651
&p_property.class_name,
652
(uint32_t)p_property.hint,
653
&p_property.hint_string,
654
p_property.usage,
655
};
656
if (_extension->validate_property(_extension_instance, &gdext_prop)) {
657
p_property.type = (Variant::Type)gdext_prop.type;
658
p_property.name = *reinterpret_cast<StringName *>(gdext_prop.name);
659
p_property.class_name = *reinterpret_cast<StringName *>(gdext_prop.class_name);
660
p_property.hint = (PropertyHint)gdext_prop.hint;
661
p_property.hint_string = *reinterpret_cast<String *>(gdext_prop.hint_string);
662
p_property.usage = gdext_prop.usage;
663
};
664
}
665
666
if (script_instance) { // Call it last to allow user altering already validated properties.
667
script_instance->validate_property(p_property);
668
}
669
}
670
671
bool Object::property_can_revert(const StringName &p_name) const {
672
if (script_instance) {
673
if (script_instance->property_can_revert(p_name)) {
674
return true;
675
}
676
}
677
678
if (_extension && _extension->property_can_revert) {
679
if (_extension->property_can_revert(_extension_instance, (GDExtensionConstStringNamePtr)&p_name)) {
680
return true;
681
}
682
}
683
684
return _property_can_revertv(p_name);
685
}
686
687
Variant Object::property_get_revert(const StringName &p_name) const {
688
Variant ret;
689
690
if (script_instance) {
691
if (script_instance->property_get_revert(p_name, ret)) {
692
return ret;
693
}
694
}
695
696
if (_extension && _extension->property_get_revert) {
697
if (_extension->property_get_revert(_extension_instance, (GDExtensionConstStringNamePtr)&p_name, (GDExtensionVariantPtr)&ret)) {
698
return ret;
699
}
700
}
701
702
if (_property_get_revertv(p_name, ret)) {
703
return ret;
704
}
705
return Variant();
706
}
707
708
void Object::get_method_list(List<MethodInfo> *p_list) const {
709
ClassDB::get_method_list(get_class_name(), p_list);
710
if (script_instance) {
711
script_instance->get_method_list(p_list);
712
}
713
}
714
715
Variant Object::_call_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
716
if (p_argcount < 1) {
717
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
718
r_error.expected = 1;
719
return Variant();
720
}
721
722
if (!p_args[0]->is_string()) {
723
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
724
r_error.argument = 0;
725
r_error.expected = Variant::STRING_NAME;
726
return Variant();
727
}
728
729
StringName method = *p_args[0];
730
731
return callp(method, &p_args[1], p_argcount - 1, r_error);
732
}
733
734
Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
735
if (p_argcount < 1) {
736
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
737
r_error.expected = 1;
738
return Variant();
739
}
740
741
if (!p_args[0]->is_string()) {
742
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
743
r_error.argument = 0;
744
r_error.expected = Variant::STRING_NAME;
745
return Variant();
746
}
747
748
r_error.error = Callable::CallError::CALL_OK;
749
750
StringName method = *p_args[0];
751
752
MessageQueue::get_singleton()->push_callp(get_instance_id(), method, &p_args[1], p_argcount - 1, true);
753
754
return Variant();
755
}
756
757
bool Object::has_method(const StringName &p_method) const {
758
if (p_method == CoreStringName(free_)) {
759
return true;
760
}
761
762
if (script_instance && script_instance->has_method(p_method)) {
763
return true;
764
}
765
766
MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
767
if (method != nullptr) {
768
return true;
769
}
770
771
const Script *scr = Object::cast_to<Script>(this);
772
if (scr != nullptr) {
773
return scr->has_static_method(p_method);
774
}
775
776
return false;
777
}
778
779
int Object::_get_method_argument_count_bind(const StringName &p_method) const {
780
return get_method_argument_count(p_method);
781
}
782
783
int Object::get_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
784
if (p_method == CoreStringName(free_)) {
785
if (r_is_valid) {
786
*r_is_valid = true;
787
}
788
return 0;
789
}
790
791
if (script_instance) {
792
bool valid = false;
793
int ret = script_instance->get_method_argument_count(p_method, &valid);
794
if (valid) {
795
if (r_is_valid) {
796
*r_is_valid = true;
797
}
798
return ret;
799
}
800
}
801
802
{
803
bool valid = false;
804
int ret = ClassDB::get_method_argument_count(get_class_name(), p_method, &valid);
805
if (valid) {
806
if (r_is_valid) {
807
*r_is_valid = true;
808
}
809
return ret;
810
}
811
}
812
813
const Script *scr = Object::cast_to<Script>(this);
814
while (scr != nullptr) {
815
bool valid = false;
816
int ret = scr->get_script_method_argument_count(p_method, &valid);
817
if (valid) {
818
if (r_is_valid) {
819
*r_is_valid = true;
820
}
821
return ret;
822
}
823
scr = scr->get_base_script().ptr();
824
}
825
826
if (r_is_valid) {
827
*r_is_valid = false;
828
}
829
return 0;
830
}
831
832
Variant Object::getvar(const Variant &p_key, bool *r_valid) const {
833
if (r_valid) {
834
*r_valid = false;
835
}
836
837
if (p_key.is_string()) {
838
return get(p_key, r_valid);
839
}
840
return Variant();
841
}
842
843
void Object::setvar(const Variant &p_key, const Variant &p_value, bool *r_valid) {
844
if (r_valid) {
845
*r_valid = false;
846
}
847
if (p_key.is_string()) {
848
return set(p_key, p_value, r_valid);
849
}
850
}
851
852
Variant Object::callv(const StringName &p_method, const Array &p_args) {
853
const Variant **argptrs = nullptr;
854
855
if (p_args.size() > 0) {
856
argptrs = (const Variant **)alloca(sizeof(Variant *) * p_args.size());
857
for (int i = 0; i < p_args.size(); i++) {
858
argptrs[i] = &p_args[i];
859
}
860
}
861
862
Callable::CallError ce;
863
const Variant ret = callp(p_method, argptrs, p_args.size(), ce);
864
if (ce.error != Callable::CallError::CALL_OK) {
865
ERR_FAIL_V_MSG(Variant(), vformat("Error calling method from 'callv': %s.", Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce)));
866
}
867
return ret;
868
}
869
870
Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
871
r_error.error = Callable::CallError::CALL_OK;
872
873
if (p_method == CoreStringName(free_)) {
874
//free must be here, before anything, always ready
875
#ifdef DEBUG_ENABLED
876
if (p_argcount != 0) {
877
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
878
r_error.expected = 0;
879
return Variant();
880
}
881
if (is_ref_counted()) {
882
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
883
ERR_FAIL_V_MSG(Variant(), "Can't free a RefCounted object.");
884
}
885
886
if (_lock_index.get() > 1) {
887
r_error.argument = 0;
888
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
889
ERR_FAIL_V_MSG(Variant(), "Object is locked and can't be freed.");
890
}
891
892
#endif
893
//must be here, must be before everything,
894
memdelete(this);
895
r_error.error = Callable::CallError::CALL_OK;
896
return Variant();
897
}
898
899
Variant ret;
900
OBJ_DEBUG_LOCK
901
902
if (script_instance) {
903
ret = script_instance->callp(p_method, p_args, p_argcount, r_error);
904
// Force jump table.
905
switch (r_error.error) {
906
case Callable::CallError::CALL_OK:
907
return ret;
908
case Callable::CallError::CALL_ERROR_INVALID_METHOD:
909
break;
910
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
911
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
912
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
913
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
914
return ret;
915
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
916
}
917
}
918
}
919
920
//extension does not need this, because all methods are registered in MethodBind
921
922
MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
923
924
if (method) {
925
ret = method->call(this, p_args, p_argcount, r_error);
926
} else {
927
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
928
}
929
930
return ret;
931
}
932
933
Variant Object::call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
934
r_error.error = Callable::CallError::CALL_OK;
935
936
if (p_method == CoreStringName(free_)) {
937
// Free is not const, so fail.
938
r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST;
939
return Variant();
940
}
941
942
Variant ret;
943
OBJ_DEBUG_LOCK
944
945
if (script_instance) {
946
ret = script_instance->call_const(p_method, p_args, p_argcount, r_error);
947
//force jumptable
948
switch (r_error.error) {
949
case Callable::CallError::CALL_OK:
950
return ret;
951
case Callable::CallError::CALL_ERROR_INVALID_METHOD:
952
break;
953
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
954
break;
955
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
956
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
957
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
958
return ret;
959
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
960
}
961
}
962
}
963
964
//extension does not need this, because all methods are registered in MethodBind
965
966
MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
967
968
if (method) {
969
if (!method->is_const()) {
970
r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST;
971
return ret;
972
}
973
ret = method->call(this, p_args, p_argcount, r_error);
974
} else {
975
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
976
}
977
978
return ret;
979
}
980
981
void Object::_gdvirtual_init_method_ptr(uint32_t p_compat_hash, void *&r_fn_ptr, const StringName &p_fn_name, bool p_compat) const {
982
r_fn_ptr = nullptr;
983
if (_extension->get_virtual_call_data2 && _extension->call_virtual_with_data) {
984
r_fn_ptr = _extension->get_virtual_call_data2(_extension->class_userdata, &p_fn_name, p_compat_hash);
985
} else if (_extension->get_virtual2) {
986
r_fn_ptr = (void *)_extension->get_virtual2(_extension->class_userdata, &p_fn_name, p_compat_hash);
987
#ifndef DISABLE_DEPRECATED
988
} else if (p_compat || ClassDB::get_virtual_method_compatibility_hashes(get_class_name(), p_fn_name).size() == 0) {
989
if (_extension->get_virtual_call_data && _extension->call_virtual_with_data) {
990
r_fn_ptr = _extension->get_virtual_call_data(_extension->class_userdata, &p_fn_name);
991
} else if (_extension->get_virtual) {
992
r_fn_ptr = (void *)_extension->get_virtual(_extension->class_userdata, &p_fn_name);
993
}
994
#endif
995
}
996
#ifdef TOOLS_ENABLED
997
if (_extension->reloadable) {
998
VirtualMethodTracker *tracker = memnew(VirtualMethodTracker);
999
tracker->method = (void **)&r_fn_ptr;
1000
tracker->next = virtual_method_list;
1001
virtual_method_list = tracker;
1002
}
1003
#endif
1004
if (r_fn_ptr == nullptr) {
1005
r_fn_ptr = reinterpret_cast<void *>(_INVALID_GDVIRTUAL_FUNC_ADDR);
1006
}
1007
}
1008
1009
void Object::_notification_forward(int p_notification) {
1010
// Notify classes starting with Object and ending with most derived subclass.
1011
// e.g. Object -> Node -> Node3D
1012
_notification_forwardv(p_notification);
1013
1014
if (_extension) {
1015
if (_extension->notification2) {
1016
_extension->notification2(_extension_instance, p_notification, static_cast<GDExtensionBool>(false));
1017
#ifndef DISABLE_DEPRECATED
1018
} else if (_extension->notification) {
1019
_extension->notification(_extension_instance, p_notification);
1020
#endif // DISABLE_DEPRECATED
1021
}
1022
}
1023
1024
if (script_instance) {
1025
script_instance->notification(p_notification, false);
1026
}
1027
}
1028
1029
void Object::_notification_backward(int p_notification) {
1030
if (script_instance) {
1031
script_instance->notification(p_notification, true);
1032
}
1033
1034
if (_extension) {
1035
if (_extension->notification2) {
1036
_extension->notification2(_extension_instance, p_notification, static_cast<GDExtensionBool>(true));
1037
#ifndef DISABLE_DEPRECATED
1038
} else if (_extension->notification) {
1039
_extension->notification(_extension_instance, p_notification);
1040
#endif // DISABLE_DEPRECATED
1041
}
1042
}
1043
1044
// Notify classes starting with most derived subclass and ending in Object.
1045
// e.g. Node3D -> Node -> Object
1046
_notification_backwardv(p_notification);
1047
}
1048
1049
String Object::to_string() {
1050
// Keep this method in sync with `Node::to_string`.
1051
if (script_instance) {
1052
bool valid;
1053
String ret = script_instance->to_string(&valid);
1054
if (valid) {
1055
return ret;
1056
}
1057
}
1058
if (_extension && _extension->to_string) {
1059
String ret;
1060
GDExtensionBool is_valid;
1061
_extension->to_string(_extension_instance, &is_valid, &ret);
1062
if (is_valid) {
1063
return ret;
1064
}
1065
}
1066
return _to_string();
1067
}
1068
1069
void Object::set_script(const Variant &p_script) {
1070
if (get_script() == p_script) {
1071
return;
1072
}
1073
1074
Ref<Script> s = p_script;
1075
if (!p_script.is_null()) {
1076
ERR_FAIL_COND_MSG(s.is_null(), "Cannot set object script. Parameter should be null or a reference to a valid script.");
1077
ERR_FAIL_COND_MSG(s->is_abstract(), vformat("Cannot set object script. Script '%s' should not be abstract.", s->get_path()));
1078
}
1079
1080
if (script_instance) {
1081
memdelete(script_instance);
1082
script_instance = nullptr;
1083
}
1084
1085
if (s.is_valid()) {
1086
if (s->can_instantiate()) {
1087
OBJ_DEBUG_LOCK
1088
script_instance = s->instance_create(this);
1089
} else if (Engine::get_singleton()->is_editor_hint()) {
1090
OBJ_DEBUG_LOCK
1091
script_instance = s->placeholder_instance_create(this);
1092
}
1093
}
1094
1095
notify_property_list_changed(); //scripts may add variables, so refresh is desired
1096
emit_signal(CoreStringName(script_changed));
1097
}
1098
1099
void Object::set_script_instance(ScriptInstance *p_instance) {
1100
if (script_instance == p_instance) {
1101
return;
1102
}
1103
1104
if (script_instance) {
1105
memdelete(script_instance);
1106
}
1107
1108
script_instance = p_instance;
1109
}
1110
1111
Variant Object::get_script() const {
1112
return script_instance ? Variant(script_instance->get_script()) : Variant();
1113
}
1114
1115
bool Object::has_meta(const StringName &p_name) const {
1116
return metadata.has(p_name);
1117
}
1118
1119
void Object::set_meta(const StringName &p_name, const Variant &p_value) {
1120
if (p_value.get_type() == Variant::NIL) {
1121
if (metadata.has(p_name)) {
1122
metadata.erase(p_name);
1123
1124
const String &sname = p_name;
1125
metadata_properties.erase("metadata/" + sname);
1126
if (!sname.begins_with("_")) {
1127
// Metadata starting with _ don't show up in the inspector, so no need to update.
1128
notify_property_list_changed();
1129
}
1130
}
1131
return;
1132
}
1133
1134
HashMap<StringName, Variant>::Iterator E = metadata.find(p_name);
1135
if (E) {
1136
E->value = p_value;
1137
} else {
1138
ERR_FAIL_COND_MSG(!p_name.operator String().is_valid_ascii_identifier(), vformat("Invalid metadata identifier: '%s'.", p_name));
1139
Variant *V = &metadata.insert(p_name, p_value)->value;
1140
1141
const String &sname = p_name;
1142
metadata_properties["metadata/" + sname] = V;
1143
if (!sname.begins_with("_")) {
1144
notify_property_list_changed();
1145
}
1146
}
1147
}
1148
1149
Variant Object::get_meta(const StringName &p_name, const Variant &p_default) const {
1150
if (!metadata.has(p_name)) {
1151
if (p_default != Variant()) {
1152
return p_default;
1153
} else {
1154
ERR_FAIL_V_MSG(Variant(), vformat("The object does not have any 'meta' values with the key '%s'.", p_name));
1155
}
1156
}
1157
return metadata[p_name];
1158
}
1159
1160
void Object::remove_meta(const StringName &p_name) {
1161
set_meta(p_name, Variant());
1162
}
1163
1164
void Object::merge_meta_from(const Object *p_src) {
1165
List<StringName> meta_keys;
1166
p_src->get_meta_list(&meta_keys);
1167
for (const StringName &key : meta_keys) {
1168
set_meta(key, p_src->get_meta(key));
1169
}
1170
}
1171
1172
TypedArray<Dictionary> Object::_get_property_list_bind() const {
1173
List<PropertyInfo> lpi;
1174
get_property_list(&lpi);
1175
return convert_property_list(&lpi);
1176
}
1177
1178
TypedArray<Dictionary> Object::_get_method_list_bind() const {
1179
List<MethodInfo> ml;
1180
get_method_list(&ml);
1181
TypedArray<Dictionary> ret;
1182
1183
for (const MethodInfo &mi : ml) {
1184
Dictionary d = mi;
1185
//va.push_back(d);
1186
ret.push_back(d);
1187
}
1188
1189
return ret;
1190
}
1191
1192
TypedArray<StringName> Object::_get_meta_list_bind() const {
1193
TypedArray<StringName> _metaret;
1194
1195
for (const KeyValue<StringName, Variant> &K : metadata) {
1196
_metaret.push_back(K.key);
1197
}
1198
1199
return _metaret;
1200
}
1201
1202
void Object::get_meta_list(List<StringName> *p_list) const {
1203
for (const KeyValue<StringName, Variant> &K : metadata) {
1204
p_list->push_back(K.key);
1205
}
1206
}
1207
1208
void Object::add_user_signal(const MethodInfo &p_signal) {
1209
ERR_FAIL_COND_MSG(p_signal.name.is_empty(), "Signal name cannot be empty.");
1210
ERR_FAIL_COND_MSG(ClassDB::has_signal(get_class_name(), p_signal.name), vformat("User signal's name conflicts with a built-in signal of '%s'.", get_class_name()));
1211
1212
OBJ_SIGNAL_LOCK
1213
1214
ERR_FAIL_COND_MSG(signal_map.has(p_signal.name), vformat("Trying to add already existing signal '%s'.", p_signal.name));
1215
SignalData s;
1216
s.user = p_signal;
1217
signal_map[p_signal.name] = s;
1218
}
1219
1220
bool Object::_has_user_signal(const StringName &p_name) const {
1221
OBJ_SIGNAL_LOCK
1222
1223
if (!signal_map.has(p_name)) {
1224
return false;
1225
}
1226
return signal_map[p_name].user.name.length() > 0;
1227
}
1228
1229
void Object::_remove_user_signal(const StringName &p_name) {
1230
OBJ_SIGNAL_LOCK
1231
1232
SignalData *s = signal_map.getptr(p_name);
1233
ERR_FAIL_NULL_MSG(s, "Provided signal does not exist.");
1234
ERR_FAIL_COND_MSG(!s->removable, "Signal is not removable (not added with add_user_signal).");
1235
for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
1236
Object *target = slot_kv.key.get_object();
1237
if (likely(target)) {
1238
target->connections.erase(slot_kv.value.cE);
1239
}
1240
}
1241
1242
signal_map.erase(p_name);
1243
}
1244
1245
Error Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
1246
if (unlikely(p_argcount < 1)) {
1247
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
1248
r_error.expected = 1;
1249
ERR_FAIL_V(Error::ERR_INVALID_PARAMETER);
1250
}
1251
1252
if (unlikely(!p_args[0]->is_string())) {
1253
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
1254
r_error.argument = 0;
1255
r_error.expected = Variant::STRING_NAME;
1256
ERR_FAIL_V(Error::ERR_INVALID_PARAMETER);
1257
}
1258
1259
r_error.error = Callable::CallError::CALL_OK;
1260
1261
StringName signal = *p_args[0];
1262
1263
const Variant **args = nullptr;
1264
1265
int argc = p_argcount - 1;
1266
if (argc) {
1267
args = &p_args[1];
1268
}
1269
1270
return emit_signalp(signal, args, argc);
1271
}
1272
1273
Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount) {
1274
if (_block_signals) {
1275
return ERR_CANT_ACQUIRE_RESOURCE; //no emit, signals blocked
1276
}
1277
1278
constexpr int MAX_SLOTS_ON_STACK = 5;
1279
// Don't default initialize the Callable objects on the stack, just reserve the space - we'll memnew_placement() them later.
1280
alignas(Callable) uint8_t slot_callable_stack[sizeof(Callable) * MAX_SLOTS_ON_STACK];
1281
uint32_t slot_flags_stack[MAX_SLOTS_ON_STACK];
1282
1283
Callable *slot_callables = (Callable *)slot_callable_stack;
1284
uint32_t *slot_flags = slot_flags_stack;
1285
uint32_t slot_count = 0;
1286
1287
{
1288
OBJ_SIGNAL_LOCK
1289
1290
SignalData *s = signal_map.getptr(p_name);
1291
if (!s) {
1292
#ifdef DEBUG_ENABLED
1293
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_name);
1294
//check in script
1295
ERR_FAIL_COND_V_MSG(!signal_is_valid && script_instance && !script_instance->get_script()->has_script_signal(p_name), ERR_UNAVAILABLE, vformat("Can't emit non-existing signal \"%s\".", p_name));
1296
#endif
1297
//not connected? just return
1298
return ERR_UNAVAILABLE;
1299
}
1300
1301
if (s->slot_map.size() > MAX_SLOTS_ON_STACK) {
1302
slot_callables = (Callable *)memalloc(sizeof(Callable) * s->slot_map.size());
1303
slot_flags = (uint32_t *)memalloc(sizeof(uint32_t) * s->slot_map.size());
1304
}
1305
1306
// Ensure that disconnecting the signal or even deleting the object
1307
// will not affect the signal calling.
1308
for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
1309
memnew_placement(&slot_callables[slot_count], Callable(slot_kv.value.conn.callable));
1310
slot_flags[slot_count] = slot_kv.value.conn.flags;
1311
++slot_count;
1312
}
1313
1314
DEV_ASSERT(slot_count == s->slot_map.size());
1315
1316
// Disconnect all one-shot connections before emitting to prevent recursion.
1317
for (uint32_t i = 0; i < slot_count; ++i) {
1318
bool disconnect = slot_flags[i] & CONNECT_ONE_SHOT;
1319
#ifdef TOOLS_ENABLED
1320
if (disconnect && (slot_flags[i] & CONNECT_PERSIST) && Engine::get_singleton()->is_editor_hint()) {
1321
// This signal was connected from the editor, and is being edited. Just don't disconnect for now.
1322
disconnect = false;
1323
}
1324
#endif
1325
if (disconnect) {
1326
_disconnect(p_name, slot_callables[i]);
1327
}
1328
}
1329
}
1330
1331
OBJ_DEBUG_LOCK
1332
1333
// If this is a ref-counted object, prevent it from being destroyed during signal
1334
// emission, which is needed in certain edge cases; e.g., GH-73889 and GH-109471.
1335
// Moreover, since signals can be emitted from constructors (classic example being
1336
// notify_property_list_changed), we must be careful not to do the ref init ourselves,
1337
// which would lead to the object being destroyed at the end of this function.
1338
bool pending_unref = Object::cast_to<RefCounted>(this) ? ((RefCounted *)this)->reference() : false;
1339
1340
Error err = OK;
1341
1342
Vector<const Variant *> append_source_mem;
1343
Variant source = this;
1344
1345
for (uint32_t i = 0; i < slot_count; ++i) {
1346
const Callable &callable = slot_callables[i];
1347
const uint32_t &flags = slot_flags[i];
1348
1349
if (!callable.is_valid()) {
1350
// Target might have been deleted during signal callback, this is expected and OK.
1351
continue;
1352
}
1353
1354
const Variant **args = p_args;
1355
int argc = p_argcount;
1356
1357
if (flags & CONNECT_APPEND_SOURCE_OBJECT) {
1358
// Source is being appended regardless of unbinds.
1359
// Implemented by inserting before the first to-be-unbinded arg.
1360
int source_index = p_argcount - callable.get_unbound_arguments_count();
1361
if (source_index >= 0) {
1362
append_source_mem.resize(p_argcount + 1);
1363
const Variant **args_mem = append_source_mem.ptrw();
1364
1365
for (int j = 0; j < source_index; j++) {
1366
args_mem[j] = p_args[j];
1367
}
1368
args_mem[source_index] = &source;
1369
for (int j = source_index; j < p_argcount; j++) {
1370
args_mem[j + 1] = p_args[j];
1371
}
1372
1373
args = args_mem;
1374
argc = p_argcount + 1;
1375
} else {
1376
// More args unbound than provided, call will fail.
1377
// Since appended source is non-unbindable, the error
1378
// about too many unbinds should be correct as is.
1379
}
1380
}
1381
1382
if (flags & CONNECT_DEFERRED) {
1383
MessageQueue::get_singleton()->push_callablep(callable, args, argc, true);
1384
} else {
1385
Callable::CallError ce;
1386
_emitting = true;
1387
Variant ret;
1388
callable.callp(args, argc, ret, ce);
1389
_emitting = false;
1390
1391
if (ce.error != Callable::CallError::CALL_OK) {
1392
Object *target = callable.get_object();
1393
#ifdef DEBUG_ENABLED
1394
if (target && flags & CONNECT_PERSIST && Engine::get_singleton()->is_editor_hint()) {
1395
Ref<Script> other_scr = target->get_script();
1396
if (other_scr.is_valid() && !other_scr->is_tool()) {
1397
// Trying to call not-tool method in editor, just ignore it.
1398
continue;
1399
}
1400
}
1401
#endif
1402
if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD && target && !ClassDB::class_exists(target->get_class_name())) {
1403
// Most likely object is not initialized yet, do not throw error.
1404
} else {
1405
ERR_PRINT(vformat("Error calling from signal '%s' to callable: %s.", String(p_name), Variant::get_callable_error_text(callable, args, argc, ce)));
1406
err = ERR_METHOD_NOT_FOUND;
1407
}
1408
}
1409
}
1410
}
1411
1412
for (uint32_t i = 0; i < slot_count; ++i) {
1413
slot_callables[i].~Callable();
1414
}
1415
1416
if (slot_callables != (Callable *)slot_callable_stack) {
1417
memfree(slot_callables);
1418
memfree(slot_flags);
1419
}
1420
1421
if (pending_unref) {
1422
// We have to do the same Ref<T> would do. We can't just use Ref<T>
1423
// because it would do the init ref logic, which is something this function
1424
// shouldn't do, as explained above.
1425
if (((RefCounted *)this)->unreference()) {
1426
memdelete(this);
1427
}
1428
}
1429
1430
return err;
1431
}
1432
1433
void Object::_reset_gdtype() const {
1434
if (_extension) {
1435
// Set to extension's type.
1436
_gdtype_ptr = _extension->gdtype;
1437
} else {
1438
// Reset to internal type.
1439
_gdtype_ptr = &_get_typev();
1440
}
1441
}
1442
1443
void Object::_add_user_signal(const String &p_name, const Array &p_args) {
1444
// this version of add_user_signal is meant to be used from scripts or external apis
1445
// without access to ADD_SIGNAL in bind_methods
1446
// added events are per instance, as opposed to the other ones, which are global
1447
1448
OBJ_SIGNAL_LOCK
1449
1450
MethodInfo mi;
1451
mi.name = p_name;
1452
1453
for (const Variant &arg : p_args) {
1454
Dictionary d = arg;
1455
PropertyInfo param;
1456
1457
if (d.has("name")) {
1458
param.name = d["name"];
1459
}
1460
if (d.has("type")) {
1461
param.type = (Variant::Type)(int)d["type"];
1462
}
1463
1464
mi.arguments.push_back(param);
1465
}
1466
1467
add_user_signal(mi);
1468
1469
if (signal_map.has(p_name)) {
1470
signal_map.getptr(p_name)->removable = true;
1471
}
1472
}
1473
1474
TypedArray<Dictionary> Object::_get_signal_list() const {
1475
List<MethodInfo> signal_list;
1476
get_signal_list(&signal_list);
1477
1478
TypedArray<Dictionary> ret;
1479
for (const MethodInfo &E : signal_list) {
1480
ret.push_back(Dictionary(E));
1481
}
1482
1483
return ret;
1484
}
1485
1486
TypedArray<Dictionary> Object::_get_signal_connection_list(const StringName &p_signal) const {
1487
List<Connection> conns;
1488
get_all_signal_connections(&conns);
1489
1490
TypedArray<Dictionary> ret;
1491
1492
for (const Connection &c : conns) {
1493
if (c.signal.get_name() == p_signal) {
1494
ret.push_back(c);
1495
}
1496
}
1497
1498
return ret;
1499
}
1500
1501
TypedArray<Dictionary> Object::_get_incoming_connections() const {
1502
TypedArray<Dictionary> ret;
1503
for (const Object::Connection &connection : connections) {
1504
ret.push_back(connection);
1505
}
1506
1507
return ret;
1508
}
1509
1510
bool Object::has_signal(const StringName &p_name) const {
1511
if (script_instance && script_instance->get_script()->has_script_signal(p_name)) {
1512
return true;
1513
}
1514
1515
if (ClassDB::has_signal(get_class_name(), p_name)) {
1516
return true;
1517
}
1518
1519
if (_has_user_signal(p_name)) {
1520
return true;
1521
}
1522
1523
return false;
1524
}
1525
1526
void Object::get_signal_list(List<MethodInfo> *p_signals) const {
1527
OBJ_SIGNAL_LOCK
1528
1529
if (script_instance) {
1530
script_instance->get_script()->get_script_signal_list(p_signals);
1531
}
1532
1533
ClassDB::get_signal_list(get_class_name(), p_signals);
1534
//find maybe usersignals?
1535
1536
for (const KeyValue<StringName, SignalData> &E : signal_map) {
1537
if (!E.value.user.name.is_empty()) {
1538
//user signal
1539
p_signals->push_back(E.value.user);
1540
}
1541
}
1542
}
1543
1544
void Object::get_all_signal_connections(List<Connection> *p_connections) const {
1545
OBJ_SIGNAL_LOCK
1546
1547
for (const KeyValue<StringName, SignalData> &E : signal_map) {
1548
const SignalData *s = &E.value;
1549
1550
for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
1551
p_connections->push_back(slot_kv.value.conn);
1552
}
1553
}
1554
}
1555
1556
void Object::get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const {
1557
OBJ_SIGNAL_LOCK
1558
1559
const SignalData *s = signal_map.getptr(p_signal);
1560
if (!s) {
1561
return; //nothing
1562
}
1563
1564
for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
1565
p_connections->push_back(slot_kv.value.conn);
1566
}
1567
}
1568
1569
int Object::get_persistent_signal_connection_count() const {
1570
OBJ_SIGNAL_LOCK
1571
int count = 0;
1572
1573
for (const KeyValue<StringName, SignalData> &E : signal_map) {
1574
const SignalData *s = &E.value;
1575
1576
for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
1577
if (slot_kv.value.conn.flags & CONNECT_PERSIST) {
1578
count += 1;
1579
}
1580
}
1581
}
1582
1583
return count;
1584
}
1585
1586
uint32_t Object::get_signal_connection_flags(const StringName &p_name, const Callable &p_callable) const {
1587
OBJ_SIGNAL_LOCK
1588
const SignalData *signal_data = signal_map.getptr(p_name);
1589
if (signal_data) {
1590
const SignalData::Slot *slot = signal_data->slot_map.getptr(p_callable);
1591
if (slot) {
1592
return slot->conn.flags;
1593
}
1594
}
1595
return 0;
1596
}
1597
1598
void Object::get_signals_connected_to_this(List<Connection> *p_connections) const {
1599
OBJ_SIGNAL_LOCK
1600
1601
for (const Connection &E : connections) {
1602
p_connections->push_back(E);
1603
}
1604
}
1605
1606
Error Object::connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags) {
1607
ERR_FAIL_COND_V_MSG(p_callable.is_null(), ERR_INVALID_PARAMETER, vformat("Cannot connect to '%s': the provided callable is null.", p_signal));
1608
OBJ_SIGNAL_LOCK
1609
1610
if (p_callable.is_standard()) {
1611
// FIXME: This branch should probably removed in favor of the `is_valid()` branch, but there exist some classes
1612
// that call `connect()` before they are fully registered with ClassDB. Until all such classes can be found
1613
// and registered soon enough this branch is needed to allow `connect()` to succeed.
1614
ERR_FAIL_NULL_V_MSG(p_callable.get_object(), ERR_INVALID_PARAMETER, vformat("Cannot connect to '%s' to callable '%s': the callable object is null.", p_signal, p_callable));
1615
} else {
1616
ERR_FAIL_COND_V_MSG(!p_callable.is_valid(), ERR_INVALID_PARAMETER, vformat("Cannot connect to '%s': the provided callable is not valid: '%s'.", p_signal, p_callable));
1617
}
1618
1619
SignalData *s = signal_map.getptr(p_signal);
1620
if (!s) {
1621
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
1622
//check in script
1623
if (!signal_is_valid && script_instance) {
1624
if (script_instance->get_script()->has_script_signal(p_signal)) {
1625
signal_is_valid = true;
1626
}
1627
#ifdef TOOLS_ENABLED
1628
else {
1629
//allow connecting signals anyway if script is invalid, see issue #17070
1630
if (!script_instance->get_script()->is_valid()) {
1631
signal_is_valid = true;
1632
}
1633
}
1634
#endif
1635
}
1636
1637
ERR_FAIL_COND_V_MSG(!signal_is_valid, ERR_INVALID_PARAMETER, vformat("In Object of type '%s': Attempt to connect nonexistent signal '%s' to callable '%s'.", String(get_class()), p_signal, p_callable));
1638
1639
signal_map[p_signal] = SignalData();
1640
s = &signal_map[p_signal];
1641
}
1642
1643
//compare with the base callable, so binds can be ignored
1644
if (s->slot_map.has(*p_callable.get_base_comparator())) {
1645
if (p_flags & CONNECT_REFERENCE_COUNTED) {
1646
s->slot_map[*p_callable.get_base_comparator()].reference_count++;
1647
return OK;
1648
} else {
1649
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("Signal '%s' is already connected to given callable '%s' in that object.", p_signal, p_callable));
1650
}
1651
}
1652
1653
Object *target_object = p_callable.get_object();
1654
1655
SignalData::Slot slot;
1656
1657
Connection conn;
1658
conn.callable = p_callable;
1659
conn.signal = ::Signal(this, p_signal);
1660
conn.flags = p_flags;
1661
slot.conn = conn;
1662
if (target_object) {
1663
slot.cE = target_object->connections.push_back(conn);
1664
}
1665
if (p_flags & CONNECT_REFERENCE_COUNTED) {
1666
slot.reference_count = 1;
1667
}
1668
1669
//use callable version as key, so binds can be ignored
1670
s->slot_map[*p_callable.get_base_comparator()] = slot;
1671
1672
return OK;
1673
}
1674
1675
bool Object::is_connected(const StringName &p_signal, const Callable &p_callable) const {
1676
ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, vformat("Cannot determine if connected to '%s': the provided callable is null.", p_signal)); // Should use `is_null`, see note in `connect` about the use of `is_valid`.
1677
OBJ_SIGNAL_LOCK
1678
1679
const SignalData *s = signal_map.getptr(p_signal);
1680
if (!s) {
1681
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
1682
if (signal_is_valid) {
1683
return false;
1684
}
1685
1686
if (script_instance && script_instance->get_script()->has_script_signal(p_signal)) {
1687
return false;
1688
}
1689
1690
ERR_FAIL_V_MSG(false, vformat("Nonexistent signal: '%s'.", p_signal));
1691
}
1692
1693
return s->slot_map.has(*p_callable.get_base_comparator());
1694
}
1695
1696
bool Object::has_connections(const StringName &p_signal) const {
1697
OBJ_SIGNAL_LOCK
1698
1699
const SignalData *s = signal_map.getptr(p_signal);
1700
if (!s) {
1701
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
1702
if (signal_is_valid) {
1703
return false;
1704
}
1705
1706
if (script_instance && script_instance->get_script()->has_script_signal(p_signal)) {
1707
return false;
1708
}
1709
1710
ERR_FAIL_V_MSG(false, vformat("Nonexistent signal: '%s'.", p_signal));
1711
}
1712
1713
return !s->slot_map.is_empty();
1714
}
1715
1716
void Object::disconnect(const StringName &p_signal, const Callable &p_callable) {
1717
_disconnect(p_signal, p_callable);
1718
}
1719
1720
bool Object::_disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force) {
1721
ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, vformat("Cannot disconnect from '%s': the provided callable is null.", p_signal)); // Should use `is_null`, see note in `connect` about the use of `is_valid`.
1722
OBJ_SIGNAL_LOCK
1723
1724
SignalData *s = signal_map.getptr(p_signal);
1725
if (!s) {
1726
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal) ||
1727
(script_instance && script_instance->get_script()->has_script_signal(p_signal));
1728
ERR_FAIL_COND_V_MSG(signal_is_valid, false, vformat("Attempt to disconnect a nonexistent connection from '%s'. Signal: '%s', callable: '%s'.", to_string(), p_signal, p_callable));
1729
}
1730
ERR_FAIL_NULL_V_MSG(s, false, vformat("Disconnecting nonexistent signal '%s' in '%s'.", p_signal, to_string()));
1731
1732
ERR_FAIL_COND_V_MSG(!s->slot_map.has(*p_callable.get_base_comparator()), false, vformat("Attempt to disconnect a nonexistent connection from '%s'. Signal: '%s', callable: '%s'.", to_string(), p_signal, p_callable));
1733
1734
SignalData::Slot *slot = &s->slot_map[*p_callable.get_base_comparator()];
1735
1736
if (!p_force) {
1737
slot->reference_count--; // by default is zero, if it was not referenced it will go below it
1738
if (slot->reference_count > 0) {
1739
return false;
1740
}
1741
}
1742
1743
if (slot->cE) {
1744
Object *target_object = p_callable.get_object();
1745
if (target_object) {
1746
target_object->connections.erase(slot->cE);
1747
}
1748
}
1749
1750
s->slot_map.erase(*p_callable.get_base_comparator());
1751
1752
if (s->slot_map.is_empty() && ClassDB::has_signal(get_class_name(), p_signal)) {
1753
//not user signal, delete
1754
signal_map.erase(p_signal);
1755
}
1756
1757
return true;
1758
}
1759
1760
bool Object::_uses_signal_mutex() const {
1761
return true;
1762
}
1763
1764
String Object::_get_locale() const {
1765
TranslationServer *ts = TranslationServer::get_singleton();
1766
const StringName domain_name = get_translation_domain();
1767
if (ts->has_domain(domain_name)) {
1768
const Ref<TranslationDomain> domain = ts->get_or_add_domain(domain_name);
1769
const String &overridden = domain->get_locale_override();
1770
if (!overridden.is_empty()) {
1771
return overridden;
1772
}
1773
}
1774
return ts->get_locale();
1775
}
1776
1777
void Object::_set_bind(const StringName &p_set, const Variant &p_value) {
1778
set(p_set, p_value);
1779
}
1780
1781
Variant Object::_get_bind(const StringName &p_name) const {
1782
return get(p_name);
1783
}
1784
1785
void Object::_set_indexed_bind(const NodePath &p_name, const Variant &p_value) {
1786
set_indexed(p_name.get_as_property_path().get_subnames(), p_value);
1787
}
1788
1789
Variant Object::_get_indexed_bind(const NodePath &p_name) const {
1790
return get_indexed(p_name.get_as_property_path().get_subnames());
1791
}
1792
1793
void Object::initialize_class() {
1794
static bool initialized = false;
1795
if (initialized) {
1796
return;
1797
}
1798
_add_class_to_classdb(get_gdtype_static(), nullptr);
1799
_bind_methods();
1800
_bind_compatibility_methods();
1801
initialized = true;
1802
}
1803
1804
StringName Object::get_translation_domain() const {
1805
return _translation_domain;
1806
}
1807
1808
void Object::set_translation_domain(const StringName &p_domain) {
1809
_translation_domain = p_domain;
1810
}
1811
1812
String Object::tr(const StringName &p_message, const StringName &p_context) const {
1813
if (!_can_translate || !TranslationServer::get_singleton()) {
1814
return p_message;
1815
}
1816
1817
const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain(get_translation_domain());
1818
return domain->translate(p_message, p_context);
1819
}
1820
1821
String Object::tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
1822
if (!_can_translate || !TranslationServer::get_singleton()) {
1823
// Return message based on English plural rule if translation is not possible.
1824
if (p_n == 1) {
1825
return p_message;
1826
}
1827
return p_message_plural;
1828
}
1829
1830
const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain(get_translation_domain());
1831
return domain->translate_plural(p_message, p_message_plural, p_n, p_context);
1832
}
1833
1834
void Object::_clear_internal_resource_paths(const Variant &p_var) {
1835
switch (p_var.get_type()) {
1836
case Variant::OBJECT: {
1837
Ref<Resource> r = p_var;
1838
if (r.is_null()) {
1839
return;
1840
}
1841
1842
if (!r->is_built_in()) {
1843
return; //not an internal resource
1844
}
1845
1846
Object *object = p_var;
1847
if (!object) {
1848
return;
1849
}
1850
1851
r->set_path("");
1852
r->clear_internal_resource_paths();
1853
} break;
1854
case Variant::ARRAY: {
1855
Array a = p_var;
1856
for (const Variant &var : a) {
1857
_clear_internal_resource_paths(var);
1858
}
1859
1860
} break;
1861
case Variant::DICTIONARY: {
1862
Dictionary d = p_var;
1863
1864
for (const KeyValue<Variant, Variant> &kv : d) {
1865
_clear_internal_resource_paths(kv.key);
1866
_clear_internal_resource_paths(kv.value);
1867
}
1868
} break;
1869
default: {
1870
}
1871
}
1872
}
1873
1874
void Object::_add_class_to_classdb(const GDType &p_type, const GDType *p_inherits) {
1875
ClassDB::_add_class(p_type, p_inherits);
1876
}
1877
1878
void Object::_get_property_list_from_classdb(const StringName &p_class, List<PropertyInfo> *p_list, bool p_no_inheritance, const Object *p_validator) {
1879
ClassDB::get_property_list(p_class, p_list, p_no_inheritance, p_validator);
1880
}
1881
1882
#ifdef TOOLS_ENABLED
1883
void Object::editor_set_section_unfold(const String &p_section, bool p_unfolded, bool p_initializing) {
1884
if (!p_initializing) {
1885
set_edited(true);
1886
}
1887
1888
if (p_unfolded) {
1889
editor_section_folding.insert(p_section);
1890
} else {
1891
editor_section_folding.erase(p_section);
1892
}
1893
}
1894
1895
bool Object::editor_is_section_unfolded(const String &p_section) {
1896
return editor_section_folding.has(p_section);
1897
}
1898
1899
#endif
1900
1901
void Object::clear_internal_resource_paths() {
1902
List<PropertyInfo> pinfo;
1903
1904
get_property_list(&pinfo);
1905
1906
for (const PropertyInfo &E : pinfo) {
1907
_clear_internal_resource_paths(get(E.name));
1908
}
1909
}
1910
1911
void Object::notify_property_list_changed() {
1912
emit_signal(CoreStringName(property_list_changed));
1913
}
1914
1915
String Object::_to_string() {
1916
return "<" + get_class() + "#" + itos(get_instance_id()) + ">";
1917
}
1918
1919
void Object::_bind_methods() {
1920
ClassDB::bind_method(D_METHOD("get_class"), &Object::get_class);
1921
ClassDB::bind_method(D_METHOD("is_class", "class"), &Object::is_class);
1922
ClassDB::bind_method(D_METHOD("set", "property", "value"), &Object::_set_bind);
1923
ClassDB::bind_method(D_METHOD("get", "property"), &Object::_get_bind);
1924
ClassDB::bind_method(D_METHOD("set_indexed", "property_path", "value"), &Object::_set_indexed_bind);
1925
ClassDB::bind_method(D_METHOD("get_indexed", "property_path"), &Object::_get_indexed_bind);
1926
ClassDB::bind_method(D_METHOD("get_property_list"), &Object::_get_property_list_bind);
1927
ClassDB::bind_method(D_METHOD("get_method_list"), &Object::_get_method_list_bind);
1928
ClassDB::bind_method(D_METHOD("property_can_revert", "property"), &Object::property_can_revert);
1929
ClassDB::bind_method(D_METHOD("property_get_revert", "property"), &Object::property_get_revert);
1930
ClassDB::bind_method(D_METHOD("notification", "what", "reversed"), &Object::notification, DEFVAL(false));
1931
ClassDB::bind_method(D_METHOD("to_string"), &Object::to_string);
1932
ClassDB::bind_method(D_METHOD("get_instance_id"), &Object::get_instance_id);
1933
1934
ClassDB::bind_method(D_METHOD("set_script", "script"), &Object::set_script);
1935
ClassDB::bind_method(D_METHOD("get_script"), &Object::get_script);
1936
1937
ClassDB::bind_method(D_METHOD("set_meta", "name", "value"), &Object::set_meta);
1938
ClassDB::bind_method(D_METHOD("remove_meta", "name"), &Object::remove_meta);
1939
ClassDB::bind_method(D_METHOD("get_meta", "name", "default"), &Object::get_meta, DEFVAL(Variant()));
1940
ClassDB::bind_method(D_METHOD("has_meta", "name"), &Object::has_meta);
1941
ClassDB::bind_method(D_METHOD("get_meta_list"), &Object::_get_meta_list_bind);
1942
1943
ClassDB::bind_method(D_METHOD("add_user_signal", "signal", "arguments"), &Object::_add_user_signal, DEFVAL(Array()));
1944
ClassDB::bind_method(D_METHOD("has_user_signal", "signal"), &Object::_has_user_signal);
1945
ClassDB::bind_method(D_METHOD("remove_user_signal", "signal"), &Object::_remove_user_signal);
1946
1947
{
1948
MethodInfo mi;
1949
mi.name = "emit_signal";
1950
mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "signal"));
1951
1952
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "emit_signal", &Object::_emit_signal, mi, varray(), false);
1953
}
1954
1955
{
1956
MethodInfo mi;
1957
mi.name = "call";
1958
mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
1959
1960
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call", &Object::_call_bind, mi);
1961
}
1962
1963
{
1964
MethodInfo mi;
1965
mi.name = "call_deferred";
1966
mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
1967
1968
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_deferred", &Object::_call_deferred_bind, mi, varray(), false);
1969
}
1970
1971
ClassDB::bind_method(D_METHOD("set_deferred", "property", "value"), &Object::set_deferred);
1972
1973
ClassDB::bind_method(D_METHOD("callv", "method", "arg_array"), &Object::callv);
1974
1975
ClassDB::bind_method(D_METHOD("has_method", "method"), &Object::has_method);
1976
1977
ClassDB::bind_method(D_METHOD("get_method_argument_count", "method"), &Object::_get_method_argument_count_bind);
1978
1979
ClassDB::bind_method(D_METHOD("has_signal", "signal"), &Object::has_signal);
1980
ClassDB::bind_method(D_METHOD("get_signal_list"), &Object::_get_signal_list);
1981
ClassDB::bind_method(D_METHOD("get_signal_connection_list", "signal"), &Object::_get_signal_connection_list);
1982
ClassDB::bind_method(D_METHOD("get_incoming_connections"), &Object::_get_incoming_connections);
1983
1984
ClassDB::bind_method(D_METHOD("connect", "signal", "callable", "flags"), &Object::connect, DEFVAL(0));
1985
ClassDB::bind_method(D_METHOD("disconnect", "signal", "callable"), &Object::disconnect);
1986
ClassDB::bind_method(D_METHOD("is_connected", "signal", "callable"), &Object::is_connected);
1987
ClassDB::bind_method(D_METHOD("has_connections", "signal"), &Object::has_connections);
1988
1989
ClassDB::bind_method(D_METHOD("set_block_signals", "enable"), &Object::set_block_signals);
1990
ClassDB::bind_method(D_METHOD("is_blocking_signals"), &Object::is_blocking_signals);
1991
ClassDB::bind_method(D_METHOD("notify_property_list_changed"), &Object::notify_property_list_changed);
1992
1993
ClassDB::bind_method(D_METHOD("set_message_translation", "enable"), &Object::set_message_translation);
1994
ClassDB::bind_method(D_METHOD("can_translate_messages"), &Object::can_translate_messages);
1995
ClassDB::bind_method(D_METHOD("tr", "message", "context"), &Object::tr, DEFVAL(StringName()));
1996
ClassDB::bind_method(D_METHOD("tr_n", "message", "plural_message", "n", "context"), &Object::tr_n, DEFVAL(StringName()));
1997
ClassDB::bind_method(D_METHOD("get_translation_domain"), &Object::get_translation_domain);
1998
ClassDB::bind_method(D_METHOD("set_translation_domain", "domain"), &Object::set_translation_domain);
1999
2000
ClassDB::bind_method(D_METHOD("is_queued_for_deletion"), &Object::is_queued_for_deletion);
2001
ClassDB::bind_method(D_METHOD("cancel_free"), &Object::cancel_free);
2002
2003
ClassDB::add_virtual_method("Object", MethodInfo("free"), false);
2004
2005
ADD_SIGNAL(MethodInfo("script_changed"));
2006
ADD_SIGNAL(MethodInfo("property_list_changed"));
2007
2008
#define BIND_OBJ_CORE_METHOD(m_method) \
2009
::ClassDB::add_virtual_method(get_class_static(), m_method, true, Vector<String>(), true);
2010
2011
BIND_OBJ_CORE_METHOD(MethodInfo("_init"));
2012
2013
BIND_OBJ_CORE_METHOD(MethodInfo(Variant::STRING, "_to_string"));
2014
2015
{
2016
MethodInfo mi("_notification");
2017
mi.arguments.push_back(PropertyInfo(Variant::INT, "what"));
2018
mi.arguments_metadata.push_back(GodotTypeInfo::Metadata::METADATA_INT_IS_INT32);
2019
BIND_OBJ_CORE_METHOD(mi);
2020
}
2021
2022
{
2023
MethodInfo mi("_set");
2024
mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "property"));
2025
mi.arguments.push_back(PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
2026
mi.return_val.type = Variant::BOOL;
2027
BIND_OBJ_CORE_METHOD(mi);
2028
}
2029
2030
#ifdef TOOLS_ENABLED
2031
{
2032
MethodInfo mi("_get");
2033
mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "property"));
2034
mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
2035
BIND_OBJ_CORE_METHOD(mi);
2036
}
2037
2038
{
2039
MethodInfo mi("_get_property_list");
2040
mi.return_val.type = Variant::ARRAY;
2041
mi.return_val.hint = PROPERTY_HINT_ARRAY_TYPE;
2042
mi.return_val.hint_string = "Dictionary";
2043
BIND_OBJ_CORE_METHOD(mi);
2044
}
2045
2046
BIND_OBJ_CORE_METHOD(MethodInfo(Variant::NIL, "_validate_property", PropertyInfo(Variant::DICTIONARY, "property")));
2047
2048
BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_property_can_revert", PropertyInfo(Variant::STRING_NAME, "property")));
2049
2050
{
2051
MethodInfo mi("_property_get_revert");
2052
mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "property"));
2053
mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
2054
BIND_OBJ_CORE_METHOD(mi);
2055
}
2056
2057
// These are actually `Variant` methods, but that doesn't matter since scripts can't inherit built-in types.
2058
2059
BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_iter_init", PropertyInfo(Variant::ARRAY, "iter")));
2060
2061
BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_iter_next", PropertyInfo(Variant::ARRAY, "iter")));
2062
2063
{
2064
MethodInfo mi("_iter_get");
2065
mi.arguments.push_back(PropertyInfo(Variant::NIL, "iter", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
2066
mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
2067
BIND_OBJ_CORE_METHOD(mi);
2068
}
2069
#endif
2070
2071
BIND_CONSTANT(NOTIFICATION_POSTINITIALIZE);
2072
BIND_CONSTANT(NOTIFICATION_PREDELETE);
2073
BIND_CONSTANT(NOTIFICATION_EXTENSION_RELOADED);
2074
2075
BIND_ENUM_CONSTANT(CONNECT_DEFERRED);
2076
BIND_ENUM_CONSTANT(CONNECT_PERSIST);
2077
BIND_ENUM_CONSTANT(CONNECT_ONE_SHOT);
2078
BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);
2079
BIND_ENUM_CONSTANT(CONNECT_APPEND_SOURCE_OBJECT);
2080
}
2081
2082
void Object::set_deferred(const StringName &p_property, const Variant &p_value) {
2083
MessageQueue::get_singleton()->push_set(this, p_property, p_value);
2084
}
2085
2086
void Object::set_block_signals(bool p_block) {
2087
_block_signals = p_block;
2088
}
2089
2090
bool Object::is_blocking_signals() const {
2091
return _block_signals;
2092
}
2093
2094
Variant::Type Object::get_static_property_type(const StringName &p_property, bool *r_valid) const {
2095
bool valid;
2096
Variant::Type t = ClassDB::get_property_type(get_class_name(), p_property, &valid);
2097
if (valid) {
2098
if (r_valid) {
2099
*r_valid = true;
2100
}
2101
return t;
2102
}
2103
2104
if (get_script_instance()) {
2105
return get_script_instance()->get_property_type(p_property, r_valid);
2106
}
2107
if (r_valid) {
2108
*r_valid = false;
2109
}
2110
2111
return Variant::NIL;
2112
}
2113
2114
Variant::Type Object::get_static_property_type_indexed(const Vector<StringName> &p_path, bool *r_valid) const {
2115
if (p_path.is_empty()) {
2116
if (r_valid) {
2117
*r_valid = false;
2118
}
2119
2120
return Variant::NIL;
2121
}
2122
2123
bool valid = false;
2124
Variant::Type t = get_static_property_type(p_path[0], &valid);
2125
if (!valid) {
2126
if (r_valid) {
2127
*r_valid = false;
2128
}
2129
2130
return Variant::NIL;
2131
}
2132
2133
Callable::CallError ce;
2134
Variant check;
2135
Variant::construct(t, check, nullptr, 0, ce);
2136
2137
for (int i = 1; i < p_path.size(); i++) {
2138
if (check.get_type() == Variant::OBJECT || check.get_type() == Variant::DICTIONARY || check.get_type() == Variant::ARRAY) {
2139
// We cannot be sure about the type of properties this type can have
2140
if (r_valid) {
2141
*r_valid = false;
2142
}
2143
return Variant::NIL;
2144
}
2145
2146
check = check.get_named(p_path[i], valid);
2147
2148
if (!valid) {
2149
if (r_valid) {
2150
*r_valid = false;
2151
}
2152
return Variant::NIL;
2153
}
2154
}
2155
2156
if (r_valid) {
2157
*r_valid = true;
2158
}
2159
2160
return check.get_type();
2161
}
2162
2163
bool Object::is_queued_for_deletion() const {
2164
return _is_queued_for_deletion;
2165
}
2166
2167
#ifdef TOOLS_ENABLED
2168
void Object::set_edited(bool p_edited) {
2169
_edited = p_edited;
2170
_edited_version++;
2171
}
2172
2173
bool Object::is_edited() const {
2174
return _edited;
2175
}
2176
2177
uint32_t Object::get_edited_version() const {
2178
return _edited_version;
2179
}
2180
#endif
2181
2182
const GDType &Object::get_gdtype() const {
2183
if (unlikely(!_gdtype_ptr)) {
2184
// While class is initializing / deinitializing, constructors and destructors
2185
// need access to the proper type at the proper stage.
2186
return _get_typev();
2187
}
2188
return *_gdtype_ptr;
2189
}
2190
2191
bool Object::is_class(const String &p_class) const {
2192
for (const StringName &name : get_gdtype().get_name_hierarchy()) {
2193
if (name == p_class) {
2194
return true;
2195
}
2196
}
2197
return false;
2198
}
2199
2200
const StringName &Object::get_class_name() const {
2201
return get_gdtype().get_name();
2202
}
2203
2204
StringName Object::get_class_name_for_extension(const GDExtension *p_library) const {
2205
#ifdef TOOLS_ENABLED
2206
// If this is the library this extension comes from and it's a placeholder, we
2207
// have to return the closest native parent's class name, so that it doesn't try to
2208
// use this like the real object.
2209
if (unlikely(_extension && _extension->library == p_library && _extension->is_placeholder)) {
2210
return get_class_name();
2211
}
2212
#endif
2213
2214
// Only return the class name per the extension if it matches the given p_library.
2215
if (_extension && _extension->library == p_library) {
2216
return _extension->class_name;
2217
}
2218
2219
// Extensions only have wrapper classes for classes exposed in ClassDB.
2220
const StringName &class_name = get_class_name();
2221
if (ClassDB::is_class_exposed(class_name)) {
2222
return class_name;
2223
}
2224
2225
// Find the nearest parent class that's exposed.
2226
StringName parent_class = ClassDB::get_parent_class(class_name);
2227
while (parent_class != StringName()) {
2228
if (ClassDB::is_class_exposed(parent_class)) {
2229
return parent_class;
2230
}
2231
parent_class = ClassDB::get_parent_class(parent_class);
2232
}
2233
2234
return SNAME("Object");
2235
}
2236
2237
void Object::set_instance_binding(void *p_token, void *p_binding, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
2238
// This is only meant to be used on creation by the binder, but we also
2239
// need to account for reloading (where the 'binding' will be cleared).
2240
ERR_FAIL_COND(_instance_bindings != nullptr && _instance_bindings[0].binding != nullptr);
2241
if (_instance_bindings == nullptr) {
2242
_instance_bindings = (InstanceBinding *)memalloc(sizeof(InstanceBinding));
2243
_instance_binding_count = 1;
2244
}
2245
_instance_bindings[0].binding = p_binding;
2246
_instance_bindings[0].free_callback = p_callbacks->free_callback;
2247
_instance_bindings[0].reference_callback = p_callbacks->reference_callback;
2248
_instance_bindings[0].token = p_token;
2249
}
2250
2251
void *Object::get_instance_binding(void *p_token, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
2252
void *binding = nullptr;
2253
MutexLock instance_binding_lock(_instance_binding_mutex);
2254
for (uint32_t i = 0; i < _instance_binding_count; i++) {
2255
if (_instance_bindings[i].token == p_token) {
2256
binding = _instance_bindings[i].binding;
2257
break;
2258
}
2259
}
2260
if (unlikely(!binding && p_callbacks)) {
2261
uint32_t current_size = next_power_of_2(_instance_binding_count);
2262
uint32_t new_size = next_power_of_2(_instance_binding_count + 1);
2263
2264
if (current_size == 0 || new_size > current_size) {
2265
_instance_bindings = (InstanceBinding *)memrealloc(_instance_bindings, new_size * sizeof(InstanceBinding));
2266
}
2267
2268
_instance_bindings[_instance_binding_count].free_callback = p_callbacks->free_callback;
2269
_instance_bindings[_instance_binding_count].reference_callback = p_callbacks->reference_callback;
2270
_instance_bindings[_instance_binding_count].token = p_token;
2271
2272
binding = p_callbacks->create_callback(p_token, this);
2273
_instance_bindings[_instance_binding_count].binding = binding;
2274
2275
#ifdef TOOLS_ENABLED
2276
if (!_extension && Engine::get_singleton()->is_extension_reloading_enabled()) {
2277
GDExtensionManager::get_singleton()->track_instance_binding(p_token, this);
2278
}
2279
#endif
2280
2281
_instance_binding_count++;
2282
}
2283
2284
return binding;
2285
}
2286
2287
bool Object::has_instance_binding(void *p_token) {
2288
bool found = false;
2289
MutexLock instance_binding_lock(_instance_binding_mutex);
2290
for (uint32_t i = 0; i < _instance_binding_count; i++) {
2291
if (_instance_bindings[i].token == p_token) {
2292
found = true;
2293
break;
2294
}
2295
}
2296
2297
return found;
2298
}
2299
2300
void Object::free_instance_binding(void *p_token) {
2301
bool found = false;
2302
MutexLock instance_binding_lock(_instance_binding_mutex);
2303
for (uint32_t i = 0; i < _instance_binding_count; i++) {
2304
if (!found && _instance_bindings[i].token == p_token) {
2305
if (_instance_bindings[i].free_callback) {
2306
_instance_bindings[i].free_callback(_instance_bindings[i].token, this, _instance_bindings[i].binding);
2307
}
2308
found = true;
2309
}
2310
if (found) {
2311
if (i + 1 < _instance_binding_count) {
2312
_instance_bindings[i] = _instance_bindings[i + 1];
2313
} else {
2314
_instance_bindings[i] = { nullptr };
2315
}
2316
}
2317
}
2318
if (found) {
2319
_instance_binding_count--;
2320
}
2321
}
2322
2323
#ifdef TOOLS_ENABLED
2324
void Object::clear_internal_extension() {
2325
ERR_FAIL_NULL(_extension);
2326
2327
// Free the instance inside the GDExtension.
2328
if (_extension->free_instance) {
2329
_extension->free_instance(_extension->class_userdata, _extension_instance);
2330
}
2331
_extension = nullptr;
2332
_extension_instance = nullptr;
2333
// Reset GDType to internal type.
2334
_gdtype_ptr = &_get_typev();
2335
2336
// Clear the instance bindings.
2337
_instance_binding_mutex.lock();
2338
if (_instance_bindings) {
2339
if (_instance_bindings[0].free_callback) {
2340
_instance_bindings[0].free_callback(_instance_bindings[0].token, this, _instance_bindings[0].binding);
2341
}
2342
_instance_bindings[0].binding = nullptr;
2343
_instance_bindings[0].token = nullptr;
2344
_instance_bindings[0].free_callback = nullptr;
2345
_instance_bindings[0].reference_callback = nullptr;
2346
}
2347
_instance_binding_mutex.unlock();
2348
2349
// Clear the virtual methods.
2350
while (virtual_method_list) {
2351
(*virtual_method_list->method) = nullptr;
2352
virtual_method_list = virtual_method_list->next;
2353
}
2354
}
2355
2356
void Object::reset_internal_extension(ObjectGDExtension *p_extension) {
2357
ERR_FAIL_COND(_extension != nullptr);
2358
2359
if (p_extension) {
2360
_extension_instance = p_extension->recreate_instance ? p_extension->recreate_instance(p_extension->class_userdata, (GDExtensionObjectPtr)this) : nullptr;
2361
ERR_FAIL_NULL_MSG(_extension_instance, "Unable to recreate GDExtension instance - does this extension support hot reloading?");
2362
_extension = p_extension;
2363
_gdtype_ptr = p_extension->gdtype;
2364
}
2365
}
2366
#endif
2367
2368
void Object::_construct_object(bool p_reference) {
2369
_block_signals = false;
2370
_can_translate = true;
2371
_emitting = false;
2372
_is_queued_for_deletion = false;
2373
_predelete_ok = false;
2374
2375
// ObjectDB::add_instance relies on AncestralClass::REF_COUNTED
2376
// being already set in the case of references.
2377
_ancestry = p_reference ? (uint32_t)AncestralClass::REF_COUNTED : 0;
2378
2379
_instance_id = ObjectDB::add_instance(this);
2380
2381
#ifdef TOOLS_ENABLED
2382
_edited = false;
2383
#endif
2384
2385
#ifdef DEBUG_ENABLED
2386
_lock_index.init(1);
2387
#endif
2388
}
2389
2390
Object::Object(bool p_reference) {
2391
_construct_object(p_reference);
2392
}
2393
2394
Object::Object() {
2395
_construct_object(false);
2396
}
2397
2398
void Object::detach_from_objectdb() {
2399
if (_instance_id != ObjectID()) {
2400
ObjectDB::remove_instance(this);
2401
_instance_id = ObjectID();
2402
}
2403
}
2404
2405
void Object::assign_type_static(GDType **type_ptr, const char *p_name, const GDType *super_type) {
2406
static BinaryMutex _mutex;
2407
MutexLock lock(_mutex);
2408
GDType *type = *type_ptr;
2409
if (type) {
2410
// Assigned while we were waiting.
2411
return;
2412
}
2413
type = memnew(GDType(super_type, StringName(p_name)));
2414
*type_ptr = type;
2415
2416
ClassDB::gdtype_autorelease_pool.push_back(type_ptr);
2417
}
2418
2419
Object::~Object() {
2420
if (_emitting) {
2421
//@todo this may need to actually reach the debugger prioritarily somehow because it may crash before
2422
ERR_PRINT(vformat("Object '%s' 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.", to_string()));
2423
}
2424
2425
{
2426
OBJ_SIGNAL_LOCK
2427
// Drop all connections to the signals of this object.
2428
while (signal_map.size()) {
2429
// Avoid regular iteration so erasing is safe.
2430
KeyValue<StringName, SignalData> &E = *signal_map.begin();
2431
SignalData *s = &E.value;
2432
2433
for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
2434
Object *target = slot_kv.value.conn.callable.get_object();
2435
if (likely(target)) {
2436
target->connections.erase(slot_kv.value.cE);
2437
}
2438
}
2439
2440
signal_map.erase(E.key);
2441
}
2442
2443
// Disconnect signals that connect to this object.
2444
while (connections.size()) {
2445
Connection c = connections.front()->get();
2446
Object *obj = c.callable.get_object();
2447
bool disconnected = false;
2448
if (likely(obj)) {
2449
disconnected = c.signal.get_object()->_disconnect(c.signal.get_name(), c.callable, true);
2450
}
2451
if (unlikely(!disconnected)) {
2452
// If the disconnect has failed, abandon the connection to avoid getting trapped in an infinite loop here.
2453
connections.pop_front();
2454
}
2455
}
2456
}
2457
2458
if (_instance_id != ObjectID()) {
2459
ObjectDB::remove_instance(this);
2460
_instance_id = ObjectID();
2461
}
2462
_predelete_ok = true;
2463
2464
if (_instance_bindings != nullptr) {
2465
for (uint32_t i = 0; i < _instance_binding_count; i++) {
2466
if (_instance_bindings[i].free_callback) {
2467
_instance_bindings[i].free_callback(_instance_bindings[i].token, this, _instance_bindings[i].binding);
2468
}
2469
}
2470
memfree(_instance_bindings);
2471
}
2472
2473
if (signal_mutex) {
2474
memdelete(signal_mutex);
2475
}
2476
}
2477
2478
bool predelete_handler(Object *p_object) {
2479
return p_object->_predelete();
2480
}
2481
2482
void postinitialize_handler(Object *p_object) {
2483
p_object->_initialize();
2484
p_object->_postinitialize();
2485
}
2486
2487
void ObjectDB::debug_objects(DebugFunc p_func, void *p_user_data) {
2488
spin_lock.lock();
2489
2490
for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) {
2491
if (object_slots[i].validator) {
2492
p_func(object_slots[i].object, p_user_data);
2493
count--;
2494
}
2495
}
2496
spin_lock.unlock();
2497
}
2498
2499
#ifdef TOOLS_ENABLED
2500
void Object::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
2501
const String pf = p_function;
2502
if (p_idx == 0) {
2503
if (pf == "connect" || pf == "is_connected" || pf == "disconnect" || pf == "emit_signal" || pf == "has_signal") {
2504
List<MethodInfo> signals;
2505
get_signal_list(&signals);
2506
for (const MethodInfo &E : signals) {
2507
r_options->push_back(E.name.quote());
2508
}
2509
} else if (pf == "call" || pf == "call_deferred" || pf == "callv" || pf == "has_method") {
2510
List<MethodInfo> methods;
2511
get_method_list(&methods);
2512
for (const MethodInfo &E : methods) {
2513
if (E.name.begins_with("_") && !(E.flags & METHOD_FLAG_VIRTUAL)) {
2514
continue;
2515
}
2516
r_options->push_back(E.name.quote());
2517
}
2518
} else if (pf == "set" || pf == "set_deferred" || pf == "get") {
2519
List<PropertyInfo> properties;
2520
get_property_list(&properties);
2521
for (const PropertyInfo &E : properties) {
2522
if (E.usage & PROPERTY_USAGE_DEFAULT && !(E.usage & PROPERTY_USAGE_INTERNAL)) {
2523
r_options->push_back(E.name.quote());
2524
}
2525
}
2526
} else if (pf == "set_meta" || pf == "get_meta" || pf == "has_meta" || pf == "remove_meta") {
2527
for (const KeyValue<StringName, Variant> &K : metadata) {
2528
r_options->push_back(String(K.key).quote());
2529
}
2530
}
2531
} else if (p_idx == 2) {
2532
if (pf == "connect") {
2533
// Ideally, the constants should be inferred by the parameter.
2534
// But a parameter's PropertyInfo does not store the enum they come from, so this will do for now.
2535
List<StringName> constants;
2536
ClassDB::get_enum_constants("Object", "ConnectFlags", &constants);
2537
for (const StringName &E : constants) {
2538
r_options->push_back(String(E));
2539
}
2540
}
2541
}
2542
}
2543
#endif
2544
2545
SpinLock ObjectDB::spin_lock;
2546
uint32_t ObjectDB::slot_count = 0;
2547
uint32_t ObjectDB::slot_max = 0;
2548
ObjectDB::ObjectSlot *ObjectDB::object_slots = nullptr;
2549
uint64_t ObjectDB::validator_counter = 0;
2550
2551
int ObjectDB::get_object_count() {
2552
return slot_count;
2553
}
2554
2555
ObjectID ObjectDB::add_instance(Object *p_object) {
2556
spin_lock.lock();
2557
if (unlikely(slot_count == slot_max)) {
2558
CRASH_COND(slot_count == (1 << OBJECTDB_SLOT_MAX_COUNT_BITS));
2559
2560
uint32_t new_slot_max = slot_max > 0 ? slot_max * 2 : 1;
2561
object_slots = (ObjectSlot *)memrealloc(object_slots, sizeof(ObjectSlot) * new_slot_max);
2562
for (uint32_t i = slot_max; i < new_slot_max; i++) {
2563
object_slots[i].object = nullptr;
2564
object_slots[i].is_ref_counted = false;
2565
object_slots[i].next_free = i;
2566
object_slots[i].validator = 0;
2567
}
2568
slot_max = new_slot_max;
2569
}
2570
2571
uint32_t slot = object_slots[slot_count].next_free;
2572
if (object_slots[slot].object != nullptr) {
2573
spin_lock.unlock();
2574
ERR_FAIL_COND_V(object_slots[slot].object != nullptr, ObjectID());
2575
}
2576
object_slots[slot].object = p_object;
2577
object_slots[slot].is_ref_counted = p_object->is_ref_counted();
2578
validator_counter = (validator_counter + 1) & OBJECTDB_VALIDATOR_MASK;
2579
if (unlikely(validator_counter == 0)) {
2580
validator_counter = 1;
2581
}
2582
object_slots[slot].validator = validator_counter;
2583
2584
uint64_t id = validator_counter;
2585
id <<= OBJECTDB_SLOT_MAX_COUNT_BITS;
2586
id |= uint64_t(slot);
2587
2588
if (p_object->is_ref_counted()) {
2589
id |= OBJECTDB_REFERENCE_BIT;
2590
}
2591
2592
slot_count++;
2593
2594
spin_lock.unlock();
2595
2596
return ObjectID(id);
2597
}
2598
2599
void ObjectDB::remove_instance(Object *p_object) {
2600
uint64_t t = p_object->get_instance_id();
2601
uint32_t slot = t & OBJECTDB_SLOT_MAX_COUNT_MASK; //slot is always valid on valid object
2602
2603
spin_lock.lock();
2604
2605
#ifdef DEBUG_ENABLED
2606
2607
if (object_slots[slot].object != p_object) {
2608
spin_lock.unlock();
2609
ERR_FAIL_COND(object_slots[slot].object != p_object);
2610
}
2611
{
2612
uint64_t validator = (t >> OBJECTDB_SLOT_MAX_COUNT_BITS) & OBJECTDB_VALIDATOR_MASK;
2613
if (object_slots[slot].validator != validator) {
2614
spin_lock.unlock();
2615
ERR_FAIL_COND(object_slots[slot].validator != validator);
2616
}
2617
}
2618
2619
#endif
2620
//decrease slot count
2621
slot_count--;
2622
//set the free slot properly
2623
object_slots[slot_count].next_free = slot;
2624
//invalidate, so checks against it fail
2625
object_slots[slot].validator = 0;
2626
object_slots[slot].is_ref_counted = false;
2627
object_slots[slot].object = nullptr;
2628
2629
spin_lock.unlock();
2630
}
2631
2632
void ObjectDB::setup() {
2633
//nothing to do now
2634
}
2635
2636
void ObjectDB::cleanup() {
2637
spin_lock.lock();
2638
2639
if (slot_count > 0) {
2640
WARN_PRINT("ObjectDB instances leaked at exit (run with --verbose for details).");
2641
if (OS::get_singleton()->is_stdout_verbose()) {
2642
// Ensure calling the native classes because if a leaked instance has a script
2643
// that overrides any of those methods, it'd not be OK to call them at this point,
2644
// now the scripting languages have already been terminated.
2645
MethodBind *node_get_path = ClassDB::get_method("Node", "get_path");
2646
MethodBind *resource_get_path = ClassDB::get_method("Resource", "get_path");
2647
Callable::CallError call_error;
2648
2649
for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) {
2650
if (object_slots[i].validator) {
2651
Object *obj = object_slots[i].object;
2652
2653
String extra_info;
2654
if (obj->is_class("Node")) {
2655
extra_info = " - Node path: " + String(node_get_path->call(obj, nullptr, 0, call_error));
2656
}
2657
if (obj->is_class("Resource")) {
2658
extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error));
2659
}
2660
if (obj->is_class("RefCounted")) {
2661
extra_info = " - Reference count: " + itos((static_cast<RefCounted *>(obj))->get_reference_count());
2662
}
2663
2664
uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_SLOT_MAX_COUNT_BITS) | (object_slots[i].is_ref_counted ? OBJECTDB_REFERENCE_BIT : 0);
2665
DEV_ASSERT(id == (uint64_t)obj->get_instance_id()); // We could just use the id from the object, but this check may help catching memory corruption catastrophes.
2666
print_line("Leaked instance: " + String(obj->get_class()) + ":" + uitos(id) + extra_info);
2667
2668
count--;
2669
}
2670
}
2671
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()`).");
2672
}
2673
}
2674
2675
if (object_slots) {
2676
memfree(object_slots);
2677
}
2678
2679
spin_lock.unlock();
2680
}
2681
2682