-
Notifications
You must be signed in to change notification settings - Fork 1
/
Typer.gd
690 lines (577 loc) · 21.7 KB
/
Typer.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
tool
class_name PressAccept_Typer_Typer
# |=========================================|
# | |
# | Press Accept: Typer |
# | Generalized Type Testing In Godot |
# | |
# |=========================================|
#
# This module provides functions to determine/evaluate GDScript types.
#
# Even though GDScript is a dynamically typed language, sometimes we'd like to
# know about a variable's type and even compare/process that type. These
# utility functions utilize various means to determine a variable's type,
# from determining if it's a built-in type, to a built-in class (such as Node),
# to a custom script (attached/unattached to a node). Information on these
# three different sorts of type information come from different sources. These
# static functions hope to make sorting through these layers more intuitive and
# easy.
#
# The idea is that we normalize type values to 'cascade' against these layers.
# Retrieving each layer separately is achievable through existing GDScript
# functions, but returning the most specific information (if it has a script,
# that script, if it's a built-in class, that class, or if its a primitive, the
# primitive) given any particular value, and comparing that information is
# unique to this library.
#
# The "layers" of type are as follows:
#
# A built-in primitive type, unrelated to the next two, identified ultimately
# by an integer constant (here translated into a string constant).
#
# A built in class derived from (or is) Object, these are only identified by
# strings as their class name.
#
# A script that may or may not identify a class that may or may not inherit
# from classes defined in other scripts. These are only identified by strings
# but unlike classes, they are always identified by their resource path:
# res://.... (some script have class_names, some don't)
#
# Inner classes in this system will return the string version of their base
# class if they don't inherit from another script, otherwise they'll return a
# script path, like other objects. You can customize the inner classes value
# that's returned for its type by using a custom method with an identifier
# equivalent to STR_CUSTOM_CLASS_METHOD (__class_name)
#
# |------------------|
# | Meta Information |
# |------------------|
#
# Organization Namespace : PressAccept
# Package Namespace : Typer
# Class : Typer
#
# Organization : Press Accept
# Organization URI : https://pressaccept.com/
# Organization Social : @pressaccept
#
# Author : Asher Kadar Wolfstein
# Author URI : https://wunk.me/ (Personal Blog)
# Author Social : https://incarnate.me/members/asherwolfstein/
# @asherwolfstein (Twitter)
# https://ko-fi.com/asherwolfstein
#
# Copyright : Press Accept: Typer © 2021 The Novelty Factor LLC
# (Press Accept, Asher Kadar Wolfstein)
# License : MIT (see LICENSE)
#
# |-----------|
# | Changelog |
# |-----------|
#
# 1.0.0 06/04/2021 First Release
# 1.0.1 06/05/2021 Added STR_INDEXABLE_METHOD as method name
# 2.0.0 12/18/2021 Removed STR_INDEXABLE functionality
# To verify indexable,
# just use method STR_INDEXABLE_METHOD
# Added get_type_inheritance
# (type compatibility uses this now)
# get_type_methods
# get_type_method_names
# Changed STR_CUSTOM_CLASS to STR_CUSTOM_CLASS_METHOD
# get_type now expects a method return value
# 2.1.0 12/29/2021 Added STR_SET_INDEXABLE_METHOD
# STR_SET_INDEXABLE_BY_METHOD
# STR_INDICES_METHOD
# set_indexable_by
# set_indexable
# get_indices
#
# ****************
# | Enumerations |
# ****************
# Custom enumeration of built-in TYPE_* enumeration
enum ENUM_TYPES {
NULL, # 0 - TYPE_NIL
BOOL, # 1 - TYPE_BOOL
INT, # 2 - TYPE_INT
FLOAT, # 3 - TYPE_REAL
STRING, # 4 - TYPE_STRING
VECTOR2, # 5 - TYPE_VECTOR2
RECT2, # 6 - TYPE_RECT2
VECTOR3, # 7 - TYPE_VECTOR3
TRANSFORM2D, # 8 - TYPE_TRANSFORM2D
PLANE, # 9 - TYPE_PLANE
QUAT, # 10 - TYPE_QUAT
AABBOX, # 11 - TYPE_AABB
BASIS, # 12 - TYPE_BASIS
TRANSFORM, # 13 - TYPE_TRANSFORM
COLOR, # 14 - TYPE_COLOR
NODEPATH, # 15 - TYPE_NODEPATH
RESID, # 16 - TYPE_RID
OBJECT, # 17 - TYPE_OBJECT
DICT, # 18 - TYPE_DICTIONARY
ARRAY, # 19 - TYPE_ARRAY
BYTEARRAY, # 20 - TYPE_RAW_ARRAY
INTARRAY, # 21 - TYPE_INT_ARRAY
FLOATARRAY, # 22 - TYPE_REAL_ARRAY
STRINGARRAY, # 23 - TYPE_STRING_ARRAY
VECTOR2ARRAY, # 24 - TYPE_VECTOR2_ARRAY
VECTOR3ARRAY, # 25 - TYPE_VECTOR3_ARRAY
COLORARRAY # 26 - TYPE_COLOR_ARRAY
}
# *************
# | Constants |
# *************
# String representations of built-in types
const STR_NULL : String = 'Null'
const STR_BOOL : String = 'Boolean'
const STR_INT : String = 'Integer'
const STR_FLOAT : String = 'Float'
const STR_STRING : String = 'String'
const STR_VECTOR2 : String = 'Vector2'
const STR_RECT2 : String = 'Rectangle2'
const STR_VECTOR3 : String = 'Vector3'
const STR_TRANSFORM2D : String = 'Transform2D'
const STR_PLANE : String = 'Plane'
const STR_QUAT : String = 'Quaternion'
const STR_AABBOX : String = 'Axis Aligned Bounding Box'
const STR_BASIS : String = 'Basis'
const STR_TRANSFORM : String = 'Transform'
const STR_COLOR : String = 'Color'
const STR_NODEPATH : String = 'Node Path'
const STR_RESID : String = 'Resource ID'
const STR_OBJECT : String = 'Object'
const STR_DICT : String = 'Dictionary'
const STR_ARRAY : String = 'Array'
const STR_BYTEARRAY : String = 'Pool Byte Array'
const STR_INTARRAY : String = 'Pool Int Array'
const STR_FLOATARRAY : String = 'Pool Real Array'
const STR_STRINGARRAY : String = 'Pool String Array'
const STR_VECTOR2ARRAY : String = 'Pool Vector2 Array'
const STR_VECTOR3ARRAY : String = 'Pool Vector3 Array'
const STR_COLORARRAY : String = 'Pool Color Array'
const STR_UNKNOWN : String = 'Unknown'
# Method defined on an inner class that returns custom (inner) class name
const STR_CUSTOM_CLASS_METHOD : String = '__class_name'
# method defined on a script that returns a value that is indexable
#
# indexable means the returned value can be accessed with []
#
# In 1.0 we used STR_INDEXABLE (: String = 'INDEXABLE') as a constant on a
# script to determine if that script supported being indexable. Since any
# script that provides a STR_INDEXABLE_METHOD method is thus indexable, the
# constant is not needed, we can simply test for the presence of the method
const STR_INDEXABLE_METHOD : String = '__indexable'
# sets the indexable value
const STR_SET_INDEXABLE_METHOD : String = '__set_indexable'
# sets an index in the indexable value
const STR_SET_INDEXABLE_BY_METHOD : String = '__set_indexable_by'
# returns the values that can be used to index
const STR_INDICES_METHOD : String = '__indices'
# String's equivalent to ENUM_TYPES labels
const ARR_TYPES_ENUM: Array = [
'NULL', # 0 - TYPE_NIL
'BOOL', # 1 - TYPE_BOOL
'INT', # 2 - TYPE_INT
'FLOAT', # 3 - TYPE_REAL
'STRING', # 4 - TYPE_STRING
'VECTOR2', # 5 - TYPE_VECTOR2
'RECT2', # 6 - TYPE_RECT2
'VECTOR3', # 7 - TYPE_VECTOR3
'TRANSFORM2D', # 8 - TYPE_TRANSFORM2D
'PLANE', # 9 - TYPE_PLANE
'QUAT', # 10 - TYPE_QUAT
'AABBOX', # 11 - TYPE_AABB
'BASIS', # 12 - TYPE_BASIS
'TRANSFORM', # 13 - TYPE_TRANSFORM
'COLOR', # 14 - TYPE_COLOR
'NODEPATH', # 15 - TYPE_NODEPATH
'RESID', # 16 - TYPE_RID
'OBJECT', # 17 - TYPE_OBJECT
'DICT', # 18 - TYPE_DICTIONARY
'ARRAY', # 19 - TYPE_ARRAY
'BYTEARRAY', # 20 - TYPE_RAW_ARRAY
'INTARRAY', # 21 - TYPE_INT_ARRAY
'FLOATARRAY', # 22 - TYPE_REAL_ARRAY
'STRINGARRAY', # 23 - TYPE_STRING_ARRAY
'VECTOR2ARRAY', # 24 - TYPE_VECTOR2_ARRAY
'VECTOR3ARRAY', # 25 - TYPE_VECTOR3_ARRAY
'COLORARRAY' # 26 - TYPE_COLOR_ARRAY
]
# Map indices (ENUM_TYPE) to strings
const ARR_TYPES: Array = [
STR_NULL, # 0 - TYPE_NIL
STR_BOOL, # 1 - TYPE_BOOL
STR_INT, # 2 - TYPE_INT
STR_FLOAT, # 3 - TYPE_REAL
STR_STRING, # 4 - TYPE_STRING
STR_VECTOR2, # 5 - TYPE_VECTOR2
STR_RECT2, # 6 - TYPE_RECT2
STR_VECTOR3, # 7 - TYPE_VECTOR3
STR_TRANSFORM2D, # 8 - TYPE_TRANSFORM2D
STR_PLANE, # 9 - TYPE_PLANE
STR_QUAT, # 10 - TYPE_QUAT
STR_AABBOX, # 11 - TYPE_AABB
STR_BASIS, # 12 - TYPE_BASIS
STR_TRANSFORM, # 13 - TYPE_TRANSFORM
STR_COLOR, # 14 - TYPE_COLOR
STR_NODEPATH, # 15 - TYPE_NODEPATH
STR_RESID, # 16 - TYPE_RID
STR_OBJECT, # 17 - TYPE_OBJECT
STR_DICT, # 18 - TYPE_DICTIONARY
STR_ARRAY, # 19 - TYPE_ARRAY
STR_BYTEARRAY, # 20 - TYPE_RAW_ARRAY
STR_INTARRAY, # 21 - TYPE_INT_ARRAY
STR_FLOATARRAY, # 22 - TYPE_REAL_ARRAY
STR_STRINGARRAY, # 23 - TYPE_STRING_ARRAY
STR_VECTOR2ARRAY, # 24 - TYPE_VECTOR2_ARRAY
STR_VECTOR3ARRAY, # 25 - TYPE_VECTOR3_ARRAY
STR_COLORARRAY # 26 - TYPE_COLOR_ARRAY
]
# types that have no callable methods or constants
const DICT_PRIMITIVES: Dictionary = {
ENUM_TYPES.NULL : STR_NULL,
ENUM_TYPES.BOOL : STR_BOOL,
ENUM_TYPES.INT : STR_INT,
ENUM_TYPES.FLOAT : STR_FLOAT
}
# types that are castable to other types
const DICT_CASTABLE: Dictionary = {
ENUM_TYPES.BOOL : STR_BOOL,
ENUM_TYPES.INT : STR_INT,
ENUM_TYPES.FLOAT : STR_FLOAT,
ENUM_TYPES.STRING : STR_STRING
}
# types that are indexable
const DICT_INDEXABLE: Dictionary = {
ENUM_TYPES.STRING : STR_STRING,
ENUM_TYPES.OBJECT : STR_OBJECT,
ENUM_TYPES.ARRAY : STR_ARRAY,
ENUM_TYPES.DICT : STR_DICT,
ENUM_TYPES.BYTEARRAY : STR_BYTEARRAY,
ENUM_TYPES.INTARRAY : STR_INTARRAY,
ENUM_TYPES.FLOATARRAY : STR_FLOATARRAY,
ENUM_TYPES.STRINGARRAY : STR_STRINGARRAY,
ENUM_TYPES.VECTOR2ARRAY : STR_VECTOR2ARRAY,
ENUM_TYPES.VECTOR3ARRAY : STR_VECTOR3ARRAY,
ENUM_TYPES.COLORARRAY : STR_COLORARRAY
}
# ***************************
# | Public Static Functions |
# ***************************
# Convert type enumeration to string representation
static func type2str(
type_code: int) -> String:
if type_code < 0 or type_code >= ARR_TYPES.size():
return STR_UNKNOWN
return ARR_TYPES[type_code]
# Convert string representation to enum integer
static func str2type(
type_str: String) -> int:
if type_str.begins_with('res://'):
return TYPE_OBJECT
type_str = type_str.to_upper()
for i in range(ARR_TYPES.size()):
if type_str == ARR_TYPES[i].to_upper():
return i
if type_str == ARR_TYPES_ENUM[i]:
return i
return -1
# normalizes an int or String to String constant
static func normalize_type_to_str(
type) -> String: # int | String
match typeof(type):
TYPE_INT:
return type2str(type)
TYPE_STRING:
return type2str(str2type(type))
return STR_UNKNOWN
# normalizes an int or String to an enumeration value
static func normalize_type_to_int(
type) -> int: # int | String
match typeof(type):
TYPE_INT:
if type in range(ARR_TYPES.size()):
return type
TYPE_STRING:
return str2type(type)
return -1
# returns true if the type has no methods or constants
static func is_primitive(
type) -> bool: # int | String
type = normalize_type_to_int(type)
return type in DICT_PRIMITIVES
# returns trye if the type is castable to other built-in types
static func is_castable(
type) -> bool: # int | String
type = normalize_type_to_int(type)
return type in DICT_CASTABLE
# returns true if the type is indexable via [] (Arrays, Dicts, Objects...)
static func is_indexable(
type) -> bool: # int | String | Script
if typeof(type) == ENUM_TYPES.STRING and type.begins_with('res://') \
or type is Script:
var methods: Array = get_type_method_names(type)
if STR_INDEXABLE_METHOD in methods:
return true
type = normalize_type_to_int(type)
return type in DICT_INDEXABLE
# return the indexable value from a given instance
static func get_indexable(
instance: Object):
if instance is Object and instance.has_method(STR_INDEXABLE_METHOD):
return instance.call(STR_INDEXABLE_METHOD)
return null
# sets the indexable value from a given instance
static func set_indexable_by(
instance: Object,
index,
value) -> bool:
if instance is Object and instance.has_method(STR_SET_INDEXABLE_BY_METHOD):
return instance.call(STR_SET_INDEXABLE_BY_METHOD, index, value)
return false
# sets the indexable value from a given instance
static func set_indexable(
instance: Object,
indexable) -> bool:
if instance is Object and instance.has_method(STR_SET_INDEXABLE_METHOD):
return instance.call(STR_SET_INDEXABLE_METHOD, indexable)
return false
# return the indexable 'keys' from a given instance
static func get_indices(
instance: Object) -> Array:
if instance is Object and instance.has_method(STR_INDICES_METHOD):
return instance.call(STR_INDICES_METHOD)
return []
# Convert a type (int, Script, or string) to an identifiable string.
#
# if the type is a script it returns the uniquely identifiable resource path.
# Not to be confused with type2str. This is used elsewhere to normalize type
# information.
static func type_to_str(
type) -> String: # int | String | Script
match typeof(type):
ENUM_TYPES.INT:
return normalize_type_to_str(type)
ENUM_TYPES.STRING:
if not type.begins_with('res://'):
var type_str: String = normalize_type_to_str(type)
# normalize to primitive or built-in class name
return type if type_str == STR_UNKNOWN else type_str
if type is Script:
if type.resource_path:
return type.resource_path
else:
var inheritance = get_type_inheritance(type)
if inheritance:
return inheritance.front()
return type
# Checks if a variant value is of a type (String or Script)
#
# NOTE: string should be a built-in class name or resource path. Strings of
# names of classes (class_name) doesn't work, provide the Script by
# referencing the class_name instead
static func is_type(
variable_value, # any
type) -> bool: # int | String (built-in class name or path) | Script
if not type is Script:
type = type_to_str(type)
if type.begins_with('res://'):
# convert to a script
type = load(type)
else:
if type in ARR_TYPES:
# primitive type
return typeof(variable_value) == ARR_TYPES.find(type)
if typeof(variable_value) == ENUM_TYPES.OBJECT:
# built-in class
return variable_value.is_class(type)
else:
# variable_value isn't a class but not testing for a primitive
return false
# failed load causes type to be null
if type and type is Script:
# is variable_value an instance of this script (does inheritance)
return variable_value is type
# testing for a script but variable_value isn't a script
return false
# Returns a variant's type information as a string
#
# Built-in types are converted to above string constants, built-in classes
# return their class names and Scripts return their resource path.
#
# NOTE: scripts override built-in classes, Script objects return their paths
# If you want a variable's built-in class just use .get_class()
#
# Inner classes return their inherited *built-in* class unless the __class_name
# property has been defined.
static func get_type(
variable_value) -> String:
var type = typeof(variable_value)
if type == TYPE_OBJECT:
if variable_value is Script:
type = variable_value
else:
type = variable_value.get_class()
# do we have a script?
var script = variable_value.get_script()
if script:
# override the class information
if script.resource_path:
# return the Script object defining this variable
type = script
else:
# did this presumably inner class inherit from a script?
var base_script = script.get_base_script()
if base_script is Script and base_script.resource_path:
type = base_script
elif variable_value.has_method(STR_CUSTOM_CLASS_METHOD):
# fall back to custom property
return variable_value.call(STR_CUSTOM_CLASS_METHOD);
return type_to_str(type)
# Builds an inheritance path as an array (base->end) for a given type
static func get_type_inheritance(
type, # String | Script
include_instance_base: bool = false) -> Array:
# we're dealing with potential strings or scripts
var type_str = type_to_str(type) \
if not typeof(type) == ENUM_TYPES.STRING \
else type
var type_arr: Array = []
var base: String = ''
if type_str.begins_with('res://'):
# we're dealing with a script
# build inheritance stack base->end
type = type if type is Script else load(type)
if type.resource_path:
type_arr.push_front(type.resource_path)
var base_script: Script = type.get_base_script()
while base_script:
if base_script.resource_path:
type_arr.push_front(base_script.resource_path)
base_script = base_script.get_base_script()
base = type.get_instance_base_type()
if not include_instance_base:
return type_arr
base = base if base else type_str
while base:
type_arr.push_front(base)
base = ClassDB.get_parent_class(base)
return type_arr
# Collects all methods (dict objects) as an array based on inheritance
static func get_type_methods(
type, # String | Script
include_instance_base: bool = false) -> Array:
if type is String:
if type.begins_with('res://'):
type = load(type)
var methods : Array = []
var method_names : Array = []
if not type is String:
var script_methods: Array = type.get_script_method_list()
for method in script_methods:
if not method['name'] in method_names:
methods.push_back(method)
method_names.push_back(method['name'])
if not include_instance_base:
return methods
type = type.get_instance_base_type()
# we're querying a built-in class
var class_methods: Array = ClassDB.class_get_method_list(type)
for method in class_methods:
if not method['name'] in method_names:
methods.push_back(method)
method_names.push_back(method['name'])
return methods
# Collects all method names as an array based on inheritance
static func get_type_method_names(
type, # String | Script
include_instance_base: bool = false) -> Array:
var methods : Array = get_type_methods(type, include_instance_base)
var method_names : Array = []
for method in methods:
method_names.push_back(method['name'])
return method_names
# Compares two types to see if they are equivalent or have a common ancestor
#
# true means they are the same type or they inherit from an equivalent base
# class. By default this doesn't include the built-in inherited class
# (Reference, Node...) but passing true to include_instance_base will include
# the base class (get_instance_base_type). If you include the built-in
# inherited class the algorithm will test the two classes for inheritance.
#
# NOTE: this compares *types* not variable values, you must retrieve a
# variable's type information prior to using this function
static func types_compatible(
type1,
type2,
include_instance_base = false) -> bool:
# we're dealing with potential integers or scripts
var type1_str: String = type_to_str(type1) \
if not typeof(type1) == ENUM_TYPES.STRING \
else type1
var type2_str: String = type_to_str(type2) \
if not typeof(type2) == ENUM_TYPES.STRING \
else type2
if not type1_str.begins_with('res://') or \
not type2_str.begins_with('res://'):
# at least one type is a built-in class or primitive
if not type1_str.begins_with('res://'):
var type_str: String = normalize_type_to_str(type1_str)
type1_str = type1_str if type_str == STR_UNKNOWN else type_str
if not type2_str.begins_with('res://'):
var type_str: String = normalize_type_to_str(type2_str)
type2_str = type2_str if type_str == STR_UNKNOWN else type_str
if not type1_str in ARR_TYPES and not type2_str in ARR_TYPES:
# normalize to built-in class
if type1_str.begins_with('res://'):
type1_str = load(type1_str).get_instance_base_type() \
if not type1 is Script \
else type1.get_instance_base_type()
if type2_str.begins_with('res://'):
type2_str = load(type2_str).get_instance_base_type() \
if not type2 is Script \
else type2.get_instance_base_type()
# types are built-in classes
return type1_str == type2_str or \
ClassDB.is_parent_class(type1_str, type2_str) or \
ClassDB.is_parent_class(type2_str, type1_str)
# at least one type is a primitive
return type1_str == type2_str
if type1_str.begins_with('res://') and type2_str.begins_with('res://'):
# both types are scripts
type1 = load(type1_str) if not type1 is Script else type1
type2 = load(type2_str) if not type2 is Script else type2
# if this is true we don't have to do the rest
if type1 == type2:
return true
# build inheritance stack base->end
var type1_arr : Array = \
get_type_inheritance(type1, include_instance_base)
var type2_arr : Array = \
get_type_inheritance(type2, include_instance_base)
# test inheritance stack
for i in type1_arr:
for j in type2_arr:
if i == j:
return true
if include_instance_base:
return ClassDB.is_parent_class(type1_arr[0], type2_arr[0]) or \
ClassDB.is_parent_class(type2_arr[0], type1_arr[0])
# failed, or didn't understand the types passed
return false
# Compares to variant's types to each other.
#
# use this function to determine if the values of two variables are of
# compatible types
static func value_types_compatible(
value1,
value2,
include_instance_base = false) -> bool:
return types_compatible(
get_type(value1),
get_type(value2),
include_instance_base
)