Skip to content

Commit

Permalink
godot-cpp with PR #1165
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitriySalnikov committed Jul 7, 2023
1 parent 47b686f commit 9a05247
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 8 deletions.
3 changes: 2 additions & 1 deletion .github/actions/compile_gdextension/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ runs:
run: |
echo "::group::🛠️ GDExtesion Compilation 🛠️"
cd godot-cpp
#git apply --ignore-space-change --ignore-whitespace ../patches/godot_cpp_exclude_unused_classes.patch
git apply --ignore-space-change --ignore-whitespace ../patches/godot_cpp_exclude_unused_classes.patch
git apply --ignore-space-change --ignore-whitespace ../patches/1165.patch
cd ..
scons platform=${{inputs.platform}} arch=${{inputs.arch}} target=${{inputs.target}} addon_output_dir=${{inputs.output_libs_path}} ${{inputs.additional}}
echo "::endgroup::"
Expand Down
3 changes: 2 additions & 1 deletion dev_build_godot_cpp.bat
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ cd godot-cpp
::set api=custom_api_file="../api.json"
set api=

::git apply --ignore-space-change --ignore-whitespace ../patches/godot_cpp_exclude_unused_classes.patch
git apply --ignore-space-change --ignore-whitespace ../patches/godot_cpp_exclude_unused_classes.patch
git apply --ignore-space-change --ignore-whitespace ../patches/unity_build.patch
git apply --ignore-space-change --ignore-whitespace ../patches/1165.patch
::git apply --ignore-space-change --ignore-whitespace ../patches/debug_string.patch

title win x64 editor dev
Expand Down
182 changes: 182 additions & 0 deletions patches/1165.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
diff --git a/binding_generator.py b/binding_generator.py
index d04c698..bb4a6a5 100644
--- a/binding_generator.py
+++ b/binding_generator.py
@@ -97,9 +97,9 @@ 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"
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 +1036,21 @@ 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"
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"
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 +1242,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 <godot_cpp/core/class_db.hpp>")
result.append("")
result.append("#include <type_traits>")
@@ -1421,6 +1421,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)
@@ -1453,7 +1498,10 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us

if is_singleton:
result.append(f"{class_name} *{class_name}::get_singleton() {{")
- result.append(f"\tconst StringName _gde_class_name = {class_name}::get_class_static();")
+ if class_name != "ClassDBSingleton":
+ result.append(f"\tconst StringName _gde_class_name = {class_name}::get_class_static();")
+ else:
+ result.append(f"\tstatic const StringName _gde_class_name = StringName(\"ClassDB\");")
result.append(
"\tstatic GDExtensionObjectPtr singleton_obj = internal::gdextension_interface_global_get_singleton(_gde_class_name._native_ptr());"
)
@@ -1480,7 +1528,10 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
result.append(method_signature + " {")

# Method body.
- result.append(f"\tconst StringName _gde_class_name = {class_name}::get_class_static();")
+ if class_name != "ClassDBSingleton":
+ result.append(f"\tconst StringName _gde_class_name = {class_name}::get_class_static();")
+ else:
+ result.append(f"\tstatic const StringName _gde_class_name = StringName(\"ClassDB\");")
result.append(f'\tconst StringName _gde_method_name = "{method["name"]}";')
result.append(
f'\tstatic GDExtensionMethodBindPtr _gde_method_bind = internal::gdextension_interface_classdb_get_method_bind(_gde_class_name._native_ptr(), _gde_method_name._native_ptr(), {method["hash"]});'
@@ -2285,6 +2336,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/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp
index b1625bf..26dfb7e 100644
--- a/include/godot_cpp/core/class_db.hpp
+++ b/include/godot_cpp/core/class_db.hpp
@@ -38,6 +38,8 @@
#include <godot_cpp/core/method_bind.hpp>
#include <godot_cpp/core/object.hpp>

+#include <godot_cpp/classes/class_db_singleton.hpp>
+
#include <list>
#include <set>
#include <string>
@@ -146,6 +148,8 @@ public:

static void initialize(GDExtensionInitializationLevel p_level);
static void deinitialize(GDExtensionInitializationLevel p_level);
+
+ CLASSDB_SINGLETON_FORWARD_METHODS;
};

#define BIND_CONSTANT(m_constant) \
diff --git a/src/core/class_db.cpp b/src/core/class_db.cpp
index e8bb40c..cfd065e 100644
--- a/src/core/class_db.cpp
+++ b/src/core/class_db.cpp
@@ -318,7 +318,18 @@ GDExtensionClassCallVirtual ClassDB::get_virtual_func(void *p_userdata, GDExtens

const GDExtensionInstanceBindingCallbacks *ClassDB::get_instance_binding_callbacks(const StringName &p_class) {
std::unordered_map<StringName, const GDExtensionInstanceBindingCallbacks *>::iterator callbacks_it = instance_binding_callbacks.find(p_class);
- ERR_FAIL_COND_V_MSG(callbacks_it == instance_binding_callbacks.end(), nullptr, String("Cannot find instance binding callbacks for class '{0}'.").format(Array::make(p_class)));
+ if (likely(callbacks_it != instance_binding_callbacks.end())) {
+ return callbacks_it->second;
+ }
+
+ // If we don't have an instance binding callback for the given class, find the closest parent where we do.
+ StringName class_name = p_class;
+ do {
+ class_name = get_parent_class(class_name);
+ ERR_FAIL_COND_V_MSG(class_name == StringName(), nullptr, String("Cannot find instance binding callbacks for class '{0}'.").format(Array::make(p_class)));
+ callbacks_it = instance_binding_callbacks.find(class_name);
+ } while (callbacks_it == instance_binding_callbacks.end());
+
return callbacks_it->second;
}

21 changes: 15 additions & 6 deletions patches/get_used_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ def read_data(opened_file):
with open(Path(dir) / f, "r", encoding="utf-8") as file:
read_data(file)
except UnicodeDecodeError as e:
print("Skipping file due to 'UnicodeDecodeError' exception: " + (Path(dir) / f).resolve().as_posix() + "\nException: " + str(e))
print("Skipping file due to 'UnicodeDecodeError' exception: " +
(Path(dir) / f).resolve().as_posix() + "\nException: " + str(e))
skips += 1
continue
return skips
Expand All @@ -78,13 +79,22 @@ def read_data(opened_file):


def scan_dependencies(api):
api = dict(api)
if not is_need_to_exclude_classes:
return

used_classes = extract_used_classes(sources_folder)

for class_api in api["classes"]:
# It will change the actual value inside the `api`!!!
#
# ClassDB Singleton is renamed in godot-cpp.
# This class cannot appear as an argument or return value, so no other renaming is required yet.
if class_api["name"] == "ClassDB":
class_api["name"] = "ClassDBSingleton"

temp_engine_class_names.add(class_api["name"])

for name in used_classes:
_get_dependencies(api, name)

Expand Down Expand Up @@ -150,19 +160,18 @@ def delete_useless(files):
return files

# convert found class names to file names
dependencies_file_names = [camel_to_snake(
c) + ".cpp" for c in found_dependencies]
deps_file_names = [camel_to_snake(c) + ".cpp" for c in found_dependencies]

src_path = "gen/src/classes/"
print("These", len(dependencies_file_names), "files from the",
src_path, "directory will be compiled:", dependencies_file_names)
print("These", len(deps_file_names), "files from the",
src_path, "directory will be compiled:", deps_file_names)
print()

new_files_list = []
for f in files:
split = f.split(src_path)
if len(split) > 1:
if split[1] in dependencies_file_names:
if split[1] in deps_file_names:
new_files_list.append(f)
else:
new_files_list.append(f)
Expand Down

0 comments on commit 9a05247

Please sign in to comment.