Allow forwarding from `ClassDB` to `ClassDBSingleton` to support enumerations

(cherry picked from commit e1b3b32db5)
pull/1466/head
David Snopek 2024-04-23 13:37:43 -05:00
parent 6123c86f06
commit 6328728dc2
2 changed files with 57 additions and 11 deletions

View File

@ -178,6 +178,10 @@ def generate_bindings(api_filepath, use_template_get_node, bits="64", precision=
generate_utility_functions(api, target_dir) generate_utility_functions(api, target_dir)
CLASS_ALIASES = {
"ClassDB": "ClassDBSingleton",
}
builtin_classes = [] builtin_classes = []
# Key is class name, value is boolean where True means the class is refcounted. # Key is class name, value is boolean where True means the class is refcounted.
@ -1079,9 +1083,9 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
# First create map of classes and singletons. # First create map of classes and singletons.
for class_api in api["classes"]: for class_api in api["classes"]:
# Generate code for the ClassDB singleton under a different name. # Generate code for the ClassDB singleton under a different name.
if class_api["name"] == "ClassDB": if class_api["name"] in CLASS_ALIASES:
class_api["name"] = "ClassDBSingleton" class_api["alias_for"] = class_api["name"]
class_api["alias_for"] = "ClassDB" class_api["name"] = CLASS_ALIASES[class_api["alias_for"]]
engine_classes[class_api["name"]] = class_api["is_refcounted"] engine_classes[class_api["name"]] = class_api["is_refcounted"]
for native_struct in api["native_structures"]: for native_struct in api["native_structures"]:
engine_classes[native_struct["name"]] = False engine_classes[native_struct["name"]] = False
@ -1089,9 +1093,9 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
for singleton in api["singletons"]: for singleton in api["singletons"]:
# Generate code for the ClassDB singleton under a different name. # Generate code for the ClassDB singleton under a different name.
if singleton["name"] == "ClassDB": if singleton["name"] in CLASS_ALIASES:
singleton["name"] = "ClassDBSingleton" singleton["alias_for"] = singleton["name"]
singleton["alias_for"] = "ClassDB" singleton["name"] = CLASS_ALIASES[singleton["name"]]
singletons.append(singleton["name"]) singletons.append(singleton["name"])
for class_api in api["classes"]: for class_api in api["classes"]:
@ -1294,6 +1298,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append("#include <type_traits>") result.append("#include <type_traits>")
result.append("") result.append("")
if class_name == "ClassDBSingleton":
result.append("#include <godot_cpp/core/binder_common.hpp>")
result.append("")
result.append("namespace godot {") result.append("namespace godot {")
result.append("") result.append("")
@ -1448,6 +1456,19 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
if class_name == "ClassDBSingleton": if class_name == "ClassDBSingleton":
result.append("#define CLASSDB_SINGLETON_FORWARD_METHODS \\") 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"]: for method in class_api["methods"]:
# ClassDBSingleton shouldn't have any static or vararg methods, but if some appear later, lets skip them. # ClassDBSingleton shouldn't have any static or vararg methods, but if some appear later, lets skip them.
if vararg: if vararg:
@ -1456,12 +1477,17 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
continue continue
method_signature = "\tstatic " method_signature = "\tstatic "
return_type = None
if "return_type" in method: 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: elif "return_value" in method:
method_signature += ( return_type = correct_type(
correct_type(method["return_value"]["type"], method["return_value"].get("meta", None)) + " " 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: else:
method_signature += "void " method_signature += "void "
@ -1480,8 +1506,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append(method_signature) result.append(method_signature)
method_body = "\t\t" method_body = "\t\t"
if "return_type" in method or "return_value" in method: if return_type is not None:
method_body += "return " 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 += f'ClassDBSingleton::get_singleton()->{method["name"]}('
method_body += ", ".join(map(lambda x: escape_identifier(x["name"]), method_arguments)) method_body += ", ".join(map(lambda x: escape_identifier(x["name"]), method_arguments))
method_body += "); \\" method_body += "); \\"
@ -1491,6 +1519,18 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append("\t;") result.append("\t;")
result.append("") 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}") result.append(f"#endif // ! {header_guard}")
return "\n".join(result) return "\n".join(result)
@ -2285,7 +2325,7 @@ def correct_typed_array(type_name):
return 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"} type_conversion = {"float": "double", "int": "int64_t", "Nil": "Variant"}
if meta != None: if meta != None:
if "int" in meta: if "int" in meta:
@ -2301,11 +2341,15 @@ def correct_type(type_name, meta=None):
if is_enum(type_name): if is_enum(type_name):
if is_bitfield(type_name): if is_bitfield(type_name):
base_class = get_enum_class(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": if base_class == "GlobalConstants":
return f"BitField<{get_enum_name(type_name)}>" return f"BitField<{get_enum_name(type_name)}>"
return f"BitField<{base_class}::{get_enum_name(type_name)}>" return f"BitField<{base_class}::{get_enum_name(type_name)}>"
else: else:
base_class = get_enum_class(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": if base_class == "GlobalConstants":
return f"{get_enum_name(type_name)}" return f"{get_enum_name(type_name)}"
return f"{base_class}::{get_enum_name(type_name)}" return f"{base_class}::{get_enum_name(type_name)}"

View File

@ -292,4 +292,6 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p
} // namespace godot } // namespace godot
CLASSDB_SINGLETON_VARIANT_CAST;
#endif // GODOT_CLASS_DB_HPP #endif // GODOT_CLASS_DB_HPP