소스 검색

Merge pull request #50202 from akien-mga/3.x-cherrypicks

Rémi Verschelde 4 년 전
부모
커밋
39c89b51d7
45개의 변경된 파일334개의 추가작업 그리고 183개의 파일을 삭제
  1. 1 0
      core/crypto/crypto.h
  2. 7 0
      core/input_map.cpp
  3. 1 0
      core/input_map.h
  4. 0 1
      core/local_vector.h
  5. 24 8
      core/variant_parser.cpp
  6. 2 0
      doc/classes/Camera2D.xml
  7. 9 0
      doc/classes/InputMap.xml
  8. 1 0
      doc/classes/NodePath.xml
  9. 0 12
      drivers/unix/ip_unix.cpp
  10. 3 3
      editor/code_editor.cpp
  11. 1 1
      editor/code_editor.h
  12. 48 8
      editor/editor_asset_installer.cpp
  13. 1 0
      editor/editor_settings.cpp
  14. 2 1
      editor/filesystem_dock.cpp
  15. 2 2
      editor/plugins/canvas_item_editor_plugin.cpp
  16. 8 7
      editor/plugins/script_text_editor.cpp
  17. 1 1
      editor/plugins/script_text_editor.h
  18. 3 3
      editor/plugins/shader_editor_plugin.cpp
  19. 1 1
      editor/plugins/shader_editor_plugin.h
  20. 7 3
      editor/plugins/spatial_editor_plugin.cpp
  21. 3 3
      editor/plugins/text_editor.cpp
  22. 1 1
      editor/plugins/text_editor.h
  23. 109 54
      editor/scene_tree_dock.cpp
  24. 3 0
      editor/scene_tree_dock.h
  25. 1 1
      modules/gdnative/nativescript/api_generator.cpp
  26. 1 1
      modules/gridmap/grid_map.cpp
  27. 7 0
      modules/mbedtls/crypto_mbedtls.cpp
  28. 1 0
      modules/mbedtls/crypto_mbedtls.h
  29. 0 6
      modules/mono/build_scripts/mono_configure.py
  30. 11 2
      modules/websocket/wsl_server.cpp
  31. 6 0
      platform/android/export/export.cpp
  32. 6 4
      platform/android/export/gradle_export_util.h
  33. 1 1
      platform/android/java/app/AndroidManifest.xml
  34. 8 8
      platform/android/java/lib/src/org/godotengine/godot/Dictionary.java
  35. 4 4
      platform/android/java/lib/src/org/godotengine/godot/Godot.java
  36. 7 7
      platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
  37. 2 2
      platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
  38. 1 1
      platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java
  39. 2 2
      platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java
  40. 3 3
      platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
  41. 2 2
      platform/android/java/lib/src/org/godotengine/godot/utils/Crypt.java
  42. 6 6
      platform/windows/os_windows.cpp
  43. 12 12
      platform/windows/windows_terminal_logger.cpp
  44. 14 11
      scene/2d/camera_2d.cpp
  45. 1 1
      scene/gui/split_container.cpp

+ 1 - 0
core/crypto/crypto.h

@@ -83,6 +83,7 @@ public:
 	virtual PoolByteArray finish() = 0;
 
 	HMACContext() {}
+	virtual ~HMACContext() {}
 };
 
 class Crypto : public Reference {

+ 7 - 0
core/input_map.cpp

@@ -45,6 +45,7 @@ void InputMap::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action);
 
 	ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone);
+	ClassDB::bind_method(D_METHOD("action_get_deadzone", "action"), &InputMap::action_get_deadzone);
 	ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event);
 	ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event);
 	ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event);
@@ -148,6 +149,12 @@ bool InputMap::has_action(const StringName &p_action) const {
 	return input_map.has(p_action);
 }
 
+float InputMap::action_get_deadzone(const StringName &p_action) {
+	ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, _suggest_actions(p_action));
+
+	return input_map[p_action].deadzone;
+}
+
 void InputMap::action_set_deadzone(const StringName &p_action, float p_deadzone) {
 	ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
 

+ 1 - 0
core/input_map.h

@@ -71,6 +71,7 @@ public:
 	void add_action(const StringName &p_action, float p_deadzone = 0.5);
 	void erase_action(const StringName &p_action);
 
+	float action_get_deadzone(const StringName &p_action);
 	void action_set_deadzone(const StringName &p_action, float p_deadzone);
 	void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event);
 	bool action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event);

+ 0 - 1
core/local_vector.h

@@ -177,7 +177,6 @@ public:
 	}
 
 	int64_t find(const T &p_val, U p_from = 0) const {
-		ERR_FAIL_UNSIGNED_INDEX_V(p_from, count, -1);
 		for (U i = p_from; i < count; i++) {
 			if (data[i] == p_val) {
 				return int64_t(i);

+ 24 - 8
core/variant_parser.cpp

@@ -1297,16 +1297,32 @@ Error VariantParser::_parse_tag(Token &token, Stream *p_stream, int &line, Strin
 		r_tag.name = "";
 		r_tag.fields.clear();
 
-		while (true) {
-			CharType c = p_stream->get_char();
-			if (p_stream->is_eof()) {
-				r_err_str = "Unexpected EOF while parsing simple tag";
-				return ERR_PARSE_ERROR;
+		if (p_stream->is_utf8()) {
+			CharString cs;
+			while (true) {
+				CharType c = p_stream->get_char();
+				if (p_stream->is_eof()) {
+					r_err_str = "Unexpected EOF while parsing simple tag";
+					return ERR_PARSE_ERROR;
+				}
+				if (c == ']') {
+					break;
+				}
+				cs += c;
 			}
-			if (c == ']') {
-				break;
+			r_tag.name.parse_utf8(cs.get_data(), cs.length());
+		} else {
+			while (true) {
+				CharType c = p_stream->get_char();
+				if (p_stream->is_eof()) {
+					r_err_str = "Unexpected EOF while parsing simple tag";
+					return ERR_PARSE_ERROR;
+				}
+				if (c == ']') {
+					break;
+				}
+				r_tag.name += String::chr(c);
 			}
-			r_tag.name += String::chr(c);
 		}
 
 		r_tag.name = r_tag.name.strip_edges();

+ 2 - 0
doc/classes/Camera2D.xml

@@ -153,6 +153,8 @@
 		</member>
 		<member name="limit_smoothed" type="bool" setter="set_limit_smoothing_enabled" getter="is_limit_smoothing_enabled" default="false">
 			If [code]true[/code], the camera smoothly stops when reaches its limits.
+			This has no effect if smoothing is disabled.
+			[b]Note:[/b] To immediately update the camera's position to be within limits without smoothing, even with this setting enabled, invoke [method reset_smoothing].
 		</member>
 		<member name="limit_top" type="int" setter="set_limit" getter="get_limit" default="-10000000">
 			Top scroll limit in pixels. The camera stops moving when reaching this value.

+ 9 - 0
doc/classes/InputMap.xml

@@ -41,6 +41,15 @@
 				Removes all events from an action.
 			</description>
 		</method>
+		<method name="action_get_deadzone">
+			<return type="float">
+			</return>
+			<argument index="0" name="action" type="String">
+			</argument>
+			<description>
+				Returns a deadzone value for the action.
+			</description>
+		</method>
 		<method name="action_has_event">
 			<return type="bool">
 			</return>

+ 1 - 0
doc/classes/NodePath.xml

@@ -20,6 +20,7 @@
 		@"/root/Main" # If your main scene's root node were named "Main".
 		@"/root/MyAutoload" # If you have an autoloaded node or scene.
 		[/codeblock]
+		[b]Note:[/b] In the editor, [NodePath] properties are automatically updated when moving, renaming or deleting a node in the scene tree, but they are never updated at runtime.
 	</description>
 	<tutorials>
 		<link title="2D Role Playing Game Demo">https://godotengine.org/asset-library/asset/520</link>

+ 0 - 12
drivers/unix/ip_unix.cpp

@@ -41,19 +41,7 @@
 #include <windows.h>
 #include <ws2tcpip.h>
 #ifndef UWP_ENABLED
-#if defined(__MINGW32__) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 4)
-// MinGW-w64 on Ubuntu 12.04 (our Travis build env) has bugs in this code where
-// some includes are missing in dependencies of iphlpapi.h for WINVER >= 0x0600 (Vista).
-// We don't use this Vista code for now, so working it around by disabling it.
-// MinGW-w64 >= 4.0 seems to be better judging by its headers.
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501 // Windows XP, disable Vista API
 #include <iphlpapi.h>
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0600 // Re-enable Vista API
-#else
-#include <iphlpapi.h>
-#endif // MINGW hack
 #endif
 #else // UNIX
 #include <netdb.h>

+ 3 - 3
editor/code_editor.cpp

@@ -712,8 +712,8 @@ void CodeTextEditor::_input(const Ref<InputEvent> &event) {
 		accept_event();
 		return;
 	}
-	if (ED_IS_SHORTCUT("script_text_editor/clone_down", key_event)) {
-		clone_lines_down();
+	if (ED_IS_SHORTCUT("script_text_editor/duplicate_selection", key_event)) {
+		duplicate_selection();
 		accept_event();
 		return;
 	}
@@ -1249,7 +1249,7 @@ void CodeTextEditor::delete_lines() {
 	text_editor->end_complex_operation();
 }
 
-void CodeTextEditor::clone_lines_down() {
+void CodeTextEditor::duplicate_selection() {
 	const int cursor_column = text_editor->cursor_get_column();
 	int from_line = text_editor->cursor_get_line();
 	int to_line = text_editor->cursor_get_line();

+ 1 - 1
editor/code_editor.h

@@ -217,7 +217,7 @@ public:
 	void move_lines_up();
 	void move_lines_down();
 	void delete_lines();
-	void clone_lines_down();
+	void duplicate_selection();
 
 	/// Toggle inline comment on currently selected lines, or on current line if nothing is selected,
 	/// by adding or removing comment delimiter

+ 48 - 8
editor/editor_asset_installer.cpp

@@ -132,14 +132,54 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
 
 	Map<String, Ref<Texture>> extension_guess;
 	{
-		extension_guess["png"] = get_icon("ImageTexture", "EditorIcons");
-		extension_guess["jpg"] = get_icon("ImageTexture", "EditorIcons");
-		extension_guess["atlastex"] = get_icon("AtlasTexture", "EditorIcons");
-		extension_guess["scn"] = get_icon("PackedScene", "EditorIcons");
-		extension_guess["tscn"] = get_icon("PackedScene", "EditorIcons");
-		extension_guess["shader"] = get_icon("Shader", "EditorIcons");
-		extension_guess["gd"] = get_icon("GDScript", "EditorIcons");
-		extension_guess["vs"] = get_icon("VisualScript", "EditorIcons");
+		extension_guess["bmp"] = tree->get_icon("ImageTexture", "EditorIcons");
+		extension_guess["dds"] = tree->get_icon("ImageTexture", "EditorIcons");
+		extension_guess["exr"] = tree->get_icon("ImageTexture", "EditorIcons");
+		extension_guess["hdr"] = tree->get_icon("ImageTexture", "EditorIcons");
+		extension_guess["jpg"] = tree->get_icon("ImageTexture", "EditorIcons");
+		extension_guess["jpeg"] = tree->get_icon("ImageTexture", "EditorIcons");
+		extension_guess["png"] = tree->get_icon("ImageTexture", "EditorIcons");
+		extension_guess["svg"] = tree->get_icon("ImageTexture", "EditorIcons");
+		extension_guess["svgz"] = tree->get_icon("ImageTexture", "EditorIcons");
+		extension_guess["tga"] = tree->get_icon("ImageTexture", "EditorIcons");
+		extension_guess["webp"] = tree->get_icon("ImageTexture", "EditorIcons");
+
+		extension_guess["wav"] = tree->get_icon("AudioStreamSample", "EditorIcons");
+		extension_guess["ogg"] = tree->get_icon("AudioStreamOGGVorbis", "EditorIcons");
+		extension_guess["mp3"] = tree->get_icon("AudioStreamMP3", "EditorIcons");
+
+		extension_guess["scn"] = tree->get_icon("PackedScene", "EditorIcons");
+		extension_guess["tscn"] = tree->get_icon("PackedScene", "EditorIcons");
+		extension_guess["escn"] = tree->get_icon("PackedScene", "EditorIcons");
+		extension_guess["dae"] = tree->get_icon("PackedScene", "EditorIcons");
+		extension_guess["gltf"] = tree->get_icon("PackedScene", "EditorIcons");
+		extension_guess["glb"] = tree->get_icon("PackedScene", "EditorIcons");
+
+		extension_guess["gdshader"] = tree->get_icon("Shader", "EditorIcons");
+		extension_guess["gd"] = tree->get_icon("GDScript", "EditorIcons");
+		if (Engine::get_singleton()->has_singleton("GodotSharp")) {
+			extension_guess["cs"] = tree->get_icon("CSharpScript", "EditorIcons");
+		} else {
+			// Mark C# support as unavailable.
+			extension_guess["cs"] = tree->get_icon("ImportFail", "EditorIcons");
+		}
+		extension_guess["vs"] = tree->get_icon("VisualScript", "EditorIcons");
+
+		extension_guess["res"] = tree->get_icon("Resource", "EditorIcons");
+		extension_guess["tres"] = tree->get_icon("Resource", "EditorIcons");
+		extension_guess["atlastex"] = tree->get_icon("AtlasTexture", "EditorIcons");
+		// By default, OBJ files are imported as Mesh resources rather than PackedScenes.
+		extension_guess["obj"] = tree->get_icon("Mesh", "EditorIcons");
+
+		extension_guess["txt"] = tree->get_icon("TextFile", "EditorIcons");
+		extension_guess["md"] = tree->get_icon("TextFile", "EditorIcons");
+		extension_guess["rst"] = tree->get_icon("TextFile", "EditorIcons");
+		extension_guess["json"] = tree->get_icon("TextFile", "EditorIcons");
+		extension_guess["yml"] = tree->get_icon("TextFile", "EditorIcons");
+		extension_guess["yaml"] = tree->get_icon("TextFile", "EditorIcons");
+		extension_guess["toml"] = tree->get_icon("TextFile", "EditorIcons");
+		extension_guess["cfg"] = tree->get_icon("TextFile", "EditorIcons");
+		extension_guess["ini"] = tree->get_icon("TextFile", "EditorIcons");
 	}
 
 	Ref<Texture> generic_extension = get_icon("Object", "EditorIcons");

+ 1 - 0
editor/editor_settings.cpp

@@ -553,6 +553,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
 	_initial_set("editors/3d/navigation/zoom_style", 0);
 	hints["editors/3d/navigation/zoom_style"] = PropertyInfo(Variant::INT, "editors/3d/navigation/zoom_style", PROPERTY_HINT_ENUM, "Vertical, Horizontal");
 
+	_initial_set("editors/3d/navigation/emulate_numpad", false);
 	_initial_set("editors/3d/navigation/emulate_3_button_mouse", false);
 	_initial_set("editors/3d/navigation/orbit_modifier", 0);
 	hints["editors/3d/navigation/orbit_modifier"] = PropertyInfo(Variant::INT, "editors/3d/navigation/orbit_modifier", PROPERTY_HINT_ENUM, "None,Shift,Alt,Meta,Ctrl");

+ 2 - 1
editor/filesystem_dock.cpp

@@ -721,7 +721,8 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
 
 		if (searched_string.length() > 0) {
 			// Display the search results.
-			_search(EditorFileSystem::get_singleton()->get_filesystem(), &filelist, 128);
+			// Limit the number of results displayed to avoid an infinite loop.
+			_search(EditorFileSystem::get_singleton()->get_filesystem(), &filelist, 10000);
 		} else {
 			if (display_mode == DISPLAY_MODE_TREE_ONLY || always_show_folders) {
 				// Display folders in the list.

+ 2 - 2
editor/plugins/canvas_item_editor_plugin.cpp

@@ -4625,11 +4625,11 @@ void CanvasItemEditor::_button_toggle_anchor_mode(bool p_status) {
 void CanvasItemEditor::_update_override_camera_button(bool p_game_running) {
 	if (p_game_running) {
 		override_camera_button->set_disabled(false);
-		override_camera_button->set_tooltip(TTR("Game Camera Override\nOverrides game camera with editor viewport camera."));
+		override_camera_button->set_tooltip(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera."));
 	} else {
 		override_camera_button->set_disabled(true);
 		override_camera_button->set_pressed(false);
-		override_camera_button->set_tooltip(TTR("Game Camera Override\nNo game instance running."));
+		override_camera_button->set_tooltip(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
 	}
 }
 

+ 8 - 7
editor/plugins/script_text_editor.cpp

@@ -1119,8 +1119,8 @@ void ScriptTextEditor::_edit_option(int p_op) {
 		case EDIT_DELETE_LINE: {
 			code_editor->delete_lines();
 		} break;
-		case EDIT_CLONE_DOWN: {
-			code_editor->clone_lines_down();
+		case EDIT_DUPLICATE_SELECTION: {
+			code_editor->duplicate_selection();
 		} break;
 		case EDIT_TOGGLE_FOLD_LINE: {
 			tx->toggle_fold_line(tx->cursor_get_line());
@@ -1504,6 +1504,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
 	}
 
 	if (d.has("type") && (String(d["type"]) == "files" || String(d["type"]) == "files_and_dirs")) {
+		const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
 		Array files = d["files"];
 
 		String text_to_drop;
@@ -1514,9 +1515,9 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
 			}
 
 			if (preload) {
-				text_to_drop += "preload(\"" + String(files[i]).c_escape() + "\")";
+				text_to_drop += "preload(" + String(files[i]).c_escape().quote(quote_style) + ")";
 			} else {
-				text_to_drop += "\"" + String(files[i]).c_escape() + "\"";
+				text_to_drop += String(files[i]).c_escape().quote(quote_style);
 			}
 		}
 
@@ -1802,7 +1803,7 @@ void ScriptTextEditor::_enable_code_editor() {
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
 	edit_menu->get_popup()->add_separator();
-	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
@@ -1969,10 +1970,10 @@ void ScriptTextEditor::register_editor() {
 	ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), 0);
 	ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), 0);
 #ifdef OSX_ENABLED
-	ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_C);
+	ED_SHORTCUT("script_text_editor/duplicate_selection", TTR("Duplicate Selection"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_C);
 	ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CTRL | KEY_SPACE);
 #else
-	ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD | KEY_D);
+	ED_SHORTCUT("script_text_editor/duplicate_selection", TTR("Duplicate Selection"), KEY_MASK_CMD | KEY_D);
 	ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CMD | KEY_SPACE);
 #endif
 	ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_E);

+ 1 - 1
editor/plugins/script_text_editor.h

@@ -119,7 +119,7 @@ class ScriptTextEditor : public ScriptEditorBase {
 		EDIT_INDENT_RIGHT,
 		EDIT_INDENT_LEFT,
 		EDIT_DELETE_LINE,
-		EDIT_CLONE_DOWN,
+		EDIT_DUPLICATE_SELECTION,
 		EDIT_PICK_COLOR,
 		EDIT_TO_UPPERCASE,
 		EDIT_TO_LOWERCASE,

+ 3 - 3
editor/plugins/shader_editor_plugin.cpp

@@ -295,8 +295,8 @@ void ShaderEditor::_menu_option(int p_option) {
 		case EDIT_DELETE_LINE: {
 			shader_editor->delete_lines();
 		} break;
-		case EDIT_CLONE_DOWN: {
-			shader_editor->clone_lines_down();
+		case EDIT_DUPLICATE_SELECTION: {
+			shader_editor->duplicate_selection();
 		} break;
 		case EDIT_TOGGLE_COMMENT: {
 			if (shader.is_null()) {
@@ -627,7 +627,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
-	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION);
 	edit_menu->get_popup()->add_separator();
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE);
 	edit_menu->get_popup()->connect("id_pressed", this, "_menu_option");

+ 1 - 1
editor/plugins/shader_editor_plugin.h

@@ -80,7 +80,7 @@ class ShaderEditor : public PanelContainer {
 		EDIT_INDENT_LEFT,
 		EDIT_INDENT_RIGHT,
 		EDIT_DELETE_LINE,
-		EDIT_CLONE_DOWN,
+		EDIT_DUPLICATE_SELECTION,
 		EDIT_TOGGLE_COMMENT,
 		EDIT_COMPLETE,
 		SEARCH_FIND,

+ 7 - 3
editor/plugins/spatial_editor_plugin.cpp

@@ -1927,6 +1927,13 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
 			return;
 		}
 
+		if (EditorSettings::get_singleton()->get("editors/3d/navigation/emulate_numpad")) {
+			const uint32_t code = k->get_scancode();
+			if (code >= KEY_0 && code <= KEY_9) {
+				k->set_scancode(code - KEY_0 + KEY_KP_0);
+			}
+		}
+
 		if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) {
 			if (_edit.mode != TRANSFORM_NONE) {
 				_edit.snap = !_edit.snap;
@@ -3076,14 +3083,12 @@ void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
 		if (!preview) {
 			preview_camera->hide();
 		}
-		view_menu->set_disabled(false);
 		surface->update();
 
 	} else {
 		previewing = preview;
 		previewing->connect("tree_exiting", this, "_preview_exited_scene");
 		VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace
-		view_menu->set_disabled(true);
 		surface->update();
 	}
 }
@@ -3316,7 +3321,6 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) {
 			previewing = Object::cast_to<Camera>(pv);
 			previewing->connect("tree_exiting", this, "_preview_exited_scene");
 			VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), previewing->get_camera()); //replace
-			view_menu->set_disabled(true);
 			surface->update();
 			preview_camera->set_pressed(true);
 			preview_camera->show();

+ 3 - 3
editor/plugins/text_editor.cpp

@@ -398,8 +398,8 @@ void TextEditor::_edit_option(int p_op) {
 		case EDIT_DELETE_LINE: {
 			code_editor->delete_lines();
 		} break;
-		case EDIT_CLONE_DOWN: {
-			code_editor->clone_lines_down();
+		case EDIT_DUPLICATE_SELECTION: {
+			code_editor->duplicate_selection();
 		} break;
 		case EDIT_TOGGLE_FOLD_LINE: {
 			tx->toggle_fold_line(tx->cursor_get_line());
@@ -629,7 +629,7 @@ TextEditor::TextEditor() {
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
 	edit_menu->get_popup()->add_separator();
-	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS);

+ 1 - 1
editor/plugins/text_editor.h

@@ -77,7 +77,7 @@ private:
 		EDIT_INDENT_RIGHT,
 		EDIT_INDENT_LEFT,
 		EDIT_DELETE_LINE,
-		EDIT_CLONE_DOWN,
+		EDIT_DUPLICATE_SELECTION,
 		EDIT_TO_UPPERCASE,
 		EDIT_TO_LOWERCASE,
 		EDIT_CAPITALIZE,

+ 109 - 54
editor/scene_tree_dock.cpp

@@ -1397,9 +1397,102 @@ void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pai
 	_fill_path_renames(base_path, new_base_path, p_node, p_renames);
 }
 
+bool SceneTreeDock::_update_node_path(const NodePath &p_root_path, NodePath &r_node_path, List<Pair<NodePath, NodePath>> *p_renames) {
+	NodePath root_path_new = p_root_path;
+	for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) {
+		if (p_root_path == F->get().first) {
+			root_path_new = F->get().second;
+			break;
+		}
+	}
+
+	// Goes through all paths to check if it's matching.
+	for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) {
+		NodePath rel_path_old = p_root_path.rel_path_to(F->get().first);
+
+		// If old path detected, then it needs to be replaced with the new one.
+		if (r_node_path == rel_path_old) {
+			NodePath rel_path_new = F->get().second;
+
+			// If not empty, get new relative path.
+			if (!rel_path_new.is_empty()) {
+				rel_path_new = root_path_new.rel_path_to(rel_path_new);
+			}
+
+			r_node_path = rel_path_new;
+			return true;
+		}
+
+		// Update the node itself if it has a valid node path and has not been deleted.
+		if (p_root_path == F->get().first && r_node_path != NodePath() && F->get().second != NodePath()) {
+			NodePath abs_path = NodePath(String(root_path_new).plus_file(r_node_path)).simplified();
+			NodePath rel_path_new = F->get().second.rel_path_to(abs_path);
+
+			r_node_path = rel_path_new;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool SceneTreeDock::_check_node_path_recursive(const NodePath &p_root_path, Variant &r_variant, List<Pair<NodePath, NodePath>> *p_renames) {
+	switch (r_variant.get_type()) {
+		case Variant::NODE_PATH: {
+			NodePath node_path = r_variant;
+			if (_update_node_path(p_root_path, node_path, p_renames)) {
+				r_variant = node_path;
+				return true;
+			}
+		} break;
+
+		case Variant::ARRAY: {
+			Array a = r_variant;
+			bool updated = false;
+			for (int i = 0; i < a.size(); i++) {
+				Variant value = a[i];
+				if (_check_node_path_recursive(p_root_path, value, p_renames)) {
+					if (!updated) {
+						a = a.duplicate(); // Need to duplicate for undo-redo to work.
+						updated = true;
+					}
+					a[i] = value;
+				}
+			}
+			if (updated) {
+				r_variant = a;
+				return true;
+			}
+		} break;
+
+		case Variant::DICTIONARY: {
+			Dictionary d = r_variant;
+			bool updated = false;
+			for (int i = 0; i < d.size(); i++) {
+				Variant value = d.get_value_at_index(i);
+				if (_check_node_path_recursive(p_root_path, value, p_renames)) {
+					if (!updated) {
+						d = d.duplicate(); // Need to duplicate for undo-redo to work.
+						updated = true;
+					}
+					d[d.get_key_at_index(i)] = value;
+				}
+			}
+			if (updated) {
+				r_variant = d;
+				return true;
+			}
+		} break;
+
+		default: {
+		}
+	}
+
+	return false;
+}
+
 void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodePath>> *p_renames, Map<Ref<Animation>, Set<int>> *r_rem_anims) {
 	Map<Ref<Animation>, Set<int>> rem_anims;
-
 	if (!r_rem_anims) {
 		r_rem_anims = &rem_anims;
 	}
@@ -1412,60 +1505,22 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP
 		return;
 	}
 
-	// Renaming node paths used in script instances
-	if (p_base->get_script_instance()) {
-		ScriptInstance *si = p_base->get_script_instance();
-
-		if (si) {
-			List<PropertyInfo> properties;
-			si->get_property_list(&properties);
-			NodePath root_path = p_base->get_path();
-
-			for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
-				String propertyname = E->get().name;
-				Variant p = p_base->get(propertyname);
-				if (p.get_type() == Variant::NODE_PATH) {
-					NodePath root_path_new = root_path;
-					for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) {
-						if (root_path == F->get().first) {
-							root_path_new = F->get().second;
-							break;
-						}
-					}
-
-					// Goes through all paths to check if its matching
-					for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) {
-						NodePath rel_path_old = root_path.rel_path_to(F->get().first);
+	// Renaming node paths used in node properties.
+	List<PropertyInfo> properties;
+	p_base->get_property_list(&properties);
+	NodePath base_root_path = p_base->get_path();
 
-						// if old path detected, then it needs to be replaced with the new one
-						if (p == rel_path_old) {
-							NodePath rel_path_new = F->get().second;
-
-							// if not empty, get new relative path
-							if (!rel_path_new.is_empty()) {
-								rel_path_new = root_path_new.rel_path_to(F->get().second);
-							}
-
-							editor_data->get_undo_redo().add_do_property(p_base, propertyname, rel_path_new);
-							editor_data->get_undo_redo().add_undo_property(p_base, propertyname, rel_path_old);
-
-							p_base->set(propertyname, rel_path_new);
-							break;
-						}
-
-						// update the node itself if it has a valid node path and has not been deleted
-						if (root_path == F->get().first && p != NodePath() && F->get().second != NodePath()) {
-							NodePath abs_path = NodePath(String(root_path).plus_file(p)).simplified();
-							NodePath rel_path_new = F->get().second.rel_path_to(abs_path);
-
-							editor_data->get_undo_redo().add_do_property(p_base, propertyname, rel_path_new);
-							editor_data->get_undo_redo().add_undo_property(p_base, propertyname, p);
-
-							p_base->set(propertyname, rel_path_new);
-						}
-					}
-				}
-			}
+	for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
+		if (!(E->get().usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR))) {
+			continue;
+		}
+		String propertyname = E->get().name;
+		Variant old_variant = p_base->get(propertyname);
+		Variant updated_variant = old_variant;
+		if (_check_node_path_recursive(base_root_path, updated_variant, p_renames)) {
+			editor_data->get_undo_redo().add_do_property(p_base, propertyname, updated_variant);
+			editor_data->get_undo_redo().add_undo_property(p_base, propertyname, old_variant);
+			p_base->set(propertyname, updated_variant);
 		}
 	}
 

+ 3 - 0
editor/scene_tree_dock.h

@@ -248,6 +248,9 @@ class SceneTreeDock : public VBoxContainer {
 	bool profile_allow_editing;
 	bool profile_allow_script_editing;
 
+	static bool _update_node_path(const NodePath &p_root_path, NodePath &r_node_path, List<Pair<NodePath, NodePath>> *p_renames);
+	static bool _check_node_path_recursive(const NodePath &p_root_path, Variant &r_variant, List<Pair<NodePath, NodePath>> *p_renames);
+
 protected:
 	void _notification(int p_what);
 	static void _bind_methods();

+ 1 - 1
modules/gdnative/nativescript/api_generator.cpp

@@ -361,7 +361,7 @@ List<ClassAPI> generate_c_api_classes() {
 							arg_type = Variant::get_type_name(arg_info.type);
 						}
 					} else {
-						arg_type = Variant::get_type_name(arg_info.type);
+						arg_type = get_type_name(arg_info);
 					}
 
 					method_api.argument_names.push_back(arg_name);

+ 1 - 1
modules/gridmap/grid_map.cpp

@@ -778,7 +778,7 @@ void GridMap::_update_octants_callback() {
 
 	while (to_delete.front()) {
 		octant_map.erase(to_delete.front()->get());
-		to_delete.pop_back();
+		to_delete.pop_front();
 	}
 
 	_update_visibility();

+ 7 - 0
modules/mbedtls/crypto_mbedtls.cpp

@@ -255,6 +255,13 @@ PoolByteArray HMACContextMbedTLS::finish() {
 	return out;
 }
 
+HMACContextMbedTLS::~HMACContextMbedTLS() {
+	if (ctx != nullptr) {
+		mbedtls_md_free((mbedtls_md_context_t *)ctx);
+		memfree((mbedtls_md_context_t *)ctx);
+	}
+}
+
 Crypto *CryptoMbedTLS::create() {
 	return memnew(CryptoMbedTLS);
 }

+ 1 - 0
modules/mbedtls/crypto_mbedtls.h

@@ -119,6 +119,7 @@ public:
 	virtual PoolByteArray finish();
 
 	HMACContextMbedTLS() {}
+	~HMACContextMbedTLS();
 };
 
 class CryptoMbedTLS : public Crypto {

+ 0 - 6
modules/mono/build_scripts/mono_configure.py

@@ -97,12 +97,6 @@ def configure(env, env_mono):
 
     mono_lib_names = ["mono-2.0-sgen", "monosgen-2.0"]
 
-    is_travis = os.environ.get("TRAVIS") == "true"
-
-    if is_travis:
-        # Travis CI may have a Mono version lower than 5.12
-        env_mono.Append(CPPDEFINES=["NO_PENDING_EXCEPTIONS"])
-
     if is_android and not env["android_arch"] in android_arch_dirs:
         raise RuntimeError("This module does not support the specified 'android_arch': " + env["android_arch"])
 

+ 11 - 2
modules/websocket/wsl_server.cpp

@@ -106,26 +106,31 @@ bool WSLServer::PendingPeer::_parse_request(const Vector<String> p_protocols) {
 
 Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uint64_t p_timeout) {
 	if (OS::get_singleton()->get_ticks_msec() - time > p_timeout) {
+		print_verbose(vformat("WebSocket handshake timed out after %.3f seconds.", p_timeout * 0.001));
 		return ERR_TIMEOUT;
 	}
+
 	if (use_ssl) {
 		Ref<StreamPeerSSL> ssl = static_cast<Ref<StreamPeerSSL>>(connection);
 		if (ssl.is_null()) {
-			return FAILED;
+			ERR_FAIL_V_MSG(ERR_BUG, "Couldn't get StreamPeerSSL for WebSocket handshake.");
 		}
 		ssl->poll();
 		if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING) {
 			return ERR_BUSY;
 		} else if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
+			print_verbose(vformat("WebSocket SSL connection error during handshake (StreamPeerSSL status code %d).", ssl->get_status()));
 			return FAILED;
 		}
 	}
+
 	if (!has_request) {
 		int read = 0;
 		while (true) {
-			ERR_FAIL_COND_V_MSG(req_pos >= WSL_MAX_HEADER_SIZE, ERR_OUT_OF_MEMORY, "Response headers too big.");
+			ERR_FAIL_COND_V_MSG(req_pos >= WSL_MAX_HEADER_SIZE, ERR_OUT_OF_MEMORY, "WebSocket response headers are too big.");
 			Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);
 			if (err != OK) { // Got an error
+				print_verbose(vformat("WebSocket error while getting partial data (StreamPeer error code %d).", err));
 				return FAILED;
 			} else if (read != 1) { // Busy, wait next poll
 				return ERR_BUSY;
@@ -152,17 +157,21 @@ Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uin
 			req_pos += 1;
 		}
 	}
+
 	if (has_request && response_sent < response.size() - 1) {
 		int sent = 0;
 		Error err = connection->put_partial_data((const uint8_t *)response.get_data() + response_sent, response.size() - response_sent - 1, sent);
 		if (err != OK) {
+			print_verbose(vformat("WebSocket error while putting partial data (StreamPeer error code %d).", err));
 			return err;
 		}
 		response_sent += sent;
 	}
+
 	if (response_sent < response.size() - 1) {
 		return ERR_BUSY;
 	}
+
 	return OK;
 }
 

+ 6 - 0
platform/android/export/export.cpp

@@ -903,6 +903,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
 		bool focus_awareness = p_preset->get("xr_features/focus_awareness");
 
 		bool backup_allowed = p_preset->get("user_data_backup/allow");
+		bool classify_as_game = p_preset->get("package/classify_as_game");
 
 		Vector<String> perms;
 		// Write permissions into the perms variable.
@@ -1006,6 +1007,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
 							encode_uint32(backup_allowed, &p_manifest.write[iofs + 16]);
 						}
 
+						if (tname == "application" && attrname == "isGame") {
+							encode_uint32(classify_as_game, &p_manifest.write[iofs + 16]);
+						}
+
 						if (tname == "instrumentation" && attrname == "targetPackage") {
 							string_table.write[attr_value] = get_package_name(package_name);
 						}
@@ -1758,6 +1763,7 @@ public:
 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname"));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), ""));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true));
+		r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/classify_as_game"), true));
 
 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_icon_option, PROPERTY_HINT_FILE, "*.png"), ""));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_foreground_option, PROPERTY_HINT_FILE, "*.png"), ""));

+ 6 - 4
platform/android/export/gradle_export_util.h

@@ -263,12 +263,14 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_
 	bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
 	String manifest_application_text = vformat(
 			"    <application android:label=\"@string/godot_project_name_string\"\n"
-			"        android:allowBackup=\"%s\" tools:ignore=\"GoogleAppIndexingWarning\"\n"
-			"        tools:replace=\"android:requestLegacyExternalStorage\" "
+			"        android:allowBackup=\"%s\"\n"
+			"        android:icon=\"@mipmap/icon\"\n"
+			"        android:isGame=\"%s\"\n"
 			"        android:requestLegacyExternalStorage=\"%s\"\n"
-			"        android:icon=\"@mipmap/icon\">\n\n"
-			"        <meta-data tools:node=\"remove\" android:name=\"xr_mode_metadata_name\" />\n",
+			"        tools:replace=\"android:allowBackup,android:isGame,android:requestLegacyExternalStorage\"\n"
+			"        tools:ignore=\"GoogleAppIndexingWarning\">\n\n",
 			bool_to_string(p_preset->get("user_data_backup/allow")),
+			bool_to_string(p_preset->get("package/classify_as_game")),
 			bool_to_string(p_has_storage_permission));
 
 	if (uses_xr) {

+ 1 - 1
platform/android/java/app/AndroidManifest.xml

@@ -28,7 +28,7 @@
     <!-- If you want to add tags manually, do before it. -->
     <!-- WARNING: This should stay on a single line until the parsing code is improved. See GH-32414. -->
     <!-- TODO: Remove the 'requestLegacyExternalStorage' attribute when https://github.com/godotengine/godot/issues/38913 is resolved -->
-    <application android:label="@string/godot_project_name_string" android:allowBackup="false" tools:ignore="GoogleAppIndexingWarning" android:requestLegacyExternalStorage="false" android:icon="@mipmap/icon" >
+    <application android:label="@string/godot_project_name_string" android:allowBackup="false" android:icon="@mipmap/icon" android:isGame="true" android:requestLegacyExternalStorage="false" tools:ignore="GoogleAppIndexingWarning" >
 
         <!-- Records the version of the Godot editor used for building -->
         <meta-data

+ 8 - 8
platform/android/java/lib/src/org/godotengine/godot/Dictionary.java

@@ -43,10 +43,10 @@ public class Dictionary extends HashMap<String, Object> {
 		for (String key : keys) {
 			ret[i] = key;
 			i++;
-		};
+		}
 
 		return ret;
-	};
+	}
 
 	public Object[] get_values() {
 		Object[] ret = new Object[size()];
@@ -55,21 +55,21 @@ public class Dictionary extends HashMap<String, Object> {
 		for (String key : keys) {
 			ret[i] = get(key);
 			i++;
-		};
+		}
 
 		return ret;
-	};
+	}
 
 	public void set_keys(String[] keys) {
 		keys_cache = keys;
-	};
+	}
 
 	public void set_values(Object[] vals) {
 		int i = 0;
 		for (String key : keys_cache) {
 			put(key, vals[i]);
 			i++;
-		};
+		}
 		keys_cache = null;
-	};
-};
+	}
+}

+ 4 - 4
platform/android/java/lib/src/org/godotengine/godot/Godot.java

@@ -313,7 +313,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
 		for (int i = 0; i < permissions.length; i++) {
 			GodotLib.requestPermissionResult(permissions[i], grantResults[i] == PackageManager.PERMISSION_GRANTED);
 		}
-	};
+	}
 
 	/**
 	 * Invoked on the render thread when the Godot setup is complete.
@@ -636,7 +636,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
 		String main_pack_md5 = null;
 		String main_pack_key = null;
 
-		List<String> new_args = new LinkedList<String>();
+		List<String> new_args = new LinkedList<>();
 
 		for (int i = 0; i < command_line.length; i++) {
 			boolean has_extra = i < command_line.length - 1;
@@ -891,7 +891,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
 		int displayRotation = display.getRotation();
 
 		float[] adjustedValues = new float[3];
-		final int axisSwap[][] = {
+		final int[][] axisSwap = {
 			{ 1, -1, 0, 1 }, // ROTATION_0
 			{ -1, -1, 1, 0 }, // ROTATION_90
 			{ -1, 1, 0, 1 }, // ROTATION_180
@@ -1015,7 +1015,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
 			byte[] messageDigest = complete.digest();
 
 			// Create Hex String
-			StringBuffer hexString = new StringBuffer();
+			StringBuilder hexString = new StringBuilder();
 			for (int i = 0; i < messageDigest.length; i++) {
 				String s = Integer.toHexString(0xFF & messageDigest[i]);
 

+ 7 - 7
platform/android/java/lib/src/org/godotengine/godot/GodotIO.java

@@ -74,7 +74,7 @@ public class GodotIO {
 
 	public int last_file_id = 1;
 
-	class AssetData {
+	static class AssetData {
 		public boolean eof = false;
 		public String path;
 		public InputStream is;
@@ -233,7 +233,7 @@ public class GodotIO {
 	/// DIRECTORIES
 	/////////////////////////
 
-	class AssetDir {
+	static class AssetDir {
 		public String[] files;
 		public int current;
 		public String path;
@@ -324,8 +324,8 @@ public class GodotIO {
 		am = p_activity.getAssets();
 		activity = p_activity;
 		//streams = new HashMap<Integer, AssetData>();
-		streams = new SparseArray<AssetData>();
-		dirs = new SparseArray<AssetDir>();
+		streams = new SparseArray<>();
+		dirs = new SparseArray<>();
 	}
 
 	/////////////////////////
@@ -387,7 +387,7 @@ public class GodotIO {
 		Point size = new Point();
 		display.getRealSize(size);
 
-		int result[] = { 0, 0, size.x, size.y };
+		int[] result = { 0, 0, size.x, size.y };
 		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
 			WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets();
 			DisplayCutout cutout = insets.getDisplayCutout();
@@ -409,12 +409,12 @@ public class GodotIO {
 
 		//InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
 		//inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
-	};
+	}
 
 	public void hideKeyboard() {
 		if (edit != null)
 			edit.hideKeyboard();
-	};
+	}
 
 	public void setScreenOrientation(int p_orientation) {
 		switch (p_orientation) {

+ 2 - 2
platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java

@@ -57,7 +57,7 @@ public class GodotInputHandler implements InputDeviceListener {
 	private final String tag = this.getClass().getSimpleName();
 
 	private final SparseIntArray mJoystickIds = new SparseIntArray(4);
-	private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<Joystick>(4);
+	private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4);
 
 	private final GodotView godotView;
 	private final InputManagerCompat inputManager;
@@ -328,7 +328,7 @@ public class GodotInputHandler implements InputDeviceListener {
 		//Helps with creating new joypad mappings.
 		Log.i(tag, "=== New Input Device: " + joystick.name);
 
-		Set<Integer> already = new HashSet<Integer>();
+		Set<Integer> already = new HashSet<>();
 		for (InputDevice.MotionRange range : device.getMotionRanges()) {
 			boolean isJoystick = range.isFromSource(InputDevice.SOURCE_JOYSTICK);
 			boolean isGamepad = range.isFromSource(InputDevice.SOURCE_GAMEPAD);

+ 1 - 1
platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java

@@ -34,7 +34,7 @@ public class InputManagerV16 implements InputManagerCompat {
 
 	public InputManagerV16(Context context) {
 		mInputManager = (InputManager)context.getSystemService(Context.INPUT_SERVICE);
-		mListeners = new HashMap<InputManagerCompat.InputDeviceListener, V16InputDeviceListener>();
+		mListeners = new HashMap<>();
 	}
 
 	@Override

+ 2 - 2
platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java

@@ -41,12 +41,12 @@ import java.util.List;
 class Joystick {
 	int device_id;
 	String name;
-	List<Integer> axes = new ArrayList<Integer>();
+	List<Integer> axes = new ArrayList<>();
 	protected boolean hasAxisHat = false;
 	/*
 	 * Keep track of values so we can prevent flooding the engine with useless events.
 	 */
