summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml27
-rw-r--r--CMakeLists.txt4
-rw-r--r--binding_generator.py12
-rw-r--r--gdextension/extension_api.json140
-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/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/project/main.gd31
-rw-r--r--test/src/example.cpp45
-rw-r--r--test/src/example.h1
-rw-r--r--tools/android.py8
-rw-r--r--tools/ios.py2
19 files changed, 685 insertions, 193 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/CMakeLists.txt b/CMakeLists.txt
index 6262fb5..75ff500 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -99,10 +99,8 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
add_definitions(-DNOMINMAX)
else() # GCC/Clang
- set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -g")
-
if(CMAKE_BUILD_TYPE MATCHES Debug)
- set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0")
+ set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -g")
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3")
endif(CMAKE_BUILD_TYPE MATCHES Debug)
diff --git a/binding_generator.py b/binding_generator.py
index ed7a8d4..6ebee3d 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")
@@ -414,6 +416,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>")
@@ -523,6 +528,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
@@ -1081,6 +1089,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"])
@@ -1208,6 +1218,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/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/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/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/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 479ee15..bee58c4 100644
--- a/tools/android.py
+++ b/tools/android.py
@@ -8,7 +8,7 @@ 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_HOME",
@@ -47,11 +47,9 @@ 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 = get_android_ndk_root(env) + "/toolchains/llvm/prebuilt/"
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",