Merge remote-tracking branch 'godot/master' into cmake-exporting-config

pull/1309/head
Slawomir Grabowski 2023-12-23 08:41:06 +01:00
commit 6b02a58e5a
23 changed files with 690 additions and 168 deletions

View File

@ -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:
@ -104,33 +104,34 @@ jobs:
continue-on-error: true
- name: Set up Python (for SCons)
uses: actions/setup-python@v4
uses: actions/setup-python@v5
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 }}

View File

@ -50,11 +50,6 @@ option(GODOT_CPP_INSTALL "Enables target install for exporting godot-cpp cmake c
# Add path to modules
list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" )
# Check if we are building ourself or being included
if(${PROJECT_NAME} STREQUAL ${CMAKE_PROJECT_NAME})
set(GODOT_CPP_BUILDING_SELF ON)
endif()
# Set some helper variables for readability
set( compiler_is_clang "$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>" )
set( compiler_is_gnu "$<CXX_COMPILER_ID:GNU>" )
@ -102,10 +97,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)
@ -137,6 +130,7 @@ endif()
execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_GDEXTENSION_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", headers=True, sources=True)"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GENERATED_FILES_LIST
OUTPUT_STRIP_TRAILING_WHITESPACE
)
add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
@ -162,12 +156,6 @@ add_library(godot::cpp ALIAS ${PROJECT_NAME})
include(GodotCompilerWarnings)
# Treat warnings as errors if we are building ourself
if(GODOT_CPP_BUILDING_SELF)
unset( GODOT_CPP_WARNING_AS_ERROR CACHE )
set_warning_as_error()
endif()
target_compile_features(${PROJECT_NAME}
PRIVATE
cxx_std_17

View File

@ -7,8 +7,9 @@
> from Godot's `master` branch.
>
> For users of stable branches, switch to the branch matching your target Godot version:
> - [`4.0`](https://github.com/godotengine/godot-cpp/tree/4.0)
> - [`4.2`](https://github.com/godotengine/godot-cpp/tree/4.2)
> - [`4.1`](https://github.com/godotengine/godot-cpp/tree/4.1)
> - [`4.0`](https://github.com/godotengine/godot-cpp/tree/4.0)
>
> Or check out the Git tag matching your Godot version (e.g. `godot-4.1.1-stable`).
>

View File

@ -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")
@ -136,9 +138,7 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
def print_file_list(api_filepath, output_dir, headers=False, sources=False):
end = ";"
for f in get_file_list(api_filepath, output_dir, headers, sources):
print(f, end=end)
print(*get_file_list(api_filepath, output_dir, headers, sources), sep=";", end=None)
def scons_emit_files(target, source, env):
@ -416,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>")
@ -525,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
@ -1083,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"])
@ -1210,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")
@ -1319,7 +1329,11 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
if "enums" in class_api:
for enum_api in class_api["enums"]:
if enum_api["is_bitfield"]:
result.append(f'\tenum {enum_api["name"]} : uint64_t {{')
else:
result.append(f'\tenum {enum_api["name"]} {{')
for value in enum_api["values"]:
result.append(f'\t\t{value["name"]} = {value["value"]},')
result.append("\t};")
@ -1676,6 +1690,8 @@ def generate_global_constants(api, output_dir):
header.append(f"#ifndef {header_guard}")
header.append(f"#define {header_guard}")
header.append("")
header.append("#include <cstdint>")
header.append("")
header.append("namespace godot {")
header.append("")
@ -1688,7 +1704,11 @@ def generate_global_constants(api, output_dir):
if enum_def["name"].startswith("Variant."):
continue
if enum_def["is_bitfield"]:
header.append(f'\tenum {enum_def["name"]} : uint64_t {{')
else:
header.append(f'\tenum {enum_def["name"]} {{')
for value in enum_def["values"]:
header.append(f'\t\t{value["name"]} = {value["value"]},')
header.append("\t};")

View File

@ -3,9 +3,9 @@
"version_major": 4,
"version_minor": 2,
"version_patch": 0,
"version_status": "beta6",
"version_status": "stable",
"version_build": "official",
"version_full_name": "Godot Engine v4.2.beta6.official"
"version_full_name": "Godot Engine v4.2.stable.official"
},
"builtin_class_sizes": [
{

View File

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

View File

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

View File

@ -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:
static void initialize_level(void *userdata, GDExtensionInitializationLevel p_level);
static void deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level);
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 *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);

View File

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

View File

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

View File

@ -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;
@ -344,6 +356,12 @@ String vformat(const String &p_text, const VarArgs... p_args) {
#include <godot_cpp/variant/builtin_vararg_methods.hpp>
#ifdef REAL_T_IS_DOUBLE
using PackedRealArray = PackedFloat64Array;
#else
using PackedRealArray = PackedFloat32Array;
#endif // REAL_T_IS_DOUBLE
} // namespace godot
#endif // GODOT_VARIANT_HPP

View File

@ -50,6 +50,12 @@ void Wrapped::_postinitialize() {
godot::internal::gdextension_interface_object_set_instance(_owner, reinterpret_cast<GDExtensionConstStringNamePtr>(extension_class), this);
}
godot::internal::gdextension_interface_object_set_instance_binding(_owner, godot::internal::token, this, _get_bindings_callbacks());
if (extension_class) {
Object *obj = dynamic_cast<Object *>(this);
if (obj) {
obj->notification(Object::NOTIFICATION_POSTINITIALIZE);
}
}
}
Wrapped::Wrapped(const StringName p_godot_class) {

View File

@ -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) {
@ -257,7 +271,12 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
} else if (internal::godot_version.minor != GODOT_VERSION_MINOR) {
compatible = internal::godot_version.minor > GODOT_VERSION_MINOR;
} else {
#if GODOT_VERSION_PATCH > 0
compatible = internal::godot_version.patch >= GODOT_VERSION_PATCH;
#else
// Prevent -Wtype-limits warning due to unsigned comparison.
compatible = true;
#endif
}
if (!compatible) {
// We need to use snprintf() here because vformat() uses Variant, and we haven't loaded
@ -390,6 +409,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 +433,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));
}
if (level_initialized[p_level] == 0) {
ClassDB::initialize(p_level);
}
void GDExtensionBinding::deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
ClassDB::current_level = p_level;
if (terminate_callback) {
terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
level_initialized[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;
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;
}
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

View File

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

View File

@ -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);
}
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;
}
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_custom_callable(CallableCustomMethodPointerBase *p_callable_method_pointer) {
Object *object = p_callable_method_pointer->get_object();
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);

