浏览代码

Merge pull request #1244 from dsnopek/4.1-cherrypicks-3

Cherry-picks for the godot-cpp 4.1 branch - 3rd batch
Rémi Verschelde 1 年之前
父节点
当前提交
4eed2d7be0

+ 4 - 4
.github/workflows/ci.yml

@@ -83,7 +83,7 @@ jobs:
 
 
     steps:
     steps:
       - name: Checkout
       - name: Checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
         with:
           submodules: recursive
           submodules: recursive
 
 
@@ -168,7 +168,7 @@ jobs:
     runs-on: ubuntu-20.04
     runs-on: ubuntu-20.04
     steps:
     steps:
       - name: Checkout
       - name: Checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
         with:
           submodules: recursive
           submodules: recursive
 
 
@@ -192,7 +192,7 @@ jobs:
     runs-on: ubuntu-20.04
     runs-on: ubuntu-20.04
     steps:
     steps:
       - name: Checkout
       - name: Checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
         with:
           submodules: recursive
           submodules: recursive
 
 
@@ -216,7 +216,7 @@ jobs:
     runs-on: windows-2019
     runs-on: windows-2019
     steps:
     steps:
       - name: Checkout
       - name: Checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
         with:
           submodules: recursive
           submodules: recursive
 
 

+ 1 - 1
.github/workflows/static_checks.yml

@@ -11,7 +11,7 @@ jobs:
     runs-on: ubuntu-20.04
     runs-on: ubuntu-20.04
     steps:
     steps:
       - name: Checkout
       - name: Checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
 
       # Azure repositories are not reliable, we need to prevent Azure giving us packages.
       # Azure repositories are not reliable, we need to prevent Azure giving us packages.
       - name: Make apt sources.list use the default Ubuntu repositories
       - name: Make apt sources.list use the default Ubuntu repositories

+ 0 - 1
SConstruct

@@ -5,7 +5,6 @@ import platform
 import sys
 import sys
 import subprocess
 import subprocess
 from binding_generator import scons_generate_bindings, scons_emit_files
 from binding_generator import scons_generate_bindings, scons_emit_files
-from SCons.Errors import UserError
 
 
 
 
 EnsureSConsVersion(4, 0)
 EnsureSConsVersion(4, 0)

+ 67 - 9
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()))
             files.append(str(source_filename.as_posix()))
 
 
     for engine_class in api["classes"]:
     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":
         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")
         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")
         source_filename = source_gen_folder / "classes" / (camel_to_snake(engine_class["name"]) + ".cpp")
         if headers:
         if headers:
@@ -1038,21 +1039,23 @@ 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"]:
-        # 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":
         if class_api["name"] == "ClassDB":
-            continue
+            class_api["name"] = "ClassDBSingleton"
+            class_api["alias_for"] = "ClassDB"
         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
         native_structures.append(native_struct["name"])
         native_structures.append(native_struct["name"])
 
 
     for singleton in api["singletons"]:
     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"])
         singletons.append(singleton["name"])
 
 
     for class_api in api["classes"]:
     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.
         # Check used classes for header include.
         used_classes = set()
         used_classes = set()
         fully_used_classes = set()
         fully_used_classes = set()
@@ -1142,6 +1145,12 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
         else:
         else:
             fully_used_classes.add("Wrapped")
             fully_used_classes.add("Wrapped")
 
 
+        # In order to ensure that PtrToArg specializations for native structs are
+        # always used, let's move any of them into 'fully_used_classes'.
+        for type_name in used_classes:
+            if is_struct_type(type_name) and not is_included_struct_type(type_name):
+                fully_used_classes.add(type_name)
+
         for type_name in fully_used_classes:
         for type_name in fully_used_classes:
             if type_name in used_classes:
             if type_name in used_classes:
                 used_classes.remove(type_name)
                 used_classes.remove(type_name)
@@ -1244,7 +1253,7 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
     if len(fully_used_classes) > 0:
     if len(fully_used_classes) > 0:
         result.append("")
         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("#include <godot_cpp/core/class_db.hpp>")
         result.append("")
         result.append("")
         result.append("#include <type_traits>")
         result.append("#include <type_traits>")
@@ -1265,7 +1274,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"
     inherits = class_api["inherits"] if "inherits" in class_api else "Wrapped"
     result.append(f"class {class_name} : public {inherits} {{")
     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("")
 
 
     result.append("public:")
     result.append("public:")
@@ -1423,6 +1435,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(f'VARIANT_ENUM_CAST({class_name}::{enum_api["name"]});')
         result.append("")
         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}")
     result.append(f"#endif // ! {header_guard}")
 
 
     return "\n".join(result)
     return "\n".join(result)
@@ -2319,6 +2376,7 @@ def escape_identifier(id):
         "operator": "_operator",
         "operator": "_operator",
         "typeof": "type_of",
         "typeof": "type_of",
         "typename": "type_name",
         "typename": "type_name",
+        "enum": "_enum",
     }
     }
     if id in cpp_keywords_map:
     if id in cpp_keywords_map:
         return cpp_keywords_map[id]
         return cpp_keywords_map[id]

+ 15 - 12
include/godot_cpp/classes/wrapped.hpp

@@ -132,16 +132,16 @@ protected:
 		return (void(::godot::Wrapped::*)(::godot::List<::godot::PropertyInfo> * p_list) const) & m_class::_get_property_list;                                                         \
 		return (void(::godot::Wrapped::*)(::godot::List<::godot::PropertyInfo> * p_list) const) & m_class::_get_property_list;                                                         \
 	}                                                                                                                                                                                  \
 	}                                                                                                                                                                                  \
                                                                                                                                                                                        \
                                                                                                                                                                                        \
-	static bool (::godot::Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) {                                                                                   \
-		return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name)) & m_class::_property_can_revert;                                                                         \
+	static bool (::godot::Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const {                                                                             \
+		return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name) const) & m_class::_property_can_revert;                                                                   \
 	}                                                                                                                                                                                  \
 	}                                                                                                                                                                                  \
                                                                                                                                                                                        \
                                                                                                                                                                                        \
-	static bool (::godot::Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, ::godot::Variant &) {                                                               \
-		return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &)) & m_class::_property_get_revert;                                                     \
+	static bool (::godot::Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, ::godot::Variant &) const {                                                         \
+		return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &) const) & m_class::_property_get_revert;                                               \
 	}                                                                                                                                                                                  \
 	}                                                                                                                                                                                  \
                                                                                                                                                                                        \
                                                                                                                                                                                        \
-	static ::godot::String (::godot::Wrapped::*_get_to_string())() {                                                                                                                   \
-		return (::godot::String(::godot::Wrapped::*)()) & m_class::_to_string;                                                                                                         \
+	static ::godot::String (::godot::Wrapped::*_get_to_string())() const {                                                                                                             \
+		return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string;                                                                                                   \
 	}                                                                                                                                                                                  \
 	}                                                                                                                                                                                  \
                                                                                                                                                                                        \
                                                                                                                                                                                        \
 	template <class T, class B>                                                                                                                                                        \
 	template <class T, class B>                                                                                                                                                        \
@@ -306,7 +306,7 @@ public:
 	};
 	};
 
 
 // Don't use this for your classes, use GDCLASS() instead.
 // 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:                                                                                                                   \
 private:                                                                                                                   \
 	void operator=(const m_class &p_rval) {}                                                                               \
 	void operator=(const m_class &p_rval) {}                                                                               \
                                                                                                                            \
                                                                                                                            \
@@ -338,15 +338,15 @@ protected:
 		return nullptr;                                                                                                    \
 		return nullptr;                                                                                                    \
 	}                                                                                                                      \
 	}                                                                                                                      \
                                                                                                                            \
                                                                                                                            \
-	static bool (Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) {                                \
+	static bool (Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const {                          \
 		return nullptr;                                                                                                    \
 		return nullptr;                                                                                                    \
 	}                                                                                                                      \
 	}                                                                                                                      \
                                                                                                                            \
                                                                                                                            \
-	static bool (Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, Variant &) {                     \
+	static bool (Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, Variant &) const {               \
 		return nullptr;                                                                                                    \
 		return nullptr;                                                                                                    \
 	}                                                                                                                      \
 	}                                                                                                                      \
                                                                                                                            \
                                                                                                                            \
-	static String (Wrapped::*_get_to_string())() {                                                                         \
+	static String (Wrapped::*_get_to_string())() const {                                                                   \
 		return nullptr;                                                                                                    \
 		return nullptr;                                                                                                    \
 	}                                                                                                                      \
 	}                                                                                                                      \
                                                                                                                            \
                                                                                                                            \
@@ -354,7 +354,7 @@ public:
 	static void initialize_class() {}                                                                                      \
 	static void initialize_class() {}                                                                                      \
                                                                                                                            \
                                                                                                                            \
 	static ::godot::StringName &get_class_static() {                                                                       \
 	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;                                                                                                \
 		return string_name;                                                                                                \
 	}                                                                                                                      \
 	}                                                                                                                      \
                                                                                                                            \
                                                                                                                            \
@@ -379,6 +379,9 @@ public:
 		_gde_binding_free_callback,                                                                                        \
 		_gde_binding_free_callback,                                                                                        \
 		_gde_binding_reference_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
 #endif // GODOT_WRAPPED_HPP

+ 4 - 0
include/godot_cpp/core/class_db.hpp

@@ -38,6 +38,8 @@
 #include <godot_cpp/core/method_bind.hpp>
 #include <godot_cpp/core/method_bind.hpp>
 #include <godot_cpp/core/object.hpp>
 #include <godot_cpp/core/object.hpp>
 
 
+#include <godot_cpp/classes/class_db_singleton.hpp>
+
 #include <list>
 #include <list>
 #include <set>
 #include <set>
 #include <string>
 #include <string>
@@ -146,6 +148,8 @@ public:
 
 
 	static void initialize(GDExtensionInitializationLevel p_level);
 	static void initialize(GDExtensionInitializationLevel p_level);
 	static void deinitialize(GDExtensionInitializationLevel p_level);
 	static void deinitialize(GDExtensionInitializationLevel p_level);
+
+	CLASSDB_SINGLETON_FORWARD_METHODS;
 };
 };
 
 
 #define BIND_CONSTANT(m_constant) \
 #define BIND_CONSTANT(m_constant) \

+ 2 - 0
include/godot_cpp/core/method_ptrcall.hpp

@@ -168,6 +168,7 @@ MAKE_PTRARG_BY_REFERENCE(Variant);
 
 
 template <class T>
 template <class T>
 struct PtrToArg<T *> {
 struct PtrToArg<T *> {
+	static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
 	_FORCE_INLINE_ static T *convert(const void *p_ptr) {
 	_FORCE_INLINE_ static T *convert(const void *p_ptr) {
 		return reinterpret_cast<T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
 		return reinterpret_cast<T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
 	}
 	}
@@ -179,6 +180,7 @@ struct PtrToArg<T *> {
 
 
 template <class T>
 template <class T>
 struct PtrToArg<const T *> {
 struct PtrToArg<const T *> {
+	static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
 	_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
 	_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
 		return reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
 		return reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
 	}
 	}

+ 42 - 13
src/godot.cpp

@@ -34,6 +34,7 @@
 #include <godot_cpp/classes/wrapped.hpp>
 #include <godot_cpp/classes/wrapped.hpp>
 #include <godot_cpp/core/class_db.hpp>
 #include <godot_cpp/core/class_db.hpp>
 #include <godot_cpp/core/memory.hpp>
 #include <godot_cpp/core/memory.hpp>
+#include <godot_cpp/core/version.hpp>
 #include <godot_cpp/variant/variant.hpp>
 #include <godot_cpp/variant/variant.hpp>
 
 
 #include <godot_cpp/core/error_macros.hpp>
 #include <godot_cpp/core/error_macros.hpp>
@@ -192,9 +193,15 @@ GDExtensionBinding::Callback GDExtensionBinding::init_callback = nullptr;
 GDExtensionBinding::Callback GDExtensionBinding::terminate_callback = nullptr;
 GDExtensionBinding::Callback GDExtensionBinding::terminate_callback = nullptr;
 GDExtensionInitializationLevel GDExtensionBinding::minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
 GDExtensionInitializationLevel GDExtensionBinding::minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
 
 
-#define LOAD_PROC_ADDRESS(m_name, m_type)                                           \
-	internal::gdextension_interface_##m_name = (m_type)p_get_proc_address(#m_name); \
-	ERR_FAIL_NULL_V_MSG(internal::gdextension_interface_##m_name, false, "Unable to load GDExtension interface function " #m_name "()")
+#define ERR_PRINT_EARLY(m_msg) \
+	internal::gdextension_interface_print_error(m_msg, FUNCTION_STR, __FILE__, __LINE__, false)
+
+#define LOAD_PROC_ADDRESS(m_name, m_type)                                               \
+	internal::gdextension_interface_##m_name = (m_type)p_get_proc_address(#m_name);     \
+	if (!internal::gdextension_interface_##m_name) {                                    \
+		ERR_PRINT_EARLY("Unable to load GDExtension interface function " #m_name "()"); \
+		return false;                                                                   \
+	}
 
 
 // Partial definition of the legacy interface so we can detect it and show an error.
 // Partial definition of the legacy interface so we can detect it and show an error.
 typedef struct {
 typedef struct {
@@ -217,14 +224,15 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
 	if (raw_interface[0] == 4 && raw_interface[1] == 0) {
 	if (raw_interface[0] == 4 && raw_interface[1] == 0) {
 		// Use the legacy interface only to give a nice error.
 		// Use the legacy interface only to give a nice error.
 		LegacyGDExtensionInterface *legacy_interface = (LegacyGDExtensionInterface *)p_get_proc_address;
 		LegacyGDExtensionInterface *legacy_interface = (LegacyGDExtensionInterface *)p_get_proc_address;
-		internal::gdextension_interface_print_error_with_message = (GDExtensionInterfacePrintErrorWithMessage)legacy_interface->print_error_with_message;
-		ERR_FAIL_V_MSG(false, "Cannot load a GDExtension built for Godot 4.1+ in Godot 4.0.");
+		internal::gdextension_interface_print_error = (GDExtensionInterfacePrintError)legacy_interface->print_error;
+		ERR_PRINT_EARLY("Cannot load a GDExtension built for Godot 4.1+ in Godot 4.0.");
+		return false;
 	}
 	}
 
 
-	// Load the "print_error_with_message" function first (needed by the ERR_FAIL_NULL_V_MSG() macro).
-	internal::gdextension_interface_print_error_with_message = (GDExtensionInterfacePrintErrorWithMessage)p_get_proc_address("print_error_with_message");
-	if (!internal::gdextension_interface_print_error_with_message) {
-		printf("ERROR: Unable to load GDExtension interface function print_error_with_message().\n");
+	// Load the "print_error" function first (needed by the ERR_PRINT_EARLY() macro).
+	internal::gdextension_interface_print_error = (GDExtensionInterfacePrintError)p_get_proc_address("print_error");
+	if (!internal::gdextension_interface_print_error) {
+		printf("ERROR: Unable to load GDExtension interface function print_error().\n");
 		return false;
 		return false;
 	}
 	}
 
 
@@ -233,10 +241,33 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
 	internal::token = p_library;
 	internal::token = p_library;
 
 
 	LOAD_PROC_ADDRESS(get_godot_version, GDExtensionInterfaceGetGodotVersion);
 	LOAD_PROC_ADDRESS(get_godot_version, GDExtensionInterfaceGetGodotVersion);
+	internal::gdextension_interface_get_godot_version(&internal::godot_version);
+
+	// Check that godot-cpp was compiled using an extension_api.json older or at the
+	// same version as the Godot that is loading it.
+	bool compatible;
+	if (internal::godot_version.major != GODOT_VERSION_MAJOR) {
+		compatible = internal::godot_version.major > GODOT_VERSION_MAJOR;
+	} else if (internal::godot_version.minor != GODOT_VERSION_MINOR) {
+		compatible = internal::godot_version.minor > GODOT_VERSION_MINOR;
+	} else {
+		compatible = internal::godot_version.patch >= GODOT_VERSION_PATCH;
+	}
+	if (!compatible) {
+		// We need to use snprintf() here because vformat() uses Variant, and we haven't loaded
+		// the GDExtension interface far enough to use Variants yet.
+		char msg[128];
+		snprintf(msg, 128, "Cannot load a GDExtension built for Godot %d.%d.%d using an older version of Godot (%d.%d.%d).",
+				GODOT_VERSION_MAJOR, GODOT_VERSION_MINOR, GODOT_VERSION_PATCH,
+				internal::godot_version.major, internal::godot_version.minor, internal::godot_version.patch);
+		ERR_PRINT_EARLY(msg);
+		return false;
+	}
+
 	LOAD_PROC_ADDRESS(mem_alloc, GDExtensionInterfaceMemAlloc);
 	LOAD_PROC_ADDRESS(mem_alloc, GDExtensionInterfaceMemAlloc);
 	LOAD_PROC_ADDRESS(mem_realloc, GDExtensionInterfaceMemRealloc);
 	LOAD_PROC_ADDRESS(mem_realloc, GDExtensionInterfaceMemRealloc);
 	LOAD_PROC_ADDRESS(mem_free, GDExtensionInterfaceMemFree);
 	LOAD_PROC_ADDRESS(mem_free, GDExtensionInterfaceMemFree);
-	LOAD_PROC_ADDRESS(print_error, GDExtensionInterfacePrintError);
+	LOAD_PROC_ADDRESS(print_error_with_message, GDExtensionInterfacePrintErrorWithMessage);
 	LOAD_PROC_ADDRESS(print_warning, GDExtensionInterfacePrintWarning);
 	LOAD_PROC_ADDRESS(print_warning, GDExtensionInterfacePrintWarning);
 	LOAD_PROC_ADDRESS(print_warning_with_message, GDExtensionInterfacePrintWarningWithMessage);
 	LOAD_PROC_ADDRESS(print_warning_with_message, GDExtensionInterfacePrintWarningWithMessage);
 	LOAD_PROC_ADDRESS(print_script_error, GDExtensionInterfacePrintScriptError);
 	LOAD_PROC_ADDRESS(print_script_error, GDExtensionInterfacePrintScriptError);
@@ -368,9 +399,6 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
 	LOAD_PROC_ADDRESS(editor_add_plugin, GDExtensionInterfaceEditorAddPlugin);
 	LOAD_PROC_ADDRESS(editor_add_plugin, GDExtensionInterfaceEditorAddPlugin);
 	LOAD_PROC_ADDRESS(editor_remove_plugin, GDExtensionInterfaceEditorRemovePlugin);
 	LOAD_PROC_ADDRESS(editor_remove_plugin, GDExtensionInterfaceEditorRemovePlugin);
 
 
-	// Load the Godot version.
-	internal::gdextension_interface_get_godot_version(&internal::godot_version);
-
 	r_initialization->initialize = initialize_level;
 	r_initialization->initialize = initialize_level;
 	r_initialization->deinitialize = deinitialize_level;
 	r_initialization->deinitialize = deinitialize_level;
 	r_initialization->minimum_initialization_level = minimum_initialization_level;
 	r_initialization->minimum_initialization_level = minimum_initialization_level;
@@ -384,6 +412,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
 }
 }
 
 
 #undef LOAD_PROC_ADDRESS
 #undef LOAD_PROC_ADDRESS
+#undef ERR_PRINT_EARLY
 
 
 void GDExtensionBinding::initialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
 void GDExtensionBinding::initialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
 	ClassDB::current_level = p_level;
 	ClassDB::current_level = p_level;

+ 1 - 1
test/project/project.godot

@@ -12,7 +12,7 @@ config_version=5
 
 
 config/name="GDExtension Test Project"
 config/name="GDExtension Test Project"
 run/main_scene="res://main.tscn"
 run/main_scene="res://main.tscn"
-config/features=PackedStringArray("4.2")
+config/features=PackedStringArray("4.1")
 config/icon="res://icon.png"
 config/icon="res://icon.png"
 
 
 [native_extensions]
 [native_extensions]

+ 1 - 1
tools/android.py

@@ -29,7 +29,7 @@ def generate(env):
 
 
     if env["arch"] not in ("arm64", "x86_64", "arm32", "x86_32"):
     if env["arch"] not in ("arm64", "x86_64", "arm32", "x86_32"):
         print("Only arm64, x86_64, arm32, and x86_32 are supported on Android. Exiting.")
         print("Only arm64, x86_64, arm32, and x86_32 are supported on Android. Exiting.")
-        Exit()
+        env.Exit(1)
 
 
     if sys.platform == "win32" or sys.platform == "msys":
     if sys.platform == "win32" or sys.platform == "msys":
         my_spawn.configure(env)
         my_spawn.configure(env)

+ 4 - 3
tools/godotcpp.py

@@ -3,6 +3,7 @@ import os, sys, platform
 from SCons.Variables import EnumVariable, PathVariable, BoolVariable
 from SCons.Variables import EnumVariable, PathVariable, BoolVariable
 from SCons.Tool import Tool
 from SCons.Tool import Tool
 from SCons.Builder import Builder
 from SCons.Builder import Builder
+from SCons.Errors import UserError
 
 
 from binding_generator import scons_generate_bindings, scons_emit_files
 from binding_generator import scons_generate_bindings, scons_emit_files
 
 
@@ -226,7 +227,7 @@ def generate(env):
                 env["arch"] = "x86_32"
                 env["arch"] = "x86_32"
             else:
             else:
                 print("Unsupported CPU architecture: " + host_machine)
                 print("Unsupported CPU architecture: " + host_machine)
-                Exit()
+                env.Exit(1)
 
 
     print("Building for architecture " + env["arch"] + " on platform " + env["platform"])
     print("Building for architecture " + env["arch"] + " on platform " + env["platform"])
 
 
@@ -284,8 +285,8 @@ def _godot_cpp(env):
     )
     )
     # Forces bindings regeneration.
     # Forces bindings regeneration.
     if env["generate_bindings"]:
     if env["generate_bindings"]:
-        AlwaysBuild(bindings)
-        NoCache(bindings)
+        env.AlwaysBuild(bindings)
+        env.NoCache(bindings)
 
 
     # Sources to compile
     # Sources to compile
     sources = []
     sources = []

+ 1 - 1
tools/javascript.py

@@ -8,7 +8,7 @@ def exists(env):
 def generate(env):
 def generate(env):
     if env["arch"] not in ("wasm32"):
     if env["arch"] not in ("wasm32"):
         print("Only wasm32 supported on web. Exiting.")
         print("Only wasm32 supported on web. Exiting.")
-        Exit()
+        env.Exit(1)
 
 
     if "EM_CONFIG" in os.environ:
     if "EM_CONFIG" in os.environ:
         env["ENV"] = os.environ
         env["ENV"] = os.environ

+ 1 - 1
tools/macos.py

@@ -20,7 +20,7 @@ def exists(env):
 def generate(env):
 def generate(env):
     if env["arch"] not in ("universal", "arm64", "x86_64"):
     if env["arch"] not in ("universal", "arm64", "x86_64"):
         print("Only universal, arm64, and x86_64 are supported on macOS. Exiting.")
         print("Only universal, arm64, and x86_64 are supported on macOS. Exiting.")
-        Exit()
+        env.Exit(1)
 
 
     if sys.platform == "darwin":
     if sys.platform == "darwin":
         # Use clang on macOS by default
         # Use clang on macOS by default