Merge pull request #1244 from dsnopek/4.1-cherrypicks-3
Cherry-picks for the godot-cpp 4.1 branch - 3rd batchpull/1261/head
commit
4eed2d7be0
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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) { \
|
static bool (::godot::Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const { \
|
||||||
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name)) & m_class::_property_can_revert; \
|
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 &) { \
|
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 &)) & m_class::_property_get_revert; \
|
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())() { \
|
static ::godot::String (::godot::Wrapped::*_get_to_string())() const { \
|
||||||
return (::godot::String(::godot::Wrapped::*)()) & m_class::_to_string; \
|
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
|
||||||
|
|
|
@ -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) \
|
||||||
|
|
|
@ -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))));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) \
|
#define ERR_PRINT_EARLY(m_msg) \
|
||||||
internal::gdextension_interface_##m_name = (m_type)p_get_proc_address(#m_name); \
|
internal::gdextension_interface_print_error(m_msg, FUNCTION_STR, __FILE__, __LINE__, false)
|
||||||
ERR_FAIL_NULL_V_MSG(internal::gdextension_interface_##m_name, false, "Unable to load GDExtension interface function " #m_name "()")
|
|
||||||
|
#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;
|
internal::gdextension_interface_print_error = (GDExtensionInterfacePrintError)legacy_interface->print_error;
|
||||||
ERR_FAIL_V_MSG(false, "Cannot load a GDExtension built for Godot 4.1+ in Godot 4.0.");
|
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).
|
// Load the "print_error" function first (needed by the ERR_PRINT_EARLY() macro).
|
||||||
internal::gdextension_interface_print_error_with_message = (GDExtensionInterfacePrintErrorWithMessage)p_get_proc_address("print_error_with_message");
|
internal::gdextension_interface_print_error = (GDExtensionInterfacePrintError)p_get_proc_address("print_error");
|
||||||
if (!internal::gdextension_interface_print_error_with_message) {
|
if (!internal::gdextension_interface_print_error) {
|
||||||
printf("ERROR: Unable to load GDExtension interface function print_error_with_message().\n");
|
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;
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
env.AlwaysBuild(bindings)
|
||||||
NoCache(bindings)
|
env.NoCache(bindings)
|
||||||
|
|
||||||
# Sources to compile
|
# Sources to compile
|
||||||
sources = []
|
sources = []
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue