1 /*************************************************************************/
2 /* class_db.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "class_db.h"
32
33 #include "core/engine.h"
34 #include "core/os/mutex.h"
35 #include "core/version.h"
36
37 #define OBJTYPE_RLOCK RWLockRead _rw_lockr_(lock);
38 #define OBJTYPE_WLOCK RWLockWrite _rw_lockw_(lock);
39
40 #ifdef DEBUG_METHODS_ENABLED
41
D_METHOD(const char * p_name)42 MethodDefinition D_METHOD(const char *p_name) {
43
44 MethodDefinition md;
45 md.name = StaticCString::create(p_name);
46 return md;
47 }
48
D_METHOD(const char * p_name,const char * p_arg1)49 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1) {
50
51 MethodDefinition md;
52 md.name = StaticCString::create(p_name);
53 md.args.push_back(StaticCString::create(p_arg1));
54 return md;
55 }
56
D_METHOD(const char * p_name,const char * p_arg1,const char * p_arg2)57 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2) {
58
59 MethodDefinition md;
60 md.name = StaticCString::create(p_name);
61 md.args.resize(2);
62 md.args.write[0] = StaticCString::create(p_arg1);
63 md.args.write[1] = StaticCString::create(p_arg2);
64 return md;
65 }
66
D_METHOD(const char * p_name,const char * p_arg1,const char * p_arg2,const char * p_arg3)67 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3) {
68
69 MethodDefinition md;
70 md.name = StaticCString::create(p_name);
71 md.args.resize(3);
72 md.args.write[0] = StaticCString::create(p_arg1);
73 md.args.write[1] = StaticCString::create(p_arg2);
74 md.args.write[2] = StaticCString::create(p_arg3);
75 return md;
76 }
77
D_METHOD(const char * p_name,const char * p_arg1,const char * p_arg2,const char * p_arg3,const char * p_arg4)78 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4) {
79
80 MethodDefinition md;
81 md.name = StaticCString::create(p_name);
82 md.args.resize(4);
83 md.args.write[0] = StaticCString::create(p_arg1);
84 md.args.write[1] = StaticCString::create(p_arg2);
85 md.args.write[2] = StaticCString::create(p_arg3);
86 md.args.write[3] = StaticCString::create(p_arg4);
87 return md;
88 }
89
D_METHOD(const char * p_name,const char * p_arg1,const char * p_arg2,const char * p_arg3,const char * p_arg4,const char * p_arg5)90 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5) {
91
92 MethodDefinition md;
93 md.name = StaticCString::create(p_name);
94 md.args.resize(5);
95 md.args.write[0] = StaticCString::create(p_arg1);
96 md.args.write[1] = StaticCString::create(p_arg2);
97 md.args.write[2] = StaticCString::create(p_arg3);
98 md.args.write[3] = StaticCString::create(p_arg4);
99 md.args.write[4] = StaticCString::create(p_arg5);
100 return md;
101 }
102
D_METHOD(const char * p_name,const char * p_arg1,const char * p_arg2,const char * p_arg3,const char * p_arg4,const char * p_arg5,const char * p_arg6)103 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6) {
104
105 MethodDefinition md;
106 md.name = StaticCString::create(p_name);
107 md.args.resize(6);
108 md.args.write[0] = StaticCString::create(p_arg1);
109 md.args.write[1] = StaticCString::create(p_arg2);
110 md.args.write[2] = StaticCString::create(p_arg3);
111 md.args.write[3] = StaticCString::create(p_arg4);
112 md.args.write[4] = StaticCString::create(p_arg5);
113 md.args.write[5] = StaticCString::create(p_arg6);
114 return md;
115 }
116
D_METHOD(const char * p_name,const char * p_arg1,const char * p_arg2,const char * p_arg3,const char * p_arg4,const char * p_arg5,const char * p_arg6,const char * p_arg7)117 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7) {
118
119 MethodDefinition md;
120 md.name = StaticCString::create(p_name);
121 md.args.resize(7);
122 md.args.write[0] = StaticCString::create(p_arg1);
123 md.args.write[1] = StaticCString::create(p_arg2);
124 md.args.write[2] = StaticCString::create(p_arg3);
125 md.args.write[3] = StaticCString::create(p_arg4);
126 md.args.write[4] = StaticCString::create(p_arg5);
127 md.args.write[5] = StaticCString::create(p_arg6);
128 md.args.write[6] = StaticCString::create(p_arg7);
129 return md;
130 }
131
D_METHOD(const char * p_name,const char * p_arg1,const char * p_arg2,const char * p_arg3,const char * p_arg4,const char * p_arg5,const char * p_arg6,const char * p_arg7,const char * p_arg8)132 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8) {
133
134 MethodDefinition md;
135 md.name = StaticCString::create(p_name);
136 md.args.resize(8);
137 md.args.write[0] = StaticCString::create(p_arg1);
138 md.args.write[1] = StaticCString::create(p_arg2);
139 md.args.write[2] = StaticCString::create(p_arg3);
140 md.args.write[3] = StaticCString::create(p_arg4);
141 md.args.write[4] = StaticCString::create(p_arg5);
142 md.args.write[5] = StaticCString::create(p_arg6);
143 md.args.write[6] = StaticCString::create(p_arg7);
144 md.args.write[7] = StaticCString::create(p_arg8);
145 return md;
146 }
147
D_METHOD(const char * p_name,const char * p_arg1,const char * p_arg2,const char * p_arg3,const char * p_arg4,const char * p_arg5,const char * p_arg6,const char * p_arg7,const char * p_arg8,const char * p_arg9)148 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9) {
149
150 MethodDefinition md;
151 md.name = StaticCString::create(p_name);
152 md.args.resize(9);
153 md.args.write[0] = StaticCString::create(p_arg1);
154 md.args.write[1] = StaticCString::create(p_arg2);
155 md.args.write[2] = StaticCString::create(p_arg3);
156 md.args.write[3] = StaticCString::create(p_arg4);
157 md.args.write[4] = StaticCString::create(p_arg5);
158 md.args.write[5] = StaticCString::create(p_arg6);
159 md.args.write[6] = StaticCString::create(p_arg7);
160 md.args.write[7] = StaticCString::create(p_arg8);
161 md.args.write[8] = StaticCString::create(p_arg9);
162 return md;
163 }
164
D_METHOD(const char * p_name,const char * p_arg1,const char * p_arg2,const char * p_arg3,const char * p_arg4,const char * p_arg5,const char * p_arg6,const char * p_arg7,const char * p_arg8,const char * p_arg9,const char * p_arg10)165 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10) {
166
167 MethodDefinition md;
168 md.name = StaticCString::create(p_name);
169 md.args.resize(10);
170 md.args.write[0] = StaticCString::create(p_arg1);
171 md.args.write[1] = StaticCString::create(p_arg2);
172 md.args.write[2] = StaticCString::create(p_arg3);
173 md.args.write[3] = StaticCString::create(p_arg4);
174 md.args.write[4] = StaticCString::create(p_arg5);
175 md.args.write[5] = StaticCString::create(p_arg6);
176 md.args.write[6] = StaticCString::create(p_arg7);
177 md.args.write[7] = StaticCString::create(p_arg8);
178 md.args.write[8] = StaticCString::create(p_arg9);
179 md.args.write[9] = StaticCString::create(p_arg10);
180 return md;
181 }
182
D_METHOD(const char * p_name,const char * p_arg1,const char * p_arg2,const char * p_arg3,const char * p_arg4,const char * p_arg5,const char * p_arg6,const char * p_arg7,const char * p_arg8,const char * p_arg9,const char * p_arg10,const char * p_arg11)183 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11) {
184
185 MethodDefinition md;
186 md.name = StaticCString::create(p_name);
187 md.args.resize(11);
188 md.args.write[0] = StaticCString::create(p_arg1);
189 md.args.write[1] = StaticCString::create(p_arg2);
190 md.args.write[2] = StaticCString::create(p_arg3);
191 md.args.write[3] = StaticCString::create(p_arg4);
192 md.args.write[4] = StaticCString::create(p_arg5);
193 md.args.write[5] = StaticCString::create(p_arg6);
194 md.args.write[6] = StaticCString::create(p_arg7);
195 md.args.write[7] = StaticCString::create(p_arg8);
196 md.args.write[8] = StaticCString::create(p_arg9);
197 md.args.write[9] = StaticCString::create(p_arg10);
198 md.args.write[10] = StaticCString::create(p_arg11);
199 return md;
200 }
201
D_METHOD(const char * p_name,const char * p_arg1,const char * p_arg2,const char * p_arg3,const char * p_arg4,const char * p_arg5,const char * p_arg6,const char * p_arg7,const char * p_arg8,const char * p_arg9,const char * p_arg10,const char * p_arg11,const char * p_arg12)202 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12) {
203
204 MethodDefinition md;
205 md.name = StaticCString::create(p_name);
206 md.args.resize(12);
207 md.args.write[0] = StaticCString::create(p_arg1);
208 md.args.write[1] = StaticCString::create(p_arg2);
209 md.args.write[2] = StaticCString::create(p_arg3);
210 md.args.write[3] = StaticCString::create(p_arg4);
211 md.args.write[4] = StaticCString::create(p_arg5);
212 md.args.write[5] = StaticCString::create(p_arg6);
213 md.args.write[6] = StaticCString::create(p_arg7);
214 md.args.write[7] = StaticCString::create(p_arg8);
215 md.args.write[8] = StaticCString::create(p_arg9);
216 md.args.write[9] = StaticCString::create(p_arg10);
217 md.args.write[10] = StaticCString::create(p_arg11);
218 md.args.write[11] = StaticCString::create(p_arg12);
219 return md;
220 }
221
D_METHOD(const char * p_name,const char * p_arg1,const char * p_arg2,const char * p_arg3,const char * p_arg4,const char * p_arg5,const char * p_arg6,const char * p_arg7,const char * p_arg8,const char * p_arg9,const char * p_arg10,const char * p_arg11,const char * p_arg12,const char * p_arg13)222 MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12, const char *p_arg13) {
223
224 MethodDefinition md;
225 md.name = StaticCString::create(p_name);
226 md.args.resize(13);
227 md.args.write[0] = StaticCString::create(p_arg1);
228 md.args.write[1] = StaticCString::create(p_arg2);
229 md.args.write[2] = StaticCString::create(p_arg3);
230 md.args.write[3] = StaticCString::create(p_arg4);
231 md.args.write[4] = StaticCString::create(p_arg5);
232 md.args.write[5] = StaticCString::create(p_arg6);
233 md.args.write[6] = StaticCString::create(p_arg7);
234 md.args.write[7] = StaticCString::create(p_arg8);
235 md.args.write[8] = StaticCString::create(p_arg9);
236 md.args.write[9] = StaticCString::create(p_arg10);
237 md.args.write[10] = StaticCString::create(p_arg11);
238 md.args.write[11] = StaticCString::create(p_arg12);
239 md.args.write[12] = StaticCString::create(p_arg13);
240 return md;
241 }
242
243 #endif
244
245 ClassDB::APIType ClassDB::current_api = API_CORE;
246
set_current_api(APIType p_api)247 void ClassDB::set_current_api(APIType p_api) {
248
249 current_api = p_api;
250 }
251
get_current_api()252 ClassDB::APIType ClassDB::get_current_api() {
253
254 return current_api;
255 }
256
257 HashMap<StringName, ClassDB::ClassInfo> ClassDB::classes;
258 HashMap<StringName, StringName> ClassDB::resource_base_extensions;
259 HashMap<StringName, StringName> ClassDB::compat_classes;
260
ClassInfo()261 ClassDB::ClassInfo::ClassInfo() {
262
263 api = API_NONE;
264 creation_func = NULL;
265 inherits_ptr = NULL;
266 disabled = false;
267 exposed = false;
268 }
269
~ClassInfo()270 ClassDB::ClassInfo::~ClassInfo() {
271 }
272
is_parent_class(const StringName & p_class,const StringName & p_inherits)273 bool ClassDB::is_parent_class(const StringName &p_class, const StringName &p_inherits) {
274
275 OBJTYPE_RLOCK;
276
277 StringName inherits = p_class;
278
279 while (inherits.operator String().length()) {
280
281 if (inherits == p_inherits)
282 return true;
283 inherits = get_parent_class(inherits);
284 }
285
286 return false;
287 }
get_class_list(List<StringName> * p_classes)288 void ClassDB::get_class_list(List<StringName> *p_classes) {
289
290 OBJTYPE_RLOCK;
291
292 const StringName *k = NULL;
293
294 while ((k = classes.next(k))) {
295
296 p_classes->push_back(*k);
297 }
298
299 p_classes->sort();
300 }
301
get_inheriters_from_class(const StringName & p_class,List<StringName> * p_classes)302 void ClassDB::get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) {
303
304 OBJTYPE_RLOCK;
305
306 const StringName *k = NULL;
307
308 while ((k = classes.next(k))) {
309
310 if (*k != p_class && is_parent_class(*k, p_class))
311 p_classes->push_back(*k);
312 }
313 }
314
get_direct_inheriters_from_class(const StringName & p_class,List<StringName> * p_classes)315 void ClassDB::get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) {
316
317 OBJTYPE_RLOCK;
318
319 const StringName *k = NULL;
320
321 while ((k = classes.next(k))) {
322
323 if (*k != p_class && get_parent_class(*k) == p_class)
324 p_classes->push_back(*k);
325 }
326 }
327
get_parent_class_nocheck(const StringName & p_class)328 StringName ClassDB::get_parent_class_nocheck(const StringName &p_class) {
329
330 OBJTYPE_RLOCK;
331
332 ClassInfo *ti = classes.getptr(p_class);
333 if (!ti)
334 return StringName();
335 return ti->inherits;
336 }
337
get_parent_class(const StringName & p_class)338 StringName ClassDB::get_parent_class(const StringName &p_class) {
339
340 OBJTYPE_RLOCK;
341
342 ClassInfo *ti = classes.getptr(p_class);
343 ERR_FAIL_COND_V_MSG(!ti, StringName(), "Cannot get class '" + String(p_class) + "'.");
344 return ti->inherits;
345 }
346
get_api_type(const StringName & p_class)347 ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) {
348
349 OBJTYPE_RLOCK;
350
351 ClassInfo *ti = classes.getptr(p_class);
352
353 ERR_FAIL_COND_V_MSG(!ti, API_NONE, "Cannot get class '" + String(p_class) + "'.");
354 return ti->api;
355 }
356
get_api_hash(APIType p_api)357 uint64_t ClassDB::get_api_hash(APIType p_api) {
358
359 OBJTYPE_RLOCK;
360 #ifdef DEBUG_METHODS_ENABLED
361
362 uint64_t hash = hash_djb2_one_64(HashMapHasherDefault::hash(VERSION_FULL_CONFIG));
363
364 List<StringName> names;
365
366 const StringName *k = NULL;
367
368 while ((k = classes.next(k))) {
369
370 names.push_back(*k);
371 }
372 //must be alphabetically sorted for hash to compute
373 names.sort_custom<StringName::AlphCompare>();
374
375 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
376
377 ClassInfo *t = classes.getptr(E->get());
378 ERR_FAIL_COND_V_MSG(!t, 0, "Cannot get class '" + String(E->get()) + "'.");
379 if (t->api != p_api || !t->exposed)
380 continue;
381 hash = hash_djb2_one_64(t->name.hash(), hash);
382 hash = hash_djb2_one_64(t->inherits.hash(), hash);
383
384 { //methods
385
386 List<StringName> snames;
387
388 k = NULL;
389
390 while ((k = t->method_map.next(k))) {
391
392 String name = k->operator String();
393
394 ERR_CONTINUE(name.empty());
395
396 if (name[0] == '_')
397 continue; // Ignore non-virtual methods that start with an underscore
398
399 snames.push_back(*k);
400 }
401
402 snames.sort_custom<StringName::AlphCompare>();
403
404 for (List<StringName>::Element *F = snames.front(); F; F = F->next()) {
405
406 MethodBind *mb = t->method_map[F->get()];
407 hash = hash_djb2_one_64(mb->get_name().hash(), hash);
408 hash = hash_djb2_one_64(mb->get_argument_count(), hash);
409 hash = hash_djb2_one_64(mb->get_argument_type(-1), hash); //return
410
411 for (int i = 0; i < mb->get_argument_count(); i++) {
412 const PropertyInfo info = mb->get_argument_info(i);
413 hash = hash_djb2_one_64(info.type, hash);
414 hash = hash_djb2_one_64(info.name.hash(), hash);
415 hash = hash_djb2_one_64(info.hint, hash);
416 hash = hash_djb2_one_64(info.hint_string.hash(), hash);
417 }
418
419 hash = hash_djb2_one_64(mb->get_default_argument_count(), hash);
420
421 for (int i = 0; i < mb->get_default_argument_count(); i++) {
422 //hash should not change, i hope for tis
423 Variant da = mb->get_default_argument(i);
424 hash = hash_djb2_one_64(da.hash(), hash);
425 }
426
427 hash = hash_djb2_one_64(mb->get_hint_flags(), hash);
428 }
429 }
430
431 { //constants
432
433 List<StringName> snames;
434
435 k = NULL;
436
437 while ((k = t->constant_map.next(k))) {
438
439 snames.push_back(*k);
440 }
441
442 snames.sort_custom<StringName::AlphCompare>();
443
444 for (List<StringName>::Element *F = snames.front(); F; F = F->next()) {
445
446 hash = hash_djb2_one_64(F->get().hash(), hash);
447 hash = hash_djb2_one_64(t->constant_map[F->get()], hash);
448 }
449 }
450
451 { //signals
452
453 List<StringName> snames;
454
455 k = NULL;
456
457 while ((k = t->signal_map.next(k))) {
458
459 snames.push_back(*k);
460 }
461
462 snames.sort_custom<StringName::AlphCompare>();
463
464 for (List<StringName>::Element *F = snames.front(); F; F = F->next()) {
465
466 MethodInfo &mi = t->signal_map[F->get()];
467 hash = hash_djb2_one_64(F->get().hash(), hash);
468 for (int i = 0; i < mi.arguments.size(); i++) {
469 hash = hash_djb2_one_64(mi.arguments[i].type, hash);
470 }
471 }
472 }
473
474 { //properties
475
476 List<StringName> snames;
477
478 k = NULL;
479
480 while ((k = t->property_setget.next(k))) {
481
482 snames.push_back(*k);
483 }
484
485 snames.sort_custom<StringName::AlphCompare>();
486
487 for (List<StringName>::Element *F = snames.front(); F; F = F->next()) {
488
489 PropertySetGet *psg = t->property_setget.getptr(F->get());
490 ERR_FAIL_COND_V(!psg, 0);
491
492 hash = hash_djb2_one_64(F->get().hash(), hash);
493 hash = hash_djb2_one_64(psg->setter.hash(), hash);
494 hash = hash_djb2_one_64(psg->getter.hash(), hash);
495 }
496 }
497
498 //property list
499 for (List<PropertyInfo>::Element *F = t->property_list.front(); F; F = F->next()) {
500
501 hash = hash_djb2_one_64(F->get().name.hash(), hash);
502 hash = hash_djb2_one_64(F->get().type, hash);
503 hash = hash_djb2_one_64(F->get().hint, hash);
504 hash = hash_djb2_one_64(F->get().hint_string.hash(), hash);
505 hash = hash_djb2_one_64(F->get().usage, hash);
506 }
507 }
508
509 return hash;
510 #else
511 return 0;
512 #endif
513 }
514
class_exists(const StringName & p_class)515 bool ClassDB::class_exists(const StringName &p_class) {
516
517 OBJTYPE_RLOCK;
518 return classes.has(p_class);
519 }
520
add_compatibility_class(const StringName & p_class,const StringName & p_fallback)521 void ClassDB::add_compatibility_class(const StringName &p_class, const StringName &p_fallback) {
522
523 OBJTYPE_WLOCK;
524 compat_classes[p_class] = p_fallback;
525 }
526
instance(const StringName & p_class)527 Object *ClassDB::instance(const StringName &p_class) {
528
529 ClassInfo *ti;
530 {
531 OBJTYPE_RLOCK;
532 ti = classes.getptr(p_class);
533 if (!ti || ti->disabled || !ti->creation_func) {
534 if (compat_classes.has(p_class)) {
535 ti = classes.getptr(compat_classes[p_class]);
536 }
537 }
538 ERR_FAIL_COND_V_MSG(!ti, NULL, "Cannot get class '" + String(p_class) + "'.");
539 ERR_FAIL_COND_V_MSG(ti->disabled, NULL, "Class '" + String(p_class) + "' is disabled.");
540 ERR_FAIL_COND_V(!ti->creation_func, NULL);
541 }
542 #ifdef TOOLS_ENABLED
543 if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
544 ERR_PRINTS("Class '" + String(p_class) + "' can only be instantiated by editor.");
545 return NULL;
546 }
547 #endif
548 return ti->creation_func();
549 }
can_instance(const StringName & p_class)550 bool ClassDB::can_instance(const StringName &p_class) {
551
552 OBJTYPE_RLOCK;
553
554 ClassInfo *ti = classes.getptr(p_class);
555 ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
556 #ifdef TOOLS_ENABLED
557 if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
558 return false;
559 }
560 #endif
561 return (!ti->disabled && ti->creation_func != NULL);
562 }
563
_add_class2(const StringName & p_class,const StringName & p_inherits)564 void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) {
565
566 OBJTYPE_WLOCK;
567
568 const StringName &name = p_class;
569
570 ERR_FAIL_COND_MSG(classes.has(name), "Class '" + String(p_class) + "' already exists.");
571
572 classes[name] = ClassInfo();
573 ClassInfo &ti = classes[name];
574 ti.name = name;
575 ti.inherits = p_inherits;
576 ti.api = current_api;
577
578 if (ti.inherits) {
579
580 ERR_FAIL_COND(!classes.has(ti.inherits)); //it MUST be registered.
581 ti.inherits_ptr = &classes[ti.inherits];
582
583 } else {
584 ti.inherits_ptr = NULL;
585 }
586 }
587
get_method_list(StringName p_class,List<MethodInfo> * p_methods,bool p_no_inheritance,bool p_exclude_from_properties)588 void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) {
589
590 OBJTYPE_RLOCK;
591
592 ClassInfo *type = classes.getptr(p_class);
593
594 while (type) {
595
596 if (type->disabled) {
597
598 if (p_no_inheritance)
599 break;
600
601 type = type->inherits_ptr;
602 continue;
603 }
604
605 #ifdef DEBUG_METHODS_ENABLED
606
607 for (List<MethodInfo>::Element *E = type->virtual_methods.front(); E; E = E->next()) {
608
609 p_methods->push_back(E->get());
610 }
611
612 for (List<StringName>::Element *E = type->method_order.front(); E; E = E->next()) {
613
614 MethodBind *method = type->method_map.get(E->get());
615 MethodInfo minfo;
616 minfo.name = E->get();
617 minfo.id = method->get_method_id();
618
619 if (p_exclude_from_properties && type->methods_in_properties.has(minfo.name))
620 continue;
621
622 for (int i = 0; i < method->get_argument_count(); i++) {
623
624 //Variant::Type t=method->get_argument_type(i);
625
626 minfo.arguments.push_back(method->get_argument_info(i));
627 }
628
629 minfo.return_val = method->get_return_info();
630 minfo.flags = method->get_hint_flags();
631
632 for (int i = 0; i < method->get_argument_count(); i++) {
633 if (method->has_default_argument(i))
634 minfo.default_arguments.push_back(method->get_default_argument(i));
635 }
636
637 p_methods->push_back(minfo);
638 }
639
640 #else
641
642 const StringName *K = NULL;
643
644 while ((K = type->method_map.next(K))) {
645
646 MethodBind *m = type->method_map[*K];
647 MethodInfo mi;
648 mi.name = m->get_name();
649 p_methods->push_back(mi);
650 }
651
652 #endif
653
654 if (p_no_inheritance)
655 break;
656
657 type = type->inherits_ptr;
658 }
659 }
660
get_method(StringName p_class,StringName p_name)661 MethodBind *ClassDB::get_method(StringName p_class, StringName p_name) {
662
663 OBJTYPE_RLOCK;
664
665 ClassInfo *type = classes.getptr(p_class);
666
667 while (type) {
668
669 MethodBind **method = type->method_map.getptr(p_name);
670 if (method && *method)
671 return *method;
672 type = type->inherits_ptr;
673 }
674 return NULL;
675 }
676
bind_integer_constant(const StringName & p_class,const StringName & p_enum,const StringName & p_name,int p_constant)677 void ClassDB::bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int p_constant) {
678
679 OBJTYPE_WLOCK;
680
681 ClassInfo *type = classes.getptr(p_class);
682
683 ERR_FAIL_COND(!type);
684
685 if (type->constant_map.has(p_name)) {
686
687 ERR_FAIL();
688 }
689
690 type->constant_map[p_name] = p_constant;
691
692 String enum_name = p_enum;
693 if (enum_name != String()) {
694 if (enum_name.find(".") != -1) {
695 enum_name = enum_name.get_slicec('.', 1);
696 }
697
698 List<StringName> *constants_list = type->enum_map.getptr(enum_name);
699
700 if (constants_list) {
701 constants_list->push_back(p_name);
702 } else {
703 List<StringName> new_list;
704 new_list.push_back(p_name);
705 type->enum_map[enum_name] = new_list;
706 }
707 }
708
709 #ifdef DEBUG_METHODS_ENABLED
710 type->constant_order.push_back(p_name);
711 #endif
712 }
713
get_integer_constant_list(const StringName & p_class,List<String> * p_constants,bool p_no_inheritance)714 void ClassDB::get_integer_constant_list(const StringName &p_class, List<String> *p_constants, bool p_no_inheritance) {
715
716 OBJTYPE_RLOCK;
717
718 ClassInfo *type = classes.getptr(p_class);
719
720 while (type) {
721
722 #ifdef DEBUG_METHODS_ENABLED
723 for (List<StringName>::Element *E = type->constant_order.front(); E; E = E->next())
724 p_constants->push_back(E->get());
725 #else
726 const StringName *K = NULL;
727
728 while ((K = type->constant_map.next(K))) {
729 p_constants->push_back(*K);
730 }
731
732 #endif
733 if (p_no_inheritance)
734 break;
735
736 type = type->inherits_ptr;
737 }
738 }
739
get_integer_constant(const StringName & p_class,const StringName & p_name,bool * p_success)740 int ClassDB::get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success) {
741
742 OBJTYPE_RLOCK;
743
744 ClassInfo *type = classes.getptr(p_class);
745
746 while (type) {
747
748 int *constant = type->constant_map.getptr(p_name);
749 if (constant) {
750
751 if (p_success)
752 *p_success = true;
753 return *constant;
754 }
755
756 type = type->inherits_ptr;
757 }
758
759 if (p_success)
760 *p_success = false;
761
762 return 0;
763 }
764
get_integer_constant_enum(const StringName & p_class,const StringName & p_name,bool p_no_inheritance)765 StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
766
767 OBJTYPE_RLOCK;
768
769 ClassInfo *type = classes.getptr(p_class);
770
771 while (type) {
772
773 const StringName *k = NULL;
774 while ((k = type->enum_map.next(k))) {
775
776 List<StringName> &constants_list = type->enum_map.get(*k);
777 const List<StringName>::Element *found = constants_list.find(p_name);
778 if (found)
779 return *k;
780 }
781
782 if (p_no_inheritance)
783 break;
784
785 type = type->inherits_ptr;
786 }
787
788 return StringName();
789 }
790
get_enum_list(const StringName & p_class,List<StringName> * p_enums,bool p_no_inheritance)791 void ClassDB::get_enum_list(const StringName &p_class, List<StringName> *p_enums, bool p_no_inheritance) {
792
793 OBJTYPE_RLOCK;
794
795 ClassInfo *type = classes.getptr(p_class);
796
797 while (type) {
798
799 const StringName *k = NULL;
800 while ((k = type->enum_map.next(k))) {
801 p_enums->push_back(*k);
802 }
803
804 if (p_no_inheritance)
805 break;
806
807 type = type->inherits_ptr;
808 }
809 }
810
get_enum_constants(const StringName & p_class,const StringName & p_enum,List<StringName> * p_constants,bool p_no_inheritance)811 void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance) {
812
813 OBJTYPE_RLOCK;
814
815 ClassInfo *type = classes.getptr(p_class);
816
817 while (type) {
818
819 const List<StringName> *constants = type->enum_map.getptr(p_enum);
820
821 if (constants) {
822 for (const List<StringName>::Element *E = constants->front(); E; E = E->next()) {
823 p_constants->push_back(E->get());
824 }
825 }
826
827 if (p_no_inheritance)
828 break;
829
830 type = type->inherits_ptr;
831 }
832 }
833
add_signal(StringName p_class,const MethodInfo & p_signal)834 void ClassDB::add_signal(StringName p_class, const MethodInfo &p_signal) {
835
836 OBJTYPE_WLOCK;
837
838 ClassInfo *type = classes.getptr(p_class);
839 ERR_FAIL_COND(!type);
840
841 StringName sname = p_signal.name;
842
843 #ifdef DEBUG_METHODS_ENABLED
844 ClassInfo *check = type;
845 while (check) {
846 ERR_FAIL_COND_MSG(check->signal_map.has(sname), "Class '" + String(p_class) + "' already has signal '" + String(sname) + "'.");
847 check = check->inherits_ptr;
848 }
849 #endif
850
851 type->signal_map[sname] = p_signal;
852 }
853
get_signal_list(StringName p_class,List<MethodInfo> * p_signals,bool p_no_inheritance)854 void ClassDB::get_signal_list(StringName p_class, List<MethodInfo> *p_signals, bool p_no_inheritance) {
855
856 OBJTYPE_RLOCK;
857
858 ClassInfo *type = classes.getptr(p_class);
859 ERR_FAIL_COND(!type);
860
861 ClassInfo *check = type;
862
863 while (check) {
864
865 const StringName *S = NULL;
866 while ((S = check->signal_map.next(S))) {
867
868 p_signals->push_back(check->signal_map[*S]);
869 }
870
871 if (p_no_inheritance)
872 return;
873
874 check = check->inherits_ptr;
875 }
876 }
877
has_signal(StringName p_class,StringName p_signal)878 bool ClassDB::has_signal(StringName p_class, StringName p_signal) {
879
880 OBJTYPE_RLOCK;
881 ClassInfo *type = classes.getptr(p_class);
882 ClassInfo *check = type;
883 while (check) {
884 if (check->signal_map.has(p_signal))
885 return true;
886 check = check->inherits_ptr;
887 }
888
889 return false;
890 }
891
get_signal(StringName p_class,StringName p_signal,MethodInfo * r_signal)892 bool ClassDB::get_signal(StringName p_class, StringName p_signal, MethodInfo *r_signal) {
893
894 OBJTYPE_RLOCK;
895 ClassInfo *type = classes.getptr(p_class);
896 ClassInfo *check = type;
897 while (check) {
898 if (check->signal_map.has(p_signal)) {
899 if (r_signal) {
900 *r_signal = check->signal_map[p_signal];
901 }
902 return true;
903 }
904 check = check->inherits_ptr;
905 }
906
907 return false;
908 }
909
add_property_group(StringName p_class,const String & p_name,const String & p_prefix)910 void ClassDB::add_property_group(StringName p_class, const String &p_name, const String &p_prefix) {
911
912 OBJTYPE_WLOCK;
913 ClassInfo *type = classes.getptr(p_class);
914 ERR_FAIL_COND(!type);
915
916 type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_GROUP));
917 }
918
add_property(StringName p_class,const PropertyInfo & p_pinfo,const StringName & p_setter,const StringName & p_getter,int p_index)919 void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
920
921 lock->read_lock();
922 ClassInfo *type = classes.getptr(p_class);
923 lock->read_unlock();
924
925 ERR_FAIL_COND(!type);
926
927 MethodBind *mb_set = NULL;
928 if (p_setter) {
929 mb_set = get_method(p_class, p_setter);
930 #ifdef DEBUG_METHODS_ENABLED
931
932 ERR_FAIL_COND_MSG(!mb_set, "Invalid setter '" + p_class + "::" + p_setter + "' for property '" + p_pinfo.name + "'.");
933
934 int exp_args = 1 + (p_index >= 0 ? 1 : 0);
935 ERR_FAIL_COND_MSG(mb_set->get_argument_count() != exp_args, "Invalid function for setter '" + p_class + "::" + p_setter + " for property '" + p_pinfo.name + "'.");
936 #endif
937 }
938
939 MethodBind *mb_get = NULL;
940 if (p_getter) {
941
942 mb_get = get_method(p_class, p_getter);
943 #ifdef DEBUG_METHODS_ENABLED
944
945 ERR_FAIL_COND_MSG(!mb_get, "Invalid getter '" + p_class + "::" + p_getter + "' for property '" + p_pinfo.name + "'.");
946
947 int exp_args = 0 + (p_index >= 0 ? 1 : 0);
948 ERR_FAIL_COND_MSG(mb_get->get_argument_count() != exp_args, "Invalid function for getter '" + p_class + "::" + p_getter + "' for property: '" + p_pinfo.name + "'.");
949 #endif
950 }
951
952 #ifdef DEBUG_METHODS_ENABLED
953 ERR_FAIL_COND_MSG(type->property_setget.has(p_pinfo.name), "Object '" + p_class + "' already has property '" + p_pinfo.name + "'.");
954 #endif
955
956 OBJTYPE_WLOCK
957
958 type->property_list.push_back(p_pinfo);
959 #ifdef DEBUG_METHODS_ENABLED
960 if (mb_get) {
961 type->methods_in_properties.insert(p_getter);
962 }
963 if (mb_set) {
964 type->methods_in_properties.insert(p_setter);
965 }
966 #endif
967 PropertySetGet psg;
968 psg.setter = p_setter;
969 psg.getter = p_getter;
970 psg._setptr = mb_set;
971 psg._getptr = mb_get;
972 psg.index = p_index;
973 psg.type = p_pinfo.type;
974
975 type->property_setget[p_pinfo.name] = psg;
976 }
977
set_property_default_value(StringName p_class,const StringName & p_name,const Variant & p_default)978 void ClassDB::set_property_default_value(StringName p_class, const StringName &p_name, const Variant &p_default) {
979 if (!default_values.has(p_class)) {
980 default_values[p_class] = HashMap<StringName, Variant>();
981 }
982 default_values[p_class][p_name] = p_default;
983 }
984
get_property_list(StringName p_class,List<PropertyInfo> * p_list,bool p_no_inheritance,const Object * p_validator)985 void ClassDB::get_property_list(StringName p_class, List<PropertyInfo> *p_list, bool p_no_inheritance, const Object *p_validator) {
986
987 OBJTYPE_RLOCK;
988
989 ClassInfo *type = classes.getptr(p_class);
990 ClassInfo *check = type;
991 while (check) {
992
993 for (List<PropertyInfo>::Element *E = check->property_list.front(); E; E = E->next()) {
994
995 if (p_validator) {
996 PropertyInfo pi = E->get();
997 p_validator->_validate_property(pi);
998 p_list->push_back(pi);
999 } else {
1000 p_list->push_back(E->get());
1001 }
1002 }
1003
1004 if (p_no_inheritance)
1005 return;
1006 check = check->inherits_ptr;
1007 }
1008 }
set_property(Object * p_object,const StringName & p_property,const Variant & p_value,bool * r_valid)1009 bool ClassDB::set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid) {
1010
1011 ClassInfo *type = classes.getptr(p_object->get_class_name());
1012 ClassInfo *check = type;
1013 while (check) {
1014 const PropertySetGet *psg = check->property_setget.getptr(p_property);
1015 if (psg) {
1016
1017 if (!psg->setter) {
1018 if (r_valid)
1019 *r_valid = false;
1020 return true; //return true but do nothing
1021 }
1022
1023 Variant::CallError ce;
1024
1025 if (psg->index >= 0) {
1026 Variant index = psg->index;
1027 const Variant *arg[2] = { &index, &p_value };
1028 //p_object->call(psg->setter,arg,2,ce);
1029 if (psg->_setptr) {
1030 psg->_setptr->call(p_object, arg, 2, ce);
1031 } else {
1032 p_object->call(psg->setter, arg, 2, ce);
1033 }
1034
1035 } else {
1036 const Variant *arg[1] = { &p_value };
1037 if (psg->_setptr) {
1038 psg->_setptr->call(p_object, arg, 1, ce);
1039 } else {
1040 p_object->call(psg->setter, arg, 1, ce);
1041 }
1042 }
1043
1044 if (r_valid)
1045 *r_valid = ce.error == Variant::CallError::CALL_OK;
1046
1047 return true;
1048 }
1049
1050 check = check->inherits_ptr;
1051 }
1052
1053 return false;
1054 }
get_property(Object * p_object,const StringName & p_property,Variant & r_value)1055 bool ClassDB::get_property(Object *p_object, const StringName &p_property, Variant &r_value) {
1056
1057 ClassInfo *type = classes.getptr(p_object->get_class_name());
1058 ClassInfo *check = type;
1059 while (check) {
1060 const PropertySetGet *psg = check->property_setget.getptr(p_property);
1061 if (psg) {
1062 if (!psg->getter)
1063 return true; //return true but do nothing
1064
1065 if (psg->index >= 0) {
1066 Variant index = psg->index;
1067 const Variant *arg[1] = { &index };
1068 Variant::CallError ce;
1069 r_value = p_object->call(psg->getter, arg, 1, ce);
1070
1071 } else {
1072
1073 Variant::CallError ce;
1074 if (psg->_getptr) {
1075
1076 r_value = psg->_getptr->call(p_object, NULL, 0, ce);
1077 } else {
1078 r_value = p_object->call(psg->getter, NULL, 0, ce);
1079 }
1080 }
1081 return true;
1082 }
1083
1084 const int *c = check->constant_map.getptr(p_property);
1085 if (c) {
1086
1087 r_value = *c;
1088 return true;
1089 }
1090
1091 check = check->inherits_ptr;
1092 }
1093
1094 return false;
1095 }
1096
get_property_index(const StringName & p_class,const StringName & p_property,bool * r_is_valid)1097 int ClassDB::get_property_index(const StringName &p_class, const StringName &p_property, bool *r_is_valid) {
1098
1099 ClassInfo *type = classes.getptr(p_class);
1100 ClassInfo *check = type;
1101 while (check) {
1102 const PropertySetGet *psg = check->property_setget.getptr(p_property);
1103 if (psg) {
1104
1105 if (r_is_valid)
1106 *r_is_valid = true;
1107
1108 return psg->index;
1109 }
1110
1111 check = check->inherits_ptr;
1112 }
1113 if (r_is_valid)
1114 *r_is_valid = false;
1115
1116 return -1;
1117 }
1118
get_property_type(const StringName & p_class,const StringName & p_property,bool * r_is_valid)1119 Variant::Type ClassDB::get_property_type(const StringName &p_class, const StringName &p_property, bool *r_is_valid) {
1120
1121 ClassInfo *type = classes.getptr(p_class);
1122 ClassInfo *check = type;
1123 while (check) {
1124 const PropertySetGet *psg = check->property_setget.getptr(p_property);
1125 if (psg) {
1126
1127 if (r_is_valid)
1128 *r_is_valid = true;
1129
1130 return psg->type;
1131 }
1132
1133 check = check->inherits_ptr;
1134 }
1135 if (r_is_valid)
1136 *r_is_valid = false;
1137
1138 return Variant::NIL;
1139 }
1140
get_property_setter(StringName p_class,const StringName & p_property)1141 StringName ClassDB::get_property_setter(StringName p_class, const StringName &p_property) {
1142
1143 ClassInfo *type = classes.getptr(p_class);
1144 ClassInfo *check = type;
1145 while (check) {
1146 const PropertySetGet *psg = check->property_setget.getptr(p_property);
1147 if (psg) {
1148
1149 return psg->setter;
1150 }
1151
1152 check = check->inherits_ptr;
1153 }
1154
1155 return StringName();
1156 }
1157
get_property_getter(StringName p_class,const StringName & p_property)1158 StringName ClassDB::get_property_getter(StringName p_class, const StringName &p_property) {
1159
1160 ClassInfo *type = classes.getptr(p_class);
1161 ClassInfo *check = type;
1162 while (check) {
1163 const PropertySetGet *psg = check->property_setget.getptr(p_property);
1164 if (psg) {
1165
1166 return psg->getter;
1167 }
1168
1169 check = check->inherits_ptr;
1170 }
1171
1172 return StringName();
1173 }
1174
has_property(const StringName & p_class,const StringName & p_property,bool p_no_inheritance)1175 bool ClassDB::has_property(const StringName &p_class, const StringName &p_property, bool p_no_inheritance) {
1176
1177 ClassInfo *type = classes.getptr(p_class);
1178 ClassInfo *check = type;
1179 while (check) {
1180 if (check->property_setget.has(p_property))
1181 return true;
1182
1183 if (p_no_inheritance)
1184 break;
1185 check = check->inherits_ptr;
1186 }
1187
1188 return false;
1189 }
1190
set_method_flags(StringName p_class,StringName p_method,int p_flags)1191 void ClassDB::set_method_flags(StringName p_class, StringName p_method, int p_flags) {
1192
1193 OBJTYPE_WLOCK;
1194 ClassInfo *type = classes.getptr(p_class);
1195 ClassInfo *check = type;
1196 ERR_FAIL_COND(!check);
1197 ERR_FAIL_COND(!check->method_map.has(p_method));
1198 check->method_map[p_method]->set_hint_flags(p_flags);
1199 }
1200
has_method(StringName p_class,StringName p_method,bool p_no_inheritance)1201 bool ClassDB::has_method(StringName p_class, StringName p_method, bool p_no_inheritance) {
1202
1203 ClassInfo *type = classes.getptr(p_class);
1204 ClassInfo *check = type;
1205 while (check) {
1206 if (check->method_map.has(p_method))
1207 return true;
1208 if (p_no_inheritance)
1209 return false;
1210 check = check->inherits_ptr;
1211 }
1212
1213 return false;
1214 }
1215
1216 #ifdef DEBUG_METHODS_ENABLED
bind_methodfi(uint32_t p_flags,MethodBind * p_bind,const MethodDefinition & method_name,const Variant ** p_defs,int p_defcount)1217 MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) {
1218 StringName mdname = method_name.name;
1219 #else
1220 MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const char *method_name, const Variant **p_defs, int p_defcount) {
1221 StringName mdname = StaticCString::create(method_name);
1222 #endif
1223
1224 OBJTYPE_WLOCK;
1225 ERR_FAIL_COND_V(!p_bind, NULL);
1226 p_bind->set_name(mdname);
1227
1228 String instance_type = p_bind->get_instance_class();
1229
1230 #ifdef DEBUG_ENABLED
1231
1232 ERR_FAIL_COND_V_MSG(has_method(instance_type, mdname), NULL, "Class " + String(instance_type) + " already has a method " + String(mdname) + ".");
1233 #endif
1234
1235 ClassInfo *type = classes.getptr(instance_type);
1236 if (!type) {
1237 memdelete(p_bind);
1238 ERR_FAIL_V_MSG(NULL, "Couldn't bind method '" + mdname + "' for instance '" + instance_type + "'.");
1239 }
1240
1241 if (type->method_map.has(mdname)) {
1242 memdelete(p_bind);
1243 // overloading not supported
1244 ERR_FAIL_V_MSG(NULL, "Method already bound '" + instance_type + "::" + mdname + "'.");
1245 }
1246
1247 #ifdef DEBUG_METHODS_ENABLED
1248
1249 if (method_name.args.size() > p_bind->get_argument_count()) {
1250 memdelete(p_bind);
1251 ERR_FAIL_V_MSG(NULL, "Method definition provides more arguments than the method actually has '" + instance_type + "::" + mdname + "'.");
1252 }
1253
1254 p_bind->set_argument_names(method_name.args);
1255
1256 type->method_order.push_back(mdname);
1257 #endif
1258
1259 type->method_map[mdname] = p_bind;
1260
1261 Vector<Variant> defvals;
1262
1263 defvals.resize(p_defcount);
1264 for (int i = 0; i < p_defcount; i++) {
1265
1266 defvals.write[i] = *p_defs[p_defcount - i - 1];
1267 }
1268
1269 p_bind->set_default_arguments(defvals);
1270 p_bind->set_hint_flags(p_flags);
1271 return p_bind;
1272 }
1273
1274 void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual) {
1275 ERR_FAIL_COND_MSG(!classes.has(p_class), "Request for nonexistent class '" + p_class + "'.");
1276
1277 OBJTYPE_WLOCK;
1278
1279 #ifdef DEBUG_METHODS_ENABLED
1280 MethodInfo mi = p_method;
1281 if (p_virtual)
1282 mi.flags |= METHOD_FLAG_VIRTUAL;
1283 classes[p_class].virtual_methods.push_back(mi);
1284
1285 #endif
1286 }
1287
1288 void ClassDB::get_virtual_methods(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance) {
1289
1290 ERR_FAIL_COND_MSG(!classes.has(p_class), "Request for nonexistent class '" + p_class + "'.");
1291
1292 #ifdef DEBUG_METHODS_ENABLED
1293
1294 ClassInfo *type = classes.getptr(p_class);
1295 ClassInfo *check = type;
1296 while (check) {
1297
1298 for (List<MethodInfo>::Element *E = check->virtual_methods.front(); E; E = E->next()) {
1299 p_methods->push_back(E->get());
1300 }
1301
1302 if (p_no_inheritance)
1303 return;
1304 check = check->inherits_ptr;
1305 }
1306
1307 #endif
1308 }
1309
1310 void ClassDB::set_class_enabled(StringName p_class, bool p_enable) {
1311
1312 OBJTYPE_WLOCK;
1313
1314 ERR_FAIL_COND_MSG(!classes.has(p_class), "Request for nonexistent class '" + p_class + "'.");
1315 classes[p_class].disabled = !p_enable;
1316 }
1317
1318 bool ClassDB::is_class_enabled(StringName p_class) {
1319
1320 OBJTYPE_RLOCK;
1321
1322 ClassInfo *ti = classes.getptr(p_class);
1323 if (!ti || !ti->creation_func) {
1324 if (compat_classes.has(p_class)) {
1325 ti = classes.getptr(compat_classes[p_class]);
1326 }
1327 }
1328
1329 ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
1330 return !ti->disabled;
1331 }
1332
1333 bool ClassDB::is_class_exposed(StringName p_class) {
1334
1335 OBJTYPE_RLOCK;
1336
1337 ClassInfo *ti = classes.getptr(p_class);
1338 ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
1339 return ti->exposed;
1340 }
1341
1342 StringName ClassDB::get_category(const StringName &p_node) {
1343
1344 ERR_FAIL_COND_V(!classes.has(p_node), StringName());
1345 #ifdef DEBUG_ENABLED
1346 return classes[p_node].category;
1347 #else
1348 return StringName();
1349 #endif
1350 }
1351
1352 void ClassDB::add_resource_base_extension(const StringName &p_extension, const StringName &p_class) {
1353
1354 if (resource_base_extensions.has(p_extension))
1355 return;
1356
1357 resource_base_extensions[p_extension] = p_class;
1358 }
1359
1360 void ClassDB::get_resource_base_extensions(List<String> *p_extensions) {
1361
1362 const StringName *K = NULL;
1363
1364 while ((K = resource_base_extensions.next(K))) {
1365
1366 p_extensions->push_back(*K);
1367 }
1368 }
1369
1370 void ClassDB::get_extensions_for_type(const StringName &p_class, List<String> *p_extensions) {
1371
1372 const StringName *K = NULL;
1373
1374 while ((K = resource_base_extensions.next(K))) {
1375 StringName cmp = resource_base_extensions[*K];
1376 if (is_parent_class(p_class, cmp) || is_parent_class(cmp, p_class))
1377 p_extensions->push_back(*K);
1378 }
1379 }
1380
1381 HashMap<StringName, HashMap<StringName, Variant> > ClassDB::default_values;
1382 Set<StringName> ClassDB::default_values_cached;
1383
1384 Variant ClassDB::class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid) {
1385
1386 if (!default_values_cached.has(p_class)) {
1387
1388 if (!default_values.has(p_class)) {
1389 default_values[p_class] = HashMap<StringName, Variant>();
1390 }
1391
1392 Object *c = NULL;
1393 bool cleanup_c = false;
1394
1395 if (Engine::get_singleton()->has_singleton(p_class)) {
1396 c = Engine::get_singleton()->get_singleton_object(p_class);
1397 cleanup_c = false;
1398 } else if (ClassDB::can_instance(p_class)) {
1399 c = ClassDB::instance(p_class);
1400 cleanup_c = true;
1401 }
1402
1403 if (c) {
1404
1405 List<PropertyInfo> plist;
1406 c->get_property_list(&plist);
1407 for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
1408 if (E->get().usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR)) {
1409
1410 if (!default_values[p_class].has(E->get().name)) {
1411 Variant v = c->get(E->get().name);
1412 default_values[p_class][E->get().name] = v;
1413 }
1414 }
1415 }
1416
1417 if (cleanup_c) {
1418 memdelete(c);
1419 }
1420 }
1421
1422 default_values_cached.insert(p_class);
1423 }
1424
1425 if (!default_values.has(p_class)) {
1426 if (r_valid != NULL) *r_valid = false;
1427 return Variant();
1428 }
1429
1430 if (!default_values[p_class].has(p_property)) {
1431 if (r_valid != NULL) *r_valid = false;
1432 return Variant();
1433 }
1434
1435 if (r_valid != NULL) *r_valid = true;
1436 return default_values[p_class][p_property];
1437 }
1438
1439 RWLock *ClassDB::lock = NULL;
1440
1441 void ClassDB::init() {
1442
1443 lock = RWLock::create();
1444 }
1445
1446 void ClassDB::cleanup_defaults() {
1447
1448 default_values.clear();
1449 default_values_cached.clear();
1450 }
1451
1452 void ClassDB::cleanup() {
1453
1454 //OBJTYPE_LOCK; hah not here
1455
1456 const StringName *k = NULL;
1457
1458 while ((k = classes.next(k))) {
1459
1460 ClassInfo &ti = classes[*k];
1461
1462 const StringName *m = NULL;
1463 while ((m = ti.method_map.next(m))) {
1464
1465 memdelete(ti.method_map[*m]);
1466 }
1467 }
1468 classes.clear();
1469 resource_base_extensions.clear();
1470 compat_classes.clear();
1471
1472 memdelete(lock);
1473 }
1474
1475 //
1476