Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/object/class_db.cpp
9903 views
1
/**************************************************************************/
2
/* class_db.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 "class_db.h"
32
33
#include "core/config/engine.h"
34
#include "core/io/resource_loader.h"
35
#include "core/object/script_language.h"
36
#include "core/version.h"
37
38
#ifdef DEBUG_ENABLED
39
40
MethodDefinition D_METHODP(const char *p_name, const char *const **p_args, uint32_t p_argcount) {
41
MethodDefinition md;
42
md.name = StringName(p_name);
43
md.args.resize(p_argcount);
44
for (uint32_t i = 0; i < p_argcount; i++) {
45
md.args.write[i] = StringName(*p_args[i]);
46
}
47
return md;
48
}
49
50
#endif // DEBUG_ENABLED
51
52
ClassDB::APIType ClassDB::current_api = API_CORE;
53
HashMap<ClassDB::APIType, uint32_t> ClassDB::api_hashes_cache;
54
55
void ClassDB::set_current_api(APIType p_api) {
56
DEV_ASSERT(!api_hashes_cache.has(p_api)); // This API type may not be suitable for caching of hash if it can change later.
57
current_api = p_api;
58
}
59
60
ClassDB::APIType ClassDB::get_current_api() {
61
return current_api;
62
}
63
64
HashMap<StringName, ClassDB::ClassInfo> ClassDB::classes;
65
HashMap<StringName, StringName> ClassDB::resource_base_extensions;
66
HashMap<StringName, StringName> ClassDB::compat_classes;
67
68
#ifdef TOOLS_ENABLED
69
HashMap<StringName, ObjectGDExtension> ClassDB::placeholder_extensions;
70
71
class PlaceholderExtensionInstance {
72
StringName class_name;
73
HashMap<StringName, Variant> properties;
74
75
// Checks if a property is from a runtime class, and not a non-runtime base class.
76
bool is_runtime_property(const StringName &p_property_name) {
77
StringName current_class_name = class_name;
78
79
while (ClassDB::is_class_runtime(current_class_name)) {
80
if (ClassDB::has_property(current_class_name, p_property_name, true)) {
81
return true;
82
}
83
84
current_class_name = ClassDB::get_parent_class(current_class_name);
85
}
86
87
return false;
88
}
89
90
public:
91
PlaceholderExtensionInstance(const StringName &p_class_name) {
92
class_name = p_class_name;
93
}
94
95
~PlaceholderExtensionInstance() {}
96
97
void set(const StringName &p_name, const Variant &p_value, bool &r_valid) {
98
r_valid = is_runtime_property(p_name);
99
if (r_valid) {
100
properties[p_name] = p_value;
101
}
102
}
103
104
Variant get(const StringName &p_name, bool &r_valid) {
105
const Variant *value = properties.getptr(p_name);
106
Variant ret;
107
108
if (value) {
109
ret = *value;
110
r_valid = true;
111
} else {
112
r_valid = is_runtime_property(p_name);
113
if (r_valid) {
114
ret = ClassDB::class_get_default_property_value(class_name, p_name);
115
}
116
}
117
118
return ret;
119
}
120
121
static GDExtensionBool placeholder_instance_set(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) {
122
PlaceholderExtensionInstance *self = (PlaceholderExtensionInstance *)p_instance;
123
const StringName &name = *(StringName *)p_name;
124
const Variant &value = *(const Variant *)p_value;
125
126
bool valid = false;
127
self->set(name, value, valid);
128
129
return valid;
130
}
131
132
static GDExtensionBool placeholder_instance_get(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) {
133
PlaceholderExtensionInstance *self = (PlaceholderExtensionInstance *)p_instance;
134
const StringName &name = *(StringName *)p_name;
135
Variant *value = (Variant *)r_ret;
136
137
bool valid = false;
138
*value = self->get(name, valid);
139
140
return valid;
141
}
142
143
static const GDExtensionPropertyInfo *placeholder_instance_get_property_list(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) {
144
*r_count = 0;
145
return nullptr;
146
}
147
148
static void placeholder_instance_free_property_list(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t p_count) {
149
}
150
151
static GDExtensionBool placeholder_instance_property_can_revert(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name) {
152
return false;
153
}
154
155
static GDExtensionBool placeholder_instance_property_get_revert(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) {
156
return false;
157
}
158
159
static GDExtensionBool placeholder_instance_validate_property(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property) {
160
return false;
161
}
162
163
static void placeholder_instance_notification(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) {
164
}
165
166
static void placeholder_instance_to_string(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr p_out) {
167
*r_is_valid = true;
168
}
169
170
static void placeholder_instance_reference(GDExtensionClassInstancePtr p_instance) {
171
}
172
173
static void placeholder_instance_unreference(GDExtensionClassInstancePtr p_instance) {
174
}
175
176
static uint64_t placeholder_instance_get_rid(GDExtensionClassInstancePtr p_instance) {
177
return 0;
178
}
179
180
static GDExtensionObjectPtr placeholder_class_create_instance(void *p_class_userdata, GDExtensionBool p_notify_postinitialize) {
181
ClassDB::ClassInfo *ti = (ClassDB::ClassInfo *)p_class_userdata;
182
183
// Find the closest native parent, that isn't a runtime class.
184
ClassDB::ClassInfo *native_parent = ti->inherits_ptr;
185
while (native_parent->gdextension || native_parent->is_runtime) {
186
native_parent = native_parent->inherits_ptr;
187
}
188
ERR_FAIL_NULL_V(native_parent->creation_func, nullptr);
189
190
// Construct a placeholder.
191
Object *obj = native_parent->creation_func(static_cast<bool>(p_notify_postinitialize));
192
193
// ClassDB::set_object_extension_instance() won't be called for placeholders.
194
// We need need to make sure that all the things it would have done (even if
195
// done in a different way to support placeholders) will also be done here.
196
197
obj->_extension = ClassDB::get_placeholder_extension(ti->name);
198
obj->_extension_instance = memnew(PlaceholderExtensionInstance(ti->name));
199
200
#ifdef TOOLS_ENABLED
201
if (obj->_extension->track_instance) {
202
obj->_extension->track_instance(obj->_extension->tracking_userdata, obj);
203
}
204
#endif
205
206
return obj;
207
}
208
209
static GDExtensionObjectPtr placeholder_class_recreate_instance(void *p_class_userdata, GDExtensionObjectPtr p_object) {
210
ClassDB::ClassInfo *ti = (ClassDB::ClassInfo *)p_class_userdata;
211
return memnew(PlaceholderExtensionInstance(ti->name));
212
}
213
214
static void placeholder_class_free_instance(void *p_class_userdata, GDExtensionClassInstancePtr p_instance) {
215
PlaceholderExtensionInstance *instance = (PlaceholderExtensionInstance *)p_instance;
216
memdelete(instance);
217
}
218
219
static GDExtensionClassCallVirtual placeholder_class_get_virtual(void *p_class_userdata, GDExtensionConstStringNamePtr p_name, uint32_t p_hash) {
220
return nullptr;
221
}
222
};
223
#endif
224
225
bool ClassDB::_is_parent_class(const StringName &p_class, const StringName &p_inherits) {
226
ClassInfo *c = classes.getptr(p_class);
227
while (c) {
228
if (c->name == p_inherits) {
229
return true;
230
}
231
c = c->inherits_ptr;
232
}
233
234
return false;
235
}
236
237
bool ClassDB::is_parent_class(const StringName &p_class, const StringName &p_inherits) {
238
Locker::Lock lock(Locker::STATE_READ);
239
240
return _is_parent_class(p_class, p_inherits);
241
}
242
243
void ClassDB::get_class_list(List<StringName> *p_classes) {
244
Locker::Lock lock(Locker::STATE_READ);
245
246
for (const KeyValue<StringName, ClassInfo> &E : classes) {
247
p_classes->push_back(E.key);
248
}
249
250
p_classes->sort_custom<StringName::AlphCompare>();
251
}
252
253
#ifdef TOOLS_ENABLED
254
void ClassDB::get_extensions_class_list(List<StringName> *p_classes) {
255
Locker::Lock lock(Locker::STATE_READ);
256
257
for (const KeyValue<StringName, ClassInfo> &E : classes) {
258
if (E.value.api != API_EXTENSION && E.value.api != API_EDITOR_EXTENSION) {
259
continue;
260
}
261
p_classes->push_back(E.key);
262
}
263
264
p_classes->sort_custom<StringName::AlphCompare>();
265
}
266
267
void ClassDB::get_extension_class_list(const Ref<GDExtension> &p_extension, List<StringName> *p_classes) {
268
Locker::Lock lock(Locker::STATE_READ);
269
270
for (const KeyValue<StringName, ClassInfo> &E : classes) {
271
if (E.value.api != API_EXTENSION && E.value.api != API_EDITOR_EXTENSION) {
272
continue;
273
}
274
if (!E.value.gdextension || E.value.gdextension->library != p_extension.ptr()) {
275
continue;
276
}
277
p_classes->push_back(E.key);
278
}
279
280
p_classes->sort_custom<StringName::AlphCompare>();
281
}
282
#endif
283
284
void ClassDB::get_inheriters_from_class(const StringName &p_class, LocalVector<StringName> &p_classes) {
285
Locker::Lock lock(Locker::STATE_READ);
286
287
for (const KeyValue<StringName, ClassInfo> &E : classes) {
288
if (E.key != p_class && _is_parent_class(E.key, p_class)) {
289
p_classes.push_back(E.key);
290
}
291
}
292
}
293
294
void ClassDB::get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) {
295
Locker::Lock lock(Locker::STATE_READ);
296
297
for (const KeyValue<StringName, ClassInfo> &E : classes) {
298
if (E.value.inherits == p_class) {
299
p_classes->push_back(E.key);
300
}
301
}
302
}
303
304
StringName ClassDB::get_parent_class_nocheck(const StringName &p_class) {
305
Locker::Lock lock(Locker::STATE_READ);
306
307
ClassInfo *ti = classes.getptr(p_class);
308
if (!ti) {
309
return StringName();
310
}
311
return ti->inherits;
312
}
313
314
bool ClassDB::get_inheritance_chain_nocheck(const StringName &p_class, Vector<StringName> &r_result) {
315
Locker::Lock lock(Locker::STATE_READ);
316
317
ClassInfo *start = classes.getptr(p_class);
318
if (!start) {
319
return false;
320
}
321
322
int classes_to_add = 0;
323
for (ClassInfo *ti = start; ti; ti = ti->inherits_ptr) {
324
classes_to_add++;
325
}
326
327
int64_t old_size = r_result.size();
328
r_result.resize(old_size + classes_to_add);
329
StringName *w = r_result.ptrw() + old_size;
330
for (ClassInfo *ti = start; ti; ti = ti->inherits_ptr) {
331
*w++ = ti->name;
332
}
333
334
return true;
335
}
336
337
StringName ClassDB::get_compatibility_remapped_class(const StringName &p_class) {
338
if (classes.has(p_class)) {
339
return p_class;
340
}
341
342
if (compat_classes.has(p_class)) {
343
return compat_classes[p_class];
344
}
345
346
return p_class;
347
}
348
349
StringName ClassDB::_get_parent_class(const StringName &p_class) {
350
ClassInfo *ti = classes.getptr(p_class);
351
ERR_FAIL_NULL_V_MSG(ti, StringName(), vformat("Cannot get class '%s'.", String(p_class)));
352
return ti->inherits;
353
}
354
355
StringName ClassDB::get_parent_class(const StringName &p_class) {
356
Locker::Lock lock(Locker::STATE_READ);
357
358
return _get_parent_class(p_class);
359
}
360
361
ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) {
362
Locker::Lock lock(Locker::STATE_READ);
363
364
ClassInfo *ti = classes.getptr(p_class);
365
366
ERR_FAIL_NULL_V_MSG(ti, API_NONE, vformat("Cannot get class '%s'.", String(p_class)));
367
return ti->api;
368
}
369
370
uint32_t ClassDB::get_api_hash(APIType p_api) {
371
#ifdef DEBUG_ENABLED
372
Locker::Lock lock(Locker::STATE_WRITE);
373
374
if (api_hashes_cache.has(p_api)) {
375
return api_hashes_cache[p_api];
376
}
377
378
uint64_t hash = hash_murmur3_one_64(HashMapHasherDefault::hash(GODOT_VERSION_FULL_CONFIG));
379
380
List<StringName> class_list;
381
for (const KeyValue<StringName, ClassInfo> &E : classes) {
382
class_list.push_back(E.key);
383
}
384
// Must be alphabetically sorted for hash to compute.
385
class_list.sort_custom<StringName::AlphCompare>();
386
387
for (const StringName &E : class_list) {
388
ClassInfo *t = classes.getptr(E);
389
ERR_FAIL_NULL_V_MSG(t, 0, vformat("Cannot get class '%s'.", String(E)));
390
if (t->api != p_api || !t->exposed) {
391
continue;
392
}
393
hash = hash_murmur3_one_64(t->name.hash(), hash);
394
hash = hash_murmur3_one_64(t->inherits.hash(), hash);
395
396
{ //methods
397
398
List<StringName> snames;
399
400
for (const KeyValue<StringName, MethodBind *> &F : t->method_map) {
401
String name = F.key.operator String();
402
403
ERR_CONTINUE(name.is_empty());
404
405
if (name[0] == '_') {
406
continue; // Ignore non-virtual methods that start with an underscore
407
}
408
409
snames.push_back(F.key);
410
}
411
412
snames.sort_custom<StringName::AlphCompare>();
413
414
for (const StringName &F : snames) {
415
MethodBind *mb = t->method_map[F];
416
hash = hash_murmur3_one_64(mb->get_name().hash(), hash);
417
hash = hash_murmur3_one_64(mb->get_argument_count(), hash);
418
hash = hash_murmur3_one_64(mb->get_argument_type(-1), hash); //return
419
420
for (int i = 0; i < mb->get_argument_count(); i++) {
421
const PropertyInfo info = mb->get_argument_info(i);
422
hash = hash_murmur3_one_64(info.type, hash);
423
hash = hash_murmur3_one_64(info.name.hash(), hash);
424
hash = hash_murmur3_one_64(info.hint, hash);
425
hash = hash_murmur3_one_64(info.hint_string.hash(), hash);
426
}
427
428
hash = hash_murmur3_one_64(mb->get_default_argument_count(), hash);
429
430
for (int i = 0; i < mb->get_argument_count(); i++) {
431
if (mb->has_default_argument(i)) {
432
Variant da = mb->get_default_argument(i);
433
hash = hash_murmur3_one_64(da.hash(), hash);
434
}
435
}
436
437
hash = hash_murmur3_one_64(mb->get_hint_flags(), hash);
438
}
439
}
440
441
{ //constants
442
443
List<StringName> snames;
444
445
for (const KeyValue<StringName, int64_t> &F : t->constant_map) {
446
snames.push_back(F.key);
447
}
448
449
snames.sort_custom<StringName::AlphCompare>();
450
451
for (const StringName &F : snames) {
452
hash = hash_murmur3_one_64(F.hash(), hash);
453
hash = hash_murmur3_one_64(uint64_t(t->constant_map[F]), hash);
454
}
455
}
456
457
{ //signals
458
459
List<StringName> snames;
460
461
for (const KeyValue<StringName, MethodInfo> &F : t->signal_map) {
462
snames.push_back(F.key);
463
}
464
465
snames.sort_custom<StringName::AlphCompare>();
466
467
for (const StringName &F : snames) {
468
MethodInfo &mi = t->signal_map[F];
469
hash = hash_murmur3_one_64(F.hash(), hash);
470
for (const PropertyInfo &pi : mi.arguments) {
471
hash = hash_murmur3_one_64(pi.type, hash);
472
}
473
}
474
}
475
476
{ //properties
477
478
List<StringName> snames;
479
480
for (const KeyValue<StringName, PropertySetGet> &F : t->property_setget) {
481
snames.push_back(F.key);
482
}
483
484
snames.sort_custom<StringName::AlphCompare>();
485
486
for (const StringName &F : snames) {
487
PropertySetGet *psg = t->property_setget.getptr(F);
488
ERR_FAIL_NULL_V(psg, 0);
489
490
hash = hash_murmur3_one_64(F.hash(), hash);
491
hash = hash_murmur3_one_64(psg->setter.hash(), hash);
492
hash = hash_murmur3_one_64(psg->getter.hash(), hash);
493
}
494
}
495
496
//property list
497
for (const PropertyInfo &F : t->property_list) {
498
hash = hash_murmur3_one_64(F.name.hash(), hash);
499
hash = hash_murmur3_one_64(F.type, hash);
500
hash = hash_murmur3_one_64(F.hint, hash);
501
hash = hash_murmur3_one_64(F.hint_string.hash(), hash);
502
hash = hash_murmur3_one_64(F.usage, hash);
503
}
504
}
505
506
hash = hash_fmix32(hash);
507
508
// Extension API changes at runtime; let's just not cache them by now.
509
if (p_api != API_EXTENSION && p_api != API_EDITOR_EXTENSION) {
510
api_hashes_cache[p_api] = hash;
511
}
512
513
return hash;
514
#else
515
return 0;
516
#endif // DEBUG_ENABLED
517
}
518
519
bool ClassDB::class_exists(const StringName &p_class) {
520
Locker::Lock lock(Locker::STATE_READ);
521
return classes.has(p_class);
522
}
523
524
void ClassDB::add_compatibility_class(const StringName &p_class, const StringName &p_fallback) {
525
Locker::Lock lock(Locker::STATE_WRITE);
526
compat_classes[p_class] = p_fallback;
527
}
528
529
StringName ClassDB::get_compatibility_class(const StringName &p_class) {
530
if (compat_classes.has(p_class)) {
531
return compat_classes[p_class];
532
}
533
return StringName();
534
}
535
536
Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require_real_class, bool p_notify_postinitialize, bool p_exposed_only) {
537
ClassInfo *ti;
538
{
539
Locker::Lock lock(Locker::STATE_READ);
540
ti = classes.getptr(p_class);
541
if (!_can_instantiate(ti, p_exposed_only)) {
542
if (compat_classes.has(p_class)) {
543
ti = classes.getptr(compat_classes[p_class]);
544
}
545
}
546
ERR_FAIL_NULL_V_MSG(ti, nullptr, vformat("Cannot get class '%s'.", String(p_class)));
547
ERR_FAIL_COND_V_MSG(ti->disabled, nullptr, vformat("Class '%s' is disabled.", String(p_class)));
548
if (p_exposed_only) {
549
ERR_FAIL_COND_V_MSG(!ti->exposed, nullptr, vformat("Class '%s' isn't exposed.", String(p_class)));
550
}
551
ERR_FAIL_NULL_V_MSG(ti->creation_func, nullptr, vformat("Class '%s' or its base class cannot be instantiated.", String(p_class)));
552
}
553
554
#ifdef TOOLS_ENABLED
555
if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
556
ERR_PRINT(vformat("Class '%s' can only be instantiated by editor.", String(p_class)));
557
return nullptr;
558
}
559
#endif
560
561
#ifdef TOOLS_ENABLED
562
// Try to create placeholder.
563
if (!p_require_real_class && ti->is_runtime && Engine::get_singleton()->is_editor_hint()) {
564
bool can_create_placeholder = false;
565
if (ti->gdextension) {
566
if (ti->gdextension->create_instance2) {
567
can_create_placeholder = true;
568
}
569
#ifndef DISABLE_DEPRECATED
570
else if (ti->gdextension->create_instance) {
571
can_create_placeholder = true;
572
}
573
#endif // DISABLE_DEPRECATED
574
} else if (!ti->inherits_ptr || !ti->inherits_ptr->creation_func) {
575
ERR_PRINT(vformat("Cannot make a placeholder instance of runtime class %s because its parent cannot be constructed.", ti->name));
576
} else {
577
can_create_placeholder = true;
578
}
579
580
if (can_create_placeholder) {
581
ObjectGDExtension *extension = get_placeholder_extension(ti->name);
582
return (Object *)extension->create_instance2(extension->class_userdata, p_notify_postinitialize);
583
}
584
}
585
#endif // TOOLS_ENABLED
586
587
if (ti->gdextension && ti->gdextension->create_instance2) {
588
ObjectGDExtension *extension = ti->gdextension;
589
return (Object *)extension->create_instance2(extension->class_userdata, p_notify_postinitialize);
590
}
591
#ifndef DISABLE_DEPRECATED
592
else if (ti->gdextension && ti->gdextension->create_instance) {
593
ObjectGDExtension *extension = ti->gdextension;
594
return (Object *)extension->create_instance(extension->class_userdata);
595
}
596
#endif // DISABLE_DEPRECATED
597
else {
598
return ti->creation_func(p_notify_postinitialize);
599
}
600
}
601
602
bool ClassDB::_can_instantiate(ClassInfo *p_class_info, bool p_exposed_only) {
603
if (!p_class_info) {
604
return false;
605
}
606
607
if (p_exposed_only && !p_class_info->exposed) {
608
return false;
609
}
610
611
if (p_class_info->disabled || !p_class_info->creation_func) {
612
return false;
613
}
614
615
if (!p_class_info->gdextension) {
616
return true;
617
}
618
619
if (p_class_info->gdextension->create_instance2) {
620
return true;
621
}
622
623
#ifndef DISABLE_DEPRECATED
624
if (p_class_info->gdextension->create_instance) {
625
return true;
626
}
627
#endif // DISABLE_DEPRECATED
628
return false;
629
}
630
631
Object *ClassDB::instantiate(const StringName &p_class) {
632
return _instantiate_internal(p_class);
633
}
634
635
Object *ClassDB::instantiate_no_placeholders(const StringName &p_class) {
636
return _instantiate_internal(p_class, true);
637
}
638
639
Object *ClassDB::instantiate_without_postinitialization(const StringName &p_class) {
640
return _instantiate_internal(p_class, true, false);
641
}
642
643
#ifdef TOOLS_ENABLED
644
ObjectGDExtension *ClassDB::get_placeholder_extension(const StringName &p_class) {
645
ObjectGDExtension *placeholder_extension = placeholder_extensions.getptr(p_class);
646
if (placeholder_extension) {
647
return placeholder_extension;
648
}
649
650
ClassInfo *ti;
651
{
652
Locker::Lock lock(Locker::STATE_READ);
653
ti = classes.getptr(p_class);
654
if (!_can_instantiate(ti)) {
655
if (compat_classes.has(p_class)) {
656
ti = classes.getptr(compat_classes[p_class]);
657
}
658
}
659
ERR_FAIL_NULL_V_MSG(ti, nullptr, vformat("Cannot get class '%s'.", String(p_class)));
660
ERR_FAIL_COND_V_MSG(ti->disabled, nullptr, vformat("Class '%s' is disabled.", String(p_class)));
661
}
662
663
// Make a "fake" extension to act as a placeholder.
664
placeholder_extensions[p_class] = ObjectGDExtension();
665
placeholder_extension = placeholder_extensions.getptr(p_class);
666
667
placeholder_extension->is_runtime = true;
668
placeholder_extension->is_placeholder = true;
669
670
if (ti->gdextension) {
671
placeholder_extension->library = ti->gdextension->library;
672
placeholder_extension->parent = ti->gdextension->parent;
673
placeholder_extension->children = ti->gdextension->children;
674
placeholder_extension->parent_class_name = ti->gdextension->parent_class_name;
675
placeholder_extension->class_name = ti->gdextension->class_name;
676
placeholder_extension->editor_class = ti->gdextension->editor_class;
677
placeholder_extension->reloadable = ti->gdextension->reloadable;
678
placeholder_extension->is_virtual = ti->gdextension->is_virtual;
679
placeholder_extension->is_abstract = ti->gdextension->is_abstract;
680
placeholder_extension->is_exposed = ti->gdextension->is_exposed;
681
682
placeholder_extension->tracking_userdata = ti->gdextension->tracking_userdata;
683
placeholder_extension->track_instance = ti->gdextension->track_instance;
684
placeholder_extension->untrack_instance = ti->gdextension->untrack_instance;
685
} else {
686
placeholder_extension->library = nullptr;
687
placeholder_extension->parent = nullptr;
688
placeholder_extension->parent_class_name = ti->inherits;
689
placeholder_extension->class_name = ti->name;
690
placeholder_extension->editor_class = ti->api == API_EDITOR;
691
placeholder_extension->reloadable = false;
692
placeholder_extension->is_virtual = ti->is_virtual;
693
placeholder_extension->is_abstract = false;
694
placeholder_extension->is_exposed = ti->exposed;
695
}
696
697
placeholder_extension->set = &PlaceholderExtensionInstance::placeholder_instance_set;
698
placeholder_extension->get = &PlaceholderExtensionInstance::placeholder_instance_get;
699
placeholder_extension->get_property_list = &PlaceholderExtensionInstance::placeholder_instance_get_property_list;
700
placeholder_extension->free_property_list2 = &PlaceholderExtensionInstance::placeholder_instance_free_property_list;
701
placeholder_extension->property_can_revert = &PlaceholderExtensionInstance::placeholder_instance_property_can_revert;
702
placeholder_extension->property_get_revert = &PlaceholderExtensionInstance::placeholder_instance_property_get_revert;
703
placeholder_extension->validate_property = &PlaceholderExtensionInstance::placeholder_instance_validate_property;
704
#ifndef DISABLE_DEPRECATED
705
placeholder_extension->notification = nullptr;
706
placeholder_extension->free_property_list = nullptr;
707
#endif // DISABLE_DEPRECATED
708
placeholder_extension->notification2 = &PlaceholderExtensionInstance::placeholder_instance_notification;
709
placeholder_extension->to_string = &PlaceholderExtensionInstance::placeholder_instance_to_string;
710
placeholder_extension->reference = &PlaceholderExtensionInstance::placeholder_instance_reference;
711
placeholder_extension->unreference = &PlaceholderExtensionInstance::placeholder_instance_unreference;
712
placeholder_extension->get_rid = &PlaceholderExtensionInstance::placeholder_instance_get_rid;
713
714
placeholder_extension->class_userdata = ti;
715
#ifndef DISABLE_DEPRECATED
716
placeholder_extension->create_instance = nullptr;
717
#endif // DISABLE_DEPRECATED
718
placeholder_extension->create_instance2 = &PlaceholderExtensionInstance::placeholder_class_create_instance;
719
placeholder_extension->free_instance = &PlaceholderExtensionInstance::placeholder_class_free_instance;
720
#ifndef DISABLE_DEPRECATED
721
placeholder_extension->get_virtual = nullptr;
722
placeholder_extension->get_virtual_call_data = nullptr;
723
#endif // DISABLE_DEPRECATED
724
placeholder_extension->get_virtual2 = &PlaceholderExtensionInstance::placeholder_class_get_virtual;
725
placeholder_extension->get_virtual_call_data2 = nullptr;
726
placeholder_extension->call_virtual_with_data = nullptr;
727
placeholder_extension->recreate_instance = &PlaceholderExtensionInstance::placeholder_class_recreate_instance;
728
729
return placeholder_extension;
730
}
731
#endif
732
733
void ClassDB::set_object_extension_instance(Object *p_object, const StringName &p_class, GDExtensionClassInstancePtr p_instance) {
734
ERR_FAIL_NULL(p_object);
735
ClassInfo *ti;
736
{
737
Locker::Lock lock(Locker::STATE_READ);
738
ti = classes.getptr(p_class);
739
if (!_can_instantiate(ti)) {
740
if (compat_classes.has(p_class)) {
741
ti = classes.getptr(compat_classes[p_class]);
742
}
743
}
744
ERR_FAIL_NULL_MSG(ti, vformat("Cannot get class '%s'.", String(p_class)));
745
ERR_FAIL_COND_MSG(ti->disabled, vformat("Class '%s' is disabled.", String(p_class)));
746
ERR_FAIL_NULL_MSG(ti->gdextension, vformat("Class '%s' has no native extension.", String(p_class)));
747
}
748
749
p_object->_extension = ti->gdextension;
750
p_object->_extension_instance = p_instance;
751
752
#ifdef TOOLS_ENABLED
753
if (p_object->_extension->track_instance) {
754
p_object->_extension->track_instance(p_object->_extension->tracking_userdata, p_object);
755
}
756
#endif
757
}
758
759
bool ClassDB::can_instantiate(const StringName &p_class) {
760
String script_path;
761
{
762
Locker::Lock lock(Locker::STATE_READ);
763
764
ClassInfo *ti = classes.getptr(p_class);
765
if (!ti) {
766
if (!ScriptServer::is_global_class(p_class)) {
767
ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class)));
768
}
769
script_path = ScriptServer::get_global_class_path(p_class);
770
goto use_script; // Open the lock for resource loading.
771
}
772
#ifdef TOOLS_ENABLED
773
if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
774
return false;
775
}
776
#endif
777
return _can_instantiate(ti);
778
}
779
780
use_script:
781
Ref<Script> scr = ResourceLoader::load(script_path);
782
return scr.is_valid() && scr->is_valid() && !scr->is_abstract();
783
}
784
785
bool ClassDB::is_abstract(const StringName &p_class) {
786
String script_path;
787
{
788
Locker::Lock lock(Locker::STATE_READ);
789
790
ClassInfo *ti = classes.getptr(p_class);
791
if (!ti) {
792
if (!ScriptServer::is_global_class(p_class)) {
793
ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class)));
794
}
795
script_path = ScriptServer::get_global_class_path(p_class);
796
goto use_script; // Open the lock for resource loading.
797
}
798
799
if (ti->creation_func != nullptr) {
800
return false;
801
}
802
if (!ti->gdextension) {
803
return true;
804
}
805
#ifndef DISABLE_DEPRECATED
806
return ti->gdextension->create_instance2 == nullptr && ti->gdextension->create_instance == nullptr;
807
#else
808
return ti->gdextension->create_instance2 == nullptr;
809
#endif // DISABLE_DEPRECATED
810
}
811
812
use_script:
813
Ref<Script> scr = ResourceLoader::load(script_path);
814
return scr.is_valid() && scr->is_valid() && scr->is_abstract();
815
}
816
817
bool ClassDB::is_virtual(const StringName &p_class) {
818
String script_path;
819
{
820
Locker::Lock lock(Locker::STATE_READ);
821
822
ClassInfo *ti = classes.getptr(p_class);
823
if (!ti) {
824
if (!ScriptServer::is_global_class(p_class)) {
825
ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class)));
826
}
827
script_path = ScriptServer::get_global_class_path(p_class);
828
goto use_script; // Open the lock for resource loading.
829
}
830
#ifdef TOOLS_ENABLED
831
if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
832
return false;
833
}
834
#endif
835
return (_can_instantiate(ti) && ti->is_virtual);
836
}
837
838
use_script:
839
Ref<Script> scr = ResourceLoader::load(script_path);
840
return scr.is_valid() && scr->is_valid() && scr->is_abstract();
841
}
842
843
void ClassDB::_add_class(const StringName &p_class, const StringName &p_inherits) {
844
Locker::Lock lock(Locker::STATE_WRITE);
845
846
const StringName &name = p_class;
847
848
ERR_FAIL_COND_MSG(classes.has(name), vformat("Class '%s' already exists.", String(p_class)));
849
850
classes[name] = ClassInfo();
851
ClassInfo &ti = classes[name];
852
ti.name = name;
853
ti.inherits = p_inherits;
854
ti.api = current_api;
855
856
if (ti.inherits) {
857
ERR_FAIL_COND(!classes.has(ti.inherits)); //it MUST be registered.
858
ti.inherits_ptr = &classes[ti.inherits];
859
860
} else {
861
ti.inherits_ptr = nullptr;
862
}
863
}
864
865
static MethodInfo info_from_bind(MethodBind *p_method) {
866
MethodInfo minfo;
867
minfo.name = p_method->get_name();
868
minfo.id = p_method->get_method_id();
869
870
for (int i = 0; i < p_method->get_argument_count(); i++) {
871
minfo.arguments.push_back(p_method->get_argument_info(i));
872
}
873
874
minfo.return_val = p_method->get_return_info();
875
minfo.flags = p_method->get_hint_flags();
876
877
for (int i = 0; i < p_method->get_argument_count(); i++) {
878
if (p_method->has_default_argument(i)) {
879
minfo.default_arguments.push_back(p_method->get_default_argument(i));
880
}
881
}
882
883
return minfo;
884
}
885
886
void ClassDB::get_method_list(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) {
887
Locker::Lock lock(Locker::STATE_READ);
888
889
ClassInfo *type = classes.getptr(p_class);
890
891
while (type) {
892
if (type->disabled) {
893
if (p_no_inheritance) {
894
break;
895
}
896
897
type = type->inherits_ptr;
898
continue;
899
}
900
901
#ifdef DEBUG_ENABLED
902
for (const MethodInfo &E : type->virtual_methods) {
903
p_methods->push_back(E);
904
}
905
906
for (const StringName &E : type->method_order) {
907
if (p_exclude_from_properties && type->methods_in_properties.has(E)) {
908
continue;
909
}
910
911
MethodBind *method = type->method_map.get(E);
912
MethodInfo minfo = info_from_bind(method);
913
914
p_methods->push_back(minfo);
915
}
916
#else
917
for (KeyValue<StringName, MethodBind *> &E : type->method_map) {
918
MethodBind *m = E.value;
919
MethodInfo minfo = info_from_bind(m);
920
p_methods->push_back(minfo);
921
}
922
#endif // DEBUG_ENABLED
923
924
if (p_no_inheritance) {
925
break;
926
}
927
928
type = type->inherits_ptr;
929
}
930
}
931
932
void ClassDB::get_method_list_with_compatibility(const StringName &p_class, List<Pair<MethodInfo, uint32_t>> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) {
933
Locker::Lock lock(Locker::STATE_READ);
934
935
ClassInfo *type = classes.getptr(p_class);
936
937
while (type) {
938
if (type->disabled) {
939
if (p_no_inheritance) {
940
break;
941
}
942
943
type = type->inherits_ptr;
944
continue;
945
}
946
947
#ifdef DEBUG_ENABLED
948
for (const MethodInfo &E : type->virtual_methods) {
949
Pair<MethodInfo, uint32_t> pair(E, E.get_compatibility_hash());
950
p_methods->push_back(pair);
951
}
952
953
for (const StringName &E : type->method_order) {
954
if (p_exclude_from_properties && type->methods_in_properties.has(E)) {
955
continue;
956
}
957
958
MethodBind *method = type->method_map.get(E);
959
MethodInfo minfo = info_from_bind(method);
960
961
Pair<MethodInfo, uint32_t> pair(minfo, method->get_hash());
962
p_methods->push_back(pair);
963
}
964
#else
965
for (KeyValue<StringName, MethodBind *> &E : type->method_map) {
966
MethodBind *method = E.value;
967
MethodInfo minfo = info_from_bind(method);
968
969
Pair<MethodInfo, uint32_t> pair(minfo, method->get_hash());
970
p_methods->push_back(pair);
971
}
972
#endif // DEBUG_ENABLED
973
974
for (const KeyValue<StringName, LocalVector<MethodBind *, unsigned int, false, false>> &E : type->method_map_compatibility) {
975
LocalVector<MethodBind *> compat = E.value;
976
for (MethodBind *method : compat) {
977
MethodInfo minfo = info_from_bind(method);
978
979
Pair<MethodInfo, uint32_t> pair(minfo, method->get_hash());
980
p_methods->push_back(pair);
981
}
982
}
983
984
if (p_no_inheritance) {
985
break;
986
}
987
988
type = type->inherits_ptr;
989
}
990
}
991
992
bool ClassDB::get_method_info(const StringName &p_class, const StringName &p_method, MethodInfo *r_info, bool p_no_inheritance, bool p_exclude_from_properties) {
993
Locker::Lock lock(Locker::STATE_READ);
994
995
ClassInfo *type = classes.getptr(p_class);
996
997
while (type) {
998
if (type->disabled) {
999
if (p_no_inheritance) {
1000
break;
1001
}
1002
1003
type = type->inherits_ptr;
1004
continue;
1005
}
1006
1007
#ifdef DEBUG_ENABLED
1008
MethodBind **method = type->method_map.getptr(p_method);
1009
if (method && *method) {
1010
if (r_info != nullptr) {
1011
MethodInfo minfo = info_from_bind(*method);
1012
*r_info = minfo;
1013
}
1014
return true;
1015
} else if (type->virtual_methods_map.has(p_method)) {
1016
if (r_info) {
1017
*r_info = type->virtual_methods_map[p_method];
1018
}
1019
return true;
1020
}
1021
#else
1022
if (type->method_map.has(p_method)) {
1023
if (r_info) {
1024
MethodBind *m = type->method_map[p_method];
1025
MethodInfo minfo = info_from_bind(m);
1026
*r_info = minfo;
1027
}
1028
return true;
1029
}
1030
#endif // DEBUG_ENABLED
1031
1032
if (p_no_inheritance) {
1033
break;
1034
}
1035
1036
type = type->inherits_ptr;
1037
}
1038
1039
return false;
1040
}
1041
1042
MethodBind *ClassDB::get_method(const StringName &p_class, const StringName &p_name) {
1043
Locker::Lock lock(Locker::STATE_READ);
1044
1045
ClassInfo *type = classes.getptr(p_class);
1046
1047
while (type) {
1048
MethodBind **method = type->method_map.getptr(p_name);
1049
if (method && *method) {
1050
return *method;
1051
}
1052
type = type->inherits_ptr;
1053
}
1054
return nullptr;
1055
}
1056
1057
Vector<uint32_t> ClassDB::get_method_compatibility_hashes(const StringName &p_class, const StringName &p_name) {
1058
Locker::Lock lock(Locker::STATE_READ);
1059
1060
ClassInfo *type = classes.getptr(p_class);
1061
1062
while (type) {
1063
if (type->method_map_compatibility.has(p_name)) {
1064
LocalVector<MethodBind *> *c = type->method_map_compatibility.getptr(p_name);
1065
Vector<uint32_t> ret;
1066
for (uint32_t i = 0; i < c->size(); i++) {
1067
ret.push_back((*c)[i]->get_hash());
1068
}
1069
return ret;
1070
}
1071
type = type->inherits_ptr;
1072
}
1073
return Vector<uint32_t>();
1074
}
1075
1076
MethodBind *ClassDB::get_method_with_compatibility(const StringName &p_class, const StringName &p_name, uint64_t p_hash, bool *r_method_exists, bool *r_is_deprecated) {
1077
Locker::Lock lock(Locker::STATE_READ);
1078
1079
ClassInfo *type = classes.getptr(p_class);
1080
1081
while (type) {
1082
MethodBind **method = type->method_map.getptr(p_name);
1083
if (method && *method) {
1084
if (r_method_exists) {
1085
*r_method_exists = true;
1086
}
1087
if ((*method)->get_hash() == p_hash) {
1088
return *method;
1089
}
1090
}
1091
1092
LocalVector<MethodBind *> *compat = type->method_map_compatibility.getptr(p_name);
1093
if (compat) {
1094
if (r_method_exists) {
1095
*r_method_exists = true;
1096
}
1097
for (uint32_t i = 0; i < compat->size(); i++) {
1098
if ((*compat)[i]->get_hash() == p_hash) {
1099
if (r_is_deprecated) {
1100
*r_is_deprecated = true;
1101
}
1102
return (*compat)[i];
1103
}
1104
}
1105
}
1106
type = type->inherits_ptr;
1107
}
1108
return nullptr;
1109
}
1110
1111
void ClassDB::bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int64_t p_constant, bool p_is_bitfield) {
1112
Locker::Lock lock(Locker::STATE_WRITE);
1113
1114
ClassInfo *type = classes.getptr(p_class);
1115
1116
ERR_FAIL_NULL(type);
1117
1118
if (type->constant_map.has(p_name)) {
1119
ERR_FAIL();
1120
}
1121
1122
type->constant_map[p_name] = p_constant;
1123
1124
String enum_name = p_enum;
1125
if (!enum_name.is_empty()) {
1126
if (enum_name.contains_char('.')) {
1127
enum_name = enum_name.get_slicec('.', 1);
1128
}
1129
1130
ClassInfo::EnumInfo *constants_list = type->enum_map.getptr(enum_name);
1131
1132
if (constants_list) {
1133
constants_list->constants.push_back(p_name);
1134
constants_list->is_bitfield = p_is_bitfield;
1135
} else {
1136
ClassInfo::EnumInfo new_list;
1137
new_list.is_bitfield = p_is_bitfield;
1138
new_list.constants.push_back(p_name);
1139
type->enum_map[enum_name] = new_list;
1140
}
1141
}
1142
1143
#ifdef DEBUG_ENABLED
1144
type->constant_order.push_back(p_name);
1145
#endif // DEBUG_ENABLED
1146
}
1147
1148
void ClassDB::get_integer_constant_list(const StringName &p_class, List<String> *p_constants, bool p_no_inheritance) {
1149
Locker::Lock lock(Locker::STATE_READ);
1150
1151
ClassInfo *type = classes.getptr(p_class);
1152
1153
while (type) {
1154
#ifdef DEBUG_ENABLED
1155
for (const StringName &E : type->constant_order) {
1156
p_constants->push_back(E);
1157
}
1158
#else
1159
1160
for (const KeyValue<StringName, int64_t> &E : type->constant_map) {
1161
p_constants->push_back(E.key);
1162
}
1163
1164
#endif // DEBUG_ENABLED
1165
if (p_no_inheritance) {
1166
break;
1167
}
1168
1169
type = type->inherits_ptr;
1170
}
1171
}
1172
1173
int64_t ClassDB::get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success) {
1174
Locker::Lock lock(Locker::STATE_READ);
1175
1176
ClassInfo *type = classes.getptr(p_class);
1177
1178
while (type) {
1179
int64_t *constant = type->constant_map.getptr(p_name);
1180
if (constant) {
1181
if (p_success) {
1182
*p_success = true;
1183
}
1184
return *constant;
1185
}
1186
1187
type = type->inherits_ptr;
1188
}
1189
1190
if (p_success) {
1191
*p_success = false;
1192
}
1193
1194
return 0;
1195
}
1196
1197
bool ClassDB::has_integer_constant(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
1198
Locker::Lock lock(Locker::STATE_READ);
1199
1200
ClassInfo *type = classes.getptr(p_class);
1201
1202
while (type) {
1203
if (type->constant_map.has(p_name)) {
1204
return true;
1205
}
1206
if (p_no_inheritance) {
1207
return false;
1208
}
1209
1210
type = type->inherits_ptr;
1211
}
1212
1213
return false;
1214
}
1215
1216
StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
1217
Locker::Lock lock(Locker::STATE_READ);
1218
1219
ClassInfo *type = classes.getptr(p_class);
1220
1221
while (type) {
1222
for (KeyValue<StringName, ClassInfo::EnumInfo> &E : type->enum_map) {
1223
List<StringName> &constants_list = E.value.constants;
1224
const List<StringName>::Element *found = constants_list.find(p_name);
1225
if (found) {
1226
return E.key;
1227
}
1228
}
1229
1230
if (p_no_inheritance) {
1231
break;
1232
}
1233
1234
type = type->inherits_ptr;
1235
}
1236
1237
return StringName();
1238
}
1239
1240
void ClassDB::get_enum_list(const StringName &p_class, List<StringName> *p_enums, bool p_no_inheritance) {
1241
Locker::Lock lock(Locker::STATE_READ);
1242
1243
ClassInfo *type = classes.getptr(p_class);
1244
1245
while (type) {
1246
for (KeyValue<StringName, ClassInfo::EnumInfo> &E : type->enum_map) {
1247
p_enums->push_back(E.key);
1248
}
1249
1250
if (p_no_inheritance) {
1251
break;
1252
}
1253
1254
type = type->inherits_ptr;
1255
}
1256
}
1257
1258
void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance) {
1259
Locker::Lock lock(Locker::STATE_READ);
1260
1261
ClassInfo *type = classes.getptr(p_class);
1262
1263
while (type) {
1264
const ClassInfo::EnumInfo *constants = type->enum_map.getptr(p_enum);
1265
1266
if (constants) {
1267
for (const List<StringName>::Element *E = constants->constants.front(); E; E = E->next()) {
1268
p_constants->push_back(E->get());
1269
}
1270
}
1271
1272
if (p_no_inheritance) {
1273
break;
1274
}
1275
1276
type = type->inherits_ptr;
1277
}
1278
}
1279
1280
void ClassDB::set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector<Error> &p_values) {
1281
#ifdef DEBUG_ENABLED
1282
Locker::Lock lock(Locker::STATE_WRITE);
1283
ClassInfo *type = classes.getptr(p_class);
1284
1285
ERR_FAIL_NULL(type);
1286
1287
type->method_error_values[p_method] = p_values;
1288
#endif // DEBUG_ENABLED
1289
}
1290
1291
Vector<Error> ClassDB::get_method_error_return_values(const StringName &p_class, const StringName &p_method) {
1292
#ifdef DEBUG_ENABLED
1293
Locker::Lock lock(Locker::STATE_READ);
1294
ClassInfo *type = classes.getptr(p_class);
1295
1296
ERR_FAIL_NULL_V(type, Vector<Error>());
1297
1298
if (!type->method_error_values.has(p_method)) {
1299
return Vector<Error>();
1300
}
1301
return type->method_error_values[p_method];
1302
#else
1303
return Vector<Error>();
1304
#endif // DEBUG_ENABLED
1305
}
1306
1307
bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
1308
Locker::Lock lock(Locker::STATE_READ);
1309
1310
ClassInfo *type = classes.getptr(p_class);
1311
1312
while (type) {
1313
if (type->enum_map.has(p_name)) {
1314
return true;
1315
}
1316
if (p_no_inheritance) {
1317
return false;
1318
}
1319
1320
type = type->inherits_ptr;
1321
}
1322
1323
return false;
1324
}
1325
1326
bool ClassDB::is_enum_bitfield(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
1327
Locker::Lock lock(Locker::STATE_READ);
1328
1329
ClassInfo *type = classes.getptr(p_class);
1330
1331
while (type) {
1332
if (type->enum_map.has(p_name) && type->enum_map[p_name].is_bitfield) {
1333
return true;
1334
}
1335
if (p_no_inheritance) {
1336
return false;
1337
}
1338
1339
type = type->inherits_ptr;
1340
}
1341
1342
return false;
1343
}
1344
1345
void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal) {
1346
Locker::Lock lock(Locker::STATE_WRITE);
1347
1348
ClassInfo *type = classes.getptr(p_class);
1349
ERR_FAIL_NULL(type);
1350
1351
StringName sname = p_signal.name;
1352
1353
#ifdef DEBUG_ENABLED
1354
ClassInfo *check = type;
1355
while (check) {
1356
ERR_FAIL_COND_MSG(check->signal_map.has(sname), vformat("Class '%s' already has signal '%s'.", String(p_class), String(sname)));
1357
check = check->inherits_ptr;
1358
}
1359
#endif // DEBUG_ENABLED
1360
1361
type->signal_map[sname] = p_signal;
1362
}
1363
1364
void ClassDB::get_signal_list(const StringName &p_class, List<MethodInfo> *p_signals, bool p_no_inheritance) {
1365
Locker::Lock lock(Locker::STATE_READ);
1366
1367
ClassInfo *type = classes.getptr(p_class);
1368
ERR_FAIL_NULL(type);
1369
1370
ClassInfo *check = type;
1371
1372
while (check) {
1373
for (KeyValue<StringName, MethodInfo> &E : check->signal_map) {
1374
p_signals->push_back(E.value);
1375
}
1376
1377
if (p_no_inheritance) {
1378
return;
1379
}
1380
1381
check = check->inherits_ptr;
1382
}
1383
}
1384
1385
bool ClassDB::has_signal(const StringName &p_class, const StringName &p_signal, bool p_no_inheritance) {
1386
Locker::Lock lock(Locker::STATE_READ);
1387
ClassInfo *type = classes.getptr(p_class);
1388
ClassInfo *check = type;
1389
while (check) {
1390
if (check->signal_map.has(p_signal)) {
1391
return true;
1392
}
1393
if (p_no_inheritance) {
1394
return false;
1395
}
1396
check = check->inherits_ptr;
1397
}
1398
1399
return false;
1400
}
1401
1402
bool ClassDB::get_signal(const StringName &p_class, const StringName &p_signal, MethodInfo *r_signal) {
1403
Locker::Lock lock(Locker::STATE_READ);
1404
ClassInfo *type = classes.getptr(p_class);
1405
ClassInfo *check = type;
1406
while (check) {
1407
if (check->signal_map.has(p_signal)) {
1408
if (r_signal) {
1409
*r_signal = check->signal_map[p_signal];
1410
}
1411
return true;
1412
}
1413
check = check->inherits_ptr;
1414
}
1415
1416
return false;
1417
}
1418
1419
void ClassDB::add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix, int p_indent_depth) {
1420
Locker::Lock lock(Locker::STATE_WRITE);
1421
ClassInfo *type = classes.getptr(p_class);
1422
ERR_FAIL_NULL(type);
1423
1424
String prefix = p_prefix;
1425
if (p_indent_depth > 0) {
1426
prefix = vformat("%s,%d", p_prefix, p_indent_depth);
1427
}
1428
1429
type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, prefix, PROPERTY_USAGE_GROUP));
1430
}
1431
1432
void ClassDB::add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix, int p_indent_depth) {
1433
Locker::Lock lock(Locker::STATE_WRITE);
1434
ClassInfo *type = classes.getptr(p_class);
1435
ERR_FAIL_NULL(type);
1436
1437
String prefix = p_prefix;
1438
if (p_indent_depth > 0) {
1439
prefix = vformat("%s,%d", p_prefix, p_indent_depth);
1440
}
1441
1442
type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, prefix, PROPERTY_USAGE_SUBGROUP));
1443
}
1444
1445
void ClassDB::add_property_array_count(const StringName &p_class, const String &p_label, const StringName &p_count_property, const StringName &p_count_setter, const StringName &p_count_getter, const String &p_array_element_prefix, uint32_t p_count_usage) {
1446
add_property(p_class, PropertyInfo(Variant::INT, p_count_property, PROPERTY_HINT_NONE, "", p_count_usage | PROPERTY_USAGE_ARRAY, vformat("%s,%s", p_label, p_array_element_prefix)), p_count_setter, p_count_getter);
1447
}
1448
1449
void ClassDB::add_property_array(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix) {
1450
Locker::Lock lock(Locker::STATE_WRITE);
1451
ClassInfo *type = classes.getptr(p_class);
1452
ERR_FAIL_NULL(type);
1453
1454
type->property_list.push_back(PropertyInfo(Variant::NIL, p_path, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, p_array_element_prefix));
1455
}
1456
1457
// NOTE: For implementation simplicity reasons, this method doesn't allow setters to have optional arguments at the end.
1458
void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
1459
Locker::Lock lock(Locker::STATE_WRITE);
1460
1461
ClassInfo *type = classes.getptr(p_class);
1462
1463
ERR_FAIL_NULL(type);
1464
1465
MethodBind *mb_set = nullptr;
1466
if (p_setter) {
1467
mb_set = get_method(p_class, p_setter);
1468
#ifdef DEBUG_ENABLED
1469
1470
ERR_FAIL_NULL_MSG(mb_set, vformat("Invalid setter '%s::%s' for property '%s'.", p_class, p_setter, p_pinfo.name));
1471
1472
int exp_args = 1 + (p_index >= 0 ? 1 : 0);
1473
ERR_FAIL_COND_MSG(mb_set->get_argument_count() != exp_args, vformat("Invalid function for setter '%s::%s' for property '%s'.", p_class, p_setter, p_pinfo.name));
1474
#endif // DEBUG_ENABLED
1475
}
1476
1477
MethodBind *mb_get = nullptr;
1478
if (p_getter) {
1479
mb_get = get_method(p_class, p_getter);
1480
#ifdef DEBUG_ENABLED
1481
1482
ERR_FAIL_NULL_MSG(mb_get, vformat("Invalid getter '%s::%s' for property '%s'.", p_class, p_getter, p_pinfo.name));
1483
1484
int exp_args = 0 + (p_index >= 0 ? 1 : 0);
1485
ERR_FAIL_COND_MSG(mb_get->get_argument_count() != exp_args, vformat("Invalid function for getter '%s::%s' for property '%s'.", p_class, p_getter, p_pinfo.name));
1486
#endif // DEBUG_ENABLED
1487
}
1488
1489
#ifdef DEBUG_ENABLED
1490
ERR_FAIL_COND_MSG(type->property_setget.has(p_pinfo.name), vformat("Object '%s' already has property '%s'.", p_class, p_pinfo.name));
1491
#endif // DEBUG_ENABLED
1492
1493
type->property_list.push_back(p_pinfo);
1494
type->property_map[p_pinfo.name] = p_pinfo;
1495
#ifdef DEBUG_ENABLED
1496
if (mb_get) {
1497
type->methods_in_properties.insert(p_getter);
1498
}
1499
if (mb_set) {
1500
type->methods_in_properties.insert(p_setter);
1501
}
1502
#endif // DEBUG_ENABLED
1503
PropertySetGet psg;
1504
psg.setter = p_setter;
1505
psg.getter = p_getter;
1506
psg._setptr = mb_set;
1507
psg._getptr = mb_get;
1508
psg.index = p_index;
1509
psg.type = p_pinfo.type;
1510
1511
type->property_setget[p_pinfo.name] = psg;
1512
}
1513
1514
void ClassDB::set_property_default_value(const StringName &p_class, const StringName &p_name, const Variant &p_default) {
1515
if (!default_values.has(p_class)) {
1516
default_values[p_class] = HashMap<StringName, Variant>();
1517
}
1518
default_values[p_class][p_name] = p_default;
1519
}
1520
1521
void ClassDB::add_linked_property(const StringName &p_class, const String &p_property, const String &p_linked_property) {
1522
#ifdef TOOLS_ENABLED
1523
Locker::Lock lock(Locker::STATE_WRITE);
1524
ClassInfo *type = classes.getptr(p_class);
1525
ERR_FAIL_NULL(type);
1526
1527
ERR_FAIL_COND(!type->property_map.has(p_property));
1528
ERR_FAIL_COND(!type->property_map.has(p_linked_property));
1529
1530
if (!type->linked_properties.has(p_property)) {
1531
type->linked_properties.insert(p_property, List<StringName>());
1532
}
1533
type->linked_properties[p_property].push_back(p_linked_property);
1534
1535
#endif
1536
}
1537
1538
void ClassDB::get_property_list(const StringName &p_class, List<PropertyInfo> *p_list, bool p_no_inheritance, const Object *p_validator) {
1539
Locker::Lock lock(Locker::STATE_READ);
1540
1541
ClassInfo *type = classes.getptr(p_class);
1542
ClassInfo *check = type;
1543
while (check) {
1544
for (const PropertyInfo &pi : check->property_list) {
1545
if (p_validator) {
1546
// Making a copy as we may modify it.
1547
PropertyInfo pi_mut = pi;
1548
p_validator->validate_property(pi_mut);
1549
p_list->push_back(pi_mut);
1550
} else {
1551
p_list->push_back(pi);
1552
}
1553
}
1554
1555
if (p_no_inheritance) {
1556
return;
1557
}
1558
check = check->inherits_ptr;
1559
}
1560
}
1561
1562
void ClassDB::get_linked_properties_info(const StringName &p_class, const StringName &p_property, List<StringName> *r_properties, bool p_no_inheritance) {
1563
#ifdef TOOLS_ENABLED
1564
ClassInfo *check = classes.getptr(p_class);
1565
while (check) {
1566
if (!check->linked_properties.has(p_property)) {
1567
return;
1568
}
1569
for (const StringName &E : check->linked_properties[p_property]) {
1570
r_properties->push_back(E);
1571
}
1572
1573
if (p_no_inheritance) {
1574
break;
1575
}
1576
check = check->inherits_ptr;
1577
}
1578
#endif
1579
}
1580
1581
bool ClassDB::get_property_info(const StringName &p_class, const StringName &p_property, PropertyInfo *r_info, bool p_no_inheritance, const Object *p_validator) {
1582
Locker::Lock lock(Locker::STATE_READ);
1583
1584
ClassInfo *check = classes.getptr(p_class);
1585
while (check) {
1586
if (check->property_map.has(p_property)) {
1587
PropertyInfo pinfo = check->property_map[p_property];
1588
if (p_validator) {
1589
p_validator->validate_property(pinfo);
1590
}
1591
if (r_info) {
1592
*r_info = pinfo;
1593
}
1594
return true;
1595
}
1596
if (p_no_inheritance) {
1597
break;
1598
}
1599
check = check->inherits_ptr;
1600
}
1601
1602
return false;
1603
}
1604
1605
bool ClassDB::set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid) {
1606
ERR_FAIL_NULL_V(p_object, false);
1607
1608
ClassInfo *type = classes.getptr(p_object->get_class_name());
1609
ClassInfo *check = type;
1610
while (check) {
1611
const PropertySetGet *psg = check->property_setget.getptr(p_property);
1612
if (psg) {
1613
if (!psg->setter) {
1614
if (r_valid) {
1615
*r_valid = false;
1616
}
1617
return true; //return true but do nothing
1618
}
1619
1620
Callable::CallError ce;
1621
1622
if (psg->index >= 0) {
1623
Variant index = psg->index;
1624
const Variant *arg[2] = { &index, &p_value };
1625
//p_object->call(psg->setter,arg,2,ce);
1626
if (psg->_setptr) {
1627
psg->_setptr->call(p_object, arg, 2, ce);
1628
} else {
1629
p_object->callp(psg->setter, arg, 2, ce);
1630
}
1631
1632
} else {
1633
const Variant *arg[1] = { &p_value };
1634
if (psg->_setptr) {
1635
psg->_setptr->call(p_object, arg, 1, ce);
1636
} else {
1637
p_object->callp(psg->setter, arg, 1, ce);
1638
}
1639
}
1640
1641
if (r_valid) {
1642
*r_valid = ce.error == Callable::CallError::CALL_OK;
1643
}
1644
1645
return true;
1646
}
1647
1648
check = check->inherits_ptr;
1649
}
1650
1651
return false;
1652
}
1653
1654
bool ClassDB::get_property(Object *p_object, const StringName &p_property, Variant &r_value) {
1655
ERR_FAIL_NULL_V(p_object, false);
1656
1657
ClassInfo *type = classes.getptr(p_object->get_class_name());
1658
ClassInfo *check = type;
1659
while (check) {
1660
const PropertySetGet *psg = check->property_setget.getptr(p_property);
1661
if (psg) {
1662
if (!psg->getter) {
1663
return true; //return true but do nothing
1664
}
1665
1666
if (psg->index >= 0) {
1667
Variant index = psg->index;
1668
const Variant *arg[1] = { &index };
1669
Callable::CallError ce;
1670
const Variant value = p_object->callp(psg->getter, arg, 1, ce);
1671
r_value = (ce.error == Callable::CallError::CALL_OK) ? value : Variant();
1672
1673
} else {
1674
Callable::CallError ce;
1675
if (psg->_getptr) {
1676
r_value = psg->_getptr->call(p_object, nullptr, 0, ce);
1677
} else {
1678
const Variant value = p_object->callp(psg->getter, nullptr, 0, ce);
1679
r_value = (ce.error == Callable::CallError::CALL_OK) ? value : Variant();
1680
}
1681
}
1682
return true;
1683
}
1684
1685
const int64_t *c = check->constant_map.getptr(p_property); //constants count
1686
if (c) {
1687
r_value = *c;
1688
return true;
1689
}
1690
1691
if (check->method_map.has(p_property)) { //methods count
1692
r_value = Callable(p_object, p_property);
1693
return true;
1694
}
1695
1696
if (check->signal_map.has(p_property)) { //signals count
1697
r_value = Signal(p_object, p_property);
1698
return true;
1699
}
1700
1701
check = check->inherits_ptr;
1702
}
1703
1704
// The "free()" method is special, so we assume it exists and return a Callable.
1705
if (p_property == CoreStringName(free_)) {
1706
r_value = Callable(p_object, p_property);
1707
return true;
1708
}
1709
1710
return false;
1711
}
1712
1713
int ClassDB::get_property_index(const StringName &p_class, const StringName &p_property, bool *r_is_valid) {
1714
ClassInfo *type = classes.getptr(p_class);
1715
ClassInfo *check = type;
1716
while (check) {
1717
const PropertySetGet *psg = check->property_setget.getptr(p_property);
1718
if (psg) {
1719
if (r_is_valid) {
1720
*r_is_valid = true;
1721
}
1722
1723
return psg->index;
1724
}
1725
1726
check = check->inherits_ptr;
1727
}
1728
if (r_is_valid) {
1729
*r_is_valid = false;
1730
}
1731
1732
return -1;
1733
}
1734
1735
Variant::Type ClassDB::get_property_type(const StringName &p_class, const StringName &p_property, bool *r_is_valid) {
1736
ClassInfo *type = classes.getptr(p_class);
1737
ClassInfo *check = type;
1738
while (check) {
1739
const PropertySetGet *psg = check->property_setget.getptr(p_property);
1740
if (psg) {
1741
if (r_is_valid) {
1742
*r_is_valid = true;
1743
}
1744
1745
return psg->type;
1746
}
1747
1748
check = check->inherits_ptr;
1749
}
1750
if (r_is_valid) {
1751
*r_is_valid = false;
1752
}
1753
1754
return Variant::NIL;
1755
}
1756
1757
StringName ClassDB::get_property_setter(const StringName &p_class, const StringName &p_property) {
1758
ClassInfo *type = classes.getptr(p_class);
1759
ClassInfo *check = type;
1760
while (check) {
1761
const PropertySetGet *psg = check->property_setget.getptr(p_property);
1762
if (psg) {
1763
return psg->setter;
1764
}
1765
1766
check = check->inherits_ptr;
1767
}
1768
1769
return StringName();
1770
}
1771
1772
StringName ClassDB::get_property_getter(const StringName &p_class, const StringName &p_property) {
1773
ClassInfo *type = classes.getptr(p_class);
1774
ClassInfo *check = type;
1775
while (check) {
1776
const PropertySetGet *psg = check->property_setget.getptr(p_property);
1777
if (psg) {
1778
return psg->getter;
1779
}
1780
1781
check = check->inherits_ptr;
1782
}
1783
1784
return StringName();
1785
}
1786
1787
bool ClassDB::has_property(const StringName &p_class, const StringName &p_property, bool p_no_inheritance) {
1788
ClassInfo *type = classes.getptr(p_class);
1789
ClassInfo *check = type;
1790
while (check) {
1791
if (check->property_setget.has(p_property)) {
1792
return true;
1793
}
1794
1795
if (p_no_inheritance) {
1796
break;
1797
}
1798
check = check->inherits_ptr;
1799
}
1800
1801
return false;
1802
}
1803
1804
void ClassDB::set_method_flags(const StringName &p_class, const StringName &p_method, int p_flags) {
1805
Locker::Lock lock(Locker::STATE_WRITE);
1806
ClassInfo *type = classes.getptr(p_class);
1807
ClassInfo *check = type;
1808
ERR_FAIL_NULL(check);
1809
ERR_FAIL_COND(!check->method_map.has(p_method));
1810
check->method_map[p_method]->set_hint_flags(p_flags);
1811
}
1812
1813
bool ClassDB::has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance) {
1814
ClassInfo *type = classes.getptr(p_class);
1815
ClassInfo *check = type;
1816
while (check) {
1817
if (check->method_map.has(p_method)) {
1818
return true;
1819
}
1820
if (p_no_inheritance) {
1821
return false;
1822
}
1823
check = check->inherits_ptr;
1824
}
1825
1826
return false;
1827
}
1828
1829
int ClassDB::get_method_argument_count(const StringName &p_class, const StringName &p_method, bool *r_is_valid, bool p_no_inheritance) {
1830
Locker::Lock lock(Locker::STATE_READ);
1831
1832
ClassInfo *type = classes.getptr(p_class);
1833
1834
while (type) {
1835
MethodBind **method = type->method_map.getptr(p_method);
1836
if (method && *method) {
1837
if (r_is_valid) {
1838
*r_is_valid = true;
1839
}
1840
return (*method)->get_argument_count();
1841
}
1842
if (p_no_inheritance) {
1843
break;
1844
}
1845
type = type->inherits_ptr;
1846
}
1847
1848
if (r_is_valid) {
1849
*r_is_valid = false;
1850
}
1851
return 0;
1852
}
1853
1854
void ClassDB::bind_method_custom(const StringName &p_class, MethodBind *p_method) {
1855
_bind_method_custom(p_class, p_method, false);
1856
}
1857
void ClassDB::bind_compatibility_method_custom(const StringName &p_class, MethodBind *p_method) {
1858
_bind_method_custom(p_class, p_method, true);
1859
}
1860
1861
void ClassDB::_bind_compatibility(ClassInfo *type, MethodBind *p_method) {
1862
if (!type->method_map_compatibility.has(p_method->get_name())) {
1863
type->method_map_compatibility.insert(p_method->get_name(), LocalVector<MethodBind *>());
1864
}
1865
type->method_map_compatibility[p_method->get_name()].push_back(p_method);
1866
}
1867
1868
void ClassDB::_bind_method_custom(const StringName &p_class, MethodBind *p_method, bool p_compatibility) {
1869
Locker::Lock lock(Locker::STATE_WRITE);
1870
1871
StringName method_name = p_method->get_name();
1872
1873
ClassInfo *type = classes.getptr(p_class);
1874
if (!type) {
1875
memdelete(p_method);
1876
ERR_FAIL_MSG(vformat("Couldn't bind custom method '%s' for instance '%s'.", method_name, p_class));
1877
}
1878
1879
if (p_compatibility) {
1880
_bind_compatibility(type, p_method);
1881
return;
1882
}
1883
1884
if (type->method_map.has(method_name)) {
1885
// overloading not supported
1886
memdelete(p_method);
1887
ERR_FAIL_MSG(vformat("Method already bound '%s::%s'.", p_class, method_name));
1888
}
1889
1890
#ifdef DEBUG_ENABLED
1891
type->method_order.push_back(method_name);
1892
#endif // DEBUG_ENABLED
1893
1894
type->method_map[method_name] = p_method;
1895
}
1896
1897
MethodBind *ClassDB::_bind_vararg_method(MethodBind *p_bind, const StringName &p_name, const Vector<Variant> &p_default_args, bool p_compatibility) {
1898
MethodBind *bind = p_bind;
1899
bind->set_name(p_name);
1900
bind->set_default_arguments(p_default_args);
1901
1902
String instance_type = bind->get_instance_class();
1903
1904
ClassInfo *type = classes.getptr(instance_type);
1905
if (!type) {
1906
memdelete(bind);
1907
ERR_FAIL_NULL_V(type, nullptr);
1908
}
1909
1910
if (p_compatibility) {
1911
_bind_compatibility(type, bind);
1912
return bind;
1913
}
1914
1915
if (type->method_map.has(p_name)) {
1916
memdelete(bind);
1917
// Overloading not supported
1918
ERR_FAIL_V_MSG(nullptr, vformat("Method already bound: '%s::%s'.", instance_type, p_name));
1919
}
1920
type->method_map[p_name] = bind;
1921
#ifdef DEBUG_ENABLED
1922
// FIXME: <reduz> set_return_type is no longer in MethodBind, so I guess it should be moved to vararg method bind
1923
//bind->set_return_type("Variant");
1924
type->method_order.push_back(p_name);
1925
#endif // DEBUG_ENABLED
1926
1927
return bind;
1928
}
1929
1930
#ifdef DEBUG_ENABLED
1931
MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, bool p_compatibility, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) {
1932
StringName mdname = method_name.name;
1933
#else
1934
MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, bool p_compatibility, const char *method_name, const Variant **p_defs, int p_defcount) {
1935
StringName mdname = StringName(method_name);
1936
#endif // DEBUG_ENABLED
1937
1938
Locker::Lock lock(Locker::STATE_WRITE);
1939
ERR_FAIL_NULL_V(p_bind, nullptr);
1940
p_bind->set_name(mdname);
1941
1942
String instance_type = p_bind->get_instance_class();
1943
1944
#ifdef DEBUG_ENABLED
1945
1946
ERR_FAIL_COND_V_MSG(!p_compatibility && has_method(instance_type, mdname), nullptr, vformat("Class '%s' already has a method '%s'.", String(instance_type), String(mdname)));
1947
#endif // DEBUG_ENABLED
1948
1949
ClassInfo *type = classes.getptr(instance_type);
1950
if (!type) {
1951
memdelete(p_bind);
1952
ERR_FAIL_V_MSG(nullptr, vformat("Couldn't bind method '%s' for instance '%s'.", mdname, instance_type));
1953
}
1954
1955
if (!p_compatibility && type->method_map.has(mdname)) {
1956
memdelete(p_bind);
1957
// overloading not supported
1958
ERR_FAIL_V_MSG(nullptr, vformat("Method already bound '%s::%s'.", instance_type, mdname));
1959
}
1960
1961
#ifdef DEBUG_ENABLED
1962
1963
if (method_name.args.size() > p_bind->get_argument_count()) {
1964
memdelete(p_bind);
1965
ERR_FAIL_V_MSG(nullptr, vformat("Method definition provides more arguments than the method actually has '%s::%s'.", instance_type, mdname));
1966
}
1967
1968
if (p_defcount > p_bind->get_argument_count()) {
1969
memdelete(p_bind);
1970
ERR_FAIL_V_MSG(nullptr, vformat("Method definition for '%s::%s' provides more default arguments than the method has arguments.", instance_type, mdname));
1971
}
1972
1973
p_bind->set_argument_names(method_name.args);
1974
1975
if (!p_compatibility) {
1976
type->method_order.push_back(mdname);
1977
}
1978
#endif // DEBUG_ENABLED
1979
1980
if (p_compatibility) {
1981
_bind_compatibility(type, p_bind);
1982
} else {
1983
type->method_map[mdname] = p_bind;
1984
}
1985
1986
Vector<Variant> defvals;
1987
1988
defvals.resize(p_defcount);
1989
for (int i = 0; i < p_defcount; i++) {
1990
defvals.write[i] = *p_defs[i];
1991
}
1992
1993
p_bind->set_default_arguments(defvals);
1994
p_bind->set_hint_flags(p_flags);
1995
return p_bind;
1996
}
1997
1998
void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual, const Vector<String> &p_arg_names, bool p_object_core) {
1999
ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class));
2000
2001
Locker::Lock lock(Locker::STATE_WRITE);
2002
2003
#ifdef DEBUG_ENABLED
2004
MethodInfo mi = p_method;
2005
if (p_virtual) {
2006
mi.flags |= METHOD_FLAG_VIRTUAL;
2007
}
2008
if (p_object_core) {
2009
mi.flags |= METHOD_FLAG_OBJECT_CORE;
2010
}
2011
2012
if (!p_object_core) {
2013
if (p_arg_names.size() != mi.arguments.size()) {
2014
WARN_PRINT(vformat("Mismatch argument name count for virtual method: '%s::%s'.", String(p_class), p_method.name));
2015
} else {
2016
for (int64_t i = 0; i < p_arg_names.size(); ++i) {
2017
mi.arguments.write[i].name = p_arg_names[i];
2018
}
2019
}
2020
}
2021
2022
if (classes[p_class].virtual_methods_map.has(p_method.name)) {
2023
// overloading not supported
2024
ERR_FAIL_MSG(vformat("Virtual method already bound '%s::%s'.", String(p_class), p_method.name));
2025
}
2026
classes[p_class].virtual_methods.push_back(mi);
2027
classes[p_class].virtual_methods_map[p_method.name] = mi;
2028
2029
#endif // DEBUG_ENABLED
2030
}
2031
2032
void ClassDB::add_virtual_compatibility_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual, const Vector<String> &p_arg_names, bool p_object_core) {
2033
ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class));
2034
2035
Locker::Lock lock(Locker::STATE_WRITE);
2036
2037
HashMap<StringName, Vector<uint32_t>> &virtual_methods_compat = classes[p_class].virtual_methods_compat;
2038
2039
Vector<uint32_t> *compat_hashes = virtual_methods_compat.getptr(p_method.name);
2040
if (!compat_hashes) {
2041
virtual_methods_compat[p_method.name] = Vector<uint32_t>();
2042
compat_hashes = &virtual_methods_compat[p_method.name];
2043
}
2044
2045
compat_hashes->push_back(p_method.get_compatibility_hash());
2046
}
2047
2048
void ClassDB::get_virtual_methods(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance) {
2049
ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class));
2050
2051
#ifdef DEBUG_ENABLED
2052
2053
ClassInfo *type = classes.getptr(p_class);
2054
ClassInfo *check = type;
2055
while (check) {
2056
for (const MethodInfo &E : check->virtual_methods) {
2057
p_methods->push_back(E);
2058
}
2059
2060
if (p_no_inheritance) {
2061
return;
2062
}
2063
check = check->inherits_ptr;
2064
}
2065
2066
#endif // DEBUG_ENABLED
2067
}
2068
2069
Vector<uint32_t> ClassDB::get_virtual_method_compatibility_hashes(const StringName &p_class, const StringName &p_name) {
2070
Locker::Lock lock(Locker::STATE_READ);
2071
2072
ClassInfo *type = classes.getptr(p_class);
2073
2074
while (type) {
2075
if (type->virtual_methods_compat.has(p_name)) {
2076
Vector<uint32_t> *compat_hashes = type->virtual_methods_compat.getptr(p_name);
2077
if (compat_hashes) {
2078
return *compat_hashes;
2079
}
2080
break;
2081
}
2082
type = type->inherits_ptr;
2083
}
2084
2085
return Vector<uint32_t>();
2086
}
2087
2088
void ClassDB::add_extension_class_virtual_method(const StringName &p_class, const GDExtensionClassVirtualMethodInfo *p_method_info) {
2089
ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class));
2090
2091
#ifdef DEBUG_ENABLED
2092
PackedStringArray arg_names;
2093
2094
MethodInfo mi;
2095
mi.name = *reinterpret_cast<StringName *>(p_method_info->name);
2096
mi.return_val = PropertyInfo(p_method_info->return_value);
2097
mi.return_val_metadata = p_method_info->return_value_metadata;
2098
mi.flags = p_method_info->method_flags;
2099
for (int i = 0; i < (int)p_method_info->argument_count; i++) {
2100
PropertyInfo arg(p_method_info->arguments[i]);
2101
mi.arguments.push_back(arg);
2102
mi.arguments_metadata.push_back(p_method_info->arguments_metadata[i]);
2103
arg_names.push_back(arg.name);
2104
}
2105
2106
add_virtual_method(p_class, mi, true, arg_names);
2107
#endif // DEBUG_ENABLED
2108
}
2109
2110
void ClassDB::set_class_enabled(const StringName &p_class, bool p_enable) {
2111
Locker::Lock lock(Locker::STATE_WRITE);
2112
2113
ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class));
2114
classes[p_class].disabled = !p_enable;
2115
}
2116
2117
bool ClassDB::is_class_enabled(const StringName &p_class) {
2118
Locker::Lock lock(Locker::STATE_READ);
2119
2120
ClassInfo *ti = classes.getptr(p_class);
2121
if (!ti || !ti->creation_func) {
2122
if (compat_classes.has(p_class)) {
2123
ti = classes.getptr(compat_classes[p_class]);
2124
}
2125
}
2126
2127
ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class)));
2128
return !ti->disabled;
2129
}
2130
2131
bool ClassDB::is_class_exposed(const StringName &p_class) {
2132
Locker::Lock lock(Locker::STATE_READ);
2133
2134
ClassInfo *ti = classes.getptr(p_class);
2135
ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class)));
2136
return ti->exposed;
2137
}
2138
2139
bool ClassDB::is_class_reloadable(const StringName &p_class) {
2140
Locker::Lock lock(Locker::STATE_READ);
2141
2142
ClassInfo *ti = classes.getptr(p_class);
2143
ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class)));
2144
return ti->reloadable;
2145
}
2146
2147
bool ClassDB::is_class_runtime(const StringName &p_class) {
2148
Locker::Lock lock(Locker::STATE_READ);
2149
2150
ClassInfo *ti = classes.getptr(p_class);
2151
ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class)));
2152
return ti->is_runtime;
2153
}
2154
2155
#ifdef TOOLS_ENABLED
2156
void ClassDB::add_class_dependency(const StringName &p_class, const StringName &p_dependency) {
2157
Locker::Lock lock(Locker::STATE_WRITE);
2158
2159
ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class));
2160
if (classes[p_class].dependency_list.find(p_dependency)) {
2161
ERR_FAIL();
2162
}
2163
2164
classes[p_class].dependency_list.push_back(p_dependency);
2165
}
2166
2167
void ClassDB::get_class_dependencies(const StringName &p_class, List<StringName> *r_rependencies) {
2168
Locker::Lock lock(Locker::STATE_READ);
2169
2170
ClassInfo *ti = classes.getptr(p_class);
2171
ERR_FAIL_NULL_MSG(ti, vformat("Cannot get class '%s'.", String(p_class)));
2172
2173
for (const StringName &dep : ti->dependency_list) {
2174
r_rependencies->push_back(dep);
2175
}
2176
}
2177
#endif // TOOLS_ENABLED
2178
2179
void ClassDB::add_resource_base_extension(const StringName &p_extension, const StringName &p_class) {
2180
if (resource_base_extensions.has(p_extension)) {
2181
return;
2182
}
2183
2184
resource_base_extensions[p_extension] = p_class;
2185
}
2186
2187
void ClassDB::get_resource_base_extensions(List<String> *p_extensions) {
2188
for (const KeyValue<StringName, StringName> &E : resource_base_extensions) {
2189
p_extensions->push_back(E.key);
2190
}
2191
}
2192
2193
bool ClassDB::is_resource_extension(const StringName &p_extension) {
2194
return resource_base_extensions.has(p_extension);
2195
}
2196
2197
void ClassDB::get_extensions_for_type(const StringName &p_class, List<String> *p_extensions) {
2198
for (const KeyValue<StringName, StringName> &E : resource_base_extensions) {
2199
if (is_parent_class(p_class, E.value) || is_parent_class(E.value, p_class)) {
2200
p_extensions->push_back(E.key);
2201
}
2202
}
2203
}
2204
2205
HashMap<StringName, HashMap<StringName, Variant>> ClassDB::default_values;
2206
HashSet<StringName> ClassDB::default_values_cached;
2207
2208
Variant ClassDB::class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid) {
2209
if (!default_values_cached.has(p_class)) {
2210
if (!default_values.has(p_class)) {
2211
default_values[p_class] = HashMap<StringName, Variant>();
2212
}
2213
2214
Object *c = nullptr;
2215
bool cleanup_c = false;
2216
2217
if (Engine::get_singleton()->has_singleton(p_class)) {
2218
c = Engine::get_singleton()->get_singleton_object(p_class);
2219
cleanup_c = false;
2220
} else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) { // Keep this condition in sync with doc_tools.cpp get_documentation_default_value.
2221
c = ClassDB::instantiate_no_placeholders(p_class);
2222
cleanup_c = true;
2223
}
2224
2225
if (c) {
2226
List<PropertyInfo> plist;
2227
c->get_property_list(&plist);
2228
for (const PropertyInfo &E : plist) {
2229
if (E.usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR)) {
2230
if (!default_values[p_class].has(E.name)) {
2231
Variant v = c->get(E.name);
2232
default_values[p_class][E.name] = v;
2233
}
2234
}
2235
}
2236
2237
if (cleanup_c) {
2238
memdelete(c);
2239
}
2240
}
2241
2242
default_values_cached.insert(p_class);
2243
}
2244
2245
if (!default_values.has(p_class)) {
2246
if (r_valid != nullptr) {
2247
*r_valid = false;
2248
}
2249
return Variant();
2250
}
2251
2252
if (!default_values[p_class].has(p_property)) {
2253
if (r_valid != nullptr) {
2254
*r_valid = false;
2255
}
2256
return Variant();
2257
}
2258
2259
if (r_valid != nullptr) {
2260
*r_valid = true;
2261
}
2262
2263
Variant var = default_values[p_class][p_property];
2264
2265
#ifdef DEBUG_ENABLED
2266
// Some properties may have an instantiated Object as default value,
2267
// (like Path2D's `curve` used to have), but that's not a good practice.
2268
// Instead, those properties should use PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT
2269
// to be auto-instantiated when created in the editor with the following method:
2270
// EditorNode::get_editor_data().instantiate_object_properties(obj);
2271
if (var.get_type() == Variant::OBJECT) {
2272
Object *obj = var.get_validated_object();
2273
if (obj) {
2274
WARN_PRINT(vformat("Instantiated %s used as default value for %s's \"%s\" property.", obj->get_class(), p_class, p_property));
2275
}
2276
}
2277
#endif // DEBUG_ENABLED
2278
2279
return var;
2280
}
2281
2282
void ClassDB::register_extension_class(ObjectGDExtension *p_extension) {
2283
GLOBAL_LOCK_FUNCTION;
2284
2285
ERR_FAIL_COND_MSG(classes.has(p_extension->class_name), vformat("Class already registered: '%s'.", String(p_extension->class_name)));
2286
ERR_FAIL_COND_MSG(!classes.has(p_extension->parent_class_name), vformat("Parent class name for extension class not found: '%s'.", String(p_extension->parent_class_name)));
2287
2288
ClassInfo *parent = classes.getptr(p_extension->parent_class_name);
2289
2290
#ifdef TOOLS_ENABLED
2291
// @todo This is a limitation of the current implementation, but it should be possible to remove.
2292
ERR_FAIL_COND_MSG(p_extension->is_runtime && parent->gdextension && !parent->is_runtime, vformat("Extension runtime class '%s' cannot descend from '%s' which isn't also a runtime class.", String(p_extension->class_name), parent->name));
2293
#endif
2294
2295
ClassInfo c;
2296
c.api = p_extension->editor_class ? API_EDITOR_EXTENSION : API_EXTENSION;
2297
c.gdextension = p_extension;
2298
c.name = p_extension->class_name;
2299
c.is_virtual = p_extension->is_virtual;
2300
if (!p_extension->is_abstract) {
2301
// Find the closest ancestor which is either non-abstract or native (or both).
2302
ClassInfo *concrete_ancestor = parent;
2303
while (concrete_ancestor->creation_func == nullptr &&
2304
concrete_ancestor->inherits_ptr != nullptr &&
2305
concrete_ancestor->gdextension != nullptr) {
2306
concrete_ancestor = concrete_ancestor->inherits_ptr;
2307
}
2308
ERR_FAIL_NULL_MSG(concrete_ancestor->creation_func, vformat("Extension class '%s' cannot extend native abstract class '%s'.", String(p_extension->class_name), String(concrete_ancestor->name)));
2309
c.creation_func = concrete_ancestor->creation_func;
2310
}
2311
c.inherits = parent->name;
2312
c.class_ptr = parent->class_ptr;
2313
c.inherits_ptr = parent;
2314
c.exposed = p_extension->is_exposed;
2315
if (c.exposed) {
2316
// The parent classes should be exposed if it has an exposed child class.
2317
while (parent && !parent->exposed) {
2318
parent->exposed = true;
2319
parent = classes.getptr(parent->name);
2320
}
2321
}
2322
c.reloadable = p_extension->reloadable;
2323
#ifdef TOOLS_ENABLED
2324
c.is_runtime = p_extension->is_runtime;
2325
#endif
2326
2327
classes[p_extension->class_name] = c;
2328
}
2329
2330
void ClassDB::unregister_extension_class(const StringName &p_class, bool p_free_method_binds) {
2331
ClassInfo *c = classes.getptr(p_class);
2332
ERR_FAIL_NULL_MSG(c, vformat("Class '%s' does not exist.", String(p_class)));
2333
if (p_free_method_binds) {
2334
for (KeyValue<StringName, MethodBind *> &F : c->method_map) {
2335
memdelete(F.value);
2336
}
2337
}
2338
classes.erase(p_class);
2339
default_values_cached.erase(p_class);
2340
default_values.erase(p_class);
2341
#ifdef TOOLS_ENABLED
2342
placeholder_extensions.erase(p_class);
2343
#endif
2344
}
2345
2346
HashMap<StringName, ClassDB::NativeStruct> ClassDB::native_structs;
2347
void ClassDB::register_native_struct(const StringName &p_name, const String &p_code, uint64_t p_current_size) {
2348
NativeStruct ns;
2349
ns.ccode = p_code;
2350
ns.struct_size = p_current_size;
2351
native_structs[p_name] = ns;
2352
}
2353
2354
void ClassDB::get_native_struct_list(List<StringName> *r_names) {
2355
for (const KeyValue<StringName, NativeStruct> &E : native_structs) {
2356
r_names->push_back(E.key);
2357
}
2358
}
2359
2360
String ClassDB::get_native_struct_code(const StringName &p_name) {
2361
ERR_FAIL_COND_V(!native_structs.has(p_name), String());
2362
return native_structs[p_name].ccode;
2363
}
2364
2365
uint64_t ClassDB::get_native_struct_size(const StringName &p_name) {
2366
ERR_FAIL_COND_V(!native_structs.has(p_name), 0);
2367
return native_structs[p_name].struct_size;
2368
}
2369
2370
Object *ClassDB::_instantiate_allow_unexposed(const StringName &p_class) {
2371
return _instantiate_internal(p_class, false, true, false);
2372
}
2373
2374
void ClassDB::cleanup_defaults() {
2375
default_values.clear();
2376
default_values_cached.clear();
2377
}
2378
2379
void ClassDB::cleanup() {
2380
//OBJTYPE_LOCK; hah not here
2381
2382
for (KeyValue<StringName, ClassInfo> &E : classes) {
2383
ClassInfo &ti = E.value;
2384
2385
for (KeyValue<StringName, MethodBind *> &F : ti.method_map) {
2386
memdelete(F.value);
2387
}
2388
for (KeyValue<StringName, LocalVector<MethodBind *>> &F : ti.method_map_compatibility) {
2389
for (uint32_t i = 0; i < F.value.size(); i++) {
2390
memdelete(F.value[i]);
2391
}
2392
}
2393
}
2394
2395
classes.clear();
2396
resource_base_extensions.clear();
2397
compat_classes.clear();
2398
native_structs.clear();
2399
}
2400
2401
// Array to use in optional parameters on methods and the DEFVAL_ARRAY macro.
2402
Array ClassDB::default_array_arg = Array::create_read_only();
2403
2404
bool ClassDB::is_default_array_arg(const Array &p_array) {
2405
return p_array.is_same_instance(default_array_arg);
2406
}
2407
2408
//
2409
2410
ClassDB::Locker::Lock::Lock(Locker::State p_state) {
2411
DEV_ASSERT(p_state != STATE_UNLOCKED);
2412
if (p_state == STATE_READ) {
2413
if (Locker::thread_state == STATE_UNLOCKED) {
2414
state = STATE_READ;
2415
Locker::thread_state = STATE_READ;
2416
Locker::lock.read_lock();
2417
}
2418
} else if (p_state == STATE_WRITE) {
2419
if (Locker::thread_state == STATE_UNLOCKED) {
2420
state = STATE_WRITE;
2421
Locker::thread_state = STATE_WRITE;
2422
Locker::lock.write_lock();
2423
} else if (Locker::thread_state == STATE_READ) {
2424
CRASH_NOW_MSG("Lock can't be upgraded from read to write.");
2425
}
2426
}
2427
}
2428
2429
ClassDB::Locker::Lock::~Lock() {
2430
if (state == STATE_READ) {
2431
Locker::lock.read_unlock();
2432
Locker::thread_state = STATE_UNLOCKED;
2433
} else if (state == STATE_WRITE) {
2434
Locker::lock.write_unlock();
2435
Locker::thread_state = STATE_UNLOCKED;
2436
}
2437
}
2438
2439