summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml27
-rw-r--r--.gitignore4
-rw-r--r--binding_generator.py12
-rw-r--r--gdextension/extension_api.json140
-rw-r--r--include/godot_cpp/classes/wrapped.hpp198
-rw-r--r--include/godot_cpp/core/memory.hpp23
-rw-r--r--include/godot_cpp/core/object.hpp24
-rw-r--r--include/godot_cpp/core/object_id.hpp62
-rw-r--r--include/godot_cpp/godot.hpp33
-rw-r--r--include/godot_cpp/variant/callable_custom.hpp64
-rw-r--r--include/godot_cpp/variant/callable_method_pointer.hpp120
-rw-r--r--include/godot_cpp/variant/variant.hpp14
-rw-r--r--src/core/memory.cpp11
-rw-r--r--src/godot.cpp92
-rw-r--r--src/variant/callable_custom.cpp113
-rw-r--r--src/variant/callable_method_pointer.cpp70
-rw-r--r--src/variant/variant.cpp16
-rw-r--r--test/SConstruct11
-rwxr-xr-xtest/generate_xcframework.sh7
-rw-r--r--test/project/bin/libgdexample.macos.template_debug.framework/Resources/Info.plist (renamed from test/project/bin/libgdexample.osx.template_debug.framework/Resources/Info.plist)0
-rw-r--r--test/project/bin/libgdexample.macos.template_release.framework/Resources/Info.plist (renamed from test/project/bin/libgdexample.osx.template_release.framework/Resources/Info.plist)0
-rw-r--r--test/project/example.gdextension16
-rw-r--r--test/project/main.gd31
-rw-r--r--test/project/project.godot1
-rw-r--r--test/src/example.cpp45
-rw-r--r--test/src/example.h1
-rw-r--r--tools/android.py34
-rw-r--r--tools/godotcpp.py22
-rw-r--r--tools/ios.py2
29 files changed, 873 insertions, 320 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1f316ff..4bb1af3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -65,7 +65,7 @@ jobs:
platform: android
artifact-name: godot-cpp-android-arm64-release
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a
- flags: ANDROID_NDK_ROOT=$ANDROID_NDK_LATEST_HOME arch=arm64
+ flags: arch=arm64
run-tests: false
cache-name: android-arm64
@@ -88,7 +88,7 @@ jobs:
env:
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
- EM_VERSION: 3.1.45
+ EM_VERSION: 3.1.39
EM_CACHE_FOLDER: "emsdk-cache"
steps:
@@ -108,29 +108,30 @@ jobs:
with:
python-version: '3.x'
- - name: Linux dependencies
- if: ${{ matrix.platform == 'linux' }}
- run: |
- sudo apt-get update -qq
- sudo apt-get install -qqq build-essential pkg-config
+ - name: Android dependencies
+ if: ${{ matrix.platform == 'android' }}
+ uses: nttld/setup-ndk@v1
+ with:
+ ndk-version: r23c
+ link-to-sdk: true
- name: Web dependencies
if: ${{ matrix.platform == 'web' }}
- uses: mymindstorm/setup-emsdk@v12
+ uses: mymindstorm/setup-emsdk@v13
with:
version: ${{env.EM_VERSION}}
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
- - name: Install scons
- run: |
- python -m pip install scons==4.0.0
-
- name: Setup MinGW for Windows/MinGW build
if: ${{ matrix.platform == 'windows' && matrix.flags == 'use_mingw=yes' }}
uses: egor-tensin/setup-mingw@v2
with:
version: 12.2.0
+ - name: Install scons
+ run: |
+ python -m pip install scons==4.0.0
+
- name: Generate godot-cpp sources only
run: |
scons platform=${{ matrix.platform }} build_library=no ${{ matrix.flags }}
@@ -172,7 +173,7 @@ jobs:
./godot-artifacts/godot.linuxbsd.editor.x86_64.mono --headless --version
cd test
# Need to run the editor so .godot is generated... but it crashes! Ignore that :-)
- (cd project && (../../godot-artifacts/godot.linuxbsd.editor.x86_64.mono --editor --headless --quit >/dev/null 2>&1 || true))
+ (cd project && (timeout 10 ../../godot-artifacts/godot.linuxbsd.editor.x86_64.mono --editor --headless --quit >/dev/null 2>&1 || true))
GODOT=../godot-artifacts/godot.linuxbsd.editor.x86_64.mono ./run-tests.sh
- name: Upload artifact
diff --git a/.gitignore b/.gitignore
index 7c87766..d4b5748 100644
--- a/.gitignore
+++ b/.gitignore
@@ -191,3 +191,7 @@ godot.creator.*
# compile commands (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
compile_commands.json
+
+# Python development
+.venv
+venv
diff --git a/binding_generator.py b/binding_generator.py
index eb201ff..676ff74 100644
--- a/binding_generator.py
+++ b/binding_generator.py
@@ -110,6 +110,8 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
for native_struct in api["native_structures"]:
struct_name = native_struct["name"]
+ if struct_name == "ObjectID":
+ continue
snake_struct_name = camel_to_snake(struct_name)
header_filename = include_gen_folder / "classes" / (snake_struct_name + ".hpp")
@@ -416,6 +418,9 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
if class_name == "Array":
result.append("#include <godot_cpp/variant/array_helpers.hpp>")
+ if class_name == "Callable":
+ result.append("#include <godot_cpp/variant/callable_custom.hpp>")
+
for include in fully_used_classes:
if include == "TypedArray":
result.append("#include <godot_cpp/variant/typed_array.hpp>")
@@ -525,6 +530,9 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append(f"\t{class_name}(const wchar_t *from);")
result.append(f"\t{class_name}(const char16_t *from);")
result.append(f"\t{class_name}(const char32_t *from);")
+ if class_name == "Callable":
+ result.append("\tCallable(CallableCustom *p_custom);")
+ result.append("\tCallableCustom *get_custom() const;")
if "constants" in builtin_api:
axis_constants_count = 0
@@ -1083,6 +1091,8 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
class_api["alias_for"] = "ClassDB"
engine_classes[class_api["name"]] = class_api["is_refcounted"]
for native_struct in api["native_structures"]:
+ if native_struct["name"] == "ObjectID":
+ continue
engine_classes[native_struct["name"]] = False
native_structures.append(native_struct["name"])
@@ -1210,6 +1220,8 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
for native_struct in api["native_structures"]:
struct_name = native_struct["name"]
+ if struct_name == "ObjectID":
+ continue
snake_struct_name = camel_to_snake(struct_name)
header_filename = include_gen_folder / (snake_struct_name + ".hpp")
diff --git a/gdextension/extension_api.json b/gdextension/extension_api.json
index c4d11e7..e8f02ed 100644
--- a/gdextension/extension_api.json
+++ b/gdextension/extension_api.json
@@ -3,9 +3,9 @@
"version_major": 4,
"version_minor": 2,
"version_patch": 0,
- "version_status": "beta3",
+ "version_status": "rc1",
"version_build": "official",
- "version_full_name": "Godot Engine v4.2.beta3.official"
+ "version_full_name": "Godot Engine v4.2.rc1.official"
},
"builtin_class_sizes": [
{
@@ -67179,6 +67179,14 @@
"value": 42
},
{
+ "name": "NOTIFICATION_MOUSE_ENTER_SELF",
+ "value": 60
+ },
+ {
+ "name": "NOTIFICATION_MOUSE_EXIT_SELF",
+ "value": 61
+ },
+ {
"name": "NOTIFICATION_FOCUS_ENTER",
"value": 43
},
@@ -72951,28 +72959,28 @@
"getter": "get_size"
},
{
- "type": "Texture",
+ "type": "Texture2D",
"name": "texture_albedo",
"setter": "set_texture",
"getter": "get_texture",
"index": 0
},
{
- "type": "Texture",
+ "type": "Texture2D",
"name": "texture_normal",
"setter": "set_texture",
"getter": "get_texture",
"index": 1
},
{
- "type": "Texture",
+ "type": "Texture2D",
"name": "texture_orm",
"setter": "set_texture",
"getter": "get_texture",
"index": 2
},
{
- "type": "Texture",
+ "type": "Texture2D",
"name": "texture_emission",
"setter": "set_texture",
"getter": "get_texture",
@@ -125379,28 +125387,28 @@
"api_type": "core",
"methods": [
{
- "name": "set_light_texture",
+ "name": "set_lightmap_textures",
"is_const": false,
"is_vararg": false,
"is_static": false,
"is_virtual": false,
- "hash": 1278366092,
+ "hash": 381264803,
"arguments": [
{
- "name": "light_texture",
- "type": "TextureLayered"
+ "name": "light_textures",
+ "type": "typedarray::TextureLayered"
}
]
},
{
- "name": "get_light_texture",
+ "name": "get_lightmap_textures",
"is_const": true,
"is_vararg": false,
"is_static": false,
"is_virtual": false,
- "hash": 3984243839,
+ "hash": 3995934104,
"return_value": {
- "type": "TextureLayered"
+ "type": "typedarray::TextureLayered"
}
},
{
@@ -125493,20 +125501,39 @@
"is_static": false,
"is_virtual": false,
"hash": 3218959716
+ },
+ {
+ "name": "set_light_texture",
+ "is_const": false,
+ "is_vararg": false,
+ "is_static": false,
+ "is_virtual": false,
+ "hash": 1278366092,
+ "arguments": [
+ {
+ "name": "light_texture",
+ "type": "TextureLayered"
+ }
+ ]
+ },
+ {
+ "name": "get_light_texture",
+ "is_const": true,
+ "is_vararg": false,
+ "is_static": false,
+ "is_virtual": false,
+ "hash": 3984243839,
+ "return_value": {
+ "type": "TextureLayered"
+ }
}
],
"properties": [
{
- "type": "TextureLayered",
- "name": "light_texture",
- "setter": "set_light_texture",
- "getter": "get_light_texture"
- },
- {
- "type": "Array",
- "name": "light_textures",
- "setter": "_set_light_textures_data",
- "getter": "_get_light_textures_data"
+ "type": "typedarray::TextureLayered",
+ "name": "lightmap_textures",
+ "setter": "set_lightmap_textures",
+ "getter": "get_lightmap_textures"
},
{
"type": "bool",
@@ -125525,6 +125552,18 @@
"name": "probe_data",
"setter": "_set_probe_data",
"getter": "_get_probe_data"
+ },
+ {
+ "type": "TextureLayered",
+ "name": "light_texture",
+ "setter": "set_light_texture",
+ "getter": "get_light_texture"
+ },
+ {
+ "type": "Array",
+ "name": "light_textures",
+ "setter": "_set_light_textures_data",
+ "getter": "_get_light_textures_data"
}
]
},
@@ -127389,7 +127428,7 @@
"getter": "is_drag_and_drop_selection_enabled"
},
{
- "type": "Texture",
+ "type": "Texture2D",
"name": "right_icon",
"setter": "set_right_icon",
"getter": "get_right_icon"
@@ -128961,6 +129000,10 @@
{
"name": "ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY",
"value": 268435456
+ },
+ {
+ "name": "ARRAY_FLAG_COMPRESS_ATTRIBUTES",
+ "value": 536870912
}
]
},
@@ -145289,10 +145332,6 @@
"value": 29
},
{
- "name": "NOTIFICATION_NODE_RECACHE_REQUESTED",
- "value": 30
- },
- {
"name": "NOTIFICATION_EDITOR_PRE_SAVE",
"value": 9001
},
@@ -225928,7 +225967,7 @@
],
"properties": [
{
- "type": "Texture",
+ "type": "Texture2D",
"name": "texture",
"setter": "set_texture",
"getter": "get_texture"
@@ -232117,6 +232156,12 @@
"properties": [
{
"type": "int",
+ "name": "tab_count",
+ "setter": "set_tab_count",
+ "getter": "get_tab_count"
+ },
+ {
+ "type": "int",
"name": "current_tab",
"setter": "set_current_tab",
"getter": "get_current_tab"
@@ -232174,12 +232219,6 @@
"name": "select_with_rmb",
"setter": "set_select_with_rmb",
"getter": "get_select_with_rmb"
- },
- {
- "type": "int",
- "name": "tab_count",
- "setter": "set_tab_count",
- "getter": "get_tab_count"
}
]
},
@@ -266708,31 +266747,6 @@
}
},
{
- "name": "set_disable_2d",
- "is_const": false,
- "is_vararg": false,
- "is_static": false,
- "is_virtual": false,
- "hash": 2586408642,
- "arguments": [
- {
- "name": "disable",
- "type": "bool"
- }
- ]
- },
- {
- "name": "is_2d_disabled",
- "is_const": true,
- "is_vararg": false,
- "is_static": false,
- "is_virtual": false,
- "hash": 36873697,
- "return_value": {
- "type": "bool"
- }
- },
- {
"name": "set_disable_3d",
"is_const": false,
"is_vararg": false,
@@ -266956,12 +266970,6 @@
"properties": [
{
"type": "bool",
- "name": "disable_2d",
- "setter": "set_disable_2d",
- "getter": "is_2d_disabled"
- },
- {
- "type": "bool",
"name": "disable_3d",
"setter": "set_disable_3d",
"getter": "is_3d_disabled"
diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp
index af2ce4c..f8f921b 100644
--- a/include/godot_cpp/classes/wrapped.hpp
+++ b/include/godot_cpp/classes/wrapped.hpp
@@ -365,105 +365,109 @@ public:
_gde_binding_create_callback, \
_gde_binding_free_callback, \
_gde_binding_reference_callback, \
- };
+ }; \
+ \
+private:
// Don't use this for your classes, use GDCLASS() instead.
-#define GDEXTENSION_CLASS_ALIAS(m_class, m_alias_for, m_inherits) \
-private: \
- inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \
- void operator=(const m_class &p_rval) {} \
- \
-protected: \
- virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
- return &_gde_binding_callbacks; \
- } \
- \
- m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \
- m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
- \
- static void (*_get_bind_methods())() { \
- return nullptr; \
- } \
- \
- static void (Wrapped::*_get_notification())(int) { \
- return nullptr; \
- } \
- \
- static bool (Wrapped::*_get_set())(const ::godot::StringName &p_name, const Variant &p_property) { \
- return nullptr; \
- } \
- \
- static bool (Wrapped::*_get_get())(const ::godot::StringName &p_name, Variant &r_ret) const { \
- return nullptr; \
- } \
- \
- static inline bool has_get_property_list() { \
- return false; \
- } \
- \
- static void (Wrapped::*_get_get_property_list())(List<PropertyInfo> * p_list) const { \
- return nullptr; \
- } \
- \
- static bool (Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const { \
- return nullptr; \
- } \
- \
- static bool (Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, Variant &) const { \
- return nullptr; \
- } \
- \
- static void (Wrapped::*_get_validate_property())(::godot::PropertyInfo & p_property) const { \
- return nullptr; \
- } \
- \
- static String (Wrapped::*_get_to_string())() const { \
- return nullptr; \
- } \
- \
-public: \
- typedef m_class self_type; \
- \
- static void initialize_class() {} \
- \
- static ::godot::StringName &get_class_static() { \
- static ::godot::StringName string_name = ::godot::StringName(#m_alias_for); \
- return string_name; \
- } \
- \
- static ::godot::StringName &get_parent_class_static() { \
- 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) { \
- } \
- \
- static void *_gde_binding_create_callback(void *p_token, void *p_instance) { \
- /* Do not call memnew here, we don't want the post-initializer to be called */ \
- return new ("") m_class((GodotObject *)p_instance); \
- } \
- static void _gde_binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
- /* Explicitly call the deconstructor to ensure proper lifecycle for non-trivial members */ \
- reinterpret_cast<m_class *>(p_binding)->~m_class(); \
- Memory::free_static(reinterpret_cast<m_class *>(p_binding)); \
- } \
- static GDExtensionBool _gde_binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \
- return true; \
- } \
- static constexpr GDExtensionInstanceBindingCallbacks _gde_binding_callbacks = { \
- _gde_binding_create_callback, \
- _gde_binding_free_callback, \
- _gde_binding_reference_callback, \
- }; \
- m_class() : m_class(#m_alias_for) {}
+#define GDEXTENSION_CLASS_ALIAS(m_class, m_alias_for, m_inherits) /******************************************************************************************************************/ \
+private: \
+ inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \
+ void operator=(const m_class &p_rval) {} \
+ \
+protected: \
+ virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
+ return &_gde_binding_callbacks; \
+ } \
+ \
+ m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \
+ m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
+ \
+ static void (*_get_bind_methods())() { \
+ return nullptr; \
+ } \
+ \
+ static void (Wrapped::*_get_notification())(int) { \
+ return nullptr; \
+ } \
+ \
+ static bool (Wrapped::*_get_set())(const ::godot::StringName &p_name, const Variant &p_property) { \
+ return nullptr; \
+ } \
+ \
+ static bool (Wrapped::*_get_get())(const ::godot::StringName &p_name, Variant &r_ret) const { \
+ return nullptr; \
+ } \
+ \
+ static inline bool has_get_property_list() { \
+ return false; \
+ } \
+ \
+ static void (Wrapped::*_get_get_property_list())(List<PropertyInfo> * p_list) const { \
+ return nullptr; \
+ } \
+ \
+ static bool (Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const { \
+ return nullptr; \
+ } \
+ \
+ static bool (Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, Variant &) const { \
+ return nullptr; \
+ } \
+ \
+ static void (Wrapped::*_get_validate_property())(::godot::PropertyInfo & p_property) const { \
+ return nullptr; \
+ } \
+ \
+ static String (Wrapped::*_get_to_string())() const { \
+ return nullptr; \
+ } \
+ \
+public: \
+ typedef m_class self_type; \
+ \
+ static void initialize_class() {} \
+ \
+ static ::godot::StringName &get_class_static() { \
+ static ::godot::StringName string_name = ::godot::StringName(#m_alias_for); \
+ return string_name; \
+ } \
+ \
+ static ::godot::StringName &get_parent_class_static() { \
+ 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) { \
+ } \
+ \
+ static void *_gde_binding_create_callback(void *p_token, void *p_instance) { \
+ /* Do not call memnew here, we don't want the post-initializer to be called */ \
+ return new ("", "") m_class((GodotObject *)p_instance); \
+ } \
+ static void _gde_binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
+ /* Explicitly call the deconstructor to ensure proper lifecycle for non-trivial members */ \
+ reinterpret_cast<m_class *>(p_binding)->~m_class(); \
+ Memory::free_static(reinterpret_cast<m_class *>(p_binding)); \
+ } \
+ static GDExtensionBool _gde_binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \
+ return true; \
+ } \
+ static constexpr GDExtensionInstanceBindingCallbacks _gde_binding_callbacks = { \
+ _gde_binding_create_callback, \
+ _gde_binding_free_callback, \
+ _gde_binding_reference_callback, \
+ }; \
+ m_class() : m_class(#m_alias_for) {} \
+ \
+private:
// 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)
diff --git a/include/godot_cpp/core/memory.hpp b/include/godot_cpp/core/memory.hpp
index 548f330..97a2b13 100644
--- a/include/godot_cpp/core/memory.hpp
+++ b/include/godot_cpp/core/memory.hpp
@@ -44,20 +44,21 @@
#define PAD_ALIGN 16 //must always be greater than this at much
#endif
-void *operator new(size_t p_size, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
-void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
-void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
+// p_dummy argument is added to avoid conflicts with the engine functions when both engine and GDExtension are built as a static library on iOS.
+void *operator new(size_t p_size, const char *p_dummy, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
+void *operator new(size_t p_size, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
+void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
-_ALWAYS_INLINE_ void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description) {
+_ALWAYS_INLINE_ void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description) {
return p_pointer;
}
#ifdef _MSC_VER
// When compiling with VC++ 2017, the above declarations of placement new generate many irrelevant warnings (C4291).
// The purpose of the following definitions is to muffle these warnings, not to provide a usable implementation of placement delete.
-void operator delete(void *p_mem, const char *p_description);
-void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size));
-void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description);
+void operator delete(void *p_mem, const char *p_dummy, const char *p_description);
+void operator delete(void *p_mem, const char *p_dummy, void *(*p_allocfunc)(size_t p_size));
+void operator delete(void *p_mem, const char *p_dummy, void *p_pointer, size_t check, const char *p_description);
#endif
namespace godot {
@@ -85,10 +86,10 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
#define memrealloc(m_mem, m_size) ::godot::Memory::realloc_static(m_mem, m_size)
#define memfree(m_mem) ::godot::Memory::free_static(m_mem)
-#define memnew(m_class) ::godot::_post_initialize(new ("") m_class)
+#define memnew(m_class) ::godot::_post_initialize(new ("", "") m_class)
-#define memnew_allocator(m_class, m_allocator) ::godot::_post_initialize(new (m_allocator::alloc) m_class)
-#define memnew_placement(m_placement, m_class) ::godot::_post_initialize(new (m_placement, sizeof(m_class), "") m_class)
+#define memnew_allocator(m_class, m_allocator) ::godot::_post_initialize(new ("", m_allocator::alloc) m_class)
+#define memnew_placement(m_placement, m_class) ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class)
// Generic comparator used in Map, List, etc.
template <class T>
@@ -154,7 +155,7 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
/* call operator new */
for (size_t i = 0; i < p_elements; i++) {
- new (&elems[i], sizeof(T), p_descr) T;
+ new ("", &elems[i], sizeof(T), p_descr) T;
}
}
diff --git a/include/godot_cpp/core/object.hpp b/include/godot_cpp/core/object.hpp
index 4e85e4d..79f8fbf 100644
--- a/include/godot_cpp/core/object.hpp
+++ b/include/godot_cpp/core/object.hpp
@@ -33,6 +33,8 @@
#include <godot_cpp/core/defs.hpp>
+#include <godot_cpp/core/object_id.hpp>
+
#include <godot_cpp/core/property_info.hpp>
#include <godot_cpp/variant/variant.hpp>
@@ -106,28 +108,6 @@ MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args
arguments = { args... };
}
-class ObjectID {
- uint64_t id = 0;
-
-public:
- _FORCE_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
- _FORCE_INLINE_ bool is_valid() const { return id != 0; }
- _FORCE_INLINE_ bool is_null() const { return id == 0; }
- _FORCE_INLINE_ operator uint64_t() const { return id; }
- _FORCE_INLINE_ operator int64_t() const { return id; }
-
- _FORCE_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
- _FORCE_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
- _FORCE_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }
-
- _FORCE_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
- _FORCE_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }
-
- _FORCE_INLINE_ ObjectID() {}
- _FORCE_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
- _FORCE_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
-};
-
class ObjectDB {
public:
static Object *get_instance(uint64_t p_object_id) {
diff --git a/include/godot_cpp/core/object_id.hpp b/include/godot_cpp/core/object_id.hpp
new file mode 100644
index 0000000..9f3bc96
--- /dev/null
+++ b/include/godot_cpp/core/object_id.hpp
@@ -0,0 +1,62 @@
+/**************************************************************************/
+/* object_id.hpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef GODOT_OBJECT_ID_HPP
+#define GODOT_OBJECT_ID_HPP
+
+#include <godot_cpp/core/defs.hpp>
+
+namespace godot {
+
+class ObjectID {
+ uint64_t id = 0;
+
+public:
+ _FORCE_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
+ _FORCE_INLINE_ bool is_valid() const { return id != 0; }
+ _FORCE_INLINE_ bool is_null() const { return id == 0; }
+ _FORCE_INLINE_ operator uint64_t() const { return id; }
+ _FORCE_INLINE_ operator int64_t() const { return id; }
+
+ _FORCE_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
+ _FORCE_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
+ _FORCE_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }
+
+ _FORCE_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
+ _FORCE_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }
+
+ _FORCE_INLINE_ ObjectID() {}
+ _FORCE_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
+ _FORCE_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
+};
+
+} // namespace godot
+
+#endif // GODOT_OBJECT_ID_HPP
diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp
index 46911dc..c9e9022 100644
--- a/include/godot_cpp/godot.hpp
+++ b/include/godot_cpp/godot.hpp
@@ -166,6 +166,7 @@ extern "C" GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to
extern "C" GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id;
extern "C" GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id;
extern "C" GDExtensionInterfaceCallableCustomCreate gdextension_interface_callable_custom_create;
+extern "C" GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata;
extern "C" GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object;
extern "C" GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object;
extern "C" GDExtensionInterfaceScriptInstanceCreate2 gdextension_interface_script_instance_create2;
@@ -193,26 +194,44 @@ enum ModuleInitializationLevel {
MODULE_INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
MODULE_INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
MODULE_INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE,
- MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR
+ MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR,
+ MODULE_INITIALIZATION_LEVEL_MAX
};
class GDExtensionBinding {
public:
using Callback = void (*)(ModuleInitializationLevel p_level);
- static Callback init_callback;
- static Callback terminate_callback;
- static GDExtensionInitializationLevel minimum_initialization_level;
- static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
+ struct InitData {
+ GDExtensionInitializationLevel minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
+ Callback init_callback = nullptr;
+ Callback terminate_callback = nullptr;
+ };
+
+ class InitDataList {
+ int data_count = 0;
+ int data_capacity = 0;
+ InitData **data = nullptr;
+
+ public:
+ void add(InitData *p_cb);
+ ~InitDataList();
+ };
+
+ static bool api_initialized;
+ static int level_initialized[MODULE_INITIALIZATION_LEVEL_MAX];
+ static InitDataList initdata;
+ static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, InitData *p_init_data, GDExtensionInitialization *r_initialization);
public:
- static void initialize_level(void *userdata, GDExtensionInitializationLevel p_level);
- static void deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level);
+ static void initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
+ static void deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
class InitObject {
GDExtensionInterfaceGetProcAddress get_proc_address;
GDExtensionClassLibraryPtr library;
GDExtensionInitialization *initialization;
+ mutable InitData *init_data = nullptr;
public:
InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
diff --git a/include/godot_cpp/variant/callable_custom.hpp b/include/godot_cpp/variant/callable_custom.hpp
new file mode 100644
index 0000000..34328f9
--- /dev/null
+++ b/include/godot_cpp/variant/callable_custom.hpp
@@ -0,0 +1,64 @@
+/**************************************************************************/
+/* callable_custom.hpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef GODOT_CALLABLE_CUSTOM_HPP
+#define GODOT_CALLABLE_CUSTOM_HPP
+
+#include <godot_cpp/core/object_id.hpp>
+#include <godot_cpp/variant/string_name.hpp>
+
+namespace godot {
+
+class Object;
+
+class CallableCustomBase {
+public:
+ virtual ObjectID get_object() const = 0;
+ virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
+ virtual ~CallableCustomBase() {}
+};
+
+class CallableCustom : public CallableCustomBase {
+public:
+ typedef bool (*CompareEqualFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
+ typedef bool (*CompareLessFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
+
+ virtual uint32_t hash() const = 0;
+ virtual String get_as_text() const = 0;
+ virtual CompareEqualFunc get_compare_equal_func() const = 0;
+ virtual CompareLessFunc get_compare_less_func() const = 0;
+ virtual bool is_valid() const;
+ virtual ObjectID get_object() const = 0;
+ virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
+};
+
+} // namespace godot
+
+#endif // GODOT_CALLABLE_CUSTOM_HPP
diff --git a/include/godot_cpp/variant/callable_method_pointer.hpp b/include/godot_cpp/variant/callable_method_pointer.hpp
index d83bcba..159f976 100644
--- a/include/godot_cpp/variant/callable_method_pointer.hpp
+++ b/include/godot_cpp/variant/callable_method_pointer.hpp
@@ -36,16 +36,23 @@
namespace godot {
-class CallableCustomMethodPointerBase {
+class CallableCustomMethodPointerBase : public CallableCustomBase {
+ uint32_t *comp_ptr = nullptr;
+ uint32_t comp_size;
+ uint32_t h;
+
+protected:
+ void _setup(uint32_t *p_base_ptr, uint32_t p_ptr_size);
+
public:
- virtual Object *get_object() const = 0;
- virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
- virtual ~CallableCustomMethodPointerBase() {}
+ _FORCE_INLINE_ const uint32_t *get_comp_ptr() const { return comp_ptr; }
+ _FORCE_INLINE_ uint32_t get_comp_size() const { return comp_size; }
+ _FORCE_INLINE_ uint32_t get_hash() const { return h; }
};
namespace internal {
-Callable create_custom_callable(CallableCustomMethodPointerBase *p_callable_method_pointer);
+Callable create_callable_from_ccmp(CallableCustomMethodPointerBase *p_callable_method_pointer);
} // namespace internal
@@ -55,21 +62,26 @@ Callable create_custom_callable(CallableCustomMethodPointerBase *p_callable_meth
template <class T, class... P>
class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
- T *instance;
- void (T::*method)(P...);
+ struct Data {
+ T *instance;
+ void (T::*method)(P...);
+ } data;
+ static_assert(sizeof(Data) % 4 == 0);
public:
- virtual Object *get_object() const override {
- return instance;
+ virtual ObjectID get_object() const override {
+ return ObjectID(data.instance->get_instance_id());
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
- call_with_variant_args(instance, method, p_arguments, p_argcount, r_call_error);
+ call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
}
CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) {
- instance = p_instance;
- method = p_method;
+ memset(&data, 0, sizeof(Data));
+ data.instance = p_instance;
+ data.method = p_method;
+ _setup((uint32_t *)&data, sizeof(Data));
}
};
@@ -77,7 +89,7 @@ template <class T, class... P>
Callable create_custom_callable_function_pointer(T *p_instance, void (T::*p_method)(P...)) {
typedef CallableCustomMethodPointer<T, P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
- return ::godot::internal::create_custom_callable(ccmp);
+ return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
@@ -86,22 +98,27 @@ Callable create_custom_callable_function_pointer(T *p_instance, void (T::*p_meth
template <class T, class R, class... P>
class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
- T *instance;
- R(T::*method)
- (P...);
+ struct Data {
+ T *instance;
+ R(T::*method)
+ (P...);
+ } data;
+ static_assert(sizeof(Data) % 4 == 0);
public:
- virtual Object *get_object() const override {
- return instance;
+ virtual ObjectID get_object() const override {
+ return ObjectID(data.instance->get_instance_id());
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
- call_with_variant_args_ret(instance, method, p_arguments, p_argcount, r_return_value, r_call_error);
+ call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) {
- instance = p_instance;
- method = p_method;
+ memset(&data, 0, sizeof(Data));
+ data.instance = p_instance;
+ data.method = p_method;
+ _setup((uint32_t *)&data, sizeof(Data));
}
};
@@ -109,7 +126,7 @@ template <class T, class R, class... P>
Callable create_custom_callable_function_pointer(T *p_instance, R (T::*p_method)(P...)) {
typedef CallableCustomMethodPointerRet<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
- return ::godot::internal::create_custom_callable(ccmp);
+ return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
@@ -118,22 +135,27 @@ Callable create_custom_callable_function_pointer(T *p_instance, R (T::*p_method)
template <class T, class R, class... P>
class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
- T *instance;
- R(T::*method)
- (P...) const;
+ struct Data {
+ T *instance;
+ R(T::*method)
+ (P...) const;
+ } data;
+ static_assert(sizeof(Data) % 4 == 0);
public:
- virtual Object *get_object() const override {
- return instance;
+ virtual ObjectID get_object() const override {
+ return ObjectID(data.instance->get_instance_id());
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
- call_with_variant_args_retc(instance, method, p_arguments, p_argcount, r_return_value, r_call_error);
+ call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomMethodPointerRetC(const T *p_instance, R (T::*p_method)(P...) const) {
- instance = const_cast<T *>(p_instance);
- method = p_method;
+ memset(&data, 0, sizeof(Data));
+ data.instance = const_cast<T *>(p_instance);
+ data.method = p_method;
+ _setup((uint32_t *)&data, sizeof(Data));
}
};
@@ -141,7 +163,7 @@ template <class T, class R, class... P>
Callable create_custom_callable_function_pointer(const T *p_instance, R (T::*p_method)(P...) const) {
typedef CallableCustomMethodPointerRetC<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
- return ::godot::internal::create_custom_callable(ccmp);
+ return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
@@ -150,20 +172,25 @@ Callable create_custom_callable_function_pointer(const T *p_instance, R (T::*p_m
template <class... P>
class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase {
- void (*method)(P...);
+ struct Data {
+ void (*method)(P...);
+ } data;
+ static_assert(sizeof(Data) % 4 == 0);
public:
- virtual Object *get_object() const override {
- return nullptr;
+ virtual ObjectID get_object() const override {
+ return ObjectID();
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
- call_with_variant_args_static_ret(method, p_arguments, p_argcount, r_return_value, r_call_error);
+ call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
r_return_value = Variant();
}
CallableCustomStaticMethodPointer(void (*p_method)(P...)) {
- method = p_method;
+ memset(&data, 0, sizeof(Data));
+ data.method = p_method;
+ _setup((uint32_t *)&data, sizeof(Data));
}
};
@@ -171,7 +198,7 @@ template <class... P>
Callable create_custom_callable_static_function_pointer(void (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointer<P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_method));
- return ::godot::internal::create_custom_callable(ccmp);
+ return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
@@ -180,20 +207,25 @@ Callable create_custom_callable_static_function_pointer(void (*p_method)(P...))
template <class R, class... P>
class CallableCustomStaticMethodPointerRet : public CallableCustomMethodPointerBase {
- R(*method)
- (P...);
+ struct Data {
+ R(*method)
+ (P...);
+ } data;
+ static_assert(sizeof(Data) % 4 == 0);
public:
- virtual Object *get_object() const override {
- return nullptr;
+ virtual ObjectID get_object() const override {
+ return ObjectID();
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
- call_with_variant_args_static_ret(method, p_arguments, p_argcount, r_return_value, r_call_error);
+ call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomStaticMethodPointerRet(R (*p_method)(P...)) {
- method = p_method;
+ memset(&data, 0, sizeof(Data));
+ data.method = p_method;
+ _setup((uint32_t *)&data, sizeof(Data));
}
};
@@ -201,7 +233,7 @@ template <class R, class... P>
Callable create_custom_callable_static_function_pointer(R (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointerRet<R, P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_method));
- return ::godot::internal::create_custom_callable(ccmp);
+ return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
diff --git a/include/godot_cpp/variant/variant.hpp b/include/godot_cpp/variant/variant.hpp
index 3e8738c..fc41014 100644
--- a/include/godot_cpp/variant/variant.hpp
+++ b/include/godot_cpp/variant/variant.hpp
@@ -154,10 +154,18 @@ public:
Variant(int64_t v);
Variant(int32_t v) :
Variant(static_cast<int64_t>(v)) {}
- Variant(uint32_t v) :
+ Variant(int16_t v) :
+ Variant(static_cast<int64_t>(v)) {}
+ Variant(int8_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(uint64_t v) :
Variant(static_cast<int64_t>(v)) {}
+ Variant(uint32_t v) :
+ Variant(static_cast<int64_t>(v)) {}
+ Variant(uint16_t v) :
+ Variant(static_cast<int64_t>(v)) {}
+ Variant(uint8_t v) :
+ Variant(static_cast<int64_t>(v)) {}
Variant(double v);
Variant(float v) :
Variant((double)v) {}
@@ -209,8 +217,12 @@ public:
operator bool() const;
operator int64_t() const;
operator int32_t() const;
+ operator int16_t() const;
+ operator int8_t() const;
operator uint64_t() const;
operator uint32_t() const;
+ operator uint16_t() const;
+ operator uint8_t() const;
operator double() const;
operator float() const;
operator String() const;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 80e71ec..8118511 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -103,28 +103,29 @@ _GlobalNil _GlobalNilClass::_nil;
} // namespace godot
-void *operator new(size_t p_size, const char *p_description) {
+// p_dummy argument is added to avoid conflicts with the engine functions when both engine and GDExtension are built as a static library on iOS.
+void *operator new(size_t p_size, const char *p_dummy, const char *p_description) {
return godot::Memory::alloc_static(p_size);
}
-void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)) {
+void *operator new(size_t p_size, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)) {
return p_allocfunc(p_size);
}
using namespace godot;
#ifdef _MSC_VER
-void operator delete(void *p_mem, const char *p_description) {
+void operator delete(void *p_mem, const char *p_dummy, const char *p_description) {
ERR_PRINT("Call to placement delete should not happen.");
CRASH_NOW();
}
-void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size)) {
+void operator delete(void *p_mem, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)) {
ERR_PRINT("Call to placement delete should not happen.");
CRASH_NOW();
}
-void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description) {
+void operator delete(void *p_mem, const char *p_dummy, void *p_pointer, size_t check, const char *p_description) {
ERR_PRINT("Call to placement delete should not happen.");
CRASH_NOW();
}
diff --git a/src/godot.cpp b/src/godot.cpp
index 7579cfd..ee4156b 100644
--- a/src/godot.cpp
+++ b/src/godot.cpp
@@ -172,6 +172,7 @@ GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to = nullptr;
GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id = nullptr;
GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id = nullptr;
GDExtensionInterfaceCallableCustomCreate gdextension_interface_callable_custom_create = nullptr;
+GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata = nullptr;
GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object = nullptr;
GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object = nullptr;
GDExtensionInterfaceScriptInstanceCreate2 gdextension_interface_script_instance_create2 = nullptr;
@@ -195,9 +196,9 @@ GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugi
} // namespace internal
-GDExtensionBinding::Callback GDExtensionBinding::init_callback = nullptr;
-GDExtensionBinding::Callback GDExtensionBinding::terminate_callback = nullptr;
-GDExtensionInitializationLevel GDExtensionBinding::minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
+bool GDExtensionBinding::api_initialized = false;
+int GDExtensionBinding::level_initialized[MODULE_INITIALIZATION_LEVEL_MAX] = { 0 };
+GDExtensionBinding::InitDataList GDExtensionBinding::initdata;
#define ERR_PRINT_EARLY(m_msg) \
internal::gdextension_interface_print_error(m_msg, FUNCTION_STR, __FILE__, __LINE__, false)
@@ -224,7 +225,20 @@ typedef struct {
GDExtensionInterfacePrintErrorWithMessage print_error_with_message;
} LegacyGDExtensionInterface;
-GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
+GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, InitData *p_init_data, GDExtensionInitialization *r_initialization) {
+ if (!p_init_data || !p_init_data->init_callback) {
+ ERR_FAIL_V_MSG(false, "Initialization callback must be defined.");
+ }
+
+ if (api_initialized) {
+ r_initialization->initialize = initialize_level;
+ r_initialization->deinitialize = deinitialize_level;
+ r_initialization->userdata = p_init_data;
+ r_initialization->minimum_initialization_level = p_init_data->minimum_initialization_level;
+
+ return true;
+ }
+
// Make sure we weren't passed the legacy struct.
uint32_t *raw_interface = (uint32_t *)(void *)p_get_proc_address;
if (raw_interface[0] == 4 && raw_interface[1] == 0) {
@@ -390,6 +404,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(object_get_instance_from_id, GDExtensionInterfaceObjectGetInstanceFromId);
LOAD_PROC_ADDRESS(object_get_instance_id, GDExtensionInterfaceObjectGetInstanceId);
LOAD_PROC_ADDRESS(callable_custom_create, GDExtensionInterfaceCallableCustomCreate);
+ LOAD_PROC_ADDRESS(callable_custom_get_userdata, GDExtensionInterfaceCallableCustomGetUserData);
LOAD_PROC_ADDRESS(ref_get_object, GDExtensionInterfaceRefGetObject);
LOAD_PROC_ADDRESS(ref_set_object, GDExtensionInterfaceRefSetObject);
LOAD_PROC_ADDRESS(script_instance_create2, GDExtensionInterfaceScriptInstanceCreate2);
@@ -413,59 +428,96 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
r_initialization->initialize = initialize_level;
r_initialization->deinitialize = deinitialize_level;
- r_initialization->minimum_initialization_level = minimum_initialization_level;
-
- ERR_FAIL_NULL_V_MSG(init_callback, false, "Initialization callback must be defined.");
+ r_initialization->userdata = p_init_data;
+ r_initialization->minimum_initialization_level = p_init_data->minimum_initialization_level;
Variant::init_bindings();
godot::internal::register_engine_classes();
+ api_initialized = true;
return true;
}
#undef LOAD_PROC_ADDRESS
#undef ERR_PRINT_EARLY
-void GDExtensionBinding::initialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
+void GDExtensionBinding::initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level) {
+ ERR_FAIL_COND(static_cast<ModuleInitializationLevel>(p_level) >= MODULE_INITIALIZATION_LEVEL_MAX);
ClassDB::current_level = p_level;
- if (init_callback) {
- init_callback(static_cast<ModuleInitializationLevel>(p_level));
+ InitData *init_data = static_cast<InitData *>(p_userdata);
+ if (init_data && init_data->init_callback) {
+ init_data->init_callback(static_cast<ModuleInitializationLevel>(p_level));
}
- ClassDB::initialize(p_level);
+ if (level_initialized[p_level] == 0) {
+ ClassDB::initialize(p_level);
+ }
+ level_initialized[p_level]++;
}
-void GDExtensionBinding::deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
+void GDExtensionBinding::deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level) {
+ ERR_FAIL_COND(static_cast<ModuleInitializationLevel>(p_level) >= MODULE_INITIALIZATION_LEVEL_MAX);
ClassDB::current_level = p_level;
- if (terminate_callback) {
- terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
+ InitData *init_data = static_cast<InitData *>(p_userdata);
+ if (init_data && init_data->terminate_callback) {
+ init_data->terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
+ }
+
+ level_initialized[p_level]--;
+ if (level_initialized[p_level] == 0) {
+ EditorPlugins::deinitialize(p_level);
+ ClassDB::deinitialize(p_level);
+ }
+}
+
+void GDExtensionBinding::InitDataList::add(InitData *p_data) {
+ if (data_count == data_capacity) {
+ void *new_ptr = realloc(data, sizeof(InitData *) * (data_capacity + 32));
+ if (new_ptr) {
+ data = (InitData **)(new_ptr);
+ data_capacity += 32;
+ } else {
+ ERR_FAIL_MSG("Unable to allocate memory for extension callbacks.");
+ }
}
+ data[data_count++] = p_data;
+}
- EditorPlugins::deinitialize(p_level);
- ClassDB::deinitialize(p_level);
+GDExtensionBinding::InitDataList::~InitDataList() {
+ for (int i = 0; i < data_count; i++) {
+ if (data[i]) {
+ delete data[i];
+ }
+ }
+ if (data) {
+ free(data);
+ }
}
+
GDExtensionBinding::InitObject::InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
get_proc_address = p_get_proc_address;
library = p_library;
initialization = r_initialization;
+ init_data = new InitData();
+ GDExtensionBinding::initdata.add(init_data);
}
void GDExtensionBinding::InitObject::register_initializer(Callback p_init) const {
- GDExtensionBinding::init_callback = p_init;
+ init_data->init_callback = p_init;
}
void GDExtensionBinding::InitObject::register_terminator(Callback p_terminate) const {
- GDExtensionBinding::terminate_callback = p_terminate;
+ init_data->terminate_callback = p_terminate;
}
void GDExtensionBinding::InitObject::set_minimum_library_initialization_level(ModuleInitializationLevel p_level) const {
- GDExtensionBinding::minimum_initialization_level = static_cast<GDExtensionInitializationLevel>(p_level);
+ init_data->minimum_initialization_level = static_cast<GDExtensionInitializationLevel>(p_level);
}
GDExtensionBool GDExtensionBinding::InitObject::init() const {
- return GDExtensionBinding::init(get_proc_address, library, initialization);
+ return GDExtensionBinding::init(get_proc_address, library, init_data, initialization);
}
} // namespace godot
diff --git a/src/variant/callable_custom.cpp b/src/variant/callable_custom.cpp
new file mode 100644
index 0000000..e0540fa
--- /dev/null
+++ b/src/variant/callable_custom.cpp
@@ -0,0 +1,113 @@
+/**************************************************************************/
+/* callable_custom.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include <godot_cpp/variant/callable_custom.hpp>
+
+#include <godot_cpp/core/object.hpp>
+#include <godot_cpp/variant/callable.hpp>
+
+namespace godot {
+
+static void callable_custom_call(void *p_userdata, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error) {
+ CallableCustom *callable_custom = (CallableCustom *)p_userdata;
+ callable_custom->call((const Variant **)p_args, p_argument_count, *(Variant *)r_return, *r_error);
+}
+
+static GDExtensionBool callable_custom_is_valid(void *p_userdata) {
+ CallableCustom *callable_custom = (CallableCustom *)p_userdata;
+ return callable_custom->is_valid();
+}
+
+static void callable_custom_free(void *p_userdata) {
+ CallableCustom *callable_custom = (CallableCustom *)p_userdata;
+ memdelete(callable_custom);
+}
+
+static uint32_t callable_custom_hash(void *p_userdata) {
+ CallableCustom *callable_custom = (CallableCustom *)p_userdata;
+ return callable_custom->hash();
+}
+
+static void callable_custom_to_string(void *p_userdata, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) {
+ CallableCustom *callable_custom = (CallableCustom *)p_userdata;
+ *((String *)r_out) = callable_custom->get_as_text();
+ *r_is_valid = true;
+}
+
+static GDExtensionBool callable_custom_equal_func(void *p_a, void *p_b) {
+ CallableCustom *a = (CallableCustom *)p_a;
+ CallableCustom *b = (CallableCustom *)p_b;
+ CallableCustom::CompareEqualFunc func_a = a->get_compare_equal_func();
+ CallableCustom::CompareEqualFunc func_b = b->get_compare_equal_func();
+ if (func_a != func_b) {
+ return false;
+ }
+ return func_a(a, b);
+}
+
+static GDExtensionBool callable_custom_less_than_func(void *p_a, void *p_b) {
+ CallableCustom *a = (CallableCustom *)p_a;
+ CallableCustom *b = (CallableCustom *)p_b;
+ CallableCustom::CompareEqualFunc func_a = a->get_compare_less_func();
+ CallableCustom::CompareEqualFunc func_b = b->get_compare_less_func();
+ if (func_a != func_b) {
+ // Just compare the addresses.
+ return p_a < p_b;
+ }
+ return func_a(a, b);
+}
+
+bool CallableCustom::is_valid() const {
+ // The same default implementation as in Godot.
+ return ObjectDB::get_instance(get_object());
+}
+
+Callable::Callable(CallableCustom *p_callable_custom) {
+ GDExtensionCallableCustomInfo info = {};
+ info.callable_userdata = p_callable_custom;
+ info.token = internal::token;
+ info.object_id = p_callable_custom->get_object();
+ info.call_func = &callable_custom_call;
+ info.is_valid_func = &callable_custom_is_valid;
+ info.free_func = &callable_custom_free;
+ info.hash_func = &callable_custom_hash;
+ info.equal_func = &callable_custom_equal_func;
+ info.less_than_func = &callable_custom_less_than_func;
+ info.to_string_func = &callable_custom_to_string;
+
+ ::godot::internal::gdextension_interface_callable_custom_create(_native_ptr(), &info);
+}
+
+CallableCustom *Callable::get_custom() const {
+ CallableCustomBase *callable_custom = (CallableCustomBase *)::godot::internal::gdextension_interface_callable_custom_get_userdata(_native_ptr(), internal::token);
+ return dynamic_cast<CallableCustom *>(callable_custom);
+}
+
+} // namespace godot
diff --git a/src/variant/callable_method_pointer.cpp b/src/variant/callable_method_pointer.cpp
index ea43632..520ed05 100644
--- a/src/variant/callable_method_pointer.cpp
+++ b/src/variant/callable_method_pointer.cpp
@@ -30,31 +30,79 @@
#include <godot_cpp/variant/callable_method_pointer.hpp>
-//#include <godot_cpp/godot.hpp>
+#include <godot_cpp/templates/hashfuncs.hpp>
namespace godot {
-static void call_custom_callable(void *userdata, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error) {
- CallableCustomMethodPointerBase *callable_method_pointer = (CallableCustomMethodPointerBase *)userdata;
+static void custom_callable_mp_call(void *p_userdata, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error) {
+ CallableCustomMethodPointerBase *callable_method_pointer = (CallableCustomMethodPointerBase *)p_userdata;
callable_method_pointer->call((const Variant **)p_args, p_argument_count, *(Variant *)r_return, *r_error);
}
-static void free_custom_callable(void *userdata) {
- CallableCustomMethodPointerBase *callable_method_pointer = (CallableCustomMethodPointerBase *)userdata;
+static GDExtensionBool custom_callable_mp_is_valid(void *p_userdata) {
+ CallableCustomMethodPointerBase *callable_method_pointer = (CallableCustomMethodPointerBase *)p_userdata;
+ ObjectID object = callable_method_pointer->get_object();
+ return object == ObjectID() || ObjectDB::get_instance(object);
+}
+
+static void custom_callable_mp_free(void *p_userdata) {
+ CallableCustomMethodPointerBase *callable_method_pointer = (CallableCustomMethodPointerBase *)p_userdata;
memdelete(callable_method_pointer);
}
-namespace internal {
+static uint32_t custom_callable_mp_hash(void *p_userdata) {
+ CallableCustomMethodPointerBase *callable_method_pointer = (CallableCustomMethodPointerBase *)p_userdata;
+ return callable_method_pointer->get_hash();
+}
+
+static GDExtensionBool custom_callable_mp_equal_func(void *p_a, void *p_b) {
+ CallableCustomMethodPointerBase *a = (CallableCustomMethodPointerBase *)p_a;
+ CallableCustomMethodPointerBase *b = (CallableCustomMethodPointerBase *)p_b;
+
+ if (a->get_comp_size() != b->get_comp_size()) {
+ return false;
+ }
+
+ return memcmp(a->get_comp_ptr(), b->get_comp_ptr(), a->get_comp_size() * 4) == 0;
+}
-Callable create_custom_callable(CallableCustomMethodPointerBase *p_callable_method_pointer) {
- Object *object = p_callable_method_pointer->get_object();
+static GDExtensionBool custom_callable_mp_less_than_func(void *p_a, void *p_b) {
+ CallableCustomMethodPointerBase *a = (CallableCustomMethodPointerBase *)p_a;
+ CallableCustomMethodPointerBase *b = (CallableCustomMethodPointerBase *)p_b;
+
+ if (a->get_comp_size() != b->get_comp_size()) {
+ return a->get_comp_size() < b->get_comp_size();
+ }
+
+ return memcmp(a->get_comp_ptr(), b->get_comp_ptr(), a->get_comp_size() * 4) < 0;
+}
+
+void CallableCustomMethodPointerBase::_setup(uint32_t *p_base_ptr, uint32_t p_ptr_size) {
+ comp_ptr = p_base_ptr;
+ comp_size = p_ptr_size / 4;
+
+ for (uint32_t i = 0; i < comp_size; i++) {
+ if (i == 0) {
+ h = hash_murmur3_one_32(comp_ptr[i]);
+ } else {
+ h = hash_murmur3_one_32(comp_ptr[i], h);
+ }
+ }
+}
+
+namespace internal {
+Callable create_callable_from_ccmp(CallableCustomMethodPointerBase *p_callable_method_pointer) {
GDExtensionCallableCustomInfo info = {};
info.callable_userdata = p_callable_method_pointer;
info.token = internal::token;
- info.object_id = object ? object->get_instance_id() : 0;
- info.call_func = &call_custom_callable;
- info.free_func = &free_custom_callable;
+ info.object_id = p_callable_method_pointer->get_object();
+ info.call_func = &custom_callable_mp_call;
+ info.is_valid_func = &custom_callable_mp_is_valid;
+ info.free_func = &custom_callable_mp_free;
+ info.hash_func = &custom_callable_mp_hash;
+ info.equal_func = &custom_callable_mp_equal_func;
+ info.less_than_func = &custom_callable_mp_less_than_func;
Callable callable;
::godot::internal::gdextension_interface_callable_custom_create(callable._native_ptr(), &info);
diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp
index db15be1..945d6f4 100644
--- a/src/variant/variant.cpp
+++ b/src/variant/variant.cpp
@@ -268,6 +268,14 @@ Variant::operator int32_t() const {
return static_cast<int32_t>(operator int64_t());
}
+Variant::operator int16_t() const {
+ return static_cast<int16_t>(operator int64_t());
+}
+
+Variant::operator int8_t() const {
+ return static_cast<int8_t>(operator int64_t());
+}
+
Variant::operator uint64_t() const {
return static_cast<uint64_t>(operator int64_t());
}
@@ -276,6 +284,14 @@ Variant::operator uint32_t() const {
return static_cast<uint32_t>(operator int64_t());
}
+Variant::operator uint16_t() const {
+ return static_cast<uint16_t>(operator int64_t());
+}
+
+Variant::operator uint8_t() const {
+ return static_cast<uint8_t>(operator int64_t());
+}
+
Variant::operator double() const {
double result;
to_type_constructor[FLOAT](&result, _native_ptr());
diff --git a/test/SConstruct b/test/SConstruct
index 1732ecd..9c25917 100644
--- a/test/SConstruct
+++ b/test/SConstruct
@@ -23,6 +23,17 @@ if env["platform"] == "macos":
),
source=sources,
)
+elif env["platform"] == "ios":
+ if env["ios_simulator"]:
+ library = env.StaticLibrary(
+ "project/bin/libgdexample.{}.{}.simulator.a".format(env["platform"], env["target"]),
+ source=sources,
+ )
+ else:
+ library = env.StaticLibrary(
+ "project/bin/libgdexample.{}.{}.a".format(env["platform"], env["target"]),
+ source=sources,
+ )
else:
library = env.SharedLibrary(
"project/bin/libgdexample{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
diff --git a/test/generate_xcframework.sh b/test/generate_xcframework.sh
new file mode 100755
index 0000000..7adddff
--- /dev/null
+++ b/test/generate_xcframework.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+scons arch=universal ios_simulator=yes platform=ios target=$1 $2
+scons arch=arm64 ios_simulator=no platform=ios target=$1 $2
+
+xcodebuild -create-xcframework -library ./project/bin/libgdexample.ios.$1.a -library ./project/bin/libgdexample.ios.$1.simulator.a -output ./project/bin/libgdexample.ios.$1.xcframework
+xcodebuild -create-xcframework -library ../bin/libgodot-cpp.ios.$1.arm64.a -library ../bin/libgodot-cpp.ios.$1.universal.simulator.a -output ./project/bin/libgodot-cpp.ios.$1.xcframework
diff --git a/test/project/bin/libgdexample.osx.template_debug.framework/Resources/Info.plist b/test/project/bin/libgdexample.macos.template_debug.framework/Resources/Info.plist
index fbdbd20..fbdbd20 100644
--- a/test/project/bin/libgdexample.osx.template_debug.framework/Resources/Info.plist
+++ b/test/project/bin/libgdexample.macos.template_debug.framework/Resources/Info.plist
diff --git a/test/project/bin/libgdexample.osx.template_release.framework/Resources/Info.plist b/test/project/bin/libgdexample.macos.template_release.framework/Resources/Info.plist
index b3bc3ca..b3bc3ca 100644
--- a/test/project/bin/libgdexample.osx.template_release.framework/Resources/Info.plist
+++ b/test/project/bin/libgdexample.macos.template_release.framework/Resources/Info.plist
diff --git a/test/project/example.gdextension b/test/project/example.gdextension
index 30279e6..4f599ce 100644
--- a/test/project/example.gdextension
+++ b/test/project/example.gdextension
@@ -11,8 +11,14 @@ windows.debug.x86_32 = "res://bin/libgdexample.windows.template_debug.x86_32.dll
windows.release.x86_32 = "res://bin/libgdexample.windows.template_release.x86_32.dll"
windows.debug.x86_64 = "res://bin/libgdexample.windows.template_debug.x86_64.dll"
windows.release.x86_64 = "res://bin/libgdexample.windows.template_release.x86_64.dll"
+windows.debug.arm64 = "res://bin/libgdexample.windows.template_debug.arm64.dll"
+windows.release.arm64 = "res://bin/libgdexample.windows.template_release.arm64.dll"
+linux.debug.x86_32 = "res://bin/libgdexample.linux.template_debug.x86_32.so"
+linux.release.x86_32 = "res://bin/libgdexample.linux.template_release.x86_32.so"
linux.debug.x86_64 = "res://bin/libgdexample.linux.template_debug.x86_64.so"
linux.release.x86_64 = "res://bin/libgdexample.linux.template_release.x86_64.so"
+linux.debug.arm32 = "res://bin/libgdexample.linux.template_debug.arm32.so"
+linux.release.arm32 = "res://bin/libgdexample.linux.template_release.arm32.so"
linux.debug.arm64 = "res://bin/libgdexample.linux.template_debug.arm64.so"
linux.release.arm64 = "res://bin/libgdexample.linux.template_release.arm64.so"
linux.debug.rv64 = "res://bin/libgdexample.linux.template_debug.rv64.so"
@@ -21,5 +27,15 @@ android.debug.x86_64 = "res://bin/libgdexample.android.template_debug.x86_64.so"
android.release.x86_64 = "res://bin/libgdexample.android.template_release.x86_64.so"
android.debug.arm64 = "res://bin/libgdexample.android.template_debug.arm64.so"
android.release.arm64 = "res://bin/libgdexample.android.template_release.arm64.so"
+ios.debug = "res://bin/libgdexample.ios.template_debug.xcframework"
+ios.release = "res://bin/libgdexample.ios.template_release.xcframework"
web.debug.wasm32 = "res://bin/libgdexample.web.template_debug.wasm32.wasm"
web.release.wasm32 = "res://bin/libgdexample.web.template_release.wasm32.wasm"
+
+[dependencies]
+ios.debug = {
+ "res://bin/libgodot-cpp.ios.template_debug.xcframework": ""
+}
+ios.release = {
+ "res://bin/libgodot-cpp.ios.template_release.xcframework": ""
+}
diff --git a/test/project/main.gd b/test/project/main.gd
index 62bd19d..233ea41 100644
--- a/test/project/main.gd
+++ b/test/project/main.gd
@@ -101,9 +101,20 @@ func _ready():
# mp_callable() with void method.
var mp_callable: Callable = example.test_callable_mp()
+ assert_equal(mp_callable.is_valid(), true)
mp_callable.call(example, "void", 36)
assert_equal(custom_signal_emitted, ["unbound_method1: Example - void", 36])
+ # Check that it works with is_connected().
+ assert_equal(example.renamed.is_connected(mp_callable), false)
+ example.renamed.connect(mp_callable)
+ assert_equal(example.renamed.is_connected(mp_callable), true)
+ # Make sure a new object is still treated as equivalent.
+ assert_equal(example.renamed.is_connected(example.test_callable_mp()), true)
+ assert_equal(mp_callable.hash(), example.test_callable_mp().hash())
+ example.renamed.disconnect(mp_callable)
+ assert_equal(example.renamed.is_connected(mp_callable), false)
+
# mp_callable() with return value.
var mp_callable_ret: Callable = example.test_callable_mp_ret()
assert_equal(mp_callable_ret.call(example, "test", 77), "unbound_method2: Example - test - 77")
@@ -117,10 +128,30 @@ func _ready():
mp_callable_static.call(example, "static", 83)
assert_equal(custom_signal_emitted, ["unbound_static_method1: Example - static", 83])
+ # Check that it works with is_connected().
+ assert_equal(example.renamed.is_connected(mp_callable_static), false)
+ example.renamed.connect(mp_callable_static)
+ assert_equal(example.renamed.is_connected(mp_callable_static), true)
+ # Make sure a new object is still treated as equivalent.
+ assert_equal(example.renamed.is_connected(example.test_callable_mp_static()), true)
+ assert_equal(mp_callable_static.hash(), example.test_callable_mp_static().hash())
+ example.renamed.disconnect(mp_callable_static)
+ assert_equal(example.renamed.is_connected(mp_callable_static), false)
+
# mp_callable_static() with return value.
var mp_callable_static_ret: Callable = example.test_callable_mp_static_ret()
assert_equal(mp_callable_static_ret.call(example, "static-ret", 84), "unbound_static_method2: Example - static-ret - 84")
+ # CallableCustom.
+ var custom_callable: Callable = example.test_custom_callable();
+ assert_equal(custom_callable.is_custom(), true);
+ assert_equal(custom_callable.is_valid(), true);
+ assert_equal(custom_callable.call(), "Hi")
+ assert_equal(custom_callable.hash(), 27);
+ assert_equal(custom_callable.get_object(), null);
+ assert_equal(custom_callable.get_method(), "");
+ assert_equal(str(custom_callable), "<MyCallableCustom>");
+
# PackedArray iterators
assert_equal(example.test_vector_ops(), 105)
diff --git a/test/project/project.godot b/test/project/project.godot
index 3ed679b..4f51c07 100644
--- a/test/project/project.godot
+++ b/test/project/project.godot
@@ -21,4 +21,5 @@ paths=["res://example.gdextension"]
[rendering]
+textures/vram_compression/import_etc2_astc=true
environment/defaults/default_environment="res://default_env.tres"
diff --git a/test/src/example.cpp b/test/src/example.cpp
index dd58f37..2b8bef6 100644
--- a/test/src/example.cpp
+++ b/test/src/example.cpp
@@ -15,6 +15,46 @@
using namespace godot;
+class MyCallableCustom : public CallableCustom {
+public:
+ virtual uint32_t hash() const {
+ return 27;
+ }
+
+ virtual String get_as_text() const {
+ return "<MyCallableCustom>";
+ }
+
+ static bool compare_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) {
+ return p_a == p_b;
+ }
+
+ virtual CompareEqualFunc get_compare_equal_func() const {
+ return &MyCallableCustom::compare_equal_func;
+ }
+
+ static bool compare_less_func(const CallableCustom *p_a, const CallableCustom *p_b) {
+ return (void *)p_a < (void *)p_b;
+ }
+
+ virtual CompareLessFunc get_compare_less_func() const {
+ return &MyCallableCustom::compare_less_func;
+ }
+
+ bool is_valid() const {
+ return true;
+ }
+
+ virtual ObjectID get_object() const {
+ return ObjectID();
+ }
+
+ virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const {
+ r_return_value = "Hi";
+ r_call_error.error = GDEXTENSION_CALL_OK;
+ }
+};
+
void ExampleRef::set_id(int p_id) {
id = p_id;
}
@@ -168,6 +208,7 @@ void Example::_bind_methods() {
ClassDB::bind_method(D_METHOD("test_callable_mp_retc"), &Example::test_callable_mp_retc);
ClassDB::bind_method(D_METHOD("test_callable_mp_static"), &Example::test_callable_mp_static);
ClassDB::bind_method(D_METHOD("test_callable_mp_static_ret"), &Example::test_callable_mp_static_ret);
+ ClassDB::bind_method(D_METHOD("test_custom_callable"), &Example::test_custom_callable);
ClassDB::bind_method(D_METHOD("test_bitfield", "flags"), &Example::test_bitfield);
@@ -378,6 +419,10 @@ Callable Example::test_callable_mp_static_ret() const {
return callable_mp_static(&Example::unbound_static_method2);
}
+Callable Example::test_custom_callable() const {
+ return Callable(memnew(MyCallableCustom));
+}
+
void Example::unbound_method1(Object *p_object, String p_string, int p_int) {
String test = "unbound_method1: ";
test += p_object->get_class();
diff --git a/test/src/example.h b/test/src/example.h
index 200c970..388cc8c 100644
--- a/test/src/example.h
+++ b/test/src/example.h
@@ -143,6 +143,7 @@ public:
Callable test_callable_mp_retc() const;
Callable test_callable_mp_static() const;
Callable test_callable_mp_static_ret() const;
+ Callable test_custom_callable() const;
void unbound_method1(Object *p_object, String p_string, int p_int);
String unbound_method2(Object *p_object, String p_string, int p_int);
diff --git a/tools/android.py b/tools/android.py
index 0e68855..bee58c4 100644
--- a/tools/android.py
+++ b/tools/android.py
@@ -8,23 +8,35 @@ def options(opts):
opts.Add(
"android_api_level",
"Target Android API level",
- "18" if "32" in ARGUMENTS.get("arch", "arm64") else "21",
+ "21",
)
opts.Add(
- "ANDROID_NDK_ROOT",
- "Path to your Android NDK installation. By default, uses ANDROID_NDK_ROOT from your defined environment variables.",
- os.environ.get("ANDROID_NDK_ROOT", None),
+ "ANDROID_HOME",
+ "Path to your Android SDK installation. By default, uses ANDROID_HOME from your defined environment variables.",
+ os.environ.get("ANDROID_HOME", os.environ.get("ANDROID_SDK_ROOT")),
)
def exists(env):
- return "ANDROID_NDK_ROOT" in os.environ or "ANDROID_NDK_ROOT" in ARGUMENTS
+ return get_android_ndk_root(env) is not None
+
+
+# This must be kept in sync with the value in https://github.com/godotengine/godot/blob/master/platform/android/detect.py#L58.
+def get_ndk_version():
+ return "23.2.8568313"
+
+
+def get_android_ndk_root(env):
+ if env["ANDROID_HOME"]:
+ return env["ANDROID_HOME"] + "/ndk/" + get_ndk_version()
+ else:
+ return os.environ.get("ANDROID_NDK_ROOT")
def generate(env):
- if "ANDROID_NDK_ROOT" not in env:
+ if get_android_ndk_root(env) is None:
raise ValueError(
- "To build for Android, ANDROID_NDK_ROOT must be defined. Please set ANDROID_NDK_ROOT to the root folder of your Android NDK installation."
+ "To build for Android, the path to the NDK must be defined. Please set ANDROID_HOME to the root folder of your Android SDK installation."
)
if env["arch"] not in ("arm64", "x86_64", "arm32", "x86_32"):
@@ -35,14 +47,12 @@ def generate(env):
my_spawn.configure(env)
# Validate API level
- api_level = int(env["android_api_level"])
- if "64" in env["arch"] and api_level < 21:
- print("WARN: 64-bit Android architectures require an API level of at least 21; setting android_api_level=21")
+ if int(env["android_api_level"]) < 21:
+ print("WARNING: minimum supported Android target api is 21. Forcing target api 21.")
env["android_api_level"] = "21"
- api_level = 21
# Setup toolchain
- toolchain = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/"
+ toolchain = get_android_ndk_root(env) + "/toolchains/llvm/prebuilt/"
if sys.platform == "win32" or sys.platform == "msys":
toolchain += "windows"
import platform as pltfm
diff --git a/tools/godotcpp.py b/tools/godotcpp.py
index 8e7e1c6..fcf4dd7 100644
--- a/tools/godotcpp.py
+++ b/tools/godotcpp.py
@@ -179,7 +179,7 @@ def options(opts, env):
BoolVariable(
key="use_hot_reload",
help="Enable the extra accounting required to support hot reload.",
- default=(env.get("target", "template_debug") != "template_release"),
+ default=env.get("use_hot_reload", None),
)
)
@@ -245,9 +245,20 @@ def generate(env):
print("Building for architecture " + env["arch"] + " on platform " + env["platform"])
+ if env.get("use_hot_reload") is None:
+ env["use_hot_reload"] = env["target"] != "template_release"
if env["use_hot_reload"]:
env.Append(CPPDEFINES=["HOT_RELOAD_ENABLED"])
+ tool = Tool(env["platform"], toolpath=["tools"])
+
+ if tool is None or not tool.exists(env):
+ raise ValueError("Required toolchain not found for platform " + env["platform"])
+
+ tool.generate(env)
+ target_tool = Tool("targets", toolpath=["tools"])
+ target_tool.generate(env)
+
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
# saves around 20% of binary size and very significant build time.
if env["disable_exceptions"]:
@@ -258,15 +269,6 @@ def generate(env):
elif env.get("is_msvc", False):
env.Append(CXXFLAGS=["/EHsc"])
- tool = Tool(env["platform"], toolpath=["tools"])
-
- if tool is None or not tool.exists(env):
- raise ValueError("Required toolchain not found for platform " + env["platform"])
-
- tool.generate(env)
- target_tool = Tool("targets", toolpath=["tools"])
- target_tool.generate(env)
-
# Require C++17
if env.get("is_msvc", False):
env.Append(CXXFLAGS=["/std:c++17"])
diff --git a/tools/ios.py b/tools/ios.py
index e387f42..9d37214 100644
--- a/tools/ios.py
+++ b/tools/ios.py
@@ -21,7 +21,7 @@ def has_ios_osxcross():
def options(opts):
opts.Add(BoolVariable("ios_simulator", "Target iOS Simulator", False))
- opts.Add("ios_min_version", "Target minimum iphoneos/iphonesimulator version", "10.0")
+ opts.Add("ios_min_version", "Target minimum iphoneos/iphonesimulator version", "12.0")
opts.Add(
"IOS_TOOLCHAIN_PATH",
"Path to iOS toolchain",