|
@@ -181,6 +181,10 @@ def generate_bindings(api_filepath, use_template_get_node, bits="64", precision=
|
|
|
generate_utility_functions(api, target_dir)
|
|
|
|
|
|
|
|
|
+CLASS_ALIASES = {
|
|
|
+ "ClassDB": "ClassDBSingleton",
|
|
|
+}
|
|
|
+
|
|
|
builtin_classes = []
|
|
|
|
|
|
# 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):
|
|
|
# First create map of classes and singletons.
|
|
|
for class_api in api["classes"]:
|
|
|
# Generate code for the ClassDB singleton under a different name.
|
|
|
- if class_api["name"] == "ClassDB":
|
|
|
- class_api["name"] = "ClassDBSingleton"
|
|
|
- class_api["alias_for"] = "ClassDB"
|
|
|
+ if class_api["name"] in CLASS_ALIASES:
|
|
|
+ class_api["alias_for"] = class_api["name"]
|
|
|
+ class_api["name"] = CLASS_ALIASES[class_api["alias_for"]]
|
|
|
engine_classes[class_api["name"]] = class_api["is_refcounted"]
|
|
|
for native_struct in api["native_structures"]:
|
|
|
if native_struct["name"] == "ObjectID":
|
|
@@ -1139,9 +1143,9 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
|
|
|
|
|
|
for singleton in api["singletons"]:
|
|
|
# Generate code for the ClassDB singleton under a different name.
|
|
|
- if singleton["name"] == "ClassDB":
|
|
|
- singleton["name"] = "ClassDBSingleton"
|
|
|
- singleton["alias_for"] = "ClassDB"
|
|
|
+ if singleton["name"] in CLASS_ALIASES:
|
|
|
+ singleton["alias_for"] = singleton["name"]
|
|
|
+ singleton["name"] = CLASS_ALIASES[singleton["name"]]
|
|
|
singletons.append(singleton["name"])
|
|
|
|
|
|
for class_api in api["classes"]:
|
|
@@ -1346,6 +1350,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
|
|
result.append("#include <type_traits>")
|
|
|
result.append("")
|
|
|
|
|
|
+ if class_name == "ClassDBSingleton":
|
|
|
+ result.append("#include <godot_cpp/core/binder_common.hpp>")
|
|
|
+ result.append("")
|
|
|
+
|
|
|
result.append("namespace godot {")
|
|
|
result.append("")
|
|
|
|
|
@@ -1367,6 +1375,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
|
|
result.append(f"\tGDEXTENSION_CLASS({class_name}, {inherits})")
|
|
|
result.append("")
|
|
|
|
|
|
+ if is_singleton:
|
|
|
+ result.append(f"\tstatic {class_name} *singleton;")
|
|
|
+ result.append("")
|
|
|
+
|
|
|
result.append("public:")
|
|
|
result.append("")
|
|
|
|
|
@@ -1447,6 +1459,11 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
|
|
|
|
|
result.append("\t}")
|
|
|
result.append("")
|
|
|
+
|
|
|
+ if is_singleton:
|
|
|
+ result.append(f"\t~{class_name}();")
|
|
|
+ result.append("")
|
|
|
+
|
|
|
result.append("public:")
|
|
|
|
|
|
# Special cases.
|
|
@@ -1504,6 +1521,19 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
|
|
|
|
|
if class_name == "ClassDBSingleton":
|
|
|
result.append("#define CLASSDB_SINGLETON_FORWARD_METHODS \\")
|
|
|
+
|
|
|
+ if "enums" in class_api:
|
|
|
+ for enum_api in class_api["enums"]:
|
|
|
+ if enum_api["is_bitfield"]:
|
|
|
+ result.append(f'\tenum {enum_api["name"]} : uint64_t {{ \\')
|
|
|
+ else:
|
|
|
+ result.append(f'\tenum {enum_api["name"]} {{ \\')
|
|
|
+
|
|
|
+ for value in enum_api["values"]:
|
|
|
+ result.append(f'\t\t{value["name"]} = {value["value"]}, \\')
|
|
|
+ result.append("\t}; \\")
|
|
|
+ result.append("\t \\")
|
|
|
+
|
|
|
for method in class_api["methods"]:
|
|
|
# ClassDBSingleton shouldn't have any static or vararg methods, but if some appear later, lets skip them.
|
|
|
if vararg:
|
|
@@ -1512,12 +1542,17 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
|
|
continue
|
|
|
|
|
|
method_signature = "\tstatic "
|
|
|
+ return_type = None
|
|
|
if "return_type" in method:
|
|
|
- method_signature += f'{correct_type(method["return_type"])} '
|
|
|
+ return_type = correct_type(method["return_type"].replace("ClassDBSingleton", "ClassDB"), None, False)
|
|
|
elif "return_value" in method:
|
|
|
- method_signature += (
|
|
|
- correct_type(method["return_value"]["type"], method["return_value"].get("meta", None)) + " "
|
|
|
+ return_type = correct_type(
|
|
|
+ method["return_value"]["type"].replace("ClassDBSingleton", "ClassDB"),
|
|
|
+ method["return_value"].get("meta", None),
|
|
|
+ False,
|
|
|
)
|
|
|
+ if return_type is not None:
|
|
|
+ method_signature += return_type + " "
|
|
|
else:
|
|
|
method_signature += "void "
|
|
|
|
|
@@ -1536,8 +1571,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
|
|
result.append(method_signature)
|
|
|
|
|
|
method_body = "\t\t"
|
|
|
- if "return_type" in method or "return_value" in method:
|
|
|
+ if return_type is not None:
|
|
|
method_body += "return "
|
|
|
+ if "alias_for" in class_api and return_type.startswith(class_api["alias_for"] + "::"):
|
|
|
+ method_body += f"({return_type})"
|
|
|
method_body += f'ClassDBSingleton::get_singleton()->{method["name"]}('
|
|
|
method_body += ", ".join(map(lambda x: escape_identifier(x["name"]), method_arguments))
|
|
|
method_body += "); \\"
|
|
@@ -1547,6 +1584,18 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
|
|
result.append("\t;")
|
|
|
result.append("")
|
|
|
|
|
|
+ result.append("#define CLASSDB_SINGLETON_VARIANT_CAST \\")
|
|
|
+
|
|
|
+ if "enums" in class_api:
|
|
|
+ for enum_api in class_api["enums"]:
|
|
|
+ if enum_api["is_bitfield"]:
|
|
|
+ result.append(f'\tVARIANT_BITFIELD_CAST({class_api["alias_for"]}::{enum_api["name"]}); \\')
|
|
|
+ else:
|
|
|
+ result.append(f'\tVARIANT_ENUM_CAST({class_api["alias_for"]}::{enum_api["name"]}); \\')
|
|
|
+
|
|
|
+ result.append("\t;")
|
|
|
+ result.append("")
|
|
|
+
|
|
|
result.append(f"#endif // ! {header_guard}")
|
|
|
|
|
|
return "\n".join(result)
|
|
@@ -1564,6 +1613,7 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
|
|
|
|
|
|
result.append(f"#include <godot_cpp/classes/{snake_class_name}.hpp>")
|
|
|
result.append("")
|
|
|
+ result.append("#include <godot_cpp/core/class_db.hpp>")
|
|
|
result.append("#include <godot_cpp/core/engine_ptrcall.hpp>")
|
|
|
result.append("#include <godot_cpp/core/error_macros.hpp>")
|
|
|
result.append("")
|
|
@@ -1578,9 +1628,10 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
|
|
|
result.append("")
|
|
|
|
|
|
if is_singleton:
|
|
|
+ result.append(f"{class_name} *{class_name}::singleton = nullptr;")
|
|
|
+ result.append("")
|
|
|
result.append(f"{class_name} *{class_name}::get_singleton() {{")
|
|
|
# We assume multi-threaded access is OK because each assignment will assign the same value every time
|
|
|
- result.append(f"\tstatic {class_name} *singleton = nullptr;")
|
|
|
result.append("\tif (unlikely(singleton == nullptr)) {")
|
|
|
result.append(
|
|
|
f"\t\tGDExtensionObjectPtr 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
|
|
|
result.append("#ifdef DEBUG_ENABLED")
|
|
|
result.append("\t\tERR_FAIL_NULL_V(singleton, nullptr);")
|
|
|
result.append("#endif // DEBUG_ENABLED")
|
|
|
+ result.append("\t\tif (likely(singleton)) {")
|
|
|
+ result.append(f"\t\t\tClassDB::_register_engine_singleton({class_name}::get_class_static(), singleton);")
|
|
|
+ result.append("\t\t}")
|
|
|
result.append("\t}")
|
|
|
result.append("\treturn singleton;")
|
|
|
result.append("}")
|
|
|
result.append("")
|
|
|
|
|
|
+ result.append(f"{class_name}::~{class_name}() {{")
|
|
|
+ result.append("\tif (singleton == this) {")
|
|
|
+ result.append(f"\t\tClassDB::_unregister_engine_singleton({class_name}::get_class_static());")
|
|
|
+ result.append("\t\tsingleton = nullptr;")
|
|
|
+ result.append("\t}")
|
|
|
+ result.append("}")
|
|
|
+ result.append("")
|
|
|
+
|
|
|
if "methods" in class_api:
|
|
|
for method in class_api["methods"]:
|
|
|
if method["is_virtual"]:
|
|
@@ -2384,7 +2446,7 @@ def correct_typed_array(type_name):
|
|
|
return type_name
|
|
|
|
|
|
|
|
|
-def correct_type(type_name, meta=None):
|
|
|
+def correct_type(type_name, meta=None, use_alias=True):
|
|
|
type_conversion = {"float": "double", "int": "int64_t", "Nil": "Variant"}
|
|
|
if meta != None:
|
|
|
if "int" in meta:
|
|
@@ -2400,11 +2462,15 @@ def correct_type(type_name, meta=None):
|
|
|
if is_enum(type_name):
|
|
|
if is_bitfield(type_name):
|
|
|
base_class = get_enum_class(type_name)
|
|
|
+ if use_alias and base_class in CLASS_ALIASES:
|
|
|
+ base_class = CLASS_ALIASES[base_class]
|
|
|
if base_class == "GlobalConstants":
|
|
|
return f"BitField<{get_enum_name(type_name)}>"
|
|
|
return f"BitField<{base_class}::{get_enum_name(type_name)}>"
|
|
|
else:
|
|
|
base_class = get_enum_class(type_name)
|
|
|
+ if use_alias and base_class in CLASS_ALIASES:
|
|
|
+ base_class = CLASS_ALIASES[base_class]
|
|
|
if base_class == "GlobalConstants":
|
|
|
return f"{get_enum_name(type_name)}"
|
|
|
return f"{base_class}::{get_enum_name(type_name)}"
|