David Snopek 2024-01-24 08:43:39 -06:00 committed by GitHub
commit 222de11aef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 99 additions and 62 deletions

View File

@ -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,

View File

@ -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",

View File

@ -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) { \
} \
\

View File

@ -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

View File

@ -112,6 +112,33 @@ private:
template <class T, bool is_abstract>
static void _register_class(bool p_virtual = false, bool p_exposed = true);
template <class T>
static GDExtensionObjectPtr _create_instance_func(void *data) {
if constexpr (!std::is_abstract_v<T>) {
T *new_object = memnew(T);
return new_object->_owner;
} else {
return nullptr;
}
}
template <class T>
static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) {
if constexpr (!std::is_abstract_v<T>) {
#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 <class T>
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<T>, // 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<T>, // GDExtensionClassRecreateInstance recreate_instance_func;
&ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;

View File

@ -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 {

View File

@ -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 <godot_cpp/variant/builtin_vararg_methods.hpp>
#ifdef REAL_T_IS_DOUBLE
using PackedRealArray = PackedFloat64Array;
#else
using PackedRealArray = PackedFloat32Array;
#endif // REAL_T_IS_DOUBLE
} // namespace godot
#endif // GODOT_VARIANT_HPP

View File

@ -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

View File

@ -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

View File

@ -25,7 +25,8 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
ClassDB::register_class<ExampleMin>();
ClassDB::register_class<Example>();
ClassDB::register_class<ExampleVirtual>(true);
ClassDB::register_abstract_class<ExampleAbstract>();
ClassDB::register_abstract_class<ExampleAbstractBase>();
ClassDB::register_class<ExampleConcrete>();
}
void uninitialize_example_module(ModuleInitializationLevel p_level) {

View File

@ -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

View File

@ -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: