summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/actions/godot-cache-restore/action.yml25
-rw-r--r--.github/actions/godot-cache-save/action.yml11
-rw-r--r--.github/workflows/ci.yml42
-rw-r--r--.github/workflows/runner.yml21
-rw-r--r--.github/workflows/static_checks.yml5
-rw-r--r--gdextension/gdextension_interface.h12
-rw-r--r--include/godot_cpp/classes/wrapped.hpp34
-rw-r--r--include/godot_cpp/core/class_db.hpp6
-rw-r--r--include/godot_cpp/godot.hpp1
-rw-r--r--include/godot_cpp/variant/basis.hpp2
-rw-r--r--include/godot_cpp/variant/quaternion.hpp86
-rw-r--r--include/godot_cpp/variant/variant.hpp2
-rw-r--r--src/classes/wrapped.cpp42
-rw-r--r--src/godot.cpp2
-rw-r--r--src/variant/basis.cpp7
-rw-r--r--src/variant/quaternion.cpp68
-rw-r--r--src/variant/variant.cpp11
-rw-r--r--test/CMakeLists.txt1
-rw-r--r--test/SConstruct1
-rw-r--r--test/project/main.gd10
-rw-r--r--test/src/example.cpp13
-rw-r--r--test/src/example.h11
-rw-r--r--test/src/register_types.cpp1
-rw-r--r--tools/godotcpp.py1
24 files changed, 251 insertions, 164 deletions
diff --git a/.github/actions/godot-cache-restore/action.yml b/.github/actions/godot-cache-restore/action.yml
index 5df5776..f10222b 100644
--- a/.github/actions/godot-cache-restore/action.yml
+++ b/.github/actions/godot-cache-restore/action.yml
@@ -3,19 +3,22 @@ description: Restore Godot build cache.
inputs:
cache-name:
description: The cache base name (job name by default).
- default: "${{github.job}}"
+ default: ${{ github.job }}
scons-cache:
- description: The scons cache path.
- default: "${{github.workspace}}/.scons-cache/"
+ description: The SCons cache path.
+ default: ${{ github.workspace }}/.scons-cache/
+
runs:
- using: "composite"
+ using: composite
steps:
- - name: Restore .scons_cache directory
- uses: actions/cache/restore@v3
+ - name: Restore SCons cache directory
+ uses: actions/cache/restore@v4
with:
- path: ${{inputs.scons-cache}}
- key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
+ path: ${{ inputs.scons-cache }}
+ key: ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
+
restore-keys: |
- ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
- ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}
- ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}
+ ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
+ ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}
+ ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-refs/heads/${{ env.GODOT_BASE_BRANCH }}
+ ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}
diff --git a/.github/actions/godot-cache-save/action.yml b/.github/actions/godot-cache-save/action.yml
index b7cbf91..df877ce 100644
--- a/.github/actions/godot-cache-save/action.yml
+++ b/.github/actions/godot-cache-save/action.yml
@@ -3,15 +3,16 @@ description: Save Godot build cache.
inputs:
cache-name:
description: The cache base name (job name by default).
- default: "${{github.job}}"
+ default: ${{ github.job }}
scons-cache:
description: The SCons cache path.
- default: "${{github.workspace}}/.scons-cache/"
+ default: ${{ github.workspace }}/.scons-cache/
+
runs:
- using: "composite"
+ using: composite
steps:
- name: Save SCons cache directory
uses: actions/cache/save@v4
with:
- path: ${{inputs.scons-cache}}
- key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
+ path: ${{ inputs.scons-cache }}
+ key: ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 13b7243..c9f5db7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,14 +1,18 @@
name: Continuous integration
-on: [push, pull_request]
+on:
+ workflow_call:
env:
# Only used for the cache key. Increment version to force clean build.
GODOT_BASE_BRANCH: master
# Used to select the version of Godot to run the tests with.
GODOT_TEST_VERSION: master
+ # Use UTF-8 on Linux.
+ LANG: en_US.UTF-8
+ LC_ALL: en_US.UTF-8
concurrency:
- group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}
+ group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}
cancel-in-progress: true
jobs:
@@ -20,7 +24,7 @@ jobs:
matrix:
include:
- name: 🐧 Linux (GCC)
- os: ubuntu-20.04
+ os: ubuntu-22.04
platform: linux
artifact-name: godot-cpp-linux-glibc2.27-x86_64-release
artifact-path: bin/libgodot-cpp.linux.template_release.x86_64.a
@@ -28,7 +32,7 @@ jobs:
cache-name: linux-x86_64
- name: 🐧 Linux (GCC, Double Precision)
- os: ubuntu-20.04
+ os: ubuntu-22.04
platform: linux
artifact-name: godot-cpp-linux-glibc2.27-x86_64-double-release
artifact-path: bin/libgodot-cpp.linux.template_release.double.x86_64.a
@@ -63,7 +67,7 @@ jobs:
cache-name: macos-universal
- name: 🤖 Android (arm64)
- os: ubuntu-20.04
+ os: ubuntu-22.04
platform: android
artifact-name: godot-cpp-android-arm64-release
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a
@@ -81,7 +85,7 @@ jobs:
cache-name: ios-arm64
- name: 🌐 Web (wasm32)
- os: ubuntu-20.04
+ os: ubuntu-22.04
platform: web
artifact-name: godot-cpp-web-wasm32-release
artifact-path: bin/libgodot-cpp.web.template_release.wasm32.a
@@ -91,7 +95,7 @@ jobs:
env:
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
EM_VERSION: 3.1.39
- EM_CACHE_FOLDER: "emsdk-cache"
+ EM_CACHE_FOLDER: emsdk-cache
steps:
- name: Checkout
@@ -108,24 +112,24 @@ jobs:
- name: Set up Python (for SCons)
uses: actions/setup-python@v5
with:
- python-version: '3.x'
+ python-version: 3.x
- name: Android dependencies
- if: ${{ matrix.platform == 'android' }}
+ if: matrix.platform == 'android'
uses: nttld/setup-ndk@v1
with:
ndk-version: r23c
link-to-sdk: true
- name: Web dependencies
- if: ${{ matrix.platform == 'web' }}
+ if: matrix.platform == 'web'
uses: mymindstorm/setup-emsdk@v14
with:
- version: ${{env.EM_VERSION}}
- actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
+ version: ${{ env.EM_VERSION }}
+ actions-cache-folder: ${{ env.EM_CACHE_FOLDER }}
- 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
with:
version: 12.2.0
@@ -161,7 +165,7 @@ jobs:
- name: Download latest Godot artifacts
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
- if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION == 'master' }}
+ if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
with:
repo: godotengine/godot
branch: master
@@ -175,13 +179,13 @@ jobs:
path: godot-artifacts
- name: Prepare Godot artifacts for testing
- if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION == 'master' }}
+ if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
run: |
chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
echo "GODOT=$(pwd)/godot-artifacts/godot.linuxbsd.editor.x86_64.mono" >> $GITHUB_ENV
- name: Download requested Godot version for testing
- if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION != 'master' }}
+ if: matrix.run-tests && env.GODOT_TEST_VERSION != 'master'
run: |
wget "https://github.com/godotengine/godot-builds/releases/download/${GODOT_TEST_VERSION}/Godot_v${GODOT_TEST_VERSION}_linux.x86_64.zip" -O Godot.zip
unzip -a Godot.zip
@@ -189,7 +193,7 @@ jobs:
echo "GODOT=$(pwd)/Godot_v${GODOT_TEST_VERSION}_linux.x86_64" >> $GITHUB_ENV
- name: Run tests
- if: ${{ matrix.run-tests }}
+ if: matrix.run-tests
run: |
$GODOT --headless --version
cd test
@@ -206,7 +210,7 @@ jobs:
linux-cmake:
name: 🐧 Build (Linux, GCC, CMake)
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -230,7 +234,7 @@ jobs:
linux-cmake-ninja:
name: 🐧 Build (Linux, GCC, CMake Ninja)
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
diff --git a/.github/workflows/runner.yml b/.github/workflows/runner.yml
new file mode 100644
index 0000000..a2e4f91
--- /dev/null
+++ b/.github/workflows/runner.yml
@@ -0,0 +1,21 @@
+name: 🔗 GHA
+on: [push, pull_request, merge_group]
+
+concurrency:
+ group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-runner
+ cancel-in-progress: true
+
+jobs:
+ # First stage: Only static checks, fast and prevent expensive builds from running.
+
+ static-checks:
+ if: '!vars.DISABLE_GODOT_CI'
+ name: 📊 Static Checks
+ uses: ./.github/workflows/static_checks.yml
+
+ # Second stage: Run all the builds and some of the tests.
+
+ ci:
+ name: 🛠️ Continuous Integration
+ needs: static-checks
+ uses: ./.github/workflows/ci.yml
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index 6899248..c8d2713 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -1,8 +1,9 @@
name: 📊 Static Checks
-on: [push, pull_request]
+on:
+ workflow_call:
concurrency:
- group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-static
+ group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-static
cancel-in-progress: true
jobs:
diff --git a/gdextension/gdextension_interface.h b/gdextension/gdextension_interface.h
index 0ffe110..ff89700 100644
--- a/gdextension/gdextension_interface.h
+++ b/gdextension/gdextension_interface.h
@@ -1272,6 +1272,18 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHasMember)(GDExtensionVaria
typedef GDExtensionBool (*GDExtensionInterfaceVariantHasKey)(GDExtensionConstVariantPtr p_self, GDExtensionConstVariantPtr p_key, GDExtensionBool *r_valid);
/**
+ * @name variant_get_object_instance_id
+ * @since 4.4
+ *
+ * Gets the object instance ID from a variant of type GDEXTENSION_VARIANT_TYPE_OBJECT.
+ *
+ * @param p_self A pointer to the Variant.
+ *
+ * @return The instance ID for the contained object.
+ */
+typedef GDObjectInstanceID (*GDExtensionInterfaceVariantGetObjectInstanceId)(GDExtensionConstVariantPtr p_self);
+
+/**
* @name variant_get_type_name
* @since 4.1
*
diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp
index 0ffd783..06b1b67 100644
--- a/include/godot_cpp/classes/wrapped.hpp
+++ b/include/godot_cpp/classes/wrapped.hpp
@@ -40,6 +40,14 @@
#include <godot_cpp/godot.hpp>
+#if defined(MACOS_ENABLED) && defined(HOT_RELOAD_ENABLED)
+#include <mutex>
+#define _GODOT_CPP_AVOID_THREAD_LOCAL
+#define _GODOT_CPP_THREAD_LOCAL
+#else
+#define _GODOT_CPP_THREAD_LOCAL thread_local
+#endif
+
namespace godot {
class ClassDB;
@@ -58,8 +66,16 @@ class Wrapped {
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
friend _ALWAYS_INLINE_ void _pre_initialize();
- thread_local static const StringName *_constructing_extension_class_name;
- thread_local static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks;
+#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
+ static std::recursive_mutex _constructing_mutex;
+#endif
+
+ _GODOT_CPP_THREAD_LOCAL static const StringName *_constructing_extension_class_name;
+ _GODOT_CPP_THREAD_LOCAL static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks;
+
+#ifdef HOT_RELOAD_ENABLED
+ _GODOT_CPP_THREAD_LOCAL static GDExtensionObjectPtr _constructing_recreate_owner;
+#endif
template <typename T>
_ALWAYS_INLINE_ static void _set_construct_info() {
@@ -71,15 +87,6 @@ protected:
virtual bool _is_extension_class() const { return false; }
static const StringName *_get_extension_class_name(); // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
-#ifdef HOT_RELOAD_ENABLED
- struct RecreateInstance {
- GDExtensionClassInstancePtr wrapper;
- GDExtensionObjectPtr owner;
- RecreateInstance *next;
- };
- inline static RecreateInstance *recreate_instance = nullptr;
-#endif
-
void _notification(int p_what) {}
bool _set(const StringName &p_name, const Variant &p_property) { return false; }
bool _get(const StringName &p_name, Variant &r_property) const { return false; }
@@ -126,6 +133,9 @@ public:
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
_ALWAYS_INLINE_ void _pre_initialize() {
+#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
+ Wrapped::_constructing_mutex.lock();
+#endif
Wrapped::_set_construct_info<T>();
}
@@ -250,7 +260,7 @@ public:
} \
\
static const ::godot::StringName &get_class_static() { \
- static const ::godot::StringName string_name = ::godot::StringName(#m_class); \
+ static const ::godot::StringName string_name = ::godot::StringName(U## #m_class); \
return string_name; \
} \
\
diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp
index 988277b..d9dce79 100644
--- a/include/godot_cpp/core/class_db.hpp
+++ b/include/godot_cpp/core/class_db.hpp
@@ -129,9 +129,11 @@ private:
static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) {
if constexpr (!std::is_abstract_v<T>) {
#ifdef HOT_RELOAD_ENABLED
+#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
+ std::lock_guard<std::recursive_mutex> lk(Wrapped::_constructing_mutex);
+#endif
+ Wrapped::_constructing_recreate_owner = obj;
T *new_instance = (T *)memalloc(sizeof(T));
- Wrapped::RecreateInstance recreate_data = { new_instance, obj, Wrapped::recreate_instance };
- Wrapped::recreate_instance = &recreate_data;
memnew_placement(new_instance, T);
return new_instance;
#else
diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp
index f410439..1d36acc 100644
--- a/include/godot_cpp/godot.hpp
+++ b/include/godot_cpp/godot.hpp
@@ -82,6 +82,7 @@ extern "C" GDExtensionInterfaceVariantGetType gdextension_interface_variant_get_
extern "C" GDExtensionInterfaceVariantHasMethod gdextension_interface_variant_has_method;
extern "C" GDExtensionInterfaceVariantHasMember gdextension_interface_variant_has_member;
extern "C" GDExtensionInterfaceVariantHasKey gdextension_interface_variant_has_key;
+extern "C" GDExtensionInterfaceVariantGetObjectInstanceId gdextension_interface_variant_get_object_instance_id;
extern "C" GDExtensionInterfaceVariantGetTypeName gdextension_interface_variant_get_type_name;
extern "C" GDExtensionInterfaceVariantCanConvert gdextension_interface_variant_can_convert;
extern "C" GDExtensionInterfaceVariantCanConvertStrict gdextension_interface_variant_can_convert_strict;
diff --git a/include/godot_cpp/variant/basis.hpp b/include/godot_cpp/variant/basis.hpp
index e740a64..f3ebe15 100644
--- a/include/godot_cpp/variant/basis.hpp
+++ b/include/godot_cpp/variant/basis.hpp
@@ -224,7 +224,7 @@ struct _NO_DISCARD_ Basis {
operator Quaternion() const { return get_quaternion(); }
- static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
+ static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false);
Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }
Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); }
diff --git a/include/godot_cpp/variant/quaternion.hpp b/include/godot_cpp/variant/quaternion.hpp
index 5de91b2..8d0afd7 100644
--- a/include/godot_cpp/variant/quaternion.hpp
+++ b/include/godot_cpp/variant/quaternion.hpp
@@ -31,6 +31,7 @@
#ifndef GODOT_QUATERNION_HPP
#define GODOT_QUATERNION_HPP
+#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/variant/vector3.hpp>
@@ -47,11 +48,11 @@ struct _NO_DISCARD_ Quaternion {
real_t components[4] = { 0, 0, 0, 1.0 };
};
- _FORCE_INLINE_ real_t &operator[](int idx) {
- return components[idx];
+ _FORCE_INLINE_ real_t &operator[](int p_idx) {
+ return components[p_idx];
}
- _FORCE_INLINE_ const real_t &operator[](int idx) const {
- return components[idx];
+ _FORCE_INLINE_ const real_t &operator[](int p_idx) const {
+ return components[p_idx];
}
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Quaternion &p_quaternion) const;
@@ -66,14 +67,13 @@ struct _NO_DISCARD_ Quaternion {
_FORCE_INLINE_ real_t dot(const Quaternion &p_q) const;
real_t angle_to(const Quaternion &p_to) const;
- Vector3 get_euler_xyz() const;
- Vector3 get_euler_yxz() const;
- Vector3 get_euler() const { return get_euler_yxz(); }
+ Vector3 get_euler(EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const;
+ static Quaternion from_euler(const Vector3 &p_euler);
- Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
- Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
- Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const;
- Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
+ Quaternion slerp(const Quaternion &p_to, real_t p_weight) const;
+ Quaternion slerpni(const Quaternion &p_to, real_t p_weight) const;
+ Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight) const;
+ Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight, real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const;
Vector3 get_axis() const;
real_t get_angle() const;
@@ -89,28 +89,28 @@ struct _NO_DISCARD_ Quaternion {
void operator*=(const Quaternion &p_q);
Quaternion operator*(const Quaternion &p_q) const;
- _FORCE_INLINE_ Vector3 xform(const Vector3 &v) const {
+ _FORCE_INLINE_ Vector3 xform(const Vector3 &p_v) const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(!is_normalized(), v, "The quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!is_normalized(), p_v, "The quaternion " + operator String() + " must be normalized.");
#endif
Vector3 u(x, y, z);
- Vector3 uv = u.cross(v);
- return v + ((uv * w) + u.cross(uv)) * ((real_t)2);
+ Vector3 uv = u.cross(p_v);
+ return p_v + ((uv * w) + u.cross(uv)) * ((real_t)2);
}
- _FORCE_INLINE_ Vector3 xform_inv(const Vector3 &v) const {
- return inverse().xform(v);
+ _FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_v) const {
+ return inverse().xform(p_v);
}
_FORCE_INLINE_ void operator+=(const Quaternion &p_q);
_FORCE_INLINE_ void operator-=(const Quaternion &p_q);
- _FORCE_INLINE_ void operator*=(const real_t &s);
- _FORCE_INLINE_ void operator/=(const real_t &s);
- _FORCE_INLINE_ Quaternion operator+(const Quaternion &q2) const;
- _FORCE_INLINE_ Quaternion operator-(const Quaternion &q2) const;
+ _FORCE_INLINE_ void operator*=(real_t p_s);
+ _FORCE_INLINE_ void operator/=(real_t p_s);
+ _FORCE_INLINE_ Quaternion operator+(const Quaternion &p_q2) const;
+ _FORCE_INLINE_ Quaternion operator-(const Quaternion &p_q2) const;
_FORCE_INLINE_ Quaternion operator-() const;
- _FORCE_INLINE_ Quaternion operator*(const real_t &s) const;
- _FORCE_INLINE_ Quaternion operator/(const real_t &s) const;
+ _FORCE_INLINE_ Quaternion operator*(real_t p_s) const;
+ _FORCE_INLINE_ Quaternion operator/(real_t p_s) const;
_FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const;
_FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const;
@@ -128,8 +128,6 @@ struct _NO_DISCARD_ Quaternion {
Quaternion(const Vector3 &p_axis, real_t p_angle);
- Quaternion(const Vector3 &p_euler);
-
Quaternion(const Quaternion &p_q) :
x(p_q.x),
y(p_q.y),
@@ -144,9 +142,9 @@ struct _NO_DISCARD_ Quaternion {
w = p_q.w;
}
- Quaternion(const Vector3 &v0, const Vector3 &v1) { // Shortest arc.
- Vector3 c = v0.cross(v1);
- real_t d = v0.dot(v1);
+ Quaternion(const Vector3 &p_v0, const Vector3 &p_v1) { // Shortest arc.
+ Vector3 c = p_v0.cross(p_v1);
+ real_t d = p_v0.dot(p_v1);
if (d < -1.0f + (real_t)CMP_EPSILON) {
x = 0;
@@ -187,25 +185,25 @@ void Quaternion::operator-=(const Quaternion &p_q) {
w -= p_q.w;
}
-void Quaternion::operator*=(const real_t &s) {
- x *= s;
- y *= s;
- z *= s;
- w *= s;
+void Quaternion::operator*=(real_t p_s) {
+ x *= p_s;
+ y *= p_s;
+ z *= p_s;
+ w *= p_s;
}
-void Quaternion::operator/=(const real_t &s) {
- *this *= 1.0f / s;
+void Quaternion::operator/=(real_t p_s) {
+ *this *= 1.0f / p_s;
}
-Quaternion Quaternion::operator+(const Quaternion &q2) const {
+Quaternion Quaternion::operator+(const Quaternion &p_q2) const {
const Quaternion &q1 = *this;
- return Quaternion(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w);
+ return Quaternion(q1.x + p_q2.x, q1.y + p_q2.y, q1.z + p_q2.z, q1.w + p_q2.w);
}
-Quaternion Quaternion::operator-(const Quaternion &q2) const {
+Quaternion Quaternion::operator-(const Quaternion &p_q2) const {
const Quaternion &q1 = *this;
- return Quaternion(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w);
+ return Quaternion(q1.x - p_q2.x, q1.y - p_q2.y, q1.z - p_q2.z, q1.w - p_q2.w);
}
Quaternion Quaternion::operator-() const {
@@ -213,12 +211,12 @@ Quaternion Quaternion::operator-() const {
return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w);
}
-Quaternion Quaternion::operator*(const real_t &s) const {
- return Quaternion(x * s, y * s, z * s, w * s);
+Quaternion Quaternion::operator*(real_t p_s) const {
+ return Quaternion(x * p_s, y * p_s, z * p_s, w * p_s);
}
-Quaternion Quaternion::operator/(const real_t &s) const {
- return *this * (1.0f / s);
+Quaternion Quaternion::operator/(real_t p_s) const {
+ return *this * (1.0f / p_s);
}
bool Quaternion::operator==(const Quaternion &p_quaternion) const {
@@ -229,7 +227,7 @@ bool Quaternion::operator!=(const Quaternion &p_quaternion) const {
return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w;
}
-_FORCE_INLINE_ Quaternion operator*(const real_t &p_real, const Quaternion &p_quaternion) {
+_FORCE_INLINE_ Quaternion operator*(real_t p_real, const Quaternion &p_quaternion) {
return p_quaternion * p_real;
}
diff --git a/include/godot_cpp/variant/variant.hpp b/include/godot_cpp/variant/variant.hpp
index a868a7c..4c5f206 100644
--- a/include/godot_cpp/variant/variant.hpp
+++ b/include/godot_cpp/variant/variant.hpp
@@ -264,6 +264,8 @@ public:
operator PackedColorArray() const;
operator PackedVector4Array() const;
+ Object *get_validated_object() const;
+
Variant &operator=(const Variant &other);
Variant &operator=(Variant &&other);
bool operator==(const Variant &other) const;
diff --git a/src/classes/wrapped.cpp b/src/classes/wrapped.cpp
index ffca4f9..3eb17ca 100644
--- a/src/classes/wrapped.cpp
+++ b/src/classes/wrapped.cpp
@@ -39,14 +39,27 @@
#include <godot_cpp/core/class_db.hpp>
namespace godot {
-thread_local const StringName *Wrapped::_constructing_extension_class_name = nullptr;
-thread_local const GDExtensionInstanceBindingCallbacks *Wrapped::_constructing_class_binding_callbacks = nullptr;
+
+#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
+std::recursive_mutex Wrapped::_constructing_mutex;
+#endif
+
+_GODOT_CPP_THREAD_LOCAL const StringName *Wrapped::_constructing_extension_class_name = nullptr;
+_GODOT_CPP_THREAD_LOCAL const GDExtensionInstanceBindingCallbacks *Wrapped::_constructing_class_binding_callbacks = nullptr;
+
+#ifdef HOT_RELOAD_ENABLED
+_GODOT_CPP_THREAD_LOCAL GDExtensionObjectPtr Wrapped::_constructing_recreate_owner = nullptr;
+#endif
const StringName *Wrapped::_get_extension_class_name() {
return nullptr;
}
void Wrapped::_postinitialize() {
+#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
+ Wrapped::_constructing_mutex.unlock();
+#endif
+
// Only send NOTIFICATION_POSTINITIALIZE for extension classes.
if (_is_extension_class()) {
_notificationv(Object::NOTIFICATION_POSTINITIALIZE);
@@ -55,25 +68,14 @@ void Wrapped::_postinitialize() {
Wrapped::Wrapped(const StringName p_godot_class) {
#ifdef HOT_RELOAD_ENABLED
- if (unlikely(Wrapped::recreate_instance)) {
- RecreateInstance *recreate_data = Wrapped::recreate_instance;
- RecreateInstance *previous = nullptr;
- while (recreate_data) {
- if (recreate_data->wrapper == this) {
- _owner = recreate_data->owner;
- if (previous) {
- previous->next = recreate_data->next;
- } else {
- Wrapped::recreate_instance = recreate_data->next;
- }
- return;
- }
- previous = recreate_data;
- recreate_data = recreate_data->next;
- }
- }
+ if (unlikely(Wrapped::_constructing_recreate_owner)) {
+ _owner = Wrapped::_constructing_recreate_owner;
+ Wrapped::_constructing_recreate_owner = nullptr;
+ } else
#endif
- _owner = godot::internal::gdextension_interface_classdb_construct_object(reinterpret_cast<GDExtensionConstStringNamePtr>(p_godot_class._native_ptr()));
+ {
+ _owner = godot::internal::gdextension_interface_classdb_construct_object(reinterpret_cast<GDExtensionConstStringNamePtr>(p_godot_class._native_ptr()));
+ }
if (_constructing_extension_class_name) {
godot::internal::gdextension_interface_object_set_instance(_owner, reinterpret_cast<GDExtensionConstStringNamePtr>(_constructing_extension_class_name), this);
diff --git a/src/godot.cpp b/src/godot.cpp
index 68da08f..2a2c889 100644
--- a/src/godot.cpp
+++ b/src/godot.cpp
@@ -88,6 +88,7 @@ GDExtensionInterfaceVariantGetType gdextension_interface_variant_get_type = null
GDExtensionInterfaceVariantHasMethod gdextension_interface_variant_has_method = nullptr;
GDExtensionInterfaceVariantHasMember gdextension_interface_variant_has_member = nullptr;
GDExtensionInterfaceVariantHasKey gdextension_interface_variant_has_key = nullptr;
+GDExtensionInterfaceVariantGetObjectInstanceId gdextension_interface_variant_get_object_instance_id = nullptr;
GDExtensionInterfaceVariantGetTypeName gdextension_interface_variant_get_type_name = nullptr;
GDExtensionInterfaceVariantCanConvert gdextension_interface_variant_can_convert = nullptr;
GDExtensionInterfaceVariantCanConvertStrict gdextension_interface_variant_can_convert_strict = nullptr;
@@ -368,6 +369,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(variant_has_method, GDExtensionInterfaceVariantHasMethod);
LOAD_PROC_ADDRESS(variant_has_member, GDExtensionInterfaceVariantHasMember);
LOAD_PROC_ADDRESS(variant_has_key, GDExtensionInterfaceVariantHasKey);
+ LOAD_PROC_ADDRESS(variant_get_object_instance_id, GDExtensionInterfaceVariantGetObjectInstanceId);
LOAD_PROC_ADDRESS(variant_get_type_name, GDExtensionInterfaceVariantGetTypeName);
LOAD_PROC_ADDRESS(variant_can_convert, GDExtensionInterfaceVariantCanConvert);
LOAD_PROC_ADDRESS(variant_can_convert_strict, GDExtensionInterfaceVariantCanConvertStrict);
diff --git a/src/variant/basis.cpp b/src/variant/basis.cpp
index 200cd06..d8a9919 100644
--- a/src/variant/basis.cpp
+++ b/src/variant/basis.cpp
@@ -1037,12 +1037,15 @@ void Basis::rotate_sh(real_t *p_values) {
p_values[8] = d4 * s_scale_dst4;
}
-Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up) {
+Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up, bool p_use_model_front) {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(p_target.is_zero_approx(), Basis(), "The target vector can't be zero.");
ERR_FAIL_COND_V_MSG(p_up.is_zero_approx(), Basis(), "The up vector can't be zero.");
#endif
- Vector3 v_z = -p_target.normalized();
+ Vector3 v_z = p_target.normalized();
+ if (!p_use_model_front) {
+ v_z = -v_z;
+ }
Vector3 v_x = p_up.cross(v_z);
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(v_x.is_zero_approx(), Basis(), "The target vector and up vector can't be parallel to each other.");
diff --git a/src/variant/quaternion.cpp b/src/variant/quaternion.cpp
index c010850..3dd7af5 100644
--- a/src/variant/quaternion.cpp
+++ b/src/variant/quaternion.cpp
@@ -37,28 +37,15 @@ namespace godot {
real_t Quaternion::angle_to(const Quaternion &p_to) const {
real_t d = dot(p_to);
- return Math::acos(CLAMP(d * d * 2 - 1, -1, 1));
+ // acos does clamping.
+ return Math::acos(d * d * 2 - 1);
}
-// get_euler_xyz returns a vector containing the Euler angles in the format
-// (ax,ay,az), where ax is the angle of rotation around x axis,
-// and similar for other axes.
-// This implementation uses XYZ convention (Z is the first rotation).
-Vector3 Quaternion::get_euler_xyz() const {
- Basis m(*this);
- return m.get_euler(EULER_ORDER_XYZ);
-}
-
-// get_euler_yxz returns a vector containing the Euler angles in the format
-// (ax,ay,az), where ax is the angle of rotation around x axis,
-// and similar for other axes.
-// This implementation uses YXZ convention (Z is the first rotation).
-Vector3 Quaternion::get_euler_yxz() const {
+Vector3 Quaternion::get_euler(EulerOrder p_order) const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion " + operator String() + " must be normalized.");
#endif
- Basis m(*this);
- return m.get_euler(EULER_ORDER_YXZ);
+ return Basis(*this).get_euler(p_order);
}
void Quaternion::operator*=(const Quaternion &p_q) {
@@ -103,7 +90,7 @@ bool Quaternion::is_normalized() const {
Quaternion Quaternion::inverse() const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The quaternion " + operator String() + " must be normalized.");
#endif
return Quaternion(-x, -y, -z, w);
}
@@ -125,10 +112,10 @@ Quaternion Quaternion::exp() const {
return Quaternion(src_v, theta);
}
-Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const {
+Quaternion Quaternion::slerp(const Quaternion &p_to, real_t p_weight) const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
- ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion " + operator String() + " must be normalized.");
+ ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion " + p_to.operator String() + " must be normalized.");
#endif
Quaternion to1;
real_t omega, cosom, sinom, scale0, scale1;
@@ -166,10 +153,10 @@ Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) con
scale0 * w + scale1 * to1.w);
}
-Quaternion Quaternion::slerpni(const Quaternion &p_to, const real_t &p_weight) const {
+Quaternion Quaternion::slerpni(const Quaternion &p_to, real_t p_weight) const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
- ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion " + operator String() + " must be normalized.");
+ ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion " + p_to.operator String() + " must be normalized.");
#endif
const Quaternion &from = *this;
@@ -190,10 +177,10 @@ Quaternion Quaternion::slerpni(const Quaternion &p_to, const real_t &p_weight) c
invFactor * from.w + newFactor * p_to.w);
}
-Quaternion Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const {
+Quaternion Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight) const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
- ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion " + operator String() + " must be normalized.");
+ ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion " + p_b.operator String() + " must be normalized.");
#endif
Quaternion from_q = *this;
Quaternion pre_q = p_pre_a;
@@ -236,15 +223,15 @@ Quaternion Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const
ln.z = Math::cubic_interpolate(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight);
Quaternion q2 = to_q * ln.exp();
- // To cancel error made by Expmap ambiguity, do blends.
+ // To cancel error made by Expmap ambiguity, do blending.
return q1.slerp(q2, p_weight);
}
-Quaternion Quaternion::spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight,
- const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const {
+Quaternion Quaternion::spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight,
+ real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
- ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion " + operator String() + " must be normalized.");
+ ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion " + p_b.operator String() + " must be normalized.");
#endif
Quaternion from_q = *this;
Quaternion pre_q = p_pre_a;
@@ -287,7 +274,7 @@ Quaternion Quaternion::spherical_cubic_interpolate_in_time(const Quaternion &p_b
ln.z = Math::cubic_interpolate_in_time(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
Quaternion q2 = to_q * ln.exp();
- // To cancel error made by Expmap ambiguity, do blends.
+ // To cancel error made by Expmap ambiguity, do blending.
return q1.slerp(q2, p_weight);
}
@@ -309,7 +296,7 @@ real_t Quaternion::get_angle() const {
Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized.");
+ ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 " + p_axis.operator String() + " must be normalized.");
#endif
real_t d = p_axis.length();
if (d == 0) {
@@ -332,7 +319,7 @@ Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) {
// (ax, ay, az), where ax is the angle of rotation around x axis,
// and similar for other axes.
// This implementation uses YXZ convention (Z is the first rotation).
-Quaternion::Quaternion(const Vector3 &p_euler) {
+Quaternion Quaternion::from_euler(const Vector3 &p_euler) {
real_t half_a1 = p_euler.y * 0.5f;
real_t half_a2 = p_euler.x * 0.5f;
real_t half_a3 = p_euler.z * 0.5f;
@@ -348,10 +335,11 @@ Quaternion::Quaternion(const Vector3 &p_euler) {
real_t cos_a3 = Math::cos(half_a3);
real_t sin_a3 = Math::sin(half_a3);
- x = sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3;
- y = sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3;
- z = -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3;
- w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3;
+ return Quaternion(
+ sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3,
+ sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3,
+ -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3,
+ sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3);
}
} // namespace godot
diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp
index 9dcf705..1f57d48 100644
--- a/src/variant/variant.cpp
+++ b/src/variant/variant.cpp
@@ -448,12 +448,7 @@ Variant::operator ObjectID() const {
if (get_type() == Type::INT) {
return ObjectID(operator uint64_t());
} else if (get_type() == Type::OBJECT) {
- Object *obj = operator Object *();
- if (obj != nullptr) {
- return ObjectID(obj->get_instance_id());
- } else {
- return ObjectID();
- }
+ return ObjectID(internal::gdextension_interface_variant_get_object_instance_id(_native_ptr()));
} else {
return ObjectID();
}
@@ -515,6 +510,10 @@ Variant::operator PackedVector4Array() const {
return PackedVector4Array(this);
}
+Object *Variant::get_validated_object() const {
+ return ObjectDB::get_instance(operator ObjectID());
+}
+
Variant &Variant::operator=(const Variant &other) {
clear();
internal::gdextension_interface_variant_new_copy(_native_ptr(), other._native_ptr());
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 42ea6e0..f1c4c0d 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -38,6 +38,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /WX") # /GF /MP
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /DTYPED_METHOD_BIND")
+ set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /utf-8")
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi
diff --git a/test/SConstruct b/test/SConstruct
index 1f1db0f..b949bca 100644
--- a/test/SConstruct
+++ b/test/SConstruct
@@ -42,4 +42,5 @@ else:
source=sources,
)
+env.NoCache(library)
Default(library)
diff --git a/test/project/main.gd b/test/project/main.gd
index 386d188..e5a3b95 100644
--- a/test/project/main.gd
+++ b/test/project/main.gd
@@ -209,6 +209,12 @@ func _ready():
assert_equal(example.test_variant_float_conversion(10.0), 10.0)
assert_equal(example.test_variant_float_conversion(10), 10.0)
+ # Test checking if objects are valid.
+ var object_of_questionable_validity = Object.new()
+ assert_equal(example.test_object_is_valid(object_of_questionable_validity), true)
+ object_of_questionable_validity.free()
+ assert_equal(example.test_object_is_valid(object_of_questionable_validity), false)
+
# Test that ptrcalls from GDExtension to the engine are correctly encoding Object and RefCounted.
var new_node = Node.new()
example.test_add_child(new_node)
@@ -279,6 +285,10 @@ func _ready():
assert_equal(library_path, ProjectSettings.globalize_path(library_path))
assert_equal(FileAccess.file_exists(library_path), true)
+ # Test a class with a unicode name.
+ var przykład = ExamplePrzykład.new()
+ assert_equal(przykład.get_the_word(), "słowo to przykład")
+
exit_with_status()
func _on_Example_custom_signal(signal_name, value):
diff --git a/test/src/example.cpp b/test/src/example.cpp
index 692d004..22739b2 100644
--- a/test/src/example.cpp
+++ b/test/src/example.cpp
@@ -217,6 +217,7 @@ void Example::_bind_methods() {
ClassDB::bind_method(D_METHOD("test_variant_vector2i_conversion", "variant"), &Example::test_variant_vector2i_conversion);
ClassDB::bind_method(D_METHOD("test_variant_int_conversion", "variant"), &Example::test_variant_int_conversion);
ClassDB::bind_method(D_METHOD("test_variant_float_conversion", "variant"), &Example::test_variant_float_conversion);
+ ClassDB::bind_method(D_METHOD("test_object_is_valid", "variant"), &Example::test_object_is_valid);
ClassDB::bind_method(D_METHOD("test_add_child", "node"), &Example::test_add_child);
ClassDB::bind_method(D_METHOD("test_set_tileset", "tilemap", "tileset"), &Example::test_set_tileset);
@@ -598,6 +599,10 @@ float Example::test_variant_float_conversion(const Variant &p_variant) const {
return p_variant;
}
+bool Example::test_object_is_valid(const Variant &p_variant) const {
+ return static_cast<bool>(p_variant.get_validated_object());
+}
+
void Example::test_add_child(Node *p_node) {
add_child(p_node);
}
@@ -755,3 +760,11 @@ ExampleRuntime::ExampleRuntime() {
ExampleRuntime::~ExampleRuntime() {
}
+
+void ExamplePrzykład::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_the_word"), &ExamplePrzykład::get_the_word);
+}
+
+String ExamplePrzykład::get_the_word() const {
+ return U"słowo to przykład";
+}
diff --git a/test/src/example.h b/test/src/example.h
index a28deff..a7ae54c 100644
--- a/test/src/example.h
+++ b/test/src/example.h
@@ -147,6 +147,7 @@ public:
Vector2i test_variant_vector2i_conversion(const Variant &p_variant) const;
int test_variant_int_conversion(const Variant &p_variant) const;
float test_variant_float_conversion(const Variant &p_variant) const;
+ bool test_object_is_valid(const Variant &p_variant) const;
void test_add_child(Node *p_node);
void test_set_tileset(TileMap *p_tilemap, const Ref<TileSet> &p_tileset) const;
@@ -275,4 +276,14 @@ public:
~ExampleRuntime();
};
+class ExamplePrzykład : public RefCounted {
+ GDCLASS(ExamplePrzykład, RefCounted);
+
+protected:
+ static void _bind_methods();
+
+public:
+ String get_the_word() const;
+};
+
#endif // EXAMPLE_CLASS_H
diff --git a/test/src/register_types.cpp b/test/src/register_types.cpp
index 7cfe689..d9290c8 100644
--- a/test/src/register_types.cpp
+++ b/test/src/register_types.cpp
@@ -30,6 +30,7 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(ExampleBase);
GDREGISTER_CLASS(ExampleChild);
GDREGISTER_RUNTIME_CLASS(ExampleRuntime);
+ GDREGISTER_CLASS(ExamplePrzykład);
}
void uninitialize_example_module(ModuleInitializationLevel p_level) {
diff --git a/tools/godotcpp.py b/tools/godotcpp.py
index 9ceac02..b2a63dc 100644
--- a/tools/godotcpp.py
+++ b/tools/godotcpp.py
@@ -552,6 +552,7 @@ def _godot_cpp(env):
if env["build_library"]:
library = env.StaticLibrary(target=env.File("bin/%s" % library_name), source=sources)
+ env.NoCache(library)
default_args = [library]
# Add compiledb if the option is set