David Snopek 2024-01-22 21:54:04 +00:00 committed by GitHub
commit 5685f73962
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 451 additions and 257 deletions

View File

@ -65,7 +65,7 @@ jobs:
platform: android platform: android
artifact-name: godot-cpp-android-arm64-release artifact-name: godot-cpp-android-arm64-release
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a 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 run-tests: false
cache-name: android-arm64 cache-name: android-arm64
@ -88,7 +88,7 @@ jobs:
env: env:
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/ SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
EM_VERSION: 3.1.45 EM_VERSION: 3.1.39
EM_CACHE_FOLDER: "emsdk-cache" EM_CACHE_FOLDER: "emsdk-cache"
steps: steps:
@ -104,33 +104,34 @@ jobs:
continue-on-error: true continue-on-error: true
- name: Set up Python (for SCons) - name: Set up Python (for SCons)
uses: actions/setup-python@v4 uses: actions/setup-python@v5
with: with:
python-version: '3.x' python-version: '3.x'
- name: Linux dependencies - name: Android dependencies
if: ${{ matrix.platform == 'linux' }} if: ${{ matrix.platform == 'android' }}
run: | uses: nttld/setup-ndk@v1
sudo apt-get update -qq with:
sudo apt-get install -qqq build-essential pkg-config ndk-version: r23c
link-to-sdk: true
- name: Web dependencies - name: Web dependencies
if: ${{ matrix.platform == 'web' }} if: ${{ matrix.platform == 'web' }}
uses: mymindstorm/setup-emsdk@v12 uses: mymindstorm/setup-emsdk@v13
with: with:
version: ${{env.EM_VERSION}} version: ${{env.EM_VERSION}}
actions-cache-folder: ${{env.EM_CACHE_FOLDER}} 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 - name: Setup MinGW for Windows/MinGW build
if: ${{ matrix.platform == 'windows' && matrix.flags == 'use_mingw=yes' }} if: ${{ matrix.platform == 'windows' && matrix.flags == 'use_mingw=yes' }}
uses: egor-tensin/setup-mingw@v2 uses: egor-tensin/setup-mingw@v2
with: with:
version: 12.2.0 version: 12.2.0
- name: Install scons
run: |
python -m pip install scons==4.0.0
- name: Generate godot-cpp sources only - name: Generate godot-cpp sources only
run: | run: |
scons platform=${{ matrix.platform }} build_library=no ${{ matrix.flags }} scons platform=${{ matrix.platform }} build_library=no ${{ matrix.flags }}

View File

