diff --git a/core/io/ip.cpp b/core/io/ip.cpp index 51ffcc723f2..2ee0268b63a 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -96,6 +96,11 @@ struct _IP_ResolverPrivate { if (queue[i].status.get() != IP::RESOLVER_STATUS_WAITING) { continue; } + // We might be overriding another result, but we don't care as long as the result is valid. + if (response.size()) { + String key = get_cache_key(hostname, type); + cache[key] = response; + } queue[i].response = response; queue[i].status.set(response.empty() ? IP::RESOLVER_STATUS_ERROR : IP::RESOLVER_STATUS_DONE); } @@ -118,30 +123,8 @@ struct _IP_ResolverPrivate { }; IP_Address IP::resolve_hostname(const String &p_hostname, IP::Type p_type) { - List res; - String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type); - - resolver->mutex.lock(); - if (resolver->cache.has(key)) { - res = resolver->cache[key]; - } else { - // This should be run unlocked so the resolver thread can keep - // resolving other requests. - resolver->mutex.unlock(); - _resolve_hostname(res, p_hostname, p_type); - resolver->mutex.lock(); - // We might be overriding another result, but we don't care (they are the - // same hostname). - resolver->cache[key] = res; - } - resolver->mutex.unlock(); - - for (int i = 0; i < res.size(); ++i) { - if (res[i].is_valid()) { - return res[i]; - } - } - return IP_Address(); + const Array addresses = resolve_hostname_addresses(p_hostname, p_type); + return addresses.size() ? addresses[0].operator IP_Address() : IP_Address(); } Array IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) { @@ -157,17 +140,16 @@ Array IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) { resolver->mutex.unlock(); _resolve_hostname(res, p_hostname, p_type); resolver->mutex.lock(); - // We might be overriding another result, but we don't care (they are the - // same hostname). - resolver->cache[key] = res; + // We might be overriding another result, but we don't care as long as the result is valid. + if (res.size()) { + resolver->cache[key] = res; + } } resolver->mutex.unlock(); Array result; for (int i = 0; i < res.size(); ++i) { - if (res[i].is_valid()) { - result.push_back(String(res[i])); - } + result.push_back(String(res[i])); } return result; } diff --git a/doc/classes/AudioEffectSpectrumAnalyzer.xml b/doc/classes/AudioEffectSpectrumAnalyzer.xml index 25af3a1cd46..b76f4ef182e 100644 --- a/doc/classes/AudioEffectSpectrumAnalyzer.xml +++ b/doc/classes/AudioEffectSpectrumAnalyzer.xml @@ -8,8 +8,8 @@ See also [AudioStreamGenerator] for procedurally generating sounds. - Audio Spectrum Demo - Godot 3.2 will get new audio features + https://godotengine.org/asset-library/asset/528 + https://godotengine.org/article/godot-32-will-get-new-audio-features diff --git a/doc/classes/AudioStreamGenerator.xml b/doc/classes/AudioStreamGenerator.xml index 07825f213c6..4973c2e5573 100644 --- a/doc/classes/AudioStreamGenerator.xml +++ b/doc/classes/AudioStreamGenerator.xml @@ -10,7 +10,7 @@ https://godotengine.org/asset-library/asset/526 - Godot 3.2 will get new audio features + https://godotengine.org/article/godot-32-will-get-new-audio-features diff --git a/doc/classes/AudioStreamGeneratorPlayback.xml b/doc/classes/AudioStreamGeneratorPlayback.xml index f035eff9074..f26a6421858 100644 --- a/doc/classes/AudioStreamGeneratorPlayback.xml +++ b/doc/classes/AudioStreamGeneratorPlayback.xml @@ -8,7 +8,7 @@ https://godotengine.org/asset-library/asset/526 - Godot 3.2 will get new audio features + https://godotengine.org/article/godot-32-will-get-new-audio-features diff --git a/doc/classes/ReflectionProbe.xml b/doc/classes/ReflectionProbe.xml index 6ec2f33f29d..301eebdf078 100644 --- a/doc/classes/ReflectionProbe.xml +++ b/doc/classes/ReflectionProbe.xml @@ -47,6 +47,7 @@ The maximum distance away from the [ReflectionProbe] an object can be before it is culled. Decrease this to improve performance, especially when using the [constant UPDATE_ALWAYS] [member update_mode]. + [b]Note:[/b] The maximum reflection distance is always at least equal to the [member extents]. This means that decreasing [member max_distance] will not always cull objects from reflections, especially if the reflection probe's [member extents] are already large. Sets the origin offset to be used when this [ReflectionProbe] is in [member box_projection] mode. This can be set to a non-zero value to ensure a reflection fits a rectangle-shaped room, while reducing the amount of objects that "get in the way" of the reflection. diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index de8afd9c8e0..f37ebd2df7e 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -115,7 +115,7 @@ void IP_Unix::_resolve_hostname(List &r_addresses, const String &p_h continue; } IP_Address ip = _sockaddr2ip(next->ai_addr); - if (!r_addresses.find(ip)) { + if (ip.is_valid() && !r_addresses.find(ip)) { r_addresses.push_back(ip); } next = next->ai_next; diff --git a/editor/plugins/skeleton_editor_plugin.cpp b/editor/plugins/skeleton_editor_plugin.cpp index 58f9f30a8c4..acf421e3115 100644 --- a/editor/plugins/skeleton_editor_plugin.cpp +++ b/editor/plugins/skeleton_editor_plugin.cpp @@ -77,7 +77,7 @@ void SkeletonEditor::create_physical_skeleton() { if (!bones_infos[parent].physical_bone) { bones_infos.write[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos); - ur->create_action(TTR("Create physical bones")); + ur->create_action(TTR("Create physical bones"), UndoRedo::MERGE_ALL); ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone); ur->add_do_reference(bones_infos[parent].physical_bone); ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone); diff --git a/modules/mono/build_scripts/mono_reg_utils.py b/modules/mono/build_scripts/mono_reg_utils.py index bad4314ce1a..596129c02cf 100644 --- a/modules/mono/build_scripts/mono_reg_utils.py +++ b/modules/mono/build_scripts/mono_reg_utils.py @@ -103,10 +103,10 @@ def find_msbuild_tools_path_reg(): raise ValueError("Cannot find `installationPath` entry") except ValueError as e: print("Error reading output from vswhere: " + e.message) - except WindowsError: - pass # Fine, vswhere not found - except (subprocess.CalledProcessError, OSError): - pass + except subprocess.CalledProcessError as e: + print(e.output) + except OSError as e: + print(e) # Try to find 14.0 in the Registry diff --git a/platform/javascript/js/engine/config.js b/platform/javascript/js/engine/config.js index ba61b14eb7f..5628ddbab5c 100644 --- a/platform/javascript/js/engine/config.js +++ b/platform/javascript/js/engine/config.js @@ -225,33 +225,34 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused- */ Config.prototype.update = function (opts) { const config = opts || {}; - function parse(key, def) { + const me = this; + function parse(key) { if (typeof (config[key]) === 'undefined') { - return def; + return me[key]; } return config[key]; } // Module config - this.unloadAfterInit = parse('unloadAfterInit', this.unloadAfterInit); - this.onPrintError = parse('onPrintError', this.onPrintError); - this.onPrint = parse('onPrint', this.onPrint); - this.onProgress = parse('onProgress', this.onProgress); + this.unloadAfterInit = parse('unloadAfterInit'); + this.onPrintError = parse('onPrintError'); + this.onPrint = parse('onPrint'); + this.onProgress = parse('onProgress'); // Godot config - this.canvas = parse('canvas', this.canvas); - this.executable = parse('executable', this.executable); - this.mainPack = parse('mainPack', this.mainPack); - this.locale = parse('locale', this.locale); - this.canvasResizePolicy = parse('canvasResizePolicy', this.canvasResizePolicy); - this.persistentPaths = parse('persistentPaths', this.persistentPaths); - this.persistentDrops = parse('persistentDrops', this.persistentDrops); - this.experimentalVK = parse('experimentalVK', this.experimentalVK); - this.focusCanvas = parse('focusCanvas', this.focusCanvas); - this.gdnativeLibs = parse('gdnativeLibs', this.gdnativeLibs); - this.fileSizes = parse('fileSizes', this.fileSizes); - this.args = parse('args', this.args); - this.onExecute = parse('onExecute', this.onExecute); - this.onExit = parse('onExit', this.onExit); + this.canvas = parse('canvas'); + this.executable = parse('executable'); + this.mainPack = parse('mainPack'); + this.locale = parse('locale'); + this.canvasResizePolicy = parse('canvasResizePolicy'); + this.persistentPaths = parse('persistentPaths'); + this.persistentDrops = parse('persistentDrops'); + this.experimentalVK = parse('experimentalVK'); + this.focusCanvas = parse('focusCanvas'); + this.gdnativeLibs = parse('gdnativeLibs'); + this.fileSizes = parse('fileSizes'); + this.args = parse('args'); + this.onExecute = parse('onExecute'); + this.onExit = parse('onExit'); }; /** diff --git a/platform/javascript/js/libs/library_godot_input.js b/platform/javascript/js/libs/library_godot_input.js index 7a4d0d81260..1e64c260f8d 100644 --- a/platform/javascript/js/libs/library_godot_input.js +++ b/platform/javascript/js/libs/library_godot_input.js @@ -87,7 +87,7 @@ const GodotInputGamepads = { }, init: function (onchange) { - GodotEventListeners.samples = []; + GodotInputGamepads.samples = []; function add(pad) { const guid = GodotInputGamepads.get_guid(pad); const c_id = GodotRuntime.allocString(pad.id); diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp index 2a561e71067..ed0fba3dd8e 100644 --- a/platform/windows/godot_windows.cpp +++ b/platform/windows/godot_windows.cpp @@ -140,6 +140,11 @@ __declspec(dllexport) int widechar_main(int argc, wchar_t **argv) { setlocale(LC_CTYPE, ""); +#ifndef TOOLS_ENABLED + // Workaround to prevent LTCG (MSVC LTO) from removing "pck" section + char *dummy_guard = dummy; +#endif + char **argv_utf8 = new char *[argc]; for (int i = 0; i < argc; ++i) { diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index a27da19b23f..2a84e77fed6 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -107,15 +107,23 @@ static String format_error_message(DWORD id) { extern HINSTANCE godot_hinstance; +void RedirectStream(const char *p_file_name, const char *p_mode, FILE *p_cpp_stream, const DWORD p_std_handle) { + const HANDLE h_existing = GetStdHandle(p_std_handle); + if (h_existing != INVALID_HANDLE_VALUE) { // Redirect only if attached console have a valid handle. + const HANDLE h_cpp = reinterpret_cast(_get_osfhandle(_fileno(p_cpp_stream))); + if (h_cpp == INVALID_HANDLE_VALUE) { // Redirect only if it's not already redirected to the pipe or file. + FILE *fp = p_cpp_stream; + freopen_s(&fp, p_file_name, p_mode, p_cpp_stream); // Redirect stream. + setvbuf(p_cpp_stream, nullptr, _IONBF, 0); // Disable stream buffering. + } + } +} + void RedirectIOToConsole() { if (AttachConsole(ATTACH_PARENT_PROCESS)) { - FILE *fpstdin = stdin; - FILE *fpstdout = stdout; - FILE *fpstderr = stderr; - - freopen_s(&fpstdin, "CONIN$", "r", stdin); - freopen_s(&fpstdout, "CONOUT$", "w", stdout); - freopen_s(&fpstderr, "CONOUT$", "w", stderr); + RedirectStream("CONIN$", "r", stdin, STD_INPUT_HANDLE); + RedirectStream("CONOUT$", "w", stdout, STD_OUTPUT_HANDLE); + RedirectStream("CONOUT$", "w", stderr, STD_ERROR_HANDLE); printf("\n"); // Make sure our output is starting from the new line. } diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index 1349cd386af..37acea048d4 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -171,7 +171,8 @@ void TextureButton::_notification(int p_what) { bool draw_focus = (has_focus() && focused.is_valid()); // If no other texture is valid, try using focused texture. - if (!texdraw.is_valid() && draw_focus) { + bool draw_focus_only = draw_focus && !texdraw.is_valid(); + if (draw_focus_only) { texdraw = focused; } @@ -230,7 +231,7 @@ void TextureButton::_notification(int p_what) { size.width *= hflip ? -1.0f : 1.0f; size.height *= vflip ? -1.0f : 1.0f; - if (texdraw == focused) { + if (draw_focus_only) { // Do nothing, we only needed to calculate the rectangle. } else if (_tile) { draw_texture_rect(texdraw, Rect2(ofs, size), _tile);