-	protected final SparseArray axesValues = new SparseArray<Float>(4);
+	protected final SparseArray<Float> axesValues = new SparseArray<>(4);
 	protected int hatX;
 	protected int hatY;
 }

+ 3 - 3
platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java

@@ -135,7 +135,7 @@ public abstract class GodotPlugin {
 		nativeRegisterSingleton(pluginName, pluginObject);
 
 		Set<Method> filteredMethods = new HashSet<>();
-		Class clazz = pluginObject.getClass();
+		Class<?> clazz = pluginObject.getClass();
 
 		Method[] methods = clazz.getDeclaredMethods();
 		for (Method method : methods) {
@@ -156,8 +156,8 @@ public abstract class GodotPlugin {
 		for (Method method : filteredMethods) {
 			List<String> ptr = new ArrayList<>();
 
-			Class[] paramTypes = method.getParameterTypes();
-			for (Class c : paramTypes) {
+			Class<?>[] paramTypes = method.getParameterTypes();
+			for (Class<?> c : paramTypes) {
 				ptr.add(c.getName());
 			}
 

+ 2 - 2
platform/android/java/lib/src/org/godotengine/godot/utils/Crypt.java

@@ -39,10 +39,10 @@ public class Crypt {
 			// Create MD5 Hash
 			MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
 			digest.update(input.getBytes());
-			byte messageDigest[] = digest.digest();
+			byte[] messageDigest = digest.digest();
 
 			// Create Hex String
-			StringBuffer hexString = new StringBuffer();
+			StringBuilder hexString = new StringBuilder();
 			for (int i = 0; i < messageDigest.length; i++)
 				hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
 			return hexString.toString();

+ 6 - 6
platform/windows/os_windows.cpp

@@ -3319,13 +3319,13 @@ String OS_Windows::get_config_path() const {
 	// The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well.
 	if (has_environment("XDG_CONFIG_HOME")) {
 		if (get_environment("XDG_CONFIG_HOME").is_abs_path()) {
-			return get_environment("XDG_CONFIG_HOME");
+			return get_environment("XDG_CONFIG_HOME").replace("\\", "/");
 		} else {
 			WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `%APPDATA%` or `.` per the XDG Base Directory specification.");
 		}
 	}
 	if (has_environment("APPDATA")) {
-		return get_environment("APPDATA");
+		return get_environment("APPDATA").replace("\\", "/");
 	}
 	return ".";
 }
@@ -3334,7 +3334,7 @@ String OS_Windows::get_data_path() const {
 	// The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well.
 	if (has_environment("XDG_DATA_HOME")) {
 		if (get_environment("XDG_DATA_HOME").is_abs_path()) {
-			return get_environment("XDG_DATA_HOME");
+			return get_environment("XDG_DATA_HOME").replace("\\", "/");
 		} else {
 			WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `get_config_path()` per the XDG Base Directory specification.");
 		}
@@ -3346,13 +3346,13 @@ String OS_Windows::get_cache_path() const {
 	// The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well.
 	if (has_environment("XDG_CACHE_HOME")) {
 		if (get_environment("XDG_CACHE_HOME").is_abs_path()) {
-			return get_environment("XDG_CACHE_HOME");
+			return get_environment("XDG_CACHE_HOME").replace("\\", "/");
 		} else {
 			WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `%TEMP%` or `get_config_path()` per the XDG Base Directory specification.");
 		}
 	}
 	if (has_environment("TEMP")) {
-		return get_environment("TEMP");
+		return get_environment("TEMP").replace("\\", "/");
 	}
 	return get_config_path();
 }
@@ -3395,7 +3395,7 @@ String OS_Windows::get_system_dir(SystemDir p_dir) const {
 	PWSTR szPath;
 	HRESULT res = SHGetKnownFolderPath(id, 0, NULL, &szPath);
 	ERR_FAIL_COND_V(res != S_OK, String());
-	String path = String(szPath);
+	String path = String(szPath).replace("\\", "/");
 	CoTaskMemFree(szPath);
 	return path;
 }

+ 12 - 12
platform/windows/windows_terminal_logger.cpp

@@ -108,47 +108,47 @@ void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file
 		SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY);
 		switch (p_type) {
 			case ERR_ERROR:
-				logf("ERROR:");
+				logf_error("ERROR:");
 				break;
 			case ERR_WARNING:
-				logf("WARNING:");
+				logf_error("WARNING:");
 				break;
 			case ERR_SCRIPT:
-				logf("SCRIPT ERROR:");
+				logf_error("SCRIPT ERROR:");
 				break;
 			case ERR_SHADER:
-				logf("SHADER ERROR:");
+				logf_error("SHADER ERROR:");
 				break;
 		}
 
 		SetConsoleTextAttribute(hCon, basecol);
 		if (p_rationale && p_rationale[0]) {
-			logf(" %s\n", p_rationale);
+			logf_error(" %s\n", p_rationale);
 		} else {
-			logf(" %s\n", p_code);
+			logf_error(" %s\n", p_code);
 		}
 
 		// `FOREGROUND_INTENSITY` alone results in gray text.
 		SetConsoleTextAttribute(hCon, FOREGROUND_INTENSITY);
 		switch (p_type) {
 			case ERR_ERROR:
-				logf("   at: ");
+				logf_error("   at: ");
 				break;
 			case ERR_WARNING:
-				logf("     at: ");
+				logf_error("     at: ");
 				break;
 			case ERR_SCRIPT:
-				logf("          at: ");
+				logf_error("          at: ");
 				break;
 			case ERR_SHADER:
-				logf("          at: ");
+				logf_error("          at: ");
 				break;
 		}
 
 		if (p_rationale && p_rationale[0]) {
-			logf("(%s:%i)\n", p_file, p_line);
+			logf_error("(%s:%i)\n", p_file, p_line);
 		} else {
-			logf("%s (%s:%i)\n", p_function, p_file, p_line);
+			logf_error("%s (%s:%i)\n", p_function, p_file, p_line);
 		}
 
 		SetConsoleTextAttribute(hCon, sbi.wAttributes);

+ 14 - 11
scene/2d/camera_2d.cpp

@@ -196,20 +196,23 @@ Transform2D Camera2D::get_camera_transform() {
 	}
 
 	Rect2 screen_rect(-screen_offset + ret_camera_pos, screen_size * zoom);
-	if (screen_rect.position.x < limit[MARGIN_LEFT]) {
-		screen_rect.position.x = limit[MARGIN_LEFT];
-	}
 
-	if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT]) {
-		screen_rect.position.x = limit[MARGIN_RIGHT] - screen_rect.size.x;
-	}
+	if (!limit_smoothing_enabled) {
+		if (screen_rect.position.x < limit[MARGIN_LEFT]) {
+			screen_rect.position.x = limit[MARGIN_LEFT];
+		}
 
-	if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM]) {
-		screen_rect.position.y = limit[MARGIN_BOTTOM] - screen_rect.size.y;
-	}
+		if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT]) {
+			screen_rect.position.x = limit[MARGIN_RIGHT] - screen_rect.size.x;
+		}
+
+		if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM]) {
+			screen_rect.position.y = limit[MARGIN_BOTTOM] - screen_rect.size.y;
+		}
 
-	if (screen_rect.position.y < limit[MARGIN_TOP]) {
-		screen_rect.position.y = limit[MARGIN_TOP];
+		if (screen_rect.position.y < limit[MARGIN_TOP]) {
+			screen_rect.position.y = limit[MARGIN_TOP];
+		}
 	}
 
 	if (offset != Vector2()) {

+ 1 - 1
scene/gui/split_container.cpp

@@ -38,7 +38,7 @@ Control *SplitContainer::_getch(int p_idx) const {
 
 	for (int i = 0; i < get_child_count(); i++) {
 		Control *c = Object::cast_to<Control>(get_child(i));
-		if (!c || !c->is_visible_in_tree()) {
+		if (!c || !c->is_visible()) {
 			continue;
 		}
 		if (c->is_set_as_toplevel()) {