View File

@ -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());

View File

@ -59,31 +59,9 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
else()
#elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# using Clang
#elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# using GCC and maybe MinGW?
set(GODOT_LINKER_FLAGS "-static-libgcc -static-libstdc++ -Wl,-R,'$$ORIGIN'")
# Hmm.. maybe to strikt?
set(GODOT_COMPILE_FLAGS "-fPIC -g -Wwrite-strings")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wchar-subscripts -Wcomment -Wdisabled-optimization")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wformat -Wformat=2 -Wformat-security -Wformat-y2k")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wimport -Winit-self -Winline -Winvalid-pch -Werror")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wmissing-braces -Wmissing-format-attribute")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wpointer-arith")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wredundant-decls -Wreturn-type -Wsequence-point")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wswitch -Wswitch-enum -Wtrigraphs")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused-label")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wunused-value -Wvariadic-macros -Wvolatile-register-var -Wno-error=attributes")
# -Wshadow -Wextra -Wall -Weffc++ -Wfloat-equal -Wstack-protector -Wunused-parameter -Wsign-compare -Wunused-variable -Wcast-align
# -Wunused-function -Wstrict-aliasing -Wstrict-aliasing=2 -Wmissing-field-initializers
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wno-ignored-attributes")
endif()
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0")

View File

@ -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)
@ -205,6 +236,11 @@ func _ready():
get_viewport().push_input(event)
assert_equal(custom_signal_emitted, ["_input: H", 72])
# Check NOTIFICATION_POST_INITIALIZED, both when created from GDScript and godot-cpp.
var new_example_ref = ExampleRef.new()
assert_equal(new_example_ref.was_post_initialized(), true)
assert_equal(example.test_post_initialize(), true)
exit_with_status()
func _on_Example_custom_signal(signal_name, value):

View File

@ -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;
}
@ -23,10 +63,18 @@ int ExampleRef::get_id() const {
return id;
}
void ExampleRef::_notification(int p_what) {
if (p_what == NOTIFICATION_POSTINITIALIZE) {
post_initialized = true;
}
}
void ExampleRef::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_id", "id"), &ExampleRef::set_id);
ClassDB::bind_method(D_METHOD("get_id"), &ExampleRef::get_id);
ClassDB::bind_method(D_METHOD("was_post_initialized"), &ExampleRef::was_post_initialized);
ADD_PROPERTY(PropertyInfo(Variant::INT, "id"), "set_id", "get_id");
}
@ -168,6 +216,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);
@ -179,6 +228,7 @@ void Example::_bind_methods() {
ClassDB::bind_method(D_METHOD("def_args", "a", "b"), &Example::def_args, DEFVAL(100), DEFVAL(200));
ClassDB::bind_method(D_METHOD("callable_bind"), &Example::callable_bind);
ClassDB::bind_method(D_METHOD("test_post_initialize"), &Example::test_post_initialize);
ClassDB::bind_static_method("Example", D_METHOD("test_static", "a", "b"), &Example::test_static);
ClassDB::bind_static_method("Example", D_METHOD("test_static2"), &Example::test_static2);
@ -378,6 +428,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();
@ -552,6 +606,12 @@ Vector4 Example::get_v4() const {
return Vector4(1.2, 3.4, 5.6, 7.8);
}
bool Example::test_post_initialize() const {
Ref<ExampleRef> new_example_ref;
new_example_ref.instantiate();
return new_example_ref->was_post_initialized();
}
// Virtual function override.
bool Example::_has_point(const Vector2 &point) const {
Label *label = get_node<Label>("Label");

View File

@ -35,16 +35,21 @@ private:
static int last_id;
int id;
bool post_initialized = false;
protected:
static void _bind_methods();
void _notification(int p_what);
public:
ExampleRef();
~ExampleRef();
void set_id(int p_id);
int get_id() const;
bool was_post_initialized() const { return post_initialized; }
};
class ExampleMin : public Control {
@ -143,6 +148,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);
@ -166,6 +172,8 @@ public:
Vector2 get_custom_position() const;
Vector4 get_v4() const;
bool test_post_initialize() const;
// Static method.
static int test_static(int p_a, int p_b);
static void test_static2();

View File

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

View File

@ -189,6 +189,15 @@ def options(opts, env):
)
)
opts.Add(
EnumVariable(
key="symbols_visibility",
help="Symbols visibility on GNU platforms. Use 'auto' to apply the default value.",
default=env.get("symbols_visibility", "hidden"),
allowed_values=["auto", "visible", "hidden"],
)
)
# Add platform options
for pl in platforms:
tool = Tool(pl, toolpath=["tools"])
@ -269,6 +278,14 @@ def generate(env):
elif env.get("is_msvc", False):
env.Append(CXXFLAGS=["/EHsc"])
if not env.get("is_msvc", False):
if env["symbols_visibility"] == "visible":
env.Append(CCFLAGS=["-fvisibility=default"])
env.Append(LINKFLAGS=["-fvisibility=default"])
elif env["symbols_visibility"] == "hidden":
env.Append(CCFLAGS=["-fvisibility=hidden"])
env.Append(LINKFLAGS=["-fvisibility=hidden"])
# Require C++17
if env.get("is_msvc", False):
env.Append(CXXFLAGS=["/std:c++17"])

View File

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