From c9fdd4d1cb08ba464a60a0ebad603ab0960c1931 Mon Sep 17 00:00:00 2001 From: David Snopek Date: Thu, 6 Jul 2023 21:16:27 -0500 Subject: [PATCH] Add static methods to `ClassDB` for the methods bound to the `ClassDB` singleton --- binding_generator.py | 70 +++++++++++++++++++++++---- include/godot_cpp/classes/wrapped.hpp | 9 ++-- include/godot_cpp/core/class_db.hpp | 4 ++ 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/binding_generator.py b/binding_generator.py index 6e47e7bcbd..6ddea19f6a 100644 --- a/binding_generator.py +++ b/binding_generator.py @@ -97,9 +97,10 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False): files.append(str(source_filename.as_posix())) for engine_class in api["classes"]: - # TODO: Properly setup this singleton since it conflicts with ClassDB in the bindings. + # Generate code for the ClassDB singleton under a different name. if engine_class["name"] == "ClassDB": - continue + engine_class["name"] = "ClassDBSingleton" + engine_class["alias_for"] = "ClassDB" header_filename = include_gen_folder / "classes" / (camel_to_snake(engine_class["name"]) + ".hpp") source_filename = source_gen_folder / "classes" / (camel_to_snake(engine_class["name"]) + ".cpp") if headers: @@ -1036,21 +1037,23 @@ 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"]: - # TODO: Properly setup this singleton since it conflicts with ClassDB in the bindings. + # Generate code for the ClassDB singleton under a different name. if class_api["name"] == "ClassDB": - continue + class_api["name"] = "ClassDBSingleton" + class_api["alias_for"] = "ClassDB" engine_classes[class_api["name"]] = class_api["is_refcounted"] for native_struct in api["native_structures"]: engine_classes[native_struct["name"]] = False native_structures.append(native_struct["name"]) 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" singletons.append(singleton["name"]) for class_api in api["classes"]: - # TODO: Properly setup this singleton since it conflicts with ClassDB in the bindings. - if class_api["name"] == "ClassDB": - continue # Check used classes for header include. used_classes = set() fully_used_classes = set() @@ -1242,7 +1245,7 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us if len(fully_used_classes) > 0: result.append("") - if class_name != "Object": + if class_name != "Object" and class_name != "ClassDBSingleton": result.append("#include ") result.append("") result.append("#include ") @@ -1263,7 +1266,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us inherits = class_api["inherits"] if "inherits" in class_api else "Wrapped" result.append(f"class {class_name} : public {inherits} {{") - result.append(f"\tGDEXTENSION_CLASS({class_name}, {inherits})") + if 'alias_for' in class_api: + result.append(f"\tGDEXTENSION_CLASS_ALIAS({class_name}, {class_api['alias_for']}, {inherits})") + else: + result.append(f"\tGDEXTENSION_CLASS({class_name}, {inherits})") result.append("") result.append("public:") @@ -1421,6 +1427,51 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us result.append(f'VARIANT_ENUM_CAST({class_name}::{enum_api["name"]});') result.append("") + if class_name == "ClassDBSingleton": + result.append("#define CLASSDB_SINGLETON_FORWARD_METHODS \\") + 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: + continue + if "is_static" in method and method["is_static"]: + continue + + method_signature = "\tstatic " + if "return_type" in method: + method_signature += f'{correct_type(method["return_type"])} ' + elif "return_value" in method: + method_signature += ( + correct_type(method["return_value"]["type"], method["return_value"].get("meta", None)) + " " + ) + else: + method_signature += "void " + + method_signature += f'{method["name"]}(' + + method_arguments = [] + if "arguments" in method: + method_arguments = method["arguments"] + + method_signature += make_function_parameters( + method_arguments, include_default=True, for_builtin=True, is_vararg=False + ) + + method_signature += ") { \\" + + result.append(method_signature) + + method_body = "\t\t" + if "return_type" in method or "return_value" in method: + method_body += "return " + method_body += f'ClassDBSingleton::get_singleton()->{method["name"]}(' + method_body += ", ".join(map(lambda x: escape_identifier(x["name"]), method_arguments)) + method_body += "); \\" + + result.append(method_body) + result.append("\t} \\") + result.append("\t;") + result.append("") + result.append(f"#endif // ! {header_guard}") return "\n".join(result) @@ -2288,6 +2339,7 @@ def escape_identifier(id): "operator": "_operator", "typeof": "type_of", "typename": "type_name", + "enum": "_enum", } if id in cpp_keywords_map: return cpp_keywords_map[id] diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index f2efbd091e..d297945d60 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -305,7 +305,7 @@ public: }; // Don't use this for your classes, use GDCLASS() instead. -#define GDEXTENSION_CLASS(m_class, m_inherits) \ +#define GDEXTENSION_CLASS_ALIAS(m_class, m_alias_for, m_inherits) \ private: \ void operator=(const m_class &p_rval) {} \ \ @@ -353,7 +353,7 @@ public: static void initialize_class() {} \ \ static ::godot::StringName &get_class_static() { \ - static ::godot::StringName string_name = ::godot::StringName(#m_class); \ + static ::godot::StringName string_name = ::godot::StringName(#m_alias_for); \ return string_name; \ } \ \ @@ -378,6 +378,9 @@ public: _gde_binding_free_callback, \ _gde_binding_reference_callback, \ }; \ - m_class() : m_class(#m_class) {} + m_class() : m_class(#m_alias_for) {} + +// Don't use this for your classes, use GDCLASS() instead. +#define GDEXTENSION_CLASS(m_class, m_inherits) GDEXTENSION_CLASS_ALIAS(m_class, m_class, m_inherits) #endif // GODOT_WRAPPED_HPP diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 0802a45dcb..35fb05310a 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -38,6 +38,8 @@ #include #include +#include + #include #include #include @@ -137,6 +139,8 @@ class ClassDB { static void initialize(GDExtensionInitializationLevel p_level); static void deinitialize(GDExtensionInitializationLevel p_level); + + CLASSDB_SINGLETON_FORWARD_METHODS; }; #define BIND_CONSTANT(m_constant) \