@ -47,11 +47,6 @@ option(GODOT_CPP_WARNING_AS_ERROR "Treat warnings as errors" OFF)
# Add path to modules # Add path to modules
list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) 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 some helper variables for readability
set( compiler_is_clang "$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>" ) set( compiler_is_clang "$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>" )
set( compiler_is_gnu "$<CXX_COMPILER_ID:GNU>" ) set( compiler_is_gnu "$<CXX_COMPILER_ID:GNU>" )
@ -99,10 +94,8 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
add_definitions(-DNOMINMAX) add_definitions(-DNOMINMAX)
else() # GCC/Clang else() # GCC/Clang
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -g")
if(CMAKE_BUILD_TYPE MATCHES Debug) 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() else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3") set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3")
endif(CMAKE_BUILD_TYPE MATCHES Debug) endif(CMAKE_BUILD_TYPE MATCHES Debug)
@ -134,6 +127,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)" 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} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GENERATED_FILES_LIST OUTPUT_VARIABLE GENERATED_FILES_LIST
OUTPUT_STRIP_TRAILING_WHITESPACE
) )
add_custom_command(OUTPUT ${GENERATED_FILES_LIST} add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
@ -159,12 +153,6 @@ add_library(godot::cpp ALIAS ${PROJECT_NAME})
include(GodotCompilerWarnings) 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} target_compile_features(${PROJECT_NAME}
PRIVATE PRIVATE
cxx_std_17 cxx_std_17

View File

@ -57,7 +57,7 @@ first-party `godot-cpp` extension.
Some compatibility breakage is to be expected as GDExtension and `godot-cpp` Some compatibility breakage is to be expected as GDExtension and `godot-cpp`
get more used, documented, and critical issues get resolved. See the get more used, documented, and critical issues get resolved. See the
[Godot issue tracker](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aopen+label%3Atopic%3Agdextension) [Godot issue tracker](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aopen+label%3Atopic%3Agdextension)
and the [godot-cpp issue tracker](https://github.com/godotengine/godot/issues) and the [godot-cpp issue tracker](https://github.com/godotengine/godot-cpp/issues)
for a list of known issues, and be sure to provide feedback on issues and PRs for a list of known issues, and be sure to provide feedback on issues and PRs
which affect your use of this extension. which affect your use of this extension.
@ -73,7 +73,10 @@ so formatting is done before your changes are submitted.
## Getting started ## Getting started
It's a bit similar to what it was for 3.x but also a bit different. You need the same C++ pre-requisites installed that are required for the `godot` repository. Follow the [official build instructions for your target platform](https://docs.godotengine.org/en/latest/contributing/development/compiling/index.html#building-for-target-platforms).
Getting started with GDExtensions is a bit similar to what it was for 3.x but also a bit different.
This new approach is much more akin to how core Godot modules are structured. This new approach is much more akin to how core Godot modules are structured.
Compiling this repository generates a static library to be linked with your shared lib, Compiling this repository generates a static library to be linked with your shared lib,

View File

@ -135,9 +135,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): def print_file_list(api_filepath, output_dir, headers=False, sources=False):
end = ";" print(*get_file_list(api_filepath, output_dir, headers, sources), sep=";", end=None)
for f in get_file_list(api_filepath, output_dir, headers, sources):
print(f, end=end)
def scons_emit_files(target, source, env): def scons_emit_files(target, source, env):
@ -543,10 +541,10 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
# Special cases. # Special cases.
if class_name == "String": if class_name == "String":
result.append("\tstatic String utf8(const char *from, int len = -1);") result.append("\tstatic String utf8(const char *from, int64_t len = -1);")
result.append("\tvoid parse_utf8(const char *from, int len = -1);") result.append("\tvoid parse_utf8(const char *from, int64_t len = -1);")
result.append("\tstatic String utf16(const char16_t *from, int len = -1);") result.append("\tstatic String utf16(const char16_t *from, int64_t len = -1);")
result.append("\tvoid parse_utf16(const char16_t *from, int len = -1);") result.append("\tvoid parse_utf16(const char16_t *from, int64_t len = -1);")
result.append("\tCharString utf8() const;") result.append("\tCharString utf8() const;")
result.append("\tCharString ascii() const;") result.append("\tCharString ascii() const;")
result.append("\tChar16String utf16() const;") result.append("\tChar16String utf16() const;")
@ -605,8 +603,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append("\tString &operator+=(const wchar_t *p_str);") result.append("\tString &operator+=(const wchar_t *p_str);")
result.append("\tString &operator+=(const char32_t *p_str);") result.append("\tString &operator+=(const char32_t *p_str);")
result.append("\tconst char32_t &operator[](int p_index) const;") result.append("\tconst char32_t &operator[](int64_t p_index) const;")
result.append("\tchar32_t &operator[](int p_index);") result.append("\tchar32_t &operator[](int64_t p_index);")
result.append("\tconst char32_t *ptr() const;") result.append("\tconst char32_t *ptr() const;")
result.append("\tchar32_t *ptrw();") result.append("\tchar32_t *ptrw();")
@ -624,8 +622,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
return_type = "int32_t" return_type = "int32_t"
elif class_name == "PackedFloat32Array": elif class_name == "PackedFloat32Array":
return_type = "float" return_type = "float"
result.append(f"\tconst {return_type} &operator[](int p_index) const;") result.append(f"\tconst {return_type} &operator[](int64_t p_index) const;")
result.append(f"\t{return_type} &operator[](int p_index);") result.append(f"\t{return_type} &operator[](int64_t p_index);")
result.append(f"\tconst {return_type} *ptr() const;") result.append(f"\tconst {return_type} *ptr() const;")
result.append(f"\t{return_type} *ptrw();") result.append(f"\t{return_type} *ptrw();")
iterators = """ iterators = """
@ -696,8 +694,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append(iterators.replace("$TYPE", return_type)) result.append(iterators.replace("$TYPE", return_type))
if class_name == "Array": if class_name == "Array":
result.append("\tconst Variant &operator[](int p_index) const;") result.append("\tconst Variant &operator[](int64_t p_index) const;")
result.append("\tVariant &operator[](int p_index);") result.append("\tVariant &operator[](int64_t p_index);")
result.append("\tvoid set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script);") result.append("\tvoid set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script);")
result.append("\tvoid _ref(const Array &p_from) const;") result.append("\tvoid _ref(const Array &p_from) const;")
@ -1640,7 +1638,7 @@ def generate_global_constants(api, output_dir):
header.append("") header.append("")
for constant in api["global_constants"]: for constant in api["global_constants"]:
header.append(f'\tconst int {escape_identifier(constant["name"])} = {constant["value"]};') header.append(f'\tconst int64_t {escape_identifier(constant["name"])} = {constant["value"]};')
header.append("") header.append("")
@ -1718,9 +1716,9 @@ def generate_global_constant_binds(api, output_dir):
continue continue
if enum_def["is_bitfield"]: if enum_def["is_bitfield"]:
header.append(f'VARIANT_BITFIELD_CAST(godot::{enum_def["name"]});') header.append(f'VARIANT_BITFIELD_CAST({enum_def["name"]});')
else: else:
header.append(f'VARIANT_ENUM_CAST(godot::{enum_def["name"]});') header.append(f'VARIANT_ENUM_CAST({enum_def["name"]});')
# Variant::Type is not a global enum, but only one line, it is worth to place in this file instead of creating new file. # Variant::Type is not a global enum, but only one line, it is worth to place in this file instead of creating new file.
header.append(f"VARIANT_ENUM_CAST(godot::Variant::Type);") header.append(f"VARIANT_ENUM_CAST(godot::Variant::Type);")
@ -2336,6 +2334,7 @@ def get_operator_id_name(op):
"unary-": "negate", "unary-": "negate",
"unary+": "positive", "unary+": "positive",
"%": "module", "%": "module",
"**": "power",
"<<": "shift_left", "<<": "shift_left",
">>": "shift_right", ">>": "shift_right",
"&": "bit_and", "&": "bit_and",

View File

@ -187,26 +187,44 @@ enum ModuleInitializationLevel {
MODULE_INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE, MODULE_INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
MODULE_INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS, MODULE_INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
MODULE_INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE, 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 { class GDExtensionBinding {
public: public:
using Callback = void (*)(ModuleInitializationLevel p_level); using Callback = void (*)(ModuleInitializationLevel p_level);
static Callback init_callback; struct InitData {
static Callback terminate_callback; GDExtensionInitializationLevel minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
static GDExtensionInitializationLevel minimum_initialization_level; Callback init_callback = nullptr;
static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization); 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: public:
static void initialize_level(void *userdata, GDExtensionInitializationLevel p_level); static void initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
static void deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level); static void deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
class InitObject { class InitObject {
GDExtensionInterfaceGetProcAddress get_proc_address; GDExtensionInterfaceGetProcAddress get_proc_address;
GDExtensionClassLibraryPtr library; GDExtensionClassLibraryPtr library;
GDExtensionInitialization *initialization; GDExtensionInitialization *initialization;
mutable InitData *init_data = nullptr;
public: public:
InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization); InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);

View File

@ -52,6 +52,8 @@ class VMap;
template <class T> template <class T>
class CharStringT; class CharStringT;
SAFE_NUMERIC_TYPE_PUN_GUARANTEES(uint64_t)
// Silence a false positive warning (see GH-52119). // Silence a false positive warning (see GH-52119).
#if defined(__GNUC__) && !defined(__clang__) #if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
@ -69,52 +71,71 @@ class CowData {
template <class TS> template <class TS>
friend class CharStringT; friend class CharStringT;
public:
typedef int64_t Size;
typedef uint64_t USize;
static constexpr USize MAX_INT = INT64_MAX;
private: private:
// Function to find the next power of 2 to an integer.
static _FORCE_INLINE_ USize next_po2(USize x) {
if (x == 0) {
return 0;
}
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
if (sizeof(USize) == 8) {
x |= x >> 32;
}
return ++x;
}
static constexpr USize ALLOC_PAD = sizeof(USize) * 2; // For size and atomic refcount.
mutable T *_ptr = nullptr; mutable T *_ptr = nullptr;
// internal helpers // internal helpers
_FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const { _FORCE_INLINE_ SafeNumeric<USize> *_get_refcount() const {
if (!_ptr) { if (!_ptr) {
return nullptr; return nullptr;
} }
return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2; return reinterpret_cast<SafeNumeric<USize> *>(_ptr) - 2;
} }
_FORCE_INLINE_ uint32_t *_get_size() const { _FORCE_INLINE_ USize *_get_size() const {
if (!_ptr) { if (!_ptr) {
return nullptr; return nullptr;
} }
return reinterpret_cast<uint32_t *>(_ptr) - 1; return reinterpret_cast<USize *>(_ptr) - 1;
} }
_FORCE_INLINE_ T *_get_data() const { _FORCE_INLINE_ USize _get_alloc_size(USize p_elements) const {
if (!_ptr) { return next_po2(p_elements * sizeof(T));
return nullptr;
}
return reinterpret_cast<T *>(_ptr);
} }
_FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const { _FORCE_INLINE_ bool _get_alloc_size_checked(USize p_elements, USize *out) const {
return next_power_of_2(p_elements * sizeof(T));
}
_FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const {
if (unlikely(p_elements == 0)) { if (unlikely(p_elements == 0)) {
*out = 0; *out = 0;
return true; return true;
} }
#if defined(__GNUC__) #if defined(__GNUC__) && defined(IS_32_BIT)
size_t o; USize o;
size_t p; USize p;
if (__builtin_mul_overflow(p_elements, sizeof(T), &o)) { if (__builtin_mul_overflow(p_elements, sizeof(T), &o)) {
*out = 0; *out = 0;
return false; return false;
} }
*out = next_power_of_2(o); *out = next_po2(o);
if (__builtin_add_overflow(o, static_cast<size_t>(32), &p)) { if (__builtin_add_overflow(o, static_cast<USize>(32), &p)) {
return false; // No longer allocated here. return false; // No longer allocated here.
} }
#else #else
@ -128,22 +149,22 @@ private:
void _unref(void *p_data); void _unref(void *p_data);
void _ref(const CowData *p_from); void _ref(const CowData *p_from);
void _ref(const CowData &p_from); void _ref(const CowData &p_from);
uint32_t _copy_on_write(); USize _copy_on_write();
public: public:
void operator=(const CowData<T> &p_from) { _ref(p_from); } void operator=(const CowData<T> &p_from) { _ref(p_from); }
_FORCE_INLINE_ T *ptrw() { _FORCE_INLINE_ T *ptrw() {
_copy_on_write(); _copy_on_write();
return (T *)_get_data(); return _ptr;
} }
_FORCE_INLINE_ const T *ptr() const { _FORCE_INLINE_ const T *ptr() const {
return _get_data(); return _ptr;
} }
_FORCE_INLINE_ int size() const { _FORCE_INLINE_ Size size() const {
uint32_t *size = (uint32_t *)_get_size(); USize *size = (USize *)_get_size();
if (size) { if (size) {
return *size; return *size;
} else { } else {
@ -154,41 +175,42 @@ public:
_FORCE_INLINE_ void clear() { resize(0); } _FORCE_INLINE_ void clear() { resize(0); }
_FORCE_INLINE_ bool is_empty() const { return _ptr == nullptr; } _FORCE_INLINE_ bool is_empty() const { return _ptr == nullptr; }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _FORCE_INLINE_ void set(Size p_index, const T &p_elem) {
ERR_FAIL_INDEX(p_index, size()); ERR_FAIL_INDEX(p_index, size());
_copy_on_write(); _copy_on_write();
_get_data()[p_index] = p_elem; _ptr[p_index] = p_elem;
} }
_FORCE_INLINE_ T &get_m(int p_index) { _FORCE_INLINE_ T &get_m(Size p_index) {
CRASH_BAD_INDEX(p_index, size()); CRASH_BAD_INDEX(p_index, size());
_copy_on_write(); _copy_on_write();
return _get_data()[p_index]; return _ptr[p_index];
} }
_FORCE_INLINE_ const T &get(int p_index) const { _FORCE_INLINE_ const T &get(Size p_index) const {
CRASH_BAD_INDEX(p_index, size()); CRASH_BAD_INDEX(p_index, size());
return _get_data()[p_index]; return _ptr[p_index];
} }
Error resize(int p_size); template <bool p_ensure_zero = false>
Error resize(Size p_size);
_FORCE_INLINE_ void remove_at(int p_index) { _FORCE_INLINE_ void remove_at(Size p_index) {
ERR_FAIL_INDEX(p_index, size()); ERR_FAIL_INDEX(p_index, size());
T *p = ptrw(); T *p = ptrw();
int len = size(); Size len = size();
for (int i = p_index; i < len - 1; i++) { for (Size i = p_index; i < len - 1; i++) {
p[i] = p[i + 1]; p[i] = p[i + 1];
} }
resize(len - 1); resize(len - 1);
} }
Error insert(int p_pos, const T &p_val) { Error insert(Size p_pos, const T &p_val) {
ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER); ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER);
resize(size() + 1); resize(size() + 1);
for (int i = (size() - 1); i > p_pos; i--) { for (Size i = (size() - 1); i > p_pos; i--) {
set(i, get(i - 1)); set(i, get(i - 1));
} }
set(p_pos, p_val); set(p_pos, p_val);
@ -196,11 +218,13 @@ public:
return OK; return OK;
} }
int find(const T &p_val, int p_from = 0) const; Size find(const T &p_val, Size p_from = 0) const;
Size rfind(const T &p_val, Size p_from = -1) const;
Size count(const T &p_val) const;
_FORCE_INLINE_ CowData() {} _FORCE_INLINE_ CowData() {}
_FORCE_INLINE_ ~CowData(); _FORCE_INLINE_ ~CowData();
_FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); } _FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); };
}; };
template <class T> template <class T>
@ -209,44 +233,45 @@ void CowData<T>::_unref(void *p_data) {
return; return;
} }
SafeNumeric<uint32_t> *refc = _get_refcount(); SafeNumeric<USize> *refc = _get_refcount();
if (refc->decrement() > 0) { if (refc->decrement() > 0) {
return; // still in use return; // still in use
} }
// clean up // clean up
if (!std::is_trivially_destructible<T>::value) { if (!std::is_trivially_destructible<T>::value) {
uint32_t *count = _get_size(); USize *count = _get_size();
T *data = (T *)(count + 1); T *data = (T *)(count + 1);
for (uint32_t i = 0; i < *count; ++i) { for (USize i = 0; i < *count; ++i) {
// call destructors // call destructors
data[i].~T(); data[i].~T();
} }
} }
// free mem // free mem
Memory::free_static((uint8_t *)p_data, true); Memory::free_static(((uint8_t *)p_data) - ALLOC_PAD, false);
} }
template <class T> template <class T>
uint32_t CowData<T>::_copy_on_write() { typename CowData<T>::USize CowData<T>::_copy_on_write() {
if (!_ptr) { if (!_ptr) {
return 0; return 0;
} }
SafeNumeric<uint32_t> *refc = _get_refcount(); SafeNumeric<USize> *refc = _get_refcount();
uint32_t rc = refc->get(); USize rc = refc->get();
if (unlikely(rc > 1)) { if (unlikely(rc > 1)) {
/* in use by more than me */ /* in use by more than me */
uint32_t current_size = *_get_size(); USize current_size = *_get_size();
uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true); USize *mem_new = (USize *)Memory::alloc_static(_get_alloc_size(current_size) + ALLOC_PAD, false);
mem_new += 2;
new (mem_new - 2) SafeNumeric<uint32_t>(1); // refcount new (mem_new - 2) SafeNumeric<USize>(1); //refcount
*(mem_new - 1) = current_size; // size *(mem_new - 1) = current_size; //size
T *_data = (T *)(mem_new); T *_data = (T *)(mem_new);
@ -255,8 +280,8 @@ uint32_t CowData<T>::_copy_on_write() {
memcpy(mem_new, _ptr, current_size * sizeof(T)); memcpy(mem_new, _ptr, current_size * sizeof(T));
} else { } else {
for (uint32_t i = 0; i < current_size; i++) { for (USize i = 0; i < current_size; i++) {
memnew_placement(&_data[i], T(_get_data()[i])); memnew_placement(&_data[i], T(_ptr[i]));
} }
} }
@ -269,10 +294,11 @@ uint32_t CowData<T>::_copy_on_write() {
} }
template <class T> template <class T>
Error CowData<T>::resize(int p_size) { template <bool p_ensure_zero>
Error CowData<T>::resize(Size p_size) {
ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
int current_size = size(); Size current_size = size();
if (p_size == current_size) { if (p_size == current_size) {
return OK; return OK;
@ -286,27 +312,29 @@ Error CowData<T>::resize(int p_size) {
} }
// possibly changing size, copy on write // possibly changing size, copy on write
uint32_t rc = _copy_on_write(); USize rc = _copy_on_write();
size_t current_alloc_size = _get_alloc_size(current_size); USize current_alloc_size = _get_alloc_size(current_size);
size_t alloc_size; USize alloc_size;
ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY); ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY);
if (p_size > current_size) { if (p_size > current_size) {
if (alloc_size != current_alloc_size) { if (alloc_size != current_alloc_size) {
if (current_size == 0) { if (current_size == 0) {
// alloc from scratch // alloc from scratch
uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true); USize *ptr = (USize *)Memory::alloc_static(alloc_size + ALLOC_PAD, false);
ptr += 2;
ERR_FAIL_NULL_V(ptr, ERR_OUT_OF_MEMORY); ERR_FAIL_NULL_V(ptr, ERR_OUT_OF_MEMORY);
*(ptr - 1) = 0; // size, currently none *(ptr - 1) = 0; //size, currently none
new (ptr - 2) SafeNumeric<uint32_t>(1); // refcount new (ptr - 2) SafeNumeric<USize>(1); //refcount
_ptr = (T *)ptr; _ptr = (T *)ptr;
} else { } else {
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true); USize *_ptrnew = (USize *)Memory::realloc_static(((uint8_t *)_ptr) - ALLOC_PAD, alloc_size + ALLOC_PAD, false);
ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY); ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount _ptrnew += 2;
new (_ptrnew - 2) SafeNumeric<USize>(rc); //refcount
_ptr = (T *)(_ptrnew); _ptr = (T *)(_ptrnew);
} }
@ -315,11 +343,11 @@ Error CowData<T>::resize(int p_size) {
// construct the newly created elements // construct the newly created elements
if (!std::is_trivially_constructible<T>::value) { if (!std::is_trivially_constructible<T>::value) {
T *elems = _get_data(); for (Size i = *_get_size(); i < p_size; i++) {
memnew_placement(&_ptr[i], T);
for (int i = *_get_size(); i < p_size; i++) {
memnew_placement(&elems[i], T);
} }
} else if (p_ensure_zero) {
memset((void *)(_ptr + current_size), 0, (p_size - current_size) * sizeof(T));
} }
*_get_size() = p_size; *_get_size() = p_size;
@ -327,16 +355,17 @@ Error CowData<T>::resize(int p_size) {
} else if (p_size < current_size) { } else if (p_size < current_size) {
if (!std::is_trivially_destructible<T>::value) { if (!std::is_trivially_destructible<T>::value) {
// deinitialize no longer needed elements // deinitialize no longer needed elements
for (uint32_t i = p_size; i < *_get_size(); i++) { for (USize i = p_size; i < *_get_size(); i++) {
T *t = &_get_data()[i]; T *t = &_ptr[i];
t->~T(); t->~T();
} }
} }
if (alloc_size != current_alloc_size) { if (alloc_size != current_alloc_size) {
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true); USize *_ptrnew = (USize *)Memory::realloc_static(((uint8_t *)_ptr) - ALLOC_PAD, alloc_size + ALLOC_PAD, false);
ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY); ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount _ptrnew += 2;
new (_ptrnew - 2) SafeNumeric<USize>(rc); //refcount
_ptr = (T *)(_ptrnew); _ptr = (T *)(_ptrnew);
} }
@ -348,14 +377,14 @@ Error CowData<T>::resize(int p_size) {
} }
template <class T> template <class T>
int CowData<T>::find(const T &p_val, int p_from) const { typename CowData<T>::Size CowData<T>::find(const T &p_val, Size p_from) const {
int ret = -1; Size ret = -1;
if (p_from < 0 || size() == 0) { if (p_from < 0 || size() == 0) {
return ret; return ret;
} }
for (int i = p_from; i < size(); i++) { for (Size i = p_from; i < size(); i++) {
if (get(i) == p_val) { if (get(i) == p_val) {
ret = i; ret = i;
break; break;
@ -365,6 +394,36 @@ int CowData<T>::find(const T &p_val, int p_from) const {
return ret; return ret;
} }
template <class T>
typename CowData<T>::Size CowData<T>::rfind(const T &p_val, Size p_from) const {
const Size s = size();
if (p_from < 0) {
p_from = s + p_from;
}
if (p_from < 0 || p_from >= s) {
p_from = s - 1;
}
for (Size i = p_from; i >= 0; i--) {
if (get(i) == p_val) {
return i;
}
}
return -1;
}
template <class T>
typename CowData<T>::Size CowData<T>::count(const T &p_val) const {
Size amount = 0;
for (Size i = 0; i < size(); i++) {
if (get(i) == p_val) {
amount++;
}
}
return amount;
}
template <class T> template <class T>
void CowData<T>::_ref(const CowData *p_from) { void CowData<T>::_ref(const CowData *p_from) {
_ref(*p_from); _ref(*p_from);

View File

@ -48,6 +48,15 @@ namespace godot {
// value and, as an important benefit, you can be sure the value is properly synchronized // value and, as an important benefit, you can be sure the value is properly synchronized
// even with threads that are already running. // even with threads that are already running.
// These are used in very specific areas of the engine where it's critical that these guarantees are held
#define SAFE_NUMERIC_TYPE_PUN_GUARANTEES(m_type) \
static_assert(sizeof(SafeNumeric<m_type>) == sizeof(m_type)); \
static_assert(alignof(SafeNumeric<m_type>) == alignof(m_type)); \
static_assert(std::is_trivially_destructible<std::atomic<m_type>>::value);
#define SAFE_FLAG_TYPE_PUN_GUARANTEES \
static_assert(sizeof(SafeFlag) == sizeof(bool)); \
static_assert(alignof(SafeFlag) == alignof(bool));
template <class T> template <class T>
class SafeNumeric { class SafeNumeric {
std::atomic<T> value; std::atomic<T> value;

View File

@ -50,7 +50,7 @@ namespace godot {
template <class T> template <class T>
class VectorWriteProxy { class VectorWriteProxy {
public: public:
_FORCE_INLINE_ T &operator[](int p_index) { _FORCE_INLINE_ T &operator[](typename CowData<T>::Size p_index) {
CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size()); CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size());
return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index]; return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index];
@ -63,22 +63,26 @@ class Vector {
public: public:
VectorWriteProxy<T> write; VectorWriteProxy<T> write;
typedef typename CowData<T>::Size Size;
private: private:
CowData<T> _cowdata; CowData<T> _cowdata;
public: public:
bool push_back(T p_elem); bool push_back(T p_elem);
_FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } // alias _FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } //alias
void fill(T p_elem); void fill(T p_elem);
void remove_at(int p_index) { _cowdata.remove_at(p_index); } void remove_at(Size p_index) { _cowdata.remove_at(p_index); }
void erase(const T &p_val) { _FORCE_INLINE_ bool erase(const T &p_val) {
int idx = find(p_val); Size idx = find(p_val);
if (idx >= 0) { if (idx >= 0) {
remove_at(idx); remove_at(idx);
return true;
} }
return false;
} }
void reverse(); void reverse();
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); } _FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
@ -86,37 +90,45 @@ public:
_FORCE_INLINE_ void clear() { resize(0); } _FORCE_INLINE_ void clear() { resize(0); }
_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); } _FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
_FORCE_INLINE_ T get(int p_index) { return _cowdata.get(p_index); } _FORCE_INLINE_ T get(Size p_index) { return _cowdata.get(p_index); }
_FORCE_INLINE_ const T &get(int p_index) const { return _cowdata.get(p_index); } _FORCE_INLINE_ const T &get(Size p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); } _FORCE_INLINE_ void set(Size p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ int size() const { return _cowdata.size(); } _FORCE_INLINE_ Size size() const { return _cowdata.size(); }
Error resize(int p_size) { return _cowdata.resize(p_size); } Error resize(Size p_size) { return _cowdata.resize(p_size); }
_FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); } Error resize_zeroed(Size p_size) { return _cowdata.template resize<true>(p_size); }
Error insert(int p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); } _FORCE_INLINE_ const T &operator[](Size p_index) const { return _cowdata.get(p_index); }
int find(const T &p_val, int p_from = 0) const { return _cowdata.find(p_val, p_from); } Error insert(Size p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); }
Size find(const T &p_val, Size p_from = 0) const { return _cowdata.find(p_val, p_from); }
Size rfind(const T &p_val, Size p_from = -1) const { return _cowdata.rfind(p_val, p_from); }
Size count(const T &p_val) const { return _cowdata.count(p_val); }
void append_array(Vector<T> p_other); void append_array(Vector<T> p_other);
_FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; } _FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; }
template <class C> void sort() {
void sort_custom() { sort_custom<_DefaultComparator<T>>();
int len = _cowdata.size(); }
template <class Comparator, bool Validate = SORT_ARRAY_VALIDATE_ENABLED, class... Args>
void sort_custom(Args &&...args) {
Size len = _cowdata.size();
if (len == 0) { if (len == 0) {
return; return;
} }
T *data = ptrw(); T *data = ptrw();
SortArray<T, C> sorter; SortArray<T, Comparator, Validate> sorter{ args... };
sorter.sort(data, len); sorter.sort(data, len);
} }
void sort() { Size bsearch(const T &p_value, bool p_before) {
sort_custom<_DefaultComparator<T>>(); return bsearch_custom<_DefaultComparator<T>>(p_value, p_before);
} }
int bsearch(const T &p_value, bool p_before) { template <class Comparator, class Value, class... Args>
SearchArray<T> search; Size bsearch_custom(const Value &p_value, bool p_before, Args &&...args) {
SearchArray<T, Comparator> search{ args... };
return search.bisect(ptrw(), size(), p_value, p_before); return search.bisect(ptrw(), size(), p_value, p_before);
} }
@ -125,7 +137,7 @@ public:
} }
void ordered_insert(const T &p_val) { void ordered_insert(const T &p_val) {
int i; Size i;
for (i = 0; i < _cowdata.size(); i++) { for (i = 0; i < _cowdata.size(); i++) {
if (p_val < operator[](i)) { if (p_val < operator[](i)) {
break; break;
@ -140,33 +152,36 @@ public:
Vector<uint8_t> to_byte_array() const { Vector<uint8_t> to_byte_array() const {
Vector<uint8_t> ret; Vector<uint8_t> ret;
if (is_empty()) {
return ret;
}
ret.resize(size() * sizeof(T)); ret.resize(size() * sizeof(T));
memcpy(ret.ptrw(), ptr(), sizeof(T) * size()); memcpy(ret.ptrw(), ptr(), sizeof(T) * size());
return ret; return ret;
} }
Vector<T> slice(int p_begin, int p_end = INT_MAX) const { Vector<T> slice(Size p_begin, Size p_end = CowData<T>::MAX_INT) const {
Vector<T> result; Vector<T> result;
const int s = size(); const Size s = size();
int begin = Math::clamp(p_begin, -s, s); Size begin = CLAMP(p_begin, -s, s);
if (begin < 0) { if (begin < 0) {
begin += s; begin += s;
} }
int end = Math::clamp(p_end, -s, s); Size end = CLAMP(p_end, -s, s);
if (end < 0) { if (end < 0) {
end += s; end += s;
} }
ERR_FAIL_COND_V(begin > end, result); ERR_FAIL_COND_V(begin > end, result);
int result_size = end - begin; Size result_size = end - begin;
result.resize(result_size); result.resize(result_size);
const T *const r = ptr(); const T *const r = ptr();
T *const w = result.ptrw(); T *const w = result.ptrw();
for (int i = 0; i < result_size; ++i) { for (Size i = 0; i < result_size; ++i) {
w[i] = r[begin + i]; w[i] = r[begin + i];
} }
@ -174,11 +189,11 @@ public:
} }
bool operator==(const Vector<T> &p_arr) const { bool operator==(const Vector<T> &p_arr) const {
int s = size(); Size s = size();
if (s != p_arr.size()) { if (s != p_arr.size()) {
return false; return false;
} }
for (int i = 0; i < s; i++) { for (Size i = 0; i < s; i++) {
if (operator[](i) != p_arr[i]) { if (operator[](i) != p_arr[i]) {
return false; return false;
} }
@ -187,11 +202,11 @@ public:
} }
bool operator!=(const Vector<T> &p_arr) const { bool operator!=(const Vector<T> &p_arr) const {
int s = size(); Size s = size();
if (s != p_arr.size()) { if (s != p_arr.size()) {
return true; return true;
} }
for (int i = 0; i < s; i++) { for (Size i = 0; i < s; i++) {
if (operator[](i) != p_arr[i]) { if (operator[](i) != p_arr[i]) {
return true; return true;
} }
@ -268,7 +283,7 @@ public:
Error err = _cowdata.resize(p_init.size()); Error err = _cowdata.resize(p_init.size());
ERR_FAIL_COND(err); ERR_FAIL_COND(err);
int i = 0; Size i = 0;
for (const T &element : p_init) { for (const T &element : p_init) {
_cowdata.set(i++, element); _cowdata.set(i++, element);
} }
@ -280,7 +295,7 @@ public:
template <class T> template <class T>
void Vector<T>::reverse() { void Vector<T>::reverse() {
for (int i = 0; i < size() / 2; i++) { for (Size i = 0; i < size() / 2; i++) {
T *p = ptrw(); T *p = ptrw();
SWAP(p[i], p[size() - i - 1]); SWAP(p[i], p[size() - i - 1]);
} }
@ -288,13 +303,13 @@ void Vector<T>::reverse() {
template <class T> template <class T>
void Vector<T>::append_array(Vector<T> p_other) { void Vector<T>::append_array(Vector<T> p_other) {
const int ds = p_other.size(); const Size ds = p_other.size();
if (ds == 0) { if (ds == 0) {
return; return;
} }
const int bs = size(); const Size bs = size();
resize(bs + ds); resize(bs + ds);
for (int i = 0; i < ds; ++i) { for (Size i = 0; i < ds; ++i) {
ptrw()[bs + i] = p_other[i]; ptrw()[bs + i] = p_other[i];
} }
} }
@ -311,7 +326,7 @@ bool Vector<T>::push_back(T p_elem) {
template <class T> template <class T>
void Vector<T>::fill(T p_elem) { void Vector<T>::fill(T p_elem) {
T *p = ptrw(); T *p = ptrw();
for (int i = 0; i < size(); i++) { for (Size i = 0; i < size(); i++) {
p[i] = p_elem; p[i] = p_elem;
} }
} }

View File

@ -46,11 +46,11 @@ class CharProxy {
template <class TS> template <class TS>
friend class CharStringT; friend class CharStringT;
const int _index; const int64_t _index;
CowData<T> &_cowdata; CowData<T> &_cowdata;
static inline const T _null = 0; static inline const T _null = 0;
_FORCE_INLINE_ CharProxy(const int &p_index, CowData<T> &p_cowdata) : _FORCE_INLINE_ CharProxy(const int64_t &p_index, CowData<T> &p_cowdata) :
_index(p_index), _index(p_index),
_cowdata(p_cowdata) {} _cowdata(p_cowdata) {}
@ -90,19 +90,19 @@ class CharStringT {
public: public:
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); } _FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); } _FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
_FORCE_INLINE_ int size() const { return _cowdata.size(); } _FORCE_INLINE_ int64_t size() const { return _cowdata.size(); }
Error resize(int p_size) { return _cowdata.resize(p_size); } Error resize(int64_t p_size) { return _cowdata.resize(p_size); }
_FORCE_INLINE_ T get(int p_index) const { return _cowdata.get(p_index); } _FORCE_INLINE_ T get(int64_t p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); } _FORCE_INLINE_ void set(int64_t p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ const T &operator[](int p_index) const { _FORCE_INLINE_ const T &operator[](int64_t p_index) const {
if (unlikely(p_index == _cowdata.size())) { if (unlikely(p_index == _cowdata.size())) {
return _null; return _null;
} }
return _cowdata.get(p_index); return _cowdata.get(p_index);
} }
_FORCE_INLINE_ CharProxy<T> operator[](int p_index) { return CharProxy<T>(p_index, _cowdata); } _FORCE_INLINE_ CharProxy<T> operator[](int64_t p_index) { return CharProxy<T>(p_index, _cowdata); }
_FORCE_INLINE_ CharStringT() {} _FORCE_INLINE_ CharStringT() {}
_FORCE_INLINE_ CharStringT(const CharStringT<T> &p_str) { _cowdata._ref(p_str._cowdata); } _FORCE_INLINE_ CharStringT(const CharStringT<T> &p_str) { _cowdata._ref(p_str._cowdata); }
@ -112,7 +112,7 @@ public:
void operator=(const T *p_cstr); void operator=(const T *p_cstr);
bool operator<(const CharStringT<T> &p_right) const; bool operator<(const CharStringT<T> &p_right) const;
CharStringT<T> &operator+=(T p_char); CharStringT<T> &operator+=(T p_char);
int length() const { return size() ? size() - 1 : 0; } int64_t length() const { return size() ? size() - 1 : 0; }
const T *get_data() const; const T *get_data() const;
operator const T *() const { return get_data(); }; operator const T *() const { return get_data(); };

View File

@ -122,6 +122,7 @@ public:
OP_NEGATE, OP_NEGATE,
OP_POSITIVE, OP_POSITIVE,
OP_MODULE, OP_MODULE,
OP_POWER,
// bitwise // bitwise
OP_SHIFT_LEFT, OP_SHIFT_LEFT,
OP_SHIFT_RIGHT, OP_SHIFT_RIGHT,
@ -154,10 +155,18 @@ public:
Variant(int64_t v); Variant(int64_t v);
Variant(int32_t v) : Variant(int32_t v) :
Variant(static_cast<int64_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(static_cast<int64_t>(v)) {}
Variant(uint64_t v) : Variant(uint64_t v) :
Variant(static_cast<int64_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(double v);
Variant(float v) : Variant(float v) :
Variant((double)v) {} Variant((double)v) {}
@ -209,8 +218,12 @@ public:
operator bool() const; operator bool() const;
operator int64_t() const; operator int64_t() const;
operator int32_t() const; operator int32_t() const;
operator int16_t() const;
operator int8_t() const;
operator uint64_t() const; operator uint64_t() const;
operator uint32_t() const; operator uint32_t() const;
operator uint16_t() const;
operator uint8_t() const;
operator double() const; operator double() const;
operator float() const; operator float() const;
operator String() const; operator String() const;

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(_owner, reinterpret_cast<GDExtensionConstStringNamePtr>(extension_class), this);
} }
godot::internal::gdextension_interface_object_set_instance_binding(_owner, godot::internal::token, this, _get_bindings_callbacks()); 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) { Wrapped::Wrapped(const StringName p_godot_class) {

View File

@ -189,9 +189,9 @@ GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugi
} // namespace internal } // namespace internal
GDExtensionBinding::Callback GDExtensionBinding::init_callback = nullptr; bool GDExtensionBinding::api_initialized = false;
GDExtensionBinding::Callback GDExtensionBinding::terminate_callback = nullptr; int GDExtensionBinding::level_initialized[MODULE_INITIALIZATION_LEVEL_MAX] = { 0 };
GDExtensionInitializationLevel GDExtensionBinding::minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE; GDExtensionBinding::InitDataList GDExtensionBinding::initdata;
#define ERR_PRINT_EARLY(m_msg) \ #define ERR_PRINT_EARLY(m_msg) \
internal::gdextension_interface_print_error(m_msg, FUNCTION_STR, __FILE__, __LINE__, false) internal::gdextension_interface_print_error(m_msg, FUNCTION_STR, __FILE__, __LINE__, false)
@ -218,7 +218,20 @@ typedef struct {
GDExtensionInterfacePrintErrorWithMessage print_error_with_message; GDExtensionInterfacePrintErrorWithMessage print_error_with_message;
} LegacyGDExtensionInterface; } 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. // Make sure we weren't passed the legacy struct.
uint32_t *raw_interface = (uint32_t *)(void *)p_get_proc_address; uint32_t *raw_interface = (uint32_t *)(void *)p_get_proc_address;
if (raw_interface[0] == 4 && raw_interface[1] == 0) { if (raw_interface[0] == 4 && raw_interface[1] == 0) {
@ -251,7 +264,12 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
} else if (internal::godot_version.minor != GODOT_VERSION_MINOR) { } else if (internal::godot_version.minor != GODOT_VERSION_MINOR) {
compatible = internal::godot_version.minor > GODOT_VERSION_MINOR; compatible = internal::godot_version.minor > GODOT_VERSION_MINOR;
} else { } else {
#if GODOT_VERSION_PATCH > 0
compatible = internal::godot_version.patch >= GODOT_VERSION_PATCH; compatible = internal::godot_version.patch >= GODOT_VERSION_PATCH;
#else
// Prevent -Wtype-limits warning due to unsigned comparison.
compatible = true;
#endif
} }
if (!compatible) { if (!compatible) {
// We need to use snprintf() here because vformat() uses Variant, and we haven't loaded // We need to use snprintf() here because vformat() uses Variant, and we haven't loaded
@ -401,59 +419,96 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
r_initialization->initialize = initialize_level; r_initialization->initialize = initialize_level;
r_initialization->deinitialize = deinitialize_level; r_initialization->deinitialize = deinitialize_level;
r_initialization->minimum_initialization_level = minimum_initialization_level; r_initialization->userdata = p_init_data;
r_initialization->minimum_initialization_level = p_init_data->minimum_initialization_level;
ERR_FAIL_NULL_V_MSG(init_callback, false, "Initialization callback must be defined.");
Variant::init_bindings(); Variant::init_bindings();
godot::internal::register_engine_classes(); godot::internal::register_engine_classes();
api_initialized = true;
return true; return true;
} }
#undef LOAD_PROC_ADDRESS #undef LOAD_PROC_ADDRESS
#undef ERR_PRINT_EARLY #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; ClassDB::current_level = p_level;
if (init_callback) { InitData *init_data = static_cast<InitData *>(p_userdata);
init_callback(static_cast<ModuleInitializationLevel>(p_level)); 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; ClassDB::current_level = p_level;
if (terminate_callback) { InitData *init_data = static_cast<InitData *>(p_userdata);
terminate_callback(static_cast<ModuleInitializationLevel>(p_level)); if (init_data && init_data->terminate_callback) {
init_data->terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
} }
EditorPlugins::deinitialize(p_level); level_initialized[p_level]--;
ClassDB::deinitialize(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) { GDExtensionBinding::InitObject::InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
get_proc_address = p_get_proc_address; get_proc_address = p_get_proc_address;
library = p_library; library = p_library;
initialization = r_initialization; initialization = r_initialization;
init_data = new InitData();
GDExtensionBinding::initdata.add(init_data);
} }
void GDExtensionBinding::InitObject::register_initializer(Callback p_init) const { 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 { 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 { 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 { 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 } // namespace godot

View File

@ -76,7 +76,7 @@ bool CharStringT<T>::operator<(const CharStringT<T> &p_right) const {
template <class T> template <class T>
CharStringT<T> &CharStringT<T>::operator+=(T p_char) { CharStringT<T> &CharStringT<T>::operator+=(T p_char) {
const int lhs_len = length(); const int64_t lhs_len = length();
resize(lhs_len + 2); resize(lhs_len + 2);
T *dst = ptrw(); T *dst = ptrw();
@ -172,23 +172,23 @@ String::String(const char32_t *from) {
internal::gdextension_interface_string_new_with_utf32_chars(_native_ptr(), from); internal::gdextension_interface_string_new_with_utf32_chars(_native_ptr(), from);
} }
String String::utf8(const char *from, int len) { String String::utf8(const char *from, int64_t len) {
String ret; String ret;
ret.parse_utf8(from, len); ret.parse_utf8(from, len);
return ret; return ret;
} }
void String::parse_utf8(const char *from, int len) { void String::parse_utf8(const char *from, int64_t len) {
internal::gdextension_interface_string_new_with_utf8_chars_and_len(_native_ptr(), from, len); internal::gdextension_interface_string_new_with_utf8_chars_and_len(_native_ptr(), from, len);
} }
String String::utf16(const char16_t *from, int len) { String String::utf16(const char16_t *from, int64_t len) {
String ret; String ret;
ret.parse_utf16(from, len); ret.parse_utf16(from, len);
return ret; return ret;
} }
void String::parse_utf16(const char16_t *from, int len) { void String::parse_utf16(const char16_t *from, int64_t len) {
internal::gdextension_interface_string_new_with_utf16_chars_and_len(_native_ptr(), from, len); internal::gdextension_interface_string_new_with_utf16_chars_and_len(_native_ptr(), from, len);
} }
@ -230,8 +230,8 @@ String rtoss(double p_val) {
} }
CharString String::utf8() const { CharString String::utf8() const {
int length = internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), nullptr, 0); int64_t length = internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), nullptr, 0);
int size = length + 1; int64_t size = length + 1;
CharString str; CharString str;
str.resize(size); str.resize(size);
internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), str.ptrw(), length); internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), str.ptrw(), length);
@ -242,8 +242,8 @@ CharString String::utf8() const {
} }
CharString String::ascii() const { CharString String::ascii() const {
int length = internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), nullptr, 0); int64_t length = internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), nullptr, 0);
int size = length + 1; int64_t size = length + 1;
CharString str; CharString str;
str.resize(size); str.resize(size);
internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), str.ptrw(), length); internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), str.ptrw(), length);
@ -254,8 +254,8 @@ CharString String::ascii() const {
} }
Char16String String::utf16() const { Char16String String::utf16() const {
int length = internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), nullptr, 0); int64_t length = internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), nullptr, 0);
int size = length + 1; int64_t size = length + 1;
Char16String str; Char16String str;
str.resize(size); str.resize(size);
internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), str.ptrw(), length); internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), str.ptrw(), length);
@ -266,8 +266,8 @@ Char16String String::utf16() const {
} }
Char32String String::utf32() const { Char32String String::utf32() const {
int length = internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), nullptr, 0); int64_t length = internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), nullptr, 0);
int size = length + 1; int64_t size = length + 1;
Char32String str; Char32String str;
str.resize(size); str.resize(size);
internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), str.ptrw(), length); internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), str.ptrw(), length);
@ -278,8 +278,8 @@ Char32String String::utf32() const {
} }
CharWideString String::wide_string() const { CharWideString String::wide_string() const {
int length = internal::gdextension_interface_string_to_wide_chars(_native_ptr(), nullptr, 0); int64_t length = internal::gdextension_interface_string_to_wide_chars(_native_ptr(), nullptr, 0);
int size = length + 1; int64_t size = length + 1;
CharWideString str; CharWideString str;
str.resize(size); str.resize(size);
internal::gdextension_interface_string_to_wide_chars(_native_ptr(), str.ptrw(), length); internal::gdextension_interface_string_to_wide_chars(_native_ptr(), str.ptrw(), length);
@ -386,11 +386,11 @@ String &String::operator+=(const char32_t *p_str) {
return *this; return *this;
} }
const char32_t &String::operator[](int p_index) const { const char32_t &String::operator[](int64_t p_index) const {
return *internal::gdextension_interface_string_operator_index_const((GDExtensionStringPtr)this, p_index); return *internal::gdextension_interface_string_operator_index_const((GDExtensionStringPtr)this, p_index);
} }
char32_t &String::operator[](int p_index) { char32_t &String::operator[](int64_t p_index) {
return *internal::gdextension_interface_string_operator_index((GDExtensionStringPtr)this, p_index); return *internal::gdextension_interface_string_operator_index((GDExtensionStringPtr)this, p_index);
} }

View File

@ -46,11 +46,11 @@
namespace godot { namespace godot {
const uint8_t &PackedByteArray::operator[](int p_index) const { const uint8_t &PackedByteArray::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_byte_array_operator_index_const((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_byte_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
} }
uint8_t &PackedByteArray::operator[](int p_index) { uint8_t &PackedByteArray::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_byte_array_operator_index((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_byte_array_operator_index((GDExtensionTypePtr *)this, p_index);
} }
@ -62,12 +62,12 @@ uint8_t *PackedByteArray::ptrw() {
return internal::gdextension_interface_packed_byte_array_operator_index((GDExtensionTypePtr *)this, 0); return internal::gdextension_interface_packed_byte_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const Color &PackedColorArray::operator[](int p_index) const { const Color &PackedColorArray::operator[](int64_t p_index) const {
const Color *color = (const Color *)internal::gdextension_interface_packed_color_array_operator_index_const((GDExtensionTypePtr *)this, p_index); const Color *color = (const Color *)internal::gdextension_interface_packed_color_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *color; return *color;
} }
Color &PackedColorArray::operator[](int p_index) { Color &PackedColorArray::operator[](int64_t p_index) {
Color *color = (Color *)internal::gdextension_interface_packed_color_array_operator_index((GDExtensionTypePtr *)this, p_index); Color *color = (Color *)internal::gdextension_interface_packed_color_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *color; return *color;
} }
@ -80,11 +80,11 @@ Color *PackedColorArray::ptrw() {
return (Color *)internal::gdextension_interface_packed_color_array_operator_index((GDExtensionTypePtr *)this, 0); return (Color *)internal::gdextension_interface_packed_color_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const float &PackedFloat32Array::operator[](int p_index) const { const float &PackedFloat32Array::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_float32_array_operator_index_const((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_float32_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
} }
float &PackedFloat32Array::operator[](int p_index) { float &PackedFloat32Array::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_float32_array_operator_index((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_float32_array_operator_index((GDExtensionTypePtr *)this, p_index);
} }
@ -96,11 +96,11 @@ float *PackedFloat32Array::ptrw() {
return internal::gdextension_interface_packed_float32_array_operator_index((GDExtensionTypePtr *)this, 0); return internal::gdextension_interface_packed_float32_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const double &PackedFloat64Array::operator[](int p_index) const { const double &PackedFloat64Array::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_float64_array_operator_index_const((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_float64_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
} }
double &PackedFloat64Array::operator[](int p_index) { double &PackedFloat64Array::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_float64_array_operator_index((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_float64_array_operator_index((GDExtensionTypePtr *)this, p_index);
} }
@ -112,11 +112,11 @@ double *PackedFloat64Array::ptrw() {
return internal::gdextension_interface_packed_float64_array_operator_index((GDExtensionTypePtr *)this, 0); return internal::gdextension_interface_packed_float64_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const int32_t &PackedInt32Array::operator[](int p_index) const { const int32_t &PackedInt32Array::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_int32_array_operator_index_const((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_int32_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
} }
int32_t &PackedInt32Array::operator[](int p_index) { int32_t &PackedInt32Array::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_int32_array_operator_index((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_int32_array_operator_index((GDExtensionTypePtr *)this, p_index);
} }
@ -128,11 +128,11 @@ int32_t *PackedInt32Array::ptrw() {
return internal::gdextension_interface_packed_int32_array_operator_index((GDExtensionTypePtr *)this, 0); return internal::gdextension_interface_packed_int32_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const int64_t &PackedInt64Array::operator[](int p_index) const { const int64_t &PackedInt64Array::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_int64_array_operator_index_const((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_int64_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
} }
int64_t &PackedInt64Array::operator[](int p_index) { int64_t &PackedInt64Array::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_int64_array_operator_index((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_int64_array_operator_index((GDExtensionTypePtr *)this, p_index);
} }
@ -144,12 +144,12 @@ int64_t *PackedInt64Array::ptrw() {
return internal::gdextension_interface_packed_int64_array_operator_index((GDExtensionTypePtr *)this, 0); return internal::gdextension_interface_packed_int64_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const String &PackedStringArray::operator[](int p_index) const { const String &PackedStringArray::operator[](int64_t p_index) const {
const String *string = (const String *)internal::gdextension_interface_packed_string_array_operator_index_const((GDExtensionTypePtr *)this, p_index); const String *string = (const String *)internal::gdextension_interface_packed_string_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *string; return *string;
} }
String &PackedStringArray::operator[](int p_index) { String &PackedStringArray::operator[](int64_t p_index) {
String *string = (String *)internal::gdextension_interface_packed_string_array_operator_index((GDExtensionTypePtr *)this, p_index); String *string = (String *)internal::gdextension_interface_packed_string_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *string; return *string;
} }
@ -162,12 +162,12 @@ String *PackedStringArray::ptrw() {
return (String *)internal::gdextension_interface_packed_string_array_operator_index((GDExtensionTypePtr *)this, 0); return (String *)internal::gdextension_interface_packed_string_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const Vector2 &PackedVector2Array::operator[](int p_index) const { const Vector2 &PackedVector2Array::operator[](int64_t p_index) const {
const Vector2 *vec = (const Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index_const((GDExtensionTypePtr *)this, p_index); const Vector2 *vec = (const Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *vec; return *vec;
} }
Vector2 &PackedVector2Array::operator[](int p_index) { Vector2 &PackedVector2Array::operator[](int64_t p_index) {
Vector2 *vec = (Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index((GDExtensionTypePtr *)this, p_index); Vector2 *vec = (Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *vec; return *vec;
} }
@ -180,12 +180,12 @@ Vector2 *PackedVector2Array::ptrw() {
return (Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index((GDExtensionTypePtr *)this, 0); return (Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const Vector3 &PackedVector3Array::operator[](int p_index) const { const Vector3 &PackedVector3Array::operator[](int64_t p_index) const {
const Vector3 *vec = (const Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index_const((GDExtensionTypePtr *)this, p_index); const Vector3 *vec = (const Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *vec; return *vec;
} }
Vector3 &PackedVector3Array::operator[](int p_index) { Vector3 &PackedVector3Array::operator[](int64_t p_index) {
Vector3 *vec = (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, p_index); Vector3 *vec = (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *vec; return *vec;
} }
@ -198,12 +198,12 @@ Vector3 *PackedVector3Array::ptrw() {
return (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, 0); return (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const Variant &Array::operator[](int p_index) const { const Variant &Array::operator[](int64_t p_index) const {
const Variant *var = (const Variant *)internal::gdextension_interface_array_operator_index_const((GDExtensionTypePtr *)this, p_index); const Variant *var = (const Variant *)internal::gdextension_interface_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *var; return *var;
} }
Variant &Array::operator[](int p_index) { Variant &Array::operator[](int64_t p_index) {
Variant *var = (Variant *)internal::gdextension_interface_array_operator_index((GDExtensionTypePtr *)this, p_index); Variant *var = (Variant *)internal::gdextension_interface_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *var; return *var;
} }

View File

@ -268,6 +268,14 @@ Variant::operator int32_t() const {
return static_cast<int32_t>(operator int64_t()); 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 { Variant::operator uint64_t() const {
return static_cast<uint64_t>(operator int64_t()); 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()); 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 { Variant::operator double() const {
double result; double result;
to_type_constructor[FLOAT](&result, _native_ptr()); to_type_constructor[FLOAT](&result, _native_ptr());

View File

@ -59,31 +59,9 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
else() 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'") 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 "-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) 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")

View File

@ -169,6 +169,11 @@ func _ready():
get_viewport().push_input(event) get_viewport().push_input(event)
assert_equal(custom_signal_emitted, ["_input: H", 72]) 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() exit_with_status()
func _on_Example_custom_signal(signal_name, value): func _on_Example_custom_signal(signal_name, value):

View File

@ -23,10 +23,18 @@ int ExampleRef::get_id() const {
return id; return id;
} }
void ExampleRef::_notification(int p_what) {
if (p_what == NOTIFICATION_POSTINITIALIZE) {
post_initialized = true;
}
}
void ExampleRef::_bind_methods() { void ExampleRef::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_id", "id"), &ExampleRef::set_id); 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("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"); ADD_PROPERTY(PropertyInfo(Variant::INT, "id"), "set_id", "get_id");
} }
@ -161,6 +169,7 @@ void Example::_bind_methods() {
ClassDB::bind_method(D_METHOD("return_last_rpc_arg"), &Example::return_last_rpc_arg); ClassDB::bind_method(D_METHOD("return_last_rpc_arg"), &Example::return_last_rpc_arg);
ClassDB::bind_method(D_METHOD("def_args", "a", "b"), &Example::def_args, DEFVAL(100), DEFVAL(200)); ClassDB::bind_method(D_METHOD("def_args", "a", "b"), &Example::def_args, DEFVAL(100), DEFVAL(200));
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_static", "a", "b"), &Example::test_static);
ClassDB::bind_static_method("Example", D_METHOD("test_static2"), &Example::test_static2); ClassDB::bind_static_method("Example", D_METHOD("test_static2"), &Example::test_static2);
@ -426,6 +435,12 @@ Vector4 Example::get_v4() const {
return Vector4(1.2, 3.4, 5.6, 7.8); 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. // Virtual function override.
bool Example::_has_point(const Vector2 &point) const { bool Example::_has_point(const Vector2 &point) const {
Label *label = get_node<Label>("Label"); Label *label = get_node<Label>("Label");

View File

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

View File

@ -8,7 +8,7 @@ def options(opts):
opts.Add( opts.Add(
"android_api_level", "android_api_level",
"Target Android API level", "Target Android API level",
"18" if "32" in ARGUMENTS.get("arch", "arm64") else "21", "21",
) )
opts.Add( opts.Add(
"ANDROID_HOME", "ANDROID_HOME",
@ -47,11 +47,9 @@ def generate(env):
my_spawn.configure(env) my_spawn.configure(env)
# Validate API level # Validate API level
api_level = int(env["android_api_level"]) if int(env["android_api_level"]) < 21:
if "64" in env["arch"] and api_level < 21: print("WARNING: minimum supported Android target api is 21. Forcing target api 21.")
print("WARN: 64-bit Android architectures require an API level of at least 21; setting android_api_level=21")
env["android_api_level"] = "21" env["android_api_level"] = "21"
api_level = 21
# Setup toolchain # Setup toolchain
toolchain = get_android_ndk_root(env) + "/toolchains/llvm/prebuilt/" toolchain = get_android_ndk_root(env) + "/toolchains/llvm/prebuilt/"
@ -66,6 +64,12 @@ def generate(env):
elif sys.platform == "darwin": elif sys.platform == "darwin":
toolchain += "darwin-x86_64" toolchain += "darwin-x86_64"
env.Append(LINKFLAGS=["-shared"]) env.Append(LINKFLAGS=["-shared"])
if not os.path.exists(toolchain):
print("ERROR: Could not find NDK toolchain at " + toolchain + ".")
print("Make sure NDK version " + get_ndk_version() + " is installed.")
env.Exit(1)
env.PrependENVPath("PATH", toolchain + "/bin") # This does nothing half of the time, but we'll put it here anyways env.PrependENVPath("PATH", toolchain + "/bin") # This does nothing half of the time, but we'll put it here anyways
# Get architecture info # Get architecture info

View File

@ -267,6 +267,9 @@ def generate(env):
if env["precision"] == "double": if env["precision"] == "double":
env.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"]) env.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"])
# Allow detecting when building as a GDExtension.
env.Append(CPPDEFINES=["GDEXTENSION"])
# Suffix # Suffix
suffix = ".{}.{}".format(env["platform"], env["target"]) suffix = ".{}.{}".format(env["platform"], env["target"])
if env.dev_build: if env.dev_build: