diff --git a/.github/actions/godot-cache/action.yml b/.github/actions/godot-cache-restore/action.yml similarity index 77% rename from .github/actions/godot-cache/action.yml rename to .github/actions/godot-cache-restore/action.yml index 2d7afc85..5df57765 100644 --- a/.github/actions/godot-cache/action.yml +++ b/.github/actions/godot-cache-restore/action.yml @@ -1,5 +1,5 @@ -name: Setup Godot build cache -description: Setup Godot build cache. +name: Restore Godot build cache +description: Restore Godot build cache. inputs: cache-name: description: The cache base name (job name by default). @@ -10,9 +10,8 @@ inputs: runs: using: "composite" steps: - # Upload cache on completion and check it out now - - name: Load .scons_cache directory - uses: actions/cache@v3 + - name: Restore .scons_cache directory + uses: actions/cache/restore@v3 with: path: ${{inputs.scons-cache}} key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}} diff --git a/.github/actions/godot-cache-save/action.yml b/.github/actions/godot-cache-save/action.yml new file mode 100644 index 00000000..b7cbf91f --- /dev/null +++ b/.github/actions/godot-cache-save/action.yml @@ -0,0 +1,17 @@ +name: Save Godot build cache +description: Save Godot build cache. +inputs: + cache-name: + description: The cache base name (job name by default). + default: "${{github.job}}" + scons-cache: + description: The SCons cache path. + default: "${{github.workspace}}/.scons-cache/" +runs: + 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}} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30ae04f3..de82d11b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -99,8 +99,8 @@ jobs: with: submodules: recursive - - name: Setup Godot build cache - uses: ./.github/actions/godot-cache + - name: Restore Godot build cache + uses: ./.github/actions/godot-cache-restore with: cache-name: ${{ matrix.cache-name }} continue-on-error: true @@ -153,6 +153,12 @@ jobs: cd test scons platform=${{ matrix.platform }} verbose=yes target=template_release ${{ matrix.flags }} + - name: Save Godot build cache + uses: ./.github/actions/godot-cache-save + with: + cache-name: ${{ matrix.cache-name }} + continue-on-error: true + - name: Download latest Godot artifacts uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9 if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION == 'master' }} diff --git a/binding_generator.py b/binding_generator.py index 7911a7eb..4825765f 100644 --- a/binding_generator.py +++ b/binding_generator.py @@ -671,14 +671,14 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl if "operators" in builtin_api: for operator in builtin_api["operators"]: - if operator["name"] not in ["in", "xor"]: + if is_valid_cpp_operator(operator["name"]): if "right_type" in operator: result.append( - f'\t{correct_type(operator["return_type"])} operator{operator["name"]}({type_for_parameter(operator["right_type"])}p_other) const;' + f'\t{correct_type(operator["return_type"])} operator{get_operator_cpp_name(operator["name"])}({type_for_parameter(operator["right_type"])}p_other) const;' ) else: result.append( - f'\t{correct_type(operator["return_type"])} operator{operator["name"].replace("unary", "")}() const;' + f'\t{correct_type(operator["return_type"])} operator{get_operator_cpp_name(operator["name"])}() const;' ) # Copy assignment. @@ -1110,10 +1110,10 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl if "operators" in builtin_api: for operator in builtin_api["operators"]: - if operator["name"] not in ["in", "xor"]: + if is_valid_cpp_operator(operator["name"]): if "right_type" in operator: result.append( - f'{correct_type(operator["return_type"])} {class_name}::operator{operator["name"]}({type_for_parameter(operator["right_type"])}p_other) const {{' + f'{correct_type(operator["return_type"])} {class_name}::operator{get_operator_cpp_name(operator["name"])}({type_for_parameter(operator["right_type"])}p_other) const {{' ) (encode, arg_name) = get_encoded_arg("other", operator["right_type"], None) result += encode @@ -1123,7 +1123,7 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl result.append("}") else: result.append( - f'{correct_type(operator["return_type"])} {class_name}::operator{operator["name"].replace("unary", "")}() const {{' + f'{correct_type(operator["return_type"])} {class_name}::operator{get_operator_cpp_name(operator["name"])}() const {{' ) result.append( f'\treturn internal::_call_builtin_operator_ptr<{get_gdextension_type(correct_type(operator["return_type"]))}>(_method_bindings.operator_{get_operator_id_name(operator["name"])}, (GDExtensionConstTypePtr)&opaque, (GDExtensionConstTypePtr)nullptr);' @@ -2451,8 +2451,6 @@ def correct_type(type_name, meta=None, use_alias=True): if meta is not None: if "int" in meta: return f"{meta}_t" - elif meta in type_conversion: - return type_conversion[type_name] else: return meta if type_name in type_conversion: @@ -2564,6 +2562,38 @@ def get_operator_id_name(op): return op_id_map[op] +def get_operator_cpp_name(op): + op_cpp_map = { + "==": "==", + "!=": "!=", + "<": "<", + "<=": "<=", + ">": ">", + ">=": ">=", + "+": "+", + "-": "-", + "*": "*", + "/": "/", + "unary-": "-", + "unary+": "+", + "%": "%", + "<<": "<<", + ">>": ">>", + "&": "&", + "|": "|", + "^": "^", + "~": "~", + "and": "&&", + "or": "||", + "not": "!", + } + return op_cpp_map[op] + + +def is_valid_cpp_operator(op): + return op not in ["**", "xor", "in"] + + def get_default_value_for_type(type_name): if type_name == "int": return "0" diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index d325fed9..33efc821 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -120,7 +120,7 @@ struct EngineClassRegistration { #define GDCLASS(m_class, m_inherits) \ private: \ - void operator=(const m_class &p_rval) {} \ + void operator=(const m_class & /*p_rval*/) {} \ friend class ::godot::ClassDB; \ \ protected: \ @@ -212,23 +212,27 @@ public: } \ \ static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { \ - if (p_instance && m_class::_get_set()) { \ + if (p_instance) { \ + if (m_inherits::set_bind(p_instance, p_name, p_value)) { \ + return true; \ + } \ if (m_class::_get_set() != m_inherits::_get_set()) { \ m_class *cls = reinterpret_cast(p_instance); \ return cls->_set(*reinterpret_cast(p_name), *reinterpret_cast(p_value)); \ } \ - return m_inherits::set_bind(p_instance, p_name, p_value); \ } \ return false; \ } \ \ static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { \ - if (p_instance && m_class::_get_get()) { \ + if (p_instance) { \ + if (m_inherits::get_bind(p_instance, p_name, r_ret)) { \ + return true; \ + } \ if (m_class::_get_get() != m_inherits::_get_get()) { \ m_class *cls = reinterpret_cast(p_instance); \ return cls->_get(*reinterpret_cast(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \ } \ - return m_inherits::get_bind(p_instance, p_name, r_ret); \ } \ return false; \ } \ @@ -304,7 +308,7 @@ public: } \ } \ \ - static void free(void *data, GDExtensionClassInstancePtr ptr) { \ + static void free(void * /*data*/, GDExtensionClassInstancePtr ptr) { \ if (ptr) { \ m_class *cls = reinterpret_cast(ptr); \ cls->~m_class(); \ @@ -312,14 +316,14 @@ public: } \ } \ \ - static void *_gde_binding_create_callback(void *p_token, void *p_instance) { \ + static void *_gde_binding_create_callback(void * /*p_token*/, void * /*p_instance*/) { \ return nullptr; \ } \ \ - static void _gde_binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \ + static void _gde_binding_free_callback(void * /*p_token*/, void * /*p_instance*/, void * /*p_binding*/) { \ } \ \ - static GDExtensionBool _gde_binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \ + static GDExtensionBool _gde_binding_reference_callback(void * /*p_token*/, void * /*p_instance*/, GDExtensionBool /*p_reference*/) { \ return true; \ } \ \ diff --git a/include/godot_cpp/core/type_info.hpp b/include/godot_cpp/core/type_info.hpp index e1f2b205..71d78283 100644 --- a/include/godot_cpp/core/type_info.hpp +++ b/include/godot_cpp/core/type_info.hpp @@ -393,17 +393,15 @@ MAKE_TYPED_ARRAY_INFO(Callable, Variant::CALLABLE) MAKE_TYPED_ARRAY_INFO(Signal, Variant::SIGNAL) MAKE_TYPED_ARRAY_INFO(Dictionary, Variant::DICTIONARY) MAKE_TYPED_ARRAY_INFO(Array, Variant::ARRAY) -/* -MAKE_TYPED_ARRAY_INFO(Vector, Variant::PACKED_BYTE_ARRAY) -MAKE_TYPED_ARRAY_INFO(Vector, Variant::PACKED_INT32_ARRAY) -MAKE_TYPED_ARRAY_INFO(Vector, Variant::PACKED_INT64_ARRAY) -MAKE_TYPED_ARRAY_INFO(Vector, Variant::PACKED_FLOAT32_ARRAY) -MAKE_TYPED_ARRAY_INFO(Vector, Variant::PACKED_FLOAT64_ARRAY) -MAKE_TYPED_ARRAY_INFO(Vector, Variant::PACKED_STRING_ARRAY) -MAKE_TYPED_ARRAY_INFO(Vector, Variant::PACKED_VECTOR2_ARRAY) -MAKE_TYPED_ARRAY_INFO(Vector, Variant::PACKED_VECTOR3_ARRAY) -MAKE_TYPED_ARRAY_INFO(Vector, Variant::PACKED_COLOR_ARRAY) -*/ +MAKE_TYPED_ARRAY_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY) +MAKE_TYPED_ARRAY_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY) +MAKE_TYPED_ARRAY_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY) +MAKE_TYPED_ARRAY_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY) +MAKE_TYPED_ARRAY_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY) +MAKE_TYPED_ARRAY_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY) +MAKE_TYPED_ARRAY_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) +MAKE_TYPED_ARRAY_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) +MAKE_TYPED_ARRAY_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY) #define CLASS_INFO(m_type) (GetTypeInfo::get_class_info()) diff --git a/include/godot_cpp/templates/safe_refcount.hpp b/include/godot_cpp/templates/safe_refcount.hpp index 12e6840a..98cb04b2 100644 --- a/include/godot_cpp/templates/safe_refcount.hpp +++ b/include/godot_cpp/templates/safe_refcount.hpp @@ -132,7 +132,7 @@ public: } } - _ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast(0)) { + _ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast(0)) { set(p_value); } }; diff --git a/test/project/example.gdextension b/test/project/example.gdextension index 30279e6d..93872c5a 100644 --- a/test/project/example.gdextension +++ b/test/project/example.gdextension @@ -21,5 +21,17 @@ android.debug.x86_64 = "res://bin/libgdexample.android.template_debug.x86_64.so" android.release.x86_64 = "res://bin/libgdexample.android.template_release.x86_64.so" android.debug.arm64 = "res://bin/libgdexample.android.template_debug.arm64.so" android.release.arm64 = "res://bin/libgdexample.android.template_release.arm64.so" -web.debug.wasm32 = "res://bin/libgdexample.web.template_debug.wasm32.wasm" -web.release.wasm32 = "res://bin/libgdexample.web.template_release.wasm32.wasm" +ios.debug = "res://bin/libgdexample.ios.template_debug.xcframework" +ios.release = "res://bin/libgdexample.ios.template_release.xcframework" +web.debug.threads.wasm32 = "res://bin/libgdexample.web.template_debug.wasm32.wasm" +web.release.threads.wasm32 = "res://bin/libgdexample.web.template_release.wasm32.wasm" +web.debug.wasm32 = "res://bin/libgdexample.web.template_debug.wasm32.nothreads.wasm" +web.release.wasm32 = "res://bin/libgdexample.web.template_release.wasm32.nothreads.wasm" + +[dependencies] +ios.debug = { + "res://bin/libgodot-cpp.ios.template_debug.xcframework": "" +} +ios.release = { + "res://bin/libgodot-cpp.ios.template_release.xcframework": "" +} diff --git a/test/src/example.cpp b/test/src/example.cpp index eded7ea7..3c3d7476 100644 --- a/test/src/example.cpp +++ b/test/src/example.cpp @@ -147,6 +147,7 @@ void Example::_bind_methods() { ClassDB::bind_method(D_METHOD("test_string_ops"), &Example::test_string_ops); ClassDB::bind_method(D_METHOD("test_str_utility"), &Example::test_str_utility); ClassDB::bind_method(D_METHOD("test_string_is_forty_two"), &Example::test_string_is_forty_two); + ClassDB::bind_method(D_METHOD("test_typed_array_of_packed"), &Example::test_typed_array_of_packed); ClassDB::bind_method(D_METHOD("test_vector_ops"), &Example::test_vector_ops); ClassDB::bind_method(D_METHOD("test_vector_init_list"), &Example::test_vector_init_list); @@ -327,6 +328,19 @@ bool Example::test_string_is_forty_two(const String &p_string) const { return strcmp(p_string.utf8().ptr(), "forty two") == 0; } +TypedArray Example::test_typed_array_of_packed() const { + TypedArray arr; + PackedInt32Array packed_arr1; + packed_arr1.push_back(1); + packed_arr1.push_back(2); + arr.push_back(packed_arr1); + PackedInt32Array packed_arr2; + packed_arr2.push_back(3); + packed_arr2.push_back(4); + arr.push_back(packed_arr2); + return arr; +} + int Example::test_vector_ops() const { PackedInt32Array arr; arr.push_back(10); diff --git a/test/src/example.h b/test/src/example.h index 4983caab..12fbe093 100644 --- a/test/src/example.h +++ b/test/src/example.h @@ -126,6 +126,7 @@ public: String test_string_ops() const; String test_str_utility() const; bool test_string_is_forty_two(const String &p_str) const; + TypedArray test_typed_array_of_packed() const; int test_vector_ops() const; int test_vector_init_list() const; diff --git a/tools/godotcpp.py b/tools/godotcpp.py index cc2b02fe..e16b17dc 100644 --- a/tools/godotcpp.py +++ b/tools/godotcpp.py @@ -267,6 +267,8 @@ def options(opts, env): ) ) + opts.Add(BoolVariable(key="threads", help="Enable threading support", default=env.get("threads", True))) + # compiledb opts.Add( BoolVariable( @@ -396,6 +398,9 @@ def generate(env): tool.generate(env) + if env["threads"]: + env.Append(CPPDEFINES=["THREADS_ENABLED"]) + if env.editor_build: env.Append(CPPDEFINES=["TOOLS_ENABLED"]) @@ -436,6 +441,8 @@ def generate(env): suffix += "." + env["arch"] if env["ios_simulator"]: suffix += ".simulator" + if not env["threads"]: + suffix += ".nothreads" env["suffix"] = suffix # Exposed when included from another project env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"] diff --git a/tools/ios.py b/tools/ios.py index d84aecd1..3f92bda4 100644 --- a/tools/ios.py +++ b/tools/ios.py @@ -1,3 +1,4 @@ +import codecs import os import subprocess import sys @@ -5,17 +6,6 @@ import sys import common_compiler_flags from SCons.Variables import BoolVariable -if sys.version_info < (3,): - - def decode_utf8(x): - return x - -else: - import codecs - - def decode_utf8(x): - return codecs.utf_8_decode(x)[0] - def has_ios_osxcross(): return "OSXCROSS_IOS" in os.environ @@ -53,9 +43,9 @@ def generate(env): if sys.platform == "darwin": if env["IOS_SDK_PATH"] == "": try: - env["IOS_SDK_PATH"] = decode_utf8( + env["IOS_SDK_PATH"] = codecs.utf_8_decode( subprocess.check_output(["xcrun", "--sdk", sdk_name, "--show-sdk-path"]).strip() - ) + )[0] except (subprocess.CalledProcessError, OSError): raise ValueError( "Failed to find SDK path while running xcrun --sdk {} --show-sdk-path.".format(sdk_name) diff --git a/tools/web.py b/tools/web.py index 79b4b24c..c8f07c55 100644 --- a/tools/web.py +++ b/tools/web.py @@ -34,12 +34,17 @@ def generate(env): env["SHLIBSUFFIX"] = ".wasm" # Thread support (via SharedArrayBuffer). - env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"]) - env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"]) + if env["threads"]: + env.Append(CCFLAGS=["-sUSE_PTHREADS=1"]) + env.Append(LINKFLAGS=["-sUSE_PTHREADS=1"]) # Build as side module (shared library). - env.Append(CPPFLAGS=["-s", "SIDE_MODULE=1"]) - env.Append(LINKFLAGS=["-s", "SIDE_MODULE=1"]) + env.Append(CCFLAGS=["-sSIDE_MODULE=1"]) + env.Append(LINKFLAGS=["-sSIDE_MODULE=1"]) + + # Force wasm longjmp mode. + env.Append(CCFLAGS=["-sSUPPORT_LONGJMP='wasm'"]) + env.Append(LINKFLAGS=["-sSUPPORT_LONGJMP='wasm'"]) env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED"])