瀏覽代碼

Merge pull request #81374 from akien-mga/3.5-cherrypicks

Cherry-picks for the 3.5 branch (future 3.5.3) - 3rd batch
Rémi Verschelde 2 年之前
父節點
當前提交
fc32e066af

+ 3 - 2
.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

+ 3 - 2
.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

+ 3 - 2
.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

+ 3 - 2
.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

+ 3 - 2
.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

+ 46 - 0
.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

+ 3 - 2
.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

+ 3 - 2
.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

+ 3 - 2
.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

+ 8 - 19
.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/
 

+ 3 - 0
core/class_db.h

@@ -170,6 +170,7 @@ public:
 	template <class T>
 	static void register_class() {
 		GLOBAL_LOCK_FUNCTION;
+		static_assert(TypesAreSame<typename T::self_type, T>::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 <class T>
 	static void register_virtual_class() {
 		GLOBAL_LOCK_FUNCTION;
+		static_assert(TypesAreSame<typename T::self_type, T>::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 <class T>
 	static void register_custom_instance_class() {
 		GLOBAL_LOCK_FUNCTION;
+		static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
 		T::initialize_class();
 		ClassInfo *t = classes.getptr(T::get_class_static());
 		ERR_FAIL_COND(!t);

+ 6 - 0
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());

+ 3 - 0
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,

+ 27 - 5
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<Variant> 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: {
 		}
 	}

+ 1 - 1
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);
 };
 

+ 3 - 0
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
 

+ 1 - 0
platform/android/java/editor/src/.gitignore

@@ -0,0 +1 @@
+!/debug

+ 6 - 0
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"])

+ 3 - 1
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;

+ 4 - 2
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.

+ 24 - 5
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<Texture> &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<Texture> TouchScreenButton::get_texture() const {
 }
 
 void TouchScreenButton::set_texture_pressed(const Ref<Texture> &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<BitMap> TouchScreenButton::get_bitmask() const {
 }
 
 void TouchScreenButton::set_shape(const Ref<Shape2D> &p_shape) {
+	if (shape == p_shape) {
+		return;
+	}
 	if (shape.is_valid()) {
-		shape->disconnect("changed", this, "update");
+		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();
 }
 

+ 19 - 18
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<AudioEffectInstance> AudioEffectRecord::instance() {
 	Ref<AudioEffectRecordInstance> ins;
 	ins.instance();
-	ins->base = Ref<AudioEffectRecord>(this);
 	ins->is_recording = false;
 
 	//Re-using the buffer size calculations from audio_effect_delay.cpp
@@ -159,16 +150,19 @@ Ref<AudioEffectInstance> 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();
 }

+ 1 - 5
servers/audio/effects/audio_effect_record.h

@@ -45,7 +45,6 @@ class AudioEffectRecord;
 class AudioEffectRecordInstance : public AudioEffectInstance {
 	GDCLASS(AudioEffectRecordInstance, AudioEffectInstance);
 	friend class AudioEffectRecord;
-	Ref<AudioEffectRecord> 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<AudioEffectRecordInstance> current_instance;
 
 	AudioStreamSample::Format format;
@@ -101,6 +96,7 @@ public:
 	Ref<AudioStreamSample> get_recording() const;
 
 	AudioEffectRecord();
+	~AudioEffectRecord();
 };
 
 #endif // AUDIO_EFFECT_RECORD_H