@@ -181,6 +181,10 @@ def generate_bindings(api_filepath, use_template_get_node, bits="64", precision=
181
181
generate_utility_functions (api , target_dir )
182
182
183
183
184
+ CLASS_ALIASES = {
185
+ "ClassDB" : "ClassDBSingleton" ,
186
+ }
187
+
184
188
builtin_classes = []
185
189
186
190
# Key is class name, value is boolean where True means the class is refcounted.
@@ -1127,9 +1131,9 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
1127
1131
# First create map of classes and singletons.
1128
1132
for class_api in api ["classes" ]:
1129
1133
# Generate code for the ClassDB singleton under a different name.
1130
- if class_api ["name" ] == "ClassDB" :
1131
- class_api ["name " ] = "ClassDBSingleton"
1132
- class_api ["alias_for " ] = "ClassDB"
1134
+ if class_api ["name" ] in CLASS_ALIASES :
1135
+ class_api ["alias_for " ] = class_api [ "name" ]
1136
+ class_api ["name " ] = CLASS_ALIASES [ class_api [ "alias_for" ]]
1133
1137
engine_classes [class_api ["name" ]] = class_api ["is_refcounted" ]
1134
1138
for native_struct in api ["native_structures" ]:
1135
1139
if native_struct ["name" ] == "ObjectID" :
@@ -1139,9 +1143,9 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
1139
1143
1140
1144
for singleton in api ["singletons" ]:
1141
1145
# Generate code for the ClassDB singleton under a different name.
1142
- if singleton ["name" ] == "ClassDB" :
1143
- singleton ["name " ] = "ClassDBSingleton"
1144
- singleton ["alias_for " ] = "ClassDB"
1146
+ if singleton ["name" ] in CLASS_ALIASES :
1147
+ singleton ["alias_for " ] = singleton [ "name" ]
1148
+ singleton ["name " ] = CLASS_ALIASES [ singleton [ "name" ]]
1145
1149
singletons .append (singleton ["name" ])
1146
1150
1147
1151
for class_api in api ["classes" ]:
@@ -1346,6 +1350,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
1346
1350
result .append ("#include <type_traits>" )
1347
1351
result .append ("" )
1348
1352
1353
+ if class_name == "ClassDBSingleton" :
1354
+ result .append ("#include <godot_cpp/core/binder_common.hpp>" )
1355
+ result .append ("" )
1356
+
1349
1357
result .append ("namespace godot {" )
1350
1358
result .append ("" )
1351
1359
@@ -1367,6 +1375,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
1367
1375
result .append (f"\t GDEXTENSION_CLASS({ class_name } , { inherits } )" )
1368
1376
result .append ("" )
1369
1377
1378
+ if is_singleton :
1379
+ result .append (f"\t static { class_name } *singleton;" )
1380
+ result .append ("" )
1381
+
1370
1382
result .append ("public:" )
1371
1383
result .append ("" )
1372
1384
@@ -1447,6 +1459,11 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
1447
1459
1448
1460
result .append ("\t }" )
1449
1461
result .append ("" )
1462
+
1463
+ if is_singleton :
1464
+ result .append (f"\t ~{ class_name } ();" )
1465
+ result .append ("" )
1466
+
1450
1467
result .append ("public:" )
1451
1468
1452
1469
# Special cases.
@@ -1504,6 +1521,19 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
1504
1521
1505
1522
if class_name == "ClassDBSingleton" :
1506
1523
result .append ("#define CLASSDB_SINGLETON_FORWARD_METHODS \\ " )
1524
+
1525
+ if "enums" in class_api :
1526
+ for enum_api in class_api ["enums" ]:
1527
+ if enum_api ["is_bitfield" ]:
1528
+ result .append (f'\t enum { enum_api ["name" ]} : uint64_t {{ \\ ' )
1529
+ else :
1530
+ result .append (f'\t enum { enum_api ["name" ]} {{ \\ ' )
1531
+
1532
+ for value in enum_api ["values" ]:
1533
+ result .append (f'\t \t { value ["name" ]} = { value ["value" ]} , \\ ' )
1534
+ result .append ("\t }; \\ " )
1535
+ result .append ("\t \\ " )
1536
+
1507
1537
for method in class_api ["methods" ]:
1508
1538
# ClassDBSingleton shouldn't have any static or vararg methods, but if some appear later, lets skip them.
1509
1539
if vararg :
@@ -1512,12 +1542,17 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
1512
1542
continue
1513
1543
1514
1544
method_signature = "\t static "
1545
+ return_type = None
1515
1546
if "return_type" in method :
1516
- method_signature += f' { correct_type (method ["return_type" ]) } '
1547
+ return_type = correct_type (method ["return_type" ]. replace ( "ClassDBSingleton" , "ClassDB" ), None , False )
1517
1548
elif "return_value" in method :
1518
- method_signature += (
1519
- correct_type (method ["return_value" ]["type" ], method ["return_value" ].get ("meta" , None )) + " "
1549
+ return_type = correct_type (
1550
+ method ["return_value" ]["type" ].replace ("ClassDBSingleton" , "ClassDB" ),
1551
+ method ["return_value" ].get ("meta" , None ),
1552
+ False ,
1520
1553
)
1554
+ if return_type is not None :
1555
+ method_signature += return_type + " "
1521
1556
else :
1522
1557
method_signature += "void "
1523
1558
@@ -1536,8 +1571,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
1536
1571
result .append (method_signature )
1537
1572
1538
1573
method_body = "\t \t "
1539
- if " return_type" in method or "return_value" in method :
1574
+ if return_type is not None :
1540
1575
method_body += "return "
1576
+ if "alias_for" in class_api and return_type .startswith (class_api ["alias_for" ] + "::" ):
1577
+ method_body += f"({ return_type } )"
1541
1578
method_body += f'ClassDBSingleton::get_singleton()->{ method ["name" ]} ('
1542
1579
method_body += ", " .join (map (lambda x : escape_identifier (x ["name" ]), method_arguments ))
1543
1580
method_body += "); \\ "
@@ -1547,6 +1584,18 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
1547
1584
result .append ("\t ;" )
1548
1585
result .append ("" )
1549
1586
1587
+ result .append ("#define CLASSDB_SINGLETON_VARIANT_CAST \\ " )
1588
+
1589
+ if "enums" in class_api :
1590
+ for enum_api in class_api ["enums" ]:
1591
+ if enum_api ["is_bitfield" ]:
1592
+ result .append (f'\t VARIANT_BITFIELD_CAST({ class_api ["alias_for" ]} ::{ enum_api ["name" ]} ); \\ ' )
1593
+ else :
1594
+ result .append (f'\t VARIANT_ENUM_CAST({ class_api ["alias_for" ]} ::{ enum_api ["name" ]} ); \\ ' )
1595
+
1596
+ result .append ("\t ;" )
1597
+ result .append ("" )
1598
+
1550
1599
result .append (f"#endif // ! { header_guard } " )
1551
1600
1552
1601
return "\n " .join (result )
@@ -1564,6 +1613,7 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
1564
1613
1565
1614
result .append (f"#include <godot_cpp/classes/{ snake_class_name } .hpp>" )
1566
1615
result .append ("" )
1616
+ result .append ("#include <godot_cpp/core/class_db.hpp>" )
1567
1617
result .append ("#include <godot_cpp/core/engine_ptrcall.hpp>" )
1568
1618
result .append ("#include <godot_cpp/core/error_macros.hpp>" )
1569
1619
result .append ("" )
@@ -1578,9 +1628,10 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
1578
1628
result .append ("" )
1579
1629
1580
1630
if is_singleton :
1631
+ result .append (f"{ class_name } *{ class_name } ::singleton = nullptr;" )
1632
+ result .append ("" )
1581
1633
result .append (f"{ class_name } *{ class_name } ::get_singleton() {{" )
1582
1634
# We assume multi-threaded access is OK because each assignment will assign the same value every time
1583
- result .append (f"\t static { class_name } *singleton = nullptr;" )
1584
1635
result .append ("\t if (unlikely(singleton == nullptr)) {" )
1585
1636
result .append (
1586
1637
f"\t \t GDExtensionObjectPtr singleton_obj = internal::gdextension_interface_global_get_singleton({ class_name } ::get_class_static()._native_ptr());"
@@ -1594,11 +1645,22 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
1594
1645
result .append ("#ifdef DEBUG_ENABLED" )
1595
1646
result .append ("\t \t ERR_FAIL_NULL_V(singleton, nullptr);" )
1596
1647
result .append ("#endif // DEBUG_ENABLED" )
1648
+ result .append ("\t \t if (likely(singleton)) {" )
1649
+ result .append (f"\t \t \t ClassDB::_register_engine_singleton({ class_name } ::get_class_static(), singleton);" )
1650
+ result .append ("\t \t }" )
1597
1651
result .append ("\t }" )
1598
1652
result .append ("\t return singleton;" )
1599
1653
result .append ("}" )
1600
1654
result .append ("" )
1601
1655
1656
+ result .append (f"{ class_name } ::~{ class_name } () {{" )
1657
+ result .append ("\t if (singleton == this) {" )
1658
+ result .append (f"\t \t ClassDB::_unregister_engine_singleton({ class_name } ::get_class_static());" )
1659
+ result .append ("\t \t singleton = nullptr;" )
1660
+ result .append ("\t }" )
1661
+ result .append ("}" )
1662
+ result .append ("" )
1663
+
1602
1664
if "methods" in class_api :
1603
1665
for method in class_api ["methods" ]:
1604
1666
if method ["is_virtual" ]:
@@ -2384,7 +2446,7 @@ def correct_typed_array(type_name):
2384
2446
return type_name
2385
2447
2386
2448
2387
- def correct_type (type_name , meta = None ):
2449
+ def correct_type (type_name , meta = None , use_alias = True ):
2388
2450
type_conversion = {"float" : "double" , "int" : "int64_t" , "Nil" : "Variant" }
2389
2451
if meta != None :
2390
2452
if "int" in meta :
@@ -2400,11 +2462,15 @@ def correct_type(type_name, meta=None):
2400
2462
if is_enum (type_name ):
2401
2463
if is_bitfield (type_name ):
2402
2464
base_class = get_enum_class (type_name )
2465
+ if use_alias and base_class in CLASS_ALIASES :
2466
+ base_class = CLASS_ALIASES [base_class ]
2403
2467
if base_class == "GlobalConstants" :
2404
2468
return f"BitField<{ get_enum_name (type_name )} >"
2405
2469
return f"BitField<{ base_class } ::{ get_enum_name (type_name )} >"
2406
2470
else :
2407
2471
base_class = get_enum_class (type_name )
2472
+ if use_alias and base_class in CLASS_ALIASES :
2473
+ base_class = CLASS_ALIASES [base_class ]
2408
2474
if base_class == "GlobalConstants" :
2409
2475
return f"{ get_enum_name (type_name )} "
2410
2476
return f"{ base_class } ::{ get_enum_name (type_name )} "
0 commit comments