瀏覽代碼

Merge pull request #1491 from dsnopek/4.1-cherrypicks-11

Cherry-picks for the godot-cpp 4.1 branch - 11th batch
David Snopek 1 年之前
父節點
當前提交
2e7f5512d1

+ 20 - 5
.github/workflows/ci.yml

@@ -4,6 +4,8 @@ on: [push, pull_request]
 env:
   # Only used for the cache key. Increment version to force clean build.
   GODOT_BASE_BRANCH: master
+  # Used to select the version of Godot to run the tests with.
+  GODOT_TEST_VERSION: 4.1.4-stable
 
 concurrency:
   group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}
@@ -153,7 +155,7 @@ jobs:
 
       - name: Download latest Godot artifacts
         uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
-        if: ${{ matrix.run-tests }}
+        if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION == 'master' }}
         with:
           repo: godotengine/godot
           branch: master
@@ -166,15 +168,28 @@ jobs:
           ensure_latest: true
           path: godot-artifacts
 
+      - name: Prepare Godot artifacts for testing
+        if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION == 'master' }}
+        run: |
+          chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
+          echo "GODOT=$(pwd)/godot-artifacts/godot.linuxbsd.editor.x86_64.mono" >> $GITHUB_ENV
+
+      - name: Download requested Godot version for testing
+        if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION != 'master' }}
+        run: |
+          wget "https://github.com/godotengine/godot-builds/releases/download/${GODOT_TEST_VERSION}/Godot_v${GODOT_TEST_VERSION}_linux.x86_64.zip" -O Godot.zip
+          unzip -a Godot.zip
+          chmod +x "Godot_v${GODOT_TEST_VERSION}_linux.x86_64"
+          echo "GODOT=$(pwd)/Godot_v${GODOT_TEST_VERSION}_linux.x86_64" >> $GITHUB_ENV
+
       - name: Run tests
         if: ${{ matrix.run-tests }}
         run: |
-          chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
-          ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono --headless --version
+          $GODOT --headless --version
           cd test
           # Need to run the editor so .godot is generated... but it crashes! Ignore that :-)
-          (cd project && (timeout 10 ../../godot-artifacts/godot.linuxbsd.editor.x86_64.mono --editor --headless --quit >/dev/null 2>&1 || true))
-          GODOT=../godot-artifacts/godot.linuxbsd.editor.x86_64.mono ./run-tests.sh
+          (cd project && (timeout 30 $GODOT --editor --headless --quit >/dev/null 2>&1 || true))
+          ./run-tests.sh
 
       - name: Upload artifact
         uses: actions/upload-artifact@v3

+ 17 - 7
binding_generator.py

@@ -1470,13 +1470,16 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
                 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:
-                continue
+            # ClassDBSingleton shouldn't have any static methods, but if some appear later, lets skip them.
             if "is_static" in method and method["is_static"]:
                 continue
 
-            method_signature = "\tstatic "
+            vararg = "is_vararg" in method and method["is_vararg"]
+            if vararg:
+                method_signature = "\ttemplate<typename... Args> static "
+            else:
+                method_signature = "\tstatic "
+
             return_type = None
             if "return_type" in method:
                 return_type = correct_type(method["return_type"].replace("ClassDBSingleton", "ClassDB"), None, False)
@@ -1498,7 +1501,7 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
                 method_arguments = method["arguments"]
 
             method_signature += make_function_parameters(
-                method_arguments, include_default=True, for_builtin=True, is_vararg=False
+                method_arguments, include_default=True, for_builtin=True, is_vararg=vararg
             )
 
             method_signature += ") { \\"
@@ -1512,6 +1515,8 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
                     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))
+            if vararg:
+                method_body += ", args..."
             method_body += "); \\"
 
             result.append(method_body)
@@ -2126,9 +2131,9 @@ def make_varargs_template(function_data, static=False):
     args_array = f"\t\tstd::array<Variant, {len(method_arguments)} + sizeof...(Args)> variant_args {{ "
     for argument in method_arguments:
         if argument["type"] == "Variant":
-            args_array += argument["name"]
+            args_array += escape_identifier(argument["name"])
         else:
-            args_array += f'Variant({argument["name"]})'
+            args_array += f'Variant({escape_identifier(argument["name"])})'
         args_array += ", "
 
     args_array += "Variant(args)... };"
@@ -2305,6 +2310,7 @@ def correct_default_value(value, type_name):
         "null": "nullptr",
         '""': "String()",
         '&""': "StringName()",
+        '^""': "NodePath()",
         "[]": "Array()",
         "{}": "Dictionary()",
         "Transform2D(1, 0, 0, 1, 0, 0)": "Transform2D()",  # Default transform.
@@ -2316,6 +2322,10 @@ def correct_default_value(value, type_name):
         return f"{type_name}()"
     if value.startswith("Array["):
         return f"{{}}"
+    if value.startswith("&"):
+        return value[1::]
+    if value.startswith("^"):
+        return value[1::]
     return value
 
 

+ 3 - 3
include/godot_cpp/core/class_db.hpp

@@ -286,9 +286,9 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p
 	return bind;
 }
 
-#define GDREGISTER_CLASS(m_class) ClassDB::register_class<m_class>();
-#define GDREGISTER_VIRTUAL_CLASS(m_class) ClassDB::register_class<m_class>(true);
-#define GDREGISTER_ABSTRACT_CLASS(m_class) ClassDB::register_abstract_class<m_class>();
+#define GDREGISTER_CLASS(m_class) ::godot::ClassDB::register_class<m_class>();
+#define GDREGISTER_VIRTUAL_CLASS(m_class) ::godot::ClassDB::register_class<m_class>(true);
+#define GDREGISTER_ABSTRACT_CLASS(m_class) ::godot::ClassDB::register_abstract_class<m_class>();
 
 } // namespace godot
 

+ 13 - 1
src/core/class_db.cpp

@@ -360,6 +360,7 @@ void ClassDB::initialize(GDExtensionInitializationLevel p_level) {
 }
 
 void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) {
+	std::set<StringName> to_erase;
 	for (std::vector<StringName>::reverse_iterator i = class_register_order.rbegin(); i != class_register_order.rend(); ++i) {
 		const StringName &name = *i;
 		const ClassInfo &cl = classes[name];
@@ -370,9 +371,20 @@ void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) {
 
 		internal::gdextension_interface_classdb_unregister_extension_class(internal::library, name._native_ptr());
 
-		for (auto method : cl.method_map) {
+		for (const std::pair<const StringName, MethodBind *> &method : cl.method_map) {
 			memdelete(method.second);
 		}
+
+		classes.erase(name);
+		to_erase.insert(name);
+	}
+
+	{
+		// The following is equivalent to c++20 `std::erase_if(class_register_order, [&](const StringName& name){ return to_erase.contains(name); });`
+		std::vector<StringName>::iterator it = std::remove_if(class_register_order.begin(), class_register_order.end(), [&](const StringName &p_name) {
+			return to_erase.count(p_name) > 0;
+		});
+		class_register_order.erase(it, class_register_order.end());
 	}
 }
 

+ 1 - 1
src/core/object.cpp

@@ -75,7 +75,7 @@ MethodInfo::operator Dictionary() const {
 	dict["name"] = name;
 	dict["args"] = internal::convert_property_list(arguments);
 	Array da;
-	for (int i = 0; i < default_arguments.size(); i++) {
+	for (size_t i = 0; i < default_arguments.size(); i++) {
 		da.push_back(default_arguments[i]);
 	}
 	dict["default_args"] = da;

+ 8 - 0
tools/common_compiler_flags.py

@@ -39,6 +39,14 @@ def generate(env):
     elif env.get("is_msvc", False):
         env.Append(CXXFLAGS=["/EHsc"])
 
+    if not env.get("is_msvc", False):
+        if env["symbols_visibility"] == "visible":
+            env.Append(CCFLAGS=["-fvisibility=default"])
+            env.Append(LINKFLAGS=["-fvisibility=default"])
+        elif env["symbols_visibility"] == "hidden":
+            env.Append(CCFLAGS=["-fvisibility=hidden"])
+            env.Append(LINKFLAGS=["-fvisibility=hidden"])
+
     # Set optimize and debug_symbols flags.
     # "custom" means do nothing and let users set their own optimization flags.
     if env.get("is_msvc", False):

+ 9 - 0
tools/godotcpp.py

@@ -291,6 +291,15 @@ def options(opts, env):
         )
     )
 
+    opts.Add(
+        EnumVariable(
+            key="symbols_visibility",
+            help="Symbols visibility on GNU platforms. Use 'auto' to apply the default value.",
+            default=env.get("symbols_visibility", "hidden"),
+            allowed_values=["auto", "visible", "hidden"],
+        )
+    )
+
     opts.Add(
         EnumVariable(
             "optimize",