diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml index 04db037a864..a9b623edf0d 100644 --- a/.github/workflows/android_builds.yml +++ b/.github/workflows/android_builds.yml @@ -1,5 +1,6 @@ name: 🤖 Android Builds -on: [push, pull_request] +on: + workflow_call: # Global Settings env: @@ -17,7 +18,7 @@ jobs: name: Template (target=release, tools=no) steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Azure repositories are not reliable, we need to prevent azure giving us packages. - name: Make apt sources.list use the default Ubuntu repositories diff --git a/.github/workflows/ios_builds.yml b/.github/workflows/ios_builds.yml index bc98f7b1ac2..8c65167961c 100644 --- a/.github/workflows/ios_builds.yml +++ b/.github/workflows/ios_builds.yml @@ -1,5 +1,6 @@ name: 🍏 iOS Builds -on: [push, pull_request] +on: + workflow_call: # Global Settings env: @@ -17,7 +18,7 @@ jobs: name: Template (target=release, tools=no) steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Godot build cache uses: ./.github/actions/godot-cache diff --git a/.github/workflows/javascript_builds.yml b/.github/workflows/javascript_builds.yml index cdb8255a143..60ca56777be 100644 --- a/.github/workflows/javascript_builds.yml +++ b/.github/workflows/javascript_builds.yml @@ -1,5 +1,6 @@ name: 🌐 JavaScript Builds -on: [push, pull_request] +on: + workflow_call: # Global Settings env: @@ -19,7 +20,7 @@ jobs: name: Template (target=release, tools=no) steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Emscripten latest uses: mymindstorm/setup-emsdk@v12 diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index 97e6dc0a3ad..6bcb2ee7a6f 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -1,5 +1,6 @@ name: 🐧 Linux Builds -on: [push, pull_request] +on: + workflow_call: # Global Settings env: @@ -48,7 +49,7 @@ jobs: artifact: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Linux dependencies shell: bash diff --git a/.github/workflows/macos_builds.yml b/.github/workflows/macos_builds.yml index a65aafa0d9d..1790284c305 100644 --- a/.github/workflows/macos_builds.yml +++ b/.github/workflows/macos_builds.yml @@ -1,5 +1,6 @@ name: 🍎 macOS Builds -on: [push, pull_request] +on: + workflow_call: # Global Settings env: @@ -31,7 +32,7 @@ jobs: tools: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Godot build cache uses: ./.github/actions/godot-cache diff --git a/.github/workflows/runner.yml b/.github/workflows/runner.yml new file mode 100644 index 00000000000..1981da5b8f0 --- /dev/null +++ b/.github/workflows/runner.yml @@ -0,0 +1,46 @@ +name: 🔗 GHA +on: [push, pull_request] + +concurrency: + group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-runner + cancel-in-progress: true + +jobs: + static-checks: + name: 📊 Static + uses: ./.github/workflows/static_checks.yml + + android-build: + name: 🤖 Android + needs: static-checks + uses: ./.github/workflows/android_builds.yml + + ios-build: + name: 🍏 iOS + needs: static-checks + uses: ./.github/workflows/ios_builds.yml + + javascript-build: + name: 🌐 JavaScript + needs: static-checks + uses: ./.github/workflows/javascript_builds.yml + + linux-build: + name: 🐧 Linux + needs: static-checks + uses: ./.github/workflows/linux_builds.yml + + macos-build: + name: 🍎 macOS + needs: static-checks + uses: ./.github/workflows/macos_builds.yml + + server-build: + name: ☁ Server + needs: static-checks + uses: ./.github/workflows/server_builds.yml + + windows-build: + name: 🏁 Windows + needs: static-checks + uses: ./.github/workflows/windows_builds.yml diff --git a/.github/workflows/server_builds.yml b/.github/workflows/server_builds.yml index 5e42dc43432..9f34041ce23 100644 --- a/.github/workflows/server_builds.yml +++ b/.github/workflows/server_builds.yml @@ -1,5 +1,6 @@ name: ☁ Server Builds -on: [push, pull_request] +on: + workflow_call: # Global Settings env: @@ -30,7 +31,7 @@ jobs: tools: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Linux dependencies shell: bash diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index 79c082666a6..082ebdebfa5 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -1,5 +1,6 @@ name: 📊 Static Checks -on: [push, pull_request] +on: + workflow_call: concurrency: group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-static @@ -11,7 +12,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Azure repositories are not reliable, we need to prevent Azure giving us packages. - name: Make apt sources.list use the default Ubuntu repositories diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml index 6d5c97a6ebf..99b02a05261 100644 --- a/.github/workflows/windows_builds.yml +++ b/.github/workflows/windows_builds.yml @@ -1,5 +1,6 @@ name: 🏁 Windows Builds -on: [push, pull_request] +on: + workflow_call: # Global Settings # SCONS_CACHE for windows must be set in the build environment @@ -34,7 +35,7 @@ jobs: tools: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Godot build cache uses: ./.github/actions/godot-cache diff --git a/.gitignore b/.gitignore index 518c3419125..619e6e04660 100644 --- a/.gitignore +++ b/.gitignore @@ -131,23 +131,9 @@ cppcheck-cppcheck-build-dir/ *.pydevproject *.launch -# Gcov and Lcov code coverage -*.gcno +# GCOV code coverage *.gcda -*.gcov.html -*.func.html -*.func-sort-c.html -*index-sort-f.html -*index-sort-l.html -*index.html -godot.info -amber.png -emerald.png -glass.png -ruby.png -snow.png -updown.png -gcov.css +*.gcno # Geany *.geany @@ -246,9 +232,6 @@ xcuserdata/ x64/ x86/ -# Do not ignore x86 folders anywhere under thirdparty libraries -!thirdparty/**/x86/ - [Ww][Ii][Nn]32/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ @@ -258,6 +241,12 @@ bld/ [Ll]og/ [Ll]ogs/ +# Do not ignore arch-specific folders anywhere under thirdparty libraries +!thirdparty/**/x64/ +!thirdparty/**/x86/ +!thirdparty/**/arm/ +!thirdparty/**/arm64/ + # Visual Studio 2015/2017 cache/options directory .vs/ diff --git a/core/class_db.h b/core/class_db.h index 0fcef8b8d41..82bcb8da25d 100644 --- a/core/class_db.h +++ b/core/class_db.h @@ -170,6 +170,7 @@ public: template static void register_class() { GLOBAL_LOCK_FUNCTION; + static_assert(TypesAreSame::value, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_COND(!t); @@ -182,6 +183,7 @@ public: template static void register_virtual_class() { GLOBAL_LOCK_FUNCTION; + static_assert(TypesAreSame::value, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_COND(!t); @@ -198,6 +200,7 @@ public: template static void register_custom_instance_class() { GLOBAL_LOCK_FUNCTION; + static_assert(TypesAreSame::value, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_COND(!t); diff --git a/core/image.cpp b/core/image.cpp index e79389f2ce4..42d2df78ad2 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -2477,6 +2477,9 @@ void Image::_repeat_pixel_over_subsequent_memory(uint8_t *p_pixel, int p_pixel_s } void Image::fill(const Color &p_color) { + if (data.size() == 0) { + return; + } ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill in compressed or custom image formats."); lock(); @@ -2495,6 +2498,9 @@ void Image::fill(const Color &p_color) { } void Image::fill_rect(const Rect2 &p_rect, const Color &p_color) { + if (data.size() == 0) { + return; + } ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats."); Rect2i r = Rect2i(0, 0, width, height).clip(p_rect.abs()); diff --git a/core/object.h b/core/object.h index a31f826ec05..58b1c08e76c 100644 --- a/core/object.h +++ b/core/object.h @@ -267,6 +267,7 @@ private: friend class ClassDB; \ \ public: \ + typedef m_class self_type; \ virtual String get_class() const { \ return String(#m_class); \ } \ @@ -405,6 +406,8 @@ class ObjectRC; class Object { public: + typedef Object self_type; + enum ConnectFlags { CONNECT_DEFERRED = 1, diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp index bb4f7c47cb1..5f617b6866a 100644 --- a/core/variant_parser.cpp +++ b/core/variant_parser.cpp @@ -1532,7 +1532,7 @@ static String rtos_fix(double p_value) { } } -Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud) { +Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count) { switch (p_variant.get_type()) { case Variant::NIL: { p_store_string_func(p_store_string_ud, "null"); @@ -1649,6 +1649,13 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::OBJECT: { + if (unlikely(p_recursion_count > MAX_RECURSION)) { + ERR_PRINT("Max recursion reached"); + p_store_string_func(p_store_string_ud, "null"); + return OK; + } + p_recursion_count++; + Object *obj = p_variant; if (!obj) { @@ -1698,7 +1705,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, "\"" + E->get().name + "\":"); - write(obj->get(E->get().name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); + write(obj->get(E->get().name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count); } } @@ -1707,6 +1714,13 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::DICTIONARY: { + if (unlikely(p_recursion_count > MAX_RECURSION)) { + ERR_PRINT("Max recursion reached"); + p_store_string_func(p_store_string_ud, "{}"); + return OK; + } + p_recursion_count++; + Dictionary dict = p_variant; List keys; @@ -1719,9 +1733,9 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (!_check_type(dict[E->get()])) continue; */ - write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); + write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count); p_store_string_func(p_store_string_ud, ": "); - write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); + write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count); if (E->next()) { p_store_string_func(p_store_string_ud, ",\n"); } else { @@ -1733,6 +1747,13 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::ARRAY: { + if (unlikely(p_recursion_count > MAX_RECURSION)) { + ERR_PRINT("Max recursion reached"); + p_store_string_func(p_store_string_ud, "[]"); + return OK; + } + p_recursion_count++; + p_store_string_func(p_store_string_ud, "[ "); Array array = p_variant; int len = array.size(); @@ -1740,7 +1761,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i > 0) { p_store_string_func(p_store_string_ud, ", "); } - write(array[i], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); + write(array[i], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count); } p_store_string_func(p_store_string_ud, " ]"); @@ -1871,6 +1892,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, " )"); } break; + default: { } } diff --git a/core/variant_parser.h b/core/variant_parser.h index f3e4357de99..6c1a7518c70 100644 --- a/core/variant_parser.h +++ b/core/variant_parser.h @@ -141,7 +141,7 @@ public: typedef Error (*StoreStringFunc)(void *ud, const String &p_string); typedef String (*EncodeResourceFunc)(void *ud, const RES &p_resource); - static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud); + static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count = 0); static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr); }; diff --git a/methods.py b/methods.py index d6dacef4cef..a5a4a2fdda5 100644 --- a/methods.py +++ b/methods.py @@ -787,6 +787,9 @@ def generate_vs_project(env, num_jobs): if env["custom_modules"]: common_build_postfix.append("custom_modules=%s" % env["custom_modules"]) + if env["incremental_link"]: + common_build_postfix.append("incremental_link=yes") + result = " ^& ".join(common_build_prefix + [" ".join([commands] + common_build_postfix)]) return result diff --git a/platform/android/java/editor/src/.gitignore b/platform/android/java/editor/src/.gitignore new file mode 100644 index 00000000000..c081ec3425d --- /dev/null +++ b/platform/android/java/editor/src/.gitignore @@ -0,0 +1 @@ +!/debug diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index a88094f9192..8a61813b5a3 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -108,6 +108,12 @@ def configure(env): env.Append(CCFLAGS=["-flto=full"]) env.Append(LINKFLAGS=["-flto=full"]) + if env["use_thinlto"] or env["use_lto"]: + # Workaround https://github.com/emscripten-core/emscripten/issues/19781. + cc_semver = tuple(get_compiler_version(env)) + if cc_semver >= (3, 1, 42): + env.Append(LINKFLAGS=["-Wl,-u,scalbnf"]) + # Sanitizers if env["use_ubsan"]: env.Append(CCFLAGS=["-fsanitize=undefined"]) diff --git a/platform/javascript/js/libs/library_godot_javascript_singleton.js b/platform/javascript/js/libs/library_godot_javascript_singleton.js index ec58ce48e6e..e6ebef0262f 100644 --- a/platform/javascript/js/libs/library_godot_javascript_singleton.js +++ b/platform/javascript/js/libs/library_godot_javascript_singleton.js @@ -205,7 +205,9 @@ const GodotJSWrapper = { return; } const args = Array.from(arguments); - func(p_ref, GodotJSWrapper.get_proxied(args), args.length); + const argsProxy = new GodotJSWrapper.MyProxy(args); + func(p_ref, argsProxy.get_id(), args.length); + argsProxy.unref(); }; id = GodotJSWrapper.get_proxied(cb); return id; diff --git a/platform/windows/detect.py b/platform/windows/detect.py index a54f730679b..df3a5ffd50f 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -73,6 +73,7 @@ def get_opts(): BoolVariable("use_thinlto", "Use ThinLTO", False), BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True), BoolVariable("use_asan", "Use address sanitizer (ASAN)", False), + BoolVariable("incremental_link", "Use MSVC incremental linking. May increase or decrease build times.", False), ] @@ -216,8 +217,9 @@ def configure_msvc(env, manual_msvc_config): else: env.AppendUnique(CCFLAGS=["/MD"]) - # MSVC incremental linking is broken and _increases_ link time (GH-77968). - env.Append(LINKFLAGS=["/INCREMENTAL:NO"]) + # MSVC incremental linking is broken and may _increase_ link time (GH-77968). + if not env["incremental_link"]: + env.Append(LINKFLAGS=["/INCREMENTAL:NO"]) env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"]) env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding. diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp index 504966354dc..0fd33ee9de0 100644 --- a/scene/2d/touch_screen_button.cpp +++ b/scene/2d/touch_screen_button.cpp @@ -33,9 +33,19 @@ #include "core/input_map.h" #include "core/os/input.h" #include "core/os/os.h" +#include "scene/scene_string_names.h" void TouchScreenButton::set_texture(const Ref &p_texture) { + if (texture == p_texture) { + return; + } + if (texture.is_valid()) { + texture->disconnect(SceneStringNames::get_singleton()->changed, this, "update"); + } texture = p_texture; + if (texture.is_valid()) { + texture->connect(SceneStringNames::get_singleton()->changed, this, "update", varray(), CONNECT_REFERENCE_COUNTED); + } update(); } @@ -44,7 +54,16 @@ Ref TouchScreenButton::get_texture() const { } void TouchScreenButton::set_texture_pressed(const Ref &p_texture_pressed) { + if (texture_pressed == p_texture_pressed) { + return; + } + if (texture_pressed.is_valid()) { + texture_pressed->disconnect(SceneStringNames::get_singleton()->changed, this, "update"); + } texture_pressed = p_texture_pressed; + if (texture_pressed.is_valid()) { + texture_pressed->connect(SceneStringNames::get_singleton()->changed, this, "update", varray(), CONNECT_REFERENCE_COUNTED); + } update(); } @@ -61,16 +80,16 @@ Ref TouchScreenButton::get_bitmask() const { } void TouchScreenButton::set_shape(const Ref &p_shape) { - if (shape.is_valid()) { - shape->disconnect("changed", this, "update"); + if (shape == p_shape) { + return; + } + if (shape.is_valid()) { + shape->disconnect(SceneStringNames::get_singleton()->changed, this, "update"); } - shape = p_shape; - if (shape.is_valid()) { - shape->connect("changed", this, "update"); + shape->connect(SceneStringNames::get_singleton()->changed, this, "update"); } - update(); } diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp index 1f274c0570c..912693c434b 100644 --- a/servers/audio/effects/audio_effect_record.cpp +++ b/servers/audio/effects/audio_effect_record.cpp @@ -67,11 +67,6 @@ bool AudioEffectRecordInstance::process_silence() const { void AudioEffectRecordInstance::_io_thread_process() { while (is_recording) { - //Check: The current recording has been requested to stop - if (!base->recording_active) { - is_recording = false; - } - _update_buffer(); if (is_recording) { @@ -119,6 +114,7 @@ void AudioEffectRecordInstance::init() { } void AudioEffectRecordInstance::finish() { + is_recording = false; #ifdef NO_THREADS AudioServer::get_singleton()->remove_update_callback(&AudioEffectRecordInstance::_update, this); #else @@ -126,14 +122,9 @@ void AudioEffectRecordInstance::finish() { #endif } -AudioEffectRecordInstance::~AudioEffectRecordInstance() { - finish(); -} - Ref AudioEffectRecord::instance() { Ref ins; ins.instance(); - ins->base = Ref(this); ins->is_recording = false; //Re-using the buffer size calculations from audio_effect_delay.cpp @@ -159,16 +150,19 @@ Ref AudioEffectRecord::instance() { ins->ring_buffer_read_pos = 0; ensure_thread_stopped(); - current_instance = ins; - if (recording_active) { + bool is_currently_recording = false; + if (current_instance != nullptr) { + is_currently_recording = current_instance->is_recording; + } + if (is_currently_recording) { ins->init(); } + current_instance = ins; return ins; } void AudioEffectRecord::ensure_thread_stopped() { - recording_active = false; if (current_instance != nullptr) { current_instance->finish(); } @@ -178,20 +172,24 @@ void AudioEffectRecord::set_recording_active(bool p_record) { if (p_record) { if (current_instance == nullptr) { WARN_PRINT("Recording should not be set as active before Godot has initialized."); - recording_active = false; return; } ensure_thread_stopped(); - recording_active = true; current_instance->init(); } else { - recording_active = false; + if (current_instance != nullptr) { + current_instance->is_recording = false; + } } } bool AudioEffectRecord::is_recording_active() const { - return recording_active; + if (current_instance != nullptr) { + return current_instance->is_recording; + } else { + return false; + } } void AudioEffectRecord::set_format(AudioStreamSample::Format p_format) { @@ -289,5 +287,8 @@ void AudioEffectRecord::_bind_methods() { AudioEffectRecord::AudioEffectRecord() { format = AudioStreamSample::FORMAT_16_BITS; - recording_active = false; +} + +AudioEffectRecord::~AudioEffectRecord() { + ensure_thread_stopped(); } diff --git a/servers/audio/effects/audio_effect_record.h b/servers/audio/effects/audio_effect_record.h index ecb74e59d9e..f45e7bbd499 100644 --- a/servers/audio/effects/audio_effect_record.h +++ b/servers/audio/effects/audio_effect_record.h @@ -45,7 +45,6 @@ class AudioEffectRecord; class AudioEffectRecordInstance : public AudioEffectInstance { GDCLASS(AudioEffectRecordInstance, AudioEffectInstance); friend class AudioEffectRecord; - Ref base; bool is_recording; Thread io_thread; @@ -68,9 +67,6 @@ public: void finish(); virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count); virtual bool process_silence() const; - - AudioEffectRecordInstance() {} - ~AudioEffectRecordInstance(); }; class AudioEffectRecord : public AudioEffect { @@ -82,7 +78,6 @@ class AudioEffectRecord : public AudioEffect { IO_BUFFER_SIZE_MS = 1500 }; - bool recording_active; Ref current_instance; AudioStreamSample::Format format; @@ -101,6 +96,7 @@ public: Ref get_recording() const; AudioEffectRecord(); + ~AudioEffectRecord(); }; #endif // AUDIO_EFFECT_RECORD_H