diff --git a/README.md b/README.md index 69693dfc..f4f3be0c 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ first-party `godot-cpp` extension. Some compatibility breakage is to be expected as GDExtension and `godot-cpp` get more used, documented, and critical issues get resolved. See the [Godot issue tracker](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aopen+label%3Atopic%3Agdextension) -and the [godot-cpp issue tracker](https://github.com/godotengine/godot/issues) +and the [godot-cpp issue tracker](https://github.com/godotengine/godot-cpp/issues) for a list of known issues, and be sure to provide feedback on issues and PRs which affect your use of this extension. @@ -74,7 +74,10 @@ so formatting is done before your changes are submitted. ## Getting started -It's a bit similar to what it was for 3.x but also a bit different. +You need the same C++ pre-requisites installed that are required for the `godot` repository. Follow the [official build instructions for your target platform](https://docs.godotengine.org/en/latest/contributing/development/compiling/index.html#building-for-target-platforms). + +Getting started with GDExtensions is a bit similar to what it was for 3.x but also a bit different. + This new approach is much more akin to how core Godot modules are structured. Compiling this repository generates a static library to be linked with your shared lib, diff --git a/binding_generator.py b/binding_generator.py index 478dafe0..27721352 100644 --- a/binding_generator.py +++ b/binding_generator.py @@ -1778,9 +1778,9 @@ def generate_global_constant_binds(api, output_dir): continue if enum_def["is_bitfield"]: - header.append(f'VARIANT_BITFIELD_CAST(godot::{enum_def["name"]});') + header.append(f'VARIANT_BITFIELD_CAST({enum_def["name"]});') else: - header.append(f'VARIANT_ENUM_CAST(godot::{enum_def["name"]});') + header.append(f'VARIANT_ENUM_CAST({enum_def["name"]});') # Variant::Type is not a global enum, but only one line, it is worth to place in this file instead of creating new file. header.append(f"VARIANT_ENUM_CAST(godot::Variant::Type);") @@ -2433,6 +2433,7 @@ def get_operator_id_name(op): "unary-": "negate", "unary+": "positive", "%": "module", + "**": "power", "<<": "shift_left", ">>": "shift_right", "&": "bit_and", diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index f8f921b3..32caf39b 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -48,6 +48,7 @@ typedef void GodotObject; // Base for all engine classes, to contain the pointer to the engine instance. class Wrapped { friend class GDExtensionBinding; + friend class ClassDB; friend void postinitialize_handler(Wrapped *); protected: @@ -131,17 +132,6 @@ struct EngineClassRegistration { } // namespace godot -#ifdef HOT_RELOAD_ENABLED -#define _GDCLASS_RECREATE(m_class, m_inherits) \ - m_class *new_instance = (m_class *)memalloc(sizeof(m_class)); \ - Wrapped::RecreateInstance recreate_data = { new_instance, obj, Wrapped::recreate_instance }; \ - Wrapped::recreate_instance = &recreate_data; \ - memnew_placement(new_instance, m_class); \ - return new_instance; -#else -#define _GDCLASS_RECREATE(m_class, m_inherits) return nullptr; -#endif - // Use this on top of your own classes. // Note: the trail of `***` is to keep sane diffs in PRs, because clang-format otherwise moves every `\` which makes // every line of the macro different @@ -226,15 +216,6 @@ public: return m_inherits::get_class_static(); \ } \ \ - static GDExtensionObjectPtr create(void *data) { \ - m_class *new_object = memnew(m_class); \ - return new_object->_owner; \ - } \ - \ - static GDExtensionClassInstancePtr recreate(void *data, GDExtensionObjectPtr obj) { \ - _GDCLASS_RECREATE(m_class, m_inherits); \ - } \ - \ static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) { \ if (p_instance && m_class::_get_notification()) { \ if (m_class::_get_notification() != m_inherits::_get_notification()) { \ @@ -437,14 +418,6 @@ public: return m_inherits::get_class_static(); \ } \ \ - static GDExtensionObjectPtr create(void *data) { \ - return nullptr; \ - } \ - \ - static GDExtensionClassInstancePtr recreate(void *data, GDExtensionObjectPtr obj) { \ - return nullptr; \ - } \ - \ static void free(void *data, GDExtensionClassInstancePtr ptr) { \ } \ \ diff --git a/include/godot_cpp/core/binder_common.hpp b/include/godot_cpp/core/binder_common.hpp index a51e15e6..ce90acda 100644 --- a/include/godot_cpp/core/binder_common.hpp +++ b/include/godot_cpp/core/binder_common.hpp @@ -281,13 +281,13 @@ void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Vari #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } if ((size_t)p_argcount < sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -299,13 +299,13 @@ void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Var #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } if ((size_t)p_argcount < sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -317,13 +317,13 @@ void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, co #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } if ((size_t)p_argcount < sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -335,7 +335,7 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const G #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -346,7 +346,7 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const G #ifdef DEBUG_ENABLED if (missing > dvs) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -370,7 +370,7 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -381,7 +381,7 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, #ifdef DEBUG_ENABLED if (missing > dvs) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -405,7 +405,7 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -416,7 +416,7 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const #ifdef DEBUG_ENABLED if (missing > dvs) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -440,7 +440,7 @@ void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -451,7 +451,7 @@ void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, #ifdef DEBUG_ENABLED if (missing > dvs) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -552,7 +552,7 @@ void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionC #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = sizeof...(P); + r_error.expected = sizeof...(P); return; } #endif @@ -563,7 +563,7 @@ void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionC #ifdef DEBUG_ENABLED if (missing > dvs) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = sizeof...(P); + r_error.expected = sizeof...(P); return; } #endif @@ -597,13 +597,13 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } if ((size_t)p_argcount < sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -615,13 +615,13 @@ void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } if ((size_t)p_argcount < sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = (int32_t)sizeof...(P); + r_error.expected = (int32_t)sizeof...(P); return; } #endif @@ -644,7 +644,7 @@ void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtension #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = sizeof...(P); + r_error.expected = sizeof...(P); return; } #endif @@ -655,7 +655,7 @@ void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtension #ifdef DEBUG_ENABLED if (missing > dvs) { r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = sizeof...(P); + r_error.expected = sizeof...(P); return; } #endif diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 4196a76b..af394f04 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -112,6 +112,33 @@ private: template static void _register_class(bool p_virtual = false, bool p_exposed = true); + template + static GDExtensionObjectPtr _create_instance_func(void *data) { + if constexpr (!std::is_abstract_v) { + T *new_object = memnew(T); + return new_object->_owner; + } else { + return nullptr; + } + } + + template + static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) { + if constexpr (!std::is_abstract_v) { +#ifdef HOT_RELOAD_ENABLED + T *new_instance = (T *)memalloc(sizeof(T)); + Wrapped::RecreateInstance recreate_data = { new_instance, obj, Wrapped::recreate_instance }; + Wrapped::recreate_instance = &recreate_data; + memnew_placement(new_instance, T); + return new_instance; +#else + return nullptr; +#endif + } else { + return nullptr; + } + } + public: template static void register_class(bool p_virtual = false); @@ -202,9 +229,9 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed) { T::to_string_bind, // GDExtensionClassToString to_string_func; nullptr, // GDExtensionClassReference reference_func; nullptr, // GDExtensionClassUnreference unreference_func; - T::create, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */ + &_create_instance_func, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */ T::free, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */ - T::recreate, // GDExtensionClassRecreateInstance recreate_instance_func; + &_recreate_instance_func, // GDExtensionClassRecreateInstance recreate_instance_func; &ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func; nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func; nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func; diff --git a/include/godot_cpp/variant/aabb.hpp b/include/godot_cpp/variant/aabb.hpp index dde392b5..7706d511 100644 --- a/include/godot_cpp/variant/aabb.hpp +++ b/include/godot_cpp/variant/aabb.hpp @@ -201,11 +201,11 @@ inline bool AABB::encloses(const AABB &p_aabb) const { return ( (src_min.x <= dst_min.x) && - (src_max.x > dst_max.x) && + (src_max.x >= dst_max.x) && (src_min.y <= dst_min.y) && - (src_max.y > dst_max.y) && + (src_max.y >= dst_max.y) && (src_min.z <= dst_min.z) && - (src_max.z > dst_max.z)); + (src_max.z >= dst_max.z)); } Vector3 AABB::get_support(const Vector3 &p_normal) const { diff --git a/include/godot_cpp/variant/variant.hpp b/include/godot_cpp/variant/variant.hpp index fc41014e..3c64791a 100644 --- a/include/godot_cpp/variant/variant.hpp +++ b/include/godot_cpp/variant/variant.hpp @@ -122,6 +122,7 @@ public: OP_NEGATE, OP_POSITIVE, OP_MODULE, + OP_POWER, // bitwise OP_SHIFT_LEFT, OP_SHIFT_RIGHT, @@ -356,6 +357,12 @@ String vformat(const String &p_text, const VarArgs... p_args) { #include +#ifdef REAL_T_IS_DOUBLE +using PackedRealArray = PackedFloat64Array; +#else +using PackedRealArray = PackedFloat32Array; +#endif // REAL_T_IS_DOUBLE + } // namespace godot #endif // GODOT_VARIANT_HPP diff --git a/src/godot.cpp b/src/godot.cpp index ee4156b5..5c2aaa65 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -271,7 +271,12 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge } else if (internal::godot_version.minor != GODOT_VERSION_MINOR) { compatible = internal::godot_version.minor > GODOT_VERSION_MINOR; } else { +#if GODOT_VERSION_PATCH > 0 compatible = internal::godot_version.patch >= GODOT_VERSION_PATCH; +#else + // Prevent -Wtype-limits warning due to unsigned comparison. + compatible = true; +#endif } if (!compatible) { // We need to use snprintf() here because vformat() uses Variant, and we haven't loaded diff --git a/test/src/example.h b/test/src/example.h index 72f6783d..c86a51fd 100644 --- a/test/src/example.h +++ b/test/src/example.h @@ -198,11 +198,22 @@ protected: static void _bind_methods() {} }; -class ExampleAbstract : public Object { - GDCLASS(ExampleAbstract, Object); +class ExampleAbstractBase : public Object { + GDCLASS(ExampleAbstractBase, Object); protected: static void _bind_methods() {} + + virtual int test_function() = 0; +}; + +class ExampleConcrete : public ExampleAbstractBase { + GDCLASS(ExampleConcrete, ExampleAbstractBase); + +protected: + static void _bind_methods() {} + + virtual int test_function() override { return 25; } }; #endif // EXAMPLE_CLASS_H diff --git a/test/src/register_types.cpp b/test/src/register_types.cpp index dbb37d90..58080d20 100644 --- a/test/src/register_types.cpp +++ b/test/src/register_types.cpp @@ -25,7 +25,8 @@ void initialize_example_module(ModuleInitializationLevel p_level) { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(true); - ClassDB::register_abstract_class(); + ClassDB::register_abstract_class(); + ClassDB::register_class(); } void uninitialize_example_module(ModuleInitializationLevel p_level) { diff --git a/tools/android.py b/tools/android.py index bee58c4e..0c253541 100644 --- a/tools/android.py +++ b/tools/android.py @@ -64,6 +64,12 @@ def generate(env): elif sys.platform == "darwin": toolchain += "darwin-x86_64" env.Append(LINKFLAGS=["-shared"]) + + if not os.path.exists(toolchain): + print("ERROR: Could not find NDK toolchain at " + toolchain + ".") + print("Make sure NDK version " + get_ndk_version() + " is installed.") + env.Exit(1) + env.PrependENVPath("PATH", toolchain + "/bin") # This does nothing half of the time, but we'll put it here anyways # Get architecture info diff --git a/tools/godotcpp.py b/tools/godotcpp.py index e445cad3..0b02eea2 100644 --- a/tools/godotcpp.py +++ b/tools/godotcpp.py @@ -295,6 +295,9 @@ def generate(env): if env["precision"] == "double": env.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"]) + # Allow detecting when building as a GDExtension. + env.Append(CPPDEFINES=["GDEXTENSION"]) + # Suffix suffix = ".{}.{}".format(env["platform"], env["target"]) if env.dev_build: