summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes1
-rw-r--r--.gitignore6
-rw-r--r--SConstruct2
-rw-r--r--core/SCsub3
-rw-r--r--core/core_builders.py35
-rw-r--r--core/io/stream_peer_ssl.cpp57
-rw-r--r--core/io/stream_peer_ssl.h5
-rw-r--r--editor/SCsub4
-rw-r--r--editor/editor_about.cpp1
-rw-r--r--editor/editor_builders.py26
-rw-r--r--editor/editor_initialize_ssl.cpp48
-rw-r--r--editor/editor_initialize_ssl.h36
-rw-r--r--editor/editor_node.cpp2
-rw-r--r--editor/editor_settings.cpp5
-rw-r--r--editor/inspector_dock.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp16
-rw-r--r--editor/plugins/script_editor_plugin.cpp1
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp13
-rw-r--r--editor/project_manager.cpp3
-rw-r--r--editor/scene_tree_dock.cpp21
-rw-r--r--editor/script_create_dialog.cpp2
-rw-r--r--editor/settings_config_dialog.cpp6
-rw-r--r--main/main.cpp16
-rw-r--r--modules/gdscript/gdscript_parser.cpp2
-rwxr-xr-xmodules/mbedtls/stream_peer_mbed_tls.cpp8
-rw-r--r--modules/mono/glue/Managed/Files/Basis.cs32
-rw-r--r--modules/mono/glue/Managed/Files/Transform.cs19
-rw-r--r--platform/javascript/os_javascript.cpp52
-rw-r--r--platform/javascript/os_javascript.h1
-rw-r--r--platform/windows/SCsub1
-rw-r--r--platform/windows/godot.natvis129
31 files changed, 359 insertions, 196 deletions
diff --git a/.gitattributes b/.gitattributes
index 03c6f96f80..47ba2b45bb 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -9,3 +9,4 @@ drivers/* linguist-vendored
*.py eol=lf
*.hpp eol=lf
*.xml eol=lf
+*.natvis eol=lf
diff --git a/.gitignore b/.gitignore
index 6db75f2324..52937b8679 100644
--- a/.gitignore
+++ b/.gitignore
@@ -91,6 +91,9 @@ bld/
*.debug
*.dSYM
+# Visual Studio cache/options directory
+.vs/
+
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
@@ -98,9 +101,6 @@ bld/
# Hints for improving IntelliSense, created together with VS project
cpp.hint
-# Visualizers for the VS debugger
-*.natvis
-
#NUNIT
*.VisualState.xml
TestResult.xml
diff --git a/SConstruct b/SConstruct
index 3f3976555d..1c55e0be93 100644
--- a/SConstruct
+++ b/SConstruct
@@ -169,9 +169,11 @@ opts.Add(BoolVariable('progress', "Show a progress indicator during compilation"
opts.Add(BoolVariable('dev', "If yes, alias for verbose=yes warnings=all", False))
opts.Add(EnumVariable('macports_clang', "Build using Clang from MacPorts", 'no', ('no', '5.0', 'devel')))
opts.Add(BoolVariable('no_editor_splash', "Don't use the custom splash screen for the editor", False))
+opts.Add('system_certs_path', "Use this path as SSL certificates default for editor (for package maintainers)", '')
# Thirdparty libraries
opts.Add(BoolVariable('builtin_bullet', "Use the built-in Bullet library", True))
+opts.Add(BoolVariable('builtin_certs', "Bundle default SSL certificates to be used if you don't specify an override in the project settings", True))
opts.Add(BoolVariable('builtin_enet', "Use the built-in ENet library", True))
opts.Add(BoolVariable('builtin_freetype', "Use the built-in FreeType library", True))
opts.Add(BoolVariable('builtin_libogg', "Use the built-in libogg library", True))
diff --git a/core/SCsub b/core/SCsub
index a6365bf925..6746cc871a 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -93,6 +93,9 @@ if 'builtin_zstd' in env and env['builtin_zstd']:
# Godot's own sources
env.add_source_files(env.core_sources, "*.cpp")
+# Certificates
+env.Depends("#core/io/certs_compressed.gen.h", ["#thirdparty/certs/ca-certificates.crt", env.Value(env['builtin_certs']), env.Value(env['system_certs_path'])])
+env.CommandNoCache("#core/io/certs_compressed.gen.h", "#thirdparty/certs/ca-certificates.crt", run_in_subprocess(core_builders.make_certs_header))
# Make binders
env.CommandNoCache(['method_bind.gen.inc', 'method_bind_ext.gen.inc'], 'make_binders.py', run_in_subprocess(make_binders.run))
diff --git a/core/core_builders.py b/core/core_builders.py
index 90e505aab9..f3a9e3b221 100644
--- a/core/core_builders.py
+++ b/core/core_builders.py
@@ -4,7 +4,40 @@ All such functions are invoked in a subprocess on Windows to prevent build flaki
"""
from platform_methods import subprocess_main
-from compat import iteritems, itervalues, open_utf8, escape_string
+from compat import iteritems, itervalues, open_utf8, escape_string, byte_to_str
+
+
+def make_certs_header(target, source, env):
+
+ src = source[0]
+ dst = target[0]
+ f = open(src, "rb")
+ g = open_utf8(dst, "w")
+ buf = f.read()
+ decomp_size = len(buf)
+ import zlib
+ buf = zlib.compress(buf)
+
+ g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
+ g.write("#ifndef _CERTS_RAW_H\n")
+ g.write("#define _CERTS_RAW_H\n")
+
+ # System certs path. Editor will use them if defined. (for package maintainers)
+ path = env['system_certs_path']
+ g.write("#define _SYSTEM_CERTS_PATH \"%s\"\n" % str(path))
+ if env['builtin_certs']:
+ # Defined here and not in env so changing it does not trigger a full rebuild.
+ g.write("#define BUILTIN_CERTS_ENABLED\n")
+ g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n")
+ g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n")
+ g.write("static const unsigned char _certs_compressed[] = {\n")
+ for i in range(len(buf)):
+ g.write("\t" + byte_to_str(buf[i]) + ",\n")
+ g.write("};\n")
+ g.write("#endif")
+
+ g.close()
+ f.close()
def make_authors_header(target, source, env):
diff --git a/core/io/stream_peer_ssl.cpp b/core/io/stream_peer_ssl.cpp
index 1f59021938..8d8682686a 100644
--- a/core/io/stream_peer_ssl.cpp
+++ b/core/io/stream_peer_ssl.cpp
@@ -30,6 +30,8 @@
#include "stream_peer_ssl.h"
+#include "core/io/certs_compressed.gen.h"
+#include "core/io/compression.h"
#include "core/os/file_access.h"
#include "core/project_settings.h"
@@ -42,13 +44,20 @@ StreamPeerSSL *StreamPeerSSL::create() {
StreamPeerSSL::LoadCertsFromMemory StreamPeerSSL::load_certs_func = NULL;
bool StreamPeerSSL::available = false;
-bool StreamPeerSSL::initialize_certs = true;
void StreamPeerSSL::load_certs_from_memory(const PoolByteArray &p_memory) {
if (load_certs_func)
load_certs_func(p_memory);
}
+void StreamPeerSSL::load_certs_from_file(String p_path) {
+ if (p_path != "") {
+ PoolByteArray certs = get_cert_file_as_array(p_path);
+ if (certs.size() > 0)
+ load_certs_func(certs);
+ }
+}
+
bool StreamPeerSSL::is_available() {
return available;
}
@@ -61,6 +70,25 @@ bool StreamPeerSSL::is_blocking_handshake_enabled() const {
return blocking_handshake;
}
+PoolByteArray StreamPeerSSL::get_cert_file_as_array(String p_path) {
+
+ PoolByteArray out;
+ FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
+ if (f) {
+ int flen = f->get_len();
+ out.resize(flen + 1);
+ PoolByteArray::Write w = out.write();
+ f->get_buffer(w.ptr(), flen);
+ w[flen] = 0; // Make sure it ends with string terminator
+ memdelete(f);
+#ifdef DEBUG_ENABLED
+ print_verbose(vformat("Loaded certs from '%s'.", p_path));
+#endif
+ }
+
+ return out;
+}
+
PoolByteArray StreamPeerSSL::get_project_cert_array() {
PoolByteArray out;
@@ -68,24 +96,21 @@ PoolByteArray StreamPeerSSL::get_project_cert_array() {
ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/certificates", PropertyInfo(Variant::STRING, "network/ssl/certificates", PROPERTY_HINT_FILE, "*.crt"));
if (certs_path != "") {
-
- FileAccess *f = FileAccess::open(certs_path, FileAccess::READ);
- if (f) {
- int flen = f->get_len();
- out.resize(flen + 1);
- {
- PoolByteArray::Write w = out.write();
- f->get_buffer(w.ptr(), flen);
- w[flen] = 0; //end f string
- }
-
- memdelete(f);
-
+ // Use certs defined in project settings.
+ return get_cert_file_as_array(certs_path);
+ }
+#ifdef BUILTIN_CERTS_ENABLED
+ else {
+ // Use builtin certs only if user did not override it in project settings.
+ out.resize(_certs_uncompressed_size + 1);
+ PoolByteArray::Write w = out.write();
+ Compression::decompress(w.ptr(), _certs_uncompressed_size, _certs_compressed, _certs_compressed_size, Compression::MODE_DEFLATE);
+ w[_certs_uncompressed_size] = 0; // Make sure it ends with string terminator
#ifdef DEBUG_ENABLED
- print_verbose(vformat("Loaded certs from '%s'.", certs_path));
+ print_verbose("Loaded builtin certs");
#endif
- }
}
+#endif
return out;
}
diff --git a/core/io/stream_peer_ssl.h b/core/io/stream_peer_ssl.h
index f66c1c7de9..8ce36d7e7d 100644
--- a/core/io/stream_peer_ssl.h
+++ b/core/io/stream_peer_ssl.h
@@ -46,9 +46,6 @@ protected:
static LoadCertsFromMemory load_certs_func;
static bool available;
- friend class Main;
- static bool initialize_certs;
-
bool blocking_handshake;
public:
@@ -72,7 +69,9 @@ public:
static StreamPeerSSL *create();
+ static PoolByteArray get_cert_file_as_array(String p_path);
static PoolByteArray get_project_cert_array();
+ static void load_certs_from_file(String p_path);
static void load_certs_from_memory(const PoolByteArray &p_memory);
static bool is_available();
diff --git a/editor/SCsub b/editor/SCsub
index 6a4b06a97a..82b982eef2 100644
--- a/editor/SCsub
+++ b/editor/SCsub
@@ -61,10 +61,6 @@ if env['tools']:
env.Depends("#editor/doc_data_compressed.gen.h", docs)
env.CommandNoCache("#editor/doc_data_compressed.gen.h", docs, run_in_subprocess(editor_builders.make_doc_header))
- # Certificates
- env.Depends("#editor/certs_compressed.gen.h", "#thirdparty/certs/ca-certificates.crt")
- env.CommandNoCache("#editor/certs_compressed.gen.h", "#thirdparty/certs/ca-certificates.crt", run_in_subprocess(editor_builders.make_certs_header))
-
import glob
path = env.Dir('.').abspath
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index e4602f0f94..cdf0e4b829 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -113,7 +113,6 @@ ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<St
EditorAbout::EditorAbout() {
set_title(TTR("Thanks from the Godot community!"));
- get_ok()->set_text(TTR("OK"));
set_hide_on_ok(true);
set_resizable(true);
diff --git a/editor/editor_builders.py b/editor/editor_builders.py
index fa037980c2..9e9fe752b4 100644
--- a/editor/editor_builders.py
+++ b/editor/editor_builders.py
@@ -9,32 +9,6 @@ from platform_methods import subprocess_main
from compat import encode_utf8, byte_to_str, open_utf8, escape_string
-def make_certs_header(target, source, env):
-
- src = source[0]
- dst = target[0]
- f = open(src, "rb")
- g = open_utf8(dst, "w")
- buf = f.read()
- decomp_size = len(buf)
- import zlib
- buf = zlib.compress(buf)
-
- g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
- g.write("#ifndef _CERTS_RAW_H\n")
- g.write("#define _CERTS_RAW_H\n")
- g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n")
- g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n")
- g.write("static const unsigned char _certs_compressed[] = {\n")
- for i in range(len(buf)):
- g.write("\t" + byte_to_str(buf[i]) + ",\n")
- g.write("};\n")
- g.write("#endif")
-
- g.close()
- f.close()
-
-
def make_doc_header(target, source, env):
dst = target[0]
diff --git a/editor/editor_initialize_ssl.cpp b/editor/editor_initialize_ssl.cpp
deleted file mode 100644
index 9f7537cc9a..0000000000
--- a/editor/editor_initialize_ssl.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*************************************************************************/
-/* editor_initialize_ssl.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "editor_initialize_ssl.h"
-
-#include "certs_compressed.gen.h"
-#include "core/io/compression.h"
-#include "core/io/stream_peer_ssl.h"
-
-void editor_initialize_certificates() {
-
- PoolByteArray data;
- data.resize(_certs_uncompressed_size + 1);
- {
- PoolByteArray::Write w = data.write();
- Compression::decompress(w.ptr(), _certs_uncompressed_size, _certs_compressed, _certs_compressed_size, Compression::MODE_DEFLATE);
- w[_certs_uncompressed_size] = 0; //make sure it ends at zero
- }
-
- StreamPeerSSL::load_certs_from_memory(data);
-}
diff --git a/editor/editor_initialize_ssl.h b/editor/editor_initialize_ssl.h
deleted file mode 100644
index 71d16b8c53..0000000000
--- a/editor/editor_initialize_ssl.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*************************************************************************/
-/* editor_initialize_ssl.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef EDITOR_INITIALIZE_SSL_H
-#define EDITOR_INITIALIZE_SSL_H
-
-void editor_initialize_certificates();
-
-#endif // EDITOR_INITIALIZE_SSL_H
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index d8e6f711ff..0ba1ef3b18 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -54,7 +54,6 @@
#include "editor/editor_audio_buses.h"
#include "editor/editor_file_system.h"
#include "editor/editor_help.h"
-#include "editor/editor_initialize_ssl.h"
#include "editor/editor_properties.h"
#include "editor/editor_settings.h"
#include "editor/editor_themes.h"
@@ -4686,7 +4685,6 @@ EditorNode::EditorNode() {
SceneState::set_disable_placeholders(true);
ResourceLoader::clear_translation_remaps(); //no remaps using during editor
ResourceLoader::clear_path_remaps();
- editor_initialize_certificates(); //for asset sharing
InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 5d3c6dd087..3e959731fc 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -30,6 +30,7 @@
#include "editor_settings.h"
+#include "core/io/certs_compressed.gen.h"
#include "core/io/compression.h"
#include "core/io/config_file.h"
#include "core/io/file_access_memory.h"
@@ -947,6 +948,10 @@ void EditorSettings::setup_network() {
_initial_set("network/debug/remote_port", port);
add_property_hint(PropertyInfo(Variant::INT, "network/debug/remote_port", PROPERTY_HINT_RANGE, "1,65535,1"));
+
+ // Editor SSL certificates override
+ _initial_set("network/ssl/editor_ssl_certificates", _SYSTEM_CERTS_PATH);
+ add_property_hint(PropertyInfo(Variant::STRING, "network/ssl/editor_ssl_certificates", PROPERTY_HINT_GLOBAL_FILE, "*.crt,*.pem"));
}
void EditorSettings::save() {
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index 5ab764fb15..16cba1db77 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -158,7 +158,6 @@ void InspectorDock::_resource_file_selected(String p_file) {
RES res = ResourceLoader::load(p_file);
if (res.is_null()) {
- warning_dialog->get_ok()->set_text(TTR("OK"));
warning_dialog->set_text(TTR("Failed to load resource."));
return;
};
@@ -319,7 +318,6 @@ void InspectorDock::_transform_keyed(Object *sp, const String &p_sub, const Tran
}
void InspectorDock::_warning_pressed() {
- warning_dialog->get_ok()->set_text(TTR("Ok"));
warning_dialog->popup_centered_minsize();
}
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 34159964a5..79578989d5 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -4412,13 +4412,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
move_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/move_mode", TTR("Move Mode"), KEY_W));
move_button->set_tooltip(TTR("Move Mode"));
- scale_button = memnew(ToolButton);
- hb->add_child(scale_button);
- scale_button->set_toggle_mode(true);
- scale_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_SCALE));
- scale_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/scale_mode", TTR("Scale Mode"), KEY_S));
- scale_button->set_tooltip(TTR("Scale Mode"));
-
rotate_button = memnew(ToolButton);
hb->add_child(rotate_button);
rotate_button->set_toggle_mode(true);
@@ -4426,6 +4419,13 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
rotate_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/rotate_mode", TTR("Rotate Mode"), KEY_E));
rotate_button->set_tooltip(TTR("Rotate Mode"));
+ scale_button = memnew(ToolButton);
+ hb->add_child(scale_button);
+ scale_button->set_toggle_mode(true);
+ scale_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_SCALE));
+ scale_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/scale_mode", TTR("Scale Mode"), KEY_S));
+ scale_button->set_tooltip(TTR("Scale Mode"));
+
hb->add_child(memnew(VSeparator));
list_select_button = memnew(ToolButton);
@@ -4917,7 +4917,6 @@ void CanvasItemEditorViewport::_perform_drop_data() {
// Without root dropping multiple files is not allowed
if (!target_node && selected_files.size() > 1) {
- accept->get_ok()->set_text(TTR("Ok"));
accept->set_text(TTR("Cannot instantiate multiple nodes without root."));
accept->popup_centered_minsize();
return;
@@ -4979,7 +4978,6 @@ void CanvasItemEditorViewport::_perform_drop_data() {
files_str += error_files[i].get_file().get_basename() + ",";
}
files_str = files_str.substr(0, files_str.length() - 1);
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str()));
accept->popup_centered_minsize();
}
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index e155daa2fa..c8e7bfb74b 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -3133,7 +3133,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
error_dialog = memnew(AcceptDialog);
add_child(error_dialog);
- error_dialog->get_ok()->set_text(TTR("OK"));
debugger = memnew(ScriptEditorDebugger(editor));
debugger->connect("goto_script_line", this, "_goto_script_line");
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index c2554acd49..6df026843a 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -3267,7 +3267,6 @@ void SpatialEditorViewport::_perform_drop_data() {
files_str += error_files[i].get_file().get_basename() + ",";
}
files_str = files_str.substr(0, files_str.length() - 1);
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str()));
accept->popup_centered_minsize();
}
@@ -3348,7 +3347,6 @@ void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p
if (root_node) {
list.push_back(root_node);
} else {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("No parent to instance a child at."));
accept->popup_centered_minsize();
_remove_preview();
@@ -3356,7 +3354,6 @@ void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p
}
}
if (list.size() != 1) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation requires a single selected node."));
accept->popup_centered_minsize();
_remove_preview();
@@ -5286,6 +5283,8 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds);
tool_button[TOOL_MODE_SELECT]->set_tooltip(TTR("Select Mode (Q)") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection"));
+ hbc_menu->add_child(memnew(VSeparator));
+
tool_button[TOOL_MODE_MOVE] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_MODE_MOVE]);
tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true);
@@ -5310,6 +5309,8 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_SCALE]->connect("pressed", this, "_menu_item_pressed", button_binds);
tool_button[TOOL_MODE_SCALE]->set_tooltip(TTR("Scale Mode (R)"));
+ hbc_menu->add_child(memnew(VSeparator));
+
tool_button[TOOL_MODE_LIST_SELECT] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_MODE_LIST_SELECT]);
tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true);
@@ -5330,8 +5331,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds);
tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock the selected object (can be moved)."));
- VSeparator *vs = memnew(VSeparator);
- hbc_menu->add_child(vs);
+ hbc_menu->add_child(memnew(VSeparator));
tool_option_button[TOOL_OPT_LOCAL_COORDS] = memnew(ToolButton);
hbc_menu->add_child(tool_option_button[TOOL_OPT_LOCAL_COORDS]);
@@ -5353,8 +5353,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
sct = ED_GET_SHORTCUT("spatial_editor/snap").ptr()->get_as_text();
tool_option_button[TOOL_OPT_USE_SNAP]->set_tooltip(vformat(TTR("Snap Mode (%s)"), sct));
- vs = memnew(VSeparator);
- hbc_menu->add_child(vs);
+ hbc_menu->add_child(memnew(VSeparator));
// Drag and drop support;
preview_node = memnew(Spatial);
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index f494c84efa..91ab5b4dff 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -41,7 +41,6 @@
#include "core/translation.h"
#include "core/version.h"
#include "core/version_hash.gen.h"
-#include "editor_initialize_ssl.h"
#include "editor_scale.h"
#include "editor_settings.h"
#include "editor_themes.h"
@@ -2059,8 +2058,6 @@ void ProjectListFilter::_bind_methods() {
ProjectListFilter::ProjectListFilter() {
- editor_initialize_certificates(); //for asset sharing
-
_current_filter = FILTER_NAME;
filter_option = memnew(OptionButton);
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index af6b998b28..8637417598 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -119,7 +119,6 @@ void SceneTreeDock::instance(const String &p_file) {
if (!edited_scene) {
current_option = -1;
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("No parent to instance a child at."));
accept->popup_centered_minsize();
return;
@@ -142,7 +141,6 @@ void SceneTreeDock::instance_scenes(const Vector<String> &p_files, Node *p_paren
if (!parent || !edited_scene) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("No parent to instance the scenes at."));
accept->popup_centered_minsize();
return;
@@ -164,7 +162,6 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node
Ref<PackedScene> sdata = ResourceLoader::load(p_files[i]);
if (!sdata.is_valid()) {
current_option = -1;
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(vformat(TTR("Error loading scene from %s"), p_files[i]));
accept->popup_centered_minsize();
error = true;
@@ -174,7 +171,6 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node
Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
if (!instanced_scene) {
current_option = -1;
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(vformat(TTR("Error instancing scene from %s"), p_files[i]));
accept->popup_centered_minsize();
error = true;
@@ -185,7 +181,6 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node
if (_cyclical_dependency_exists(edited_scene->get_filename(), instanced_scene)) {
- accept->get_ok()->set_text(TTR("Ok"));
accept->set_text(vformat(TTR("Cannot instance the scene '%s' because the current scene exists within one of its nodes."), p_files[i]));
accept->popup_centered_minsize();
error = true;
@@ -233,7 +228,6 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node
void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) {
Ref<PackedScene> sdata = ResourceLoader::load(p_file);
if (!sdata.is_valid()) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(vformat(TTR("Error loading scene from %s"), p_file));
accept->popup_centered_minsize();
return;
@@ -241,7 +235,6 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base)
Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
if (!instanced_scene) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(vformat(TTR("Error instancing scene from %s"), p_file));
accept->popup_centered_minsize();
return;
@@ -416,7 +409,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (scene_tree->get_selected() == edited_scene) {
current_option = -1;
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation can't be done on the tree root."));
accept->popup_centered_minsize();
break;
@@ -477,7 +469,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (editor_selection->is_selected(edited_scene)) {
current_option = -1;
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation can't be done on the tree root."));
accept->popup_centered_minsize();
break;
@@ -547,7 +538,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (editor_selection->is_selected(edited_scene)) {
current_option = -1;
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation can't be done on the tree root."));
accept->popup_centered_minsize();
break;
@@ -634,7 +624,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *scene = editor_data->get_edited_scene_root();
if (!scene) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation can't be done without a scene."));
accept->popup_centered_minsize();
break;
@@ -643,7 +632,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
List<Node *> selection = editor_selection->get_selected_node_list();
if (selection.size() != 1) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation requires a single selected node."));
accept->popup_centered_minsize();
break;
@@ -652,14 +640,12 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *tocopy = selection.front()->get();
if (tocopy == scene) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Can not perform with the root node."));
accept->popup_centered_minsize();
break;
}
if (tocopy != editor_data->get_edited_scene_root() && tocopy->get_filename() != "") {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation can't be done on instanced scenes."));
accept->popup_centered_minsize();
break;
@@ -1304,7 +1290,6 @@ bool SceneTreeDock::_validate_no_foreign() {
if (E->get() != edited_scene && E->get()->get_owner() != edited_scene) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Can't operate on nodes from a foreign scene!"));
accept->popup_centered_minsize();
return false;
@@ -1312,7 +1297,6 @@ bool SceneTreeDock::_validate_no_foreign() {
if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E->get())) >= 0) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Can't operate on nodes the current scene inherits from!"));
accept->popup_centered_minsize();
return false;
@@ -1792,14 +1776,12 @@ void SceneTreeDock::_new_scene_from(String p_file) {
List<Node *> selection = editor_selection->get_selected_node_list();
if (selection.size() != 1) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation requires a single selected node."));
accept->popup_centered_minsize();
return;
}
if (EditorNode::get_singleton()->is_scene_open(p_file)) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Can't overwrite scene that is still open!"));
accept->popup_centered_minsize();
return;
@@ -1817,7 +1799,6 @@ void SceneTreeDock::_new_scene_from(String p_file) {
memdelete(copy);
if (err != OK) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Couldn't save new scene. Likely dependencies (instances) couldn't be satisfied."));
accept->popup_centered_minsize();
return;
@@ -1829,14 +1810,12 @@ void SceneTreeDock::_new_scene_from(String p_file) {
err = ResourceSaver::save(p_file, sdata, flg);
if (err != OK) {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Error saving scene."));
accept->popup_centered_minsize();
return;
}
_replace_with_branch_scene(p_file, base);
} else {
- accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Error duplicating scene to save it."));
accept->popup_centered_minsize();
return;
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index be255ba4aa..d8de775d36 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -164,7 +164,6 @@ void ScriptCreateDialog::_create_new() {
if (script_template != "") {
scr = ResourceLoader::load(script_template);
if (scr.is_null()) {
- alert->get_ok()->set_text(TTR("OK"));
alert->set_text(vformat(TTR("Error loading template '%s'"), script_template));
alert->popup_centered();
return;
@@ -201,7 +200,6 @@ void ScriptCreateDialog::_load_exist() {
String path = file_path->get_text();
RES p_script = ResourceLoader::load(path, "Script");
if (p_script.is_null()) {
- alert->get_ok()->set_text(TTR("OK"));
alert->set_text(vformat(TTR("Error loading script from %s"), path));
alert->popup_centered();
return;
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index 97cdd43fee..fe384da75b 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -56,11 +56,7 @@ void EditorSettingsDialog::_settings_property_edited(const String &p_name) {
String full_name = inspector->get_full_item_path(p_name);
- // Small usability workaround to update the text color settings when the
- // color theme is changed
- if (full_name == "text_editor/theme/color_theme") {
- inspector->get_inspector()->update_tree();
- } else if (full_name == "interface/theme/accent_color" || full_name == "interface/theme/base_color" || full_name == "interface/theme/contrast") {
+ if (full_name == "interface/theme/accent_color" || full_name == "interface/theme/base_color" || full_name == "interface/theme/contrast") {
EditorSettings::get_singleton()->set_manually("interface/theme/preset", "Custom"); // set preset to Custom
} else if (full_name.begins_with("text_editor/highlighting")) {
EditorSettings::get_singleton()->set_manually("text_editor/theme/color_theme", "Custom");
diff --git a/main/main.cpp b/main/main.cpp
index 90d4db2948..db82ff8f6e 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -73,6 +73,7 @@
#include "editor/doc/doc_data.h"
#include "editor/doc/doc_data_class_path.gen.h"
#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
#include "editor/project_manager.h"
#endif
@@ -756,7 +757,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (editor) {
packed_data->set_disabled(true);
globals->set_disable_feature_overrides(true);
- StreamPeerSSL::initialize_certs = false; //will be initialized by editor
}
#endif
@@ -1595,6 +1595,7 @@ bool Main::start() {
sml->set_use_font_oversampling(font_oversampling);
} else {
+
GLOBAL_DEF("display/window/stretch/mode", "disabled");
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/mode", PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,2d,viewport"));
GLOBAL_DEF("display/window/stretch/aspect", "ignore");
@@ -1654,6 +1655,10 @@ bool Main::start() {
}
if (!project_manager && !editor) { // game
+
+ // Load SSL Certificates from Project Settings (or builtin)
+ StreamPeerSSL::load_certs_from_memory(StreamPeerSSL::get_project_cert_array());
+
if (game_path != "") {
Node *scene = NULL;
Ref<PackedScene> scenedata = ResourceLoader::load(local_game_path);
@@ -1686,6 +1691,15 @@ bool Main::start() {
sml->get_root()->add_child(pmanager);
OS::get_singleton()->set_context(OS::CONTEXT_PROJECTMAN);
}
+
+ if (project_manager || editor) {
+ // Load SSL Certificates from Editor Settings (or builtin)
+ String certs = EditorSettings::get_singleton()->get_setting("network/ssl/editor_ssl_certificates").operator String();
+ if (certs != "")
+ StreamPeerSSL::load_certs_from_file(certs);
+ else
+ StreamPeerSSL::load_certs_from_memory(StreamPeerSSL::get_project_cert_array());
+ }
#endif
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 89e102a858..81652c3d37 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -4443,7 +4443,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
continue;
} break;
case GDScriptTokenizer::TK_PR_SLAVE:
+#ifdef DEBUG_ENABLED
_add_warning(GDScriptWarning::DEPRECATED_KEYWORD, tokenizer->get_token_line(), "slave", "puppet");
+#endif
case GDScriptTokenizer::TK_PR_PUPPET: {
//may be fallthrough from export, ignore if so
diff --git a/modules/mbedtls/stream_peer_mbed_tls.cpp b/modules/mbedtls/stream_peer_mbed_tls.cpp
index 3398957775..3c04254fd4 100755
--- a/modules/mbedtls/stream_peer_mbed_tls.cpp
+++ b/modules/mbedtls/stream_peer_mbed_tls.cpp
@@ -317,15 +317,13 @@ void StreamPeerMbedTLS::initialize_ssl() {
mbedtls_debug_set_threshold(1);
#endif
- PoolByteArray cert_array = StreamPeerSSL::get_project_cert_array();
-
- if (cert_array.size() > 0)
- _load_certs(cert_array);
-
available = true;
}
void StreamPeerMbedTLS::finalize_ssl() {
+ available = false;
+ _create = NULL;
+ load_certs_func = NULL;
mbedtls_x509_crt_free(&cacert);
}
diff --git a/modules/mono/glue/Managed/Files/Basis.cs b/modules/mono/glue/Managed/Files/Basis.cs
index ec96a9e2fa..a5618cb28d 100644
--- a/modules/mono/glue/Managed/Files/Basis.cs
+++ b/modules/mono/glue/Managed/Files/Basis.cs
@@ -165,6 +165,38 @@ namespace Godot
);
}
+ internal Quat RotationQuat()
+ {
+ Basis orthonormalizedBasis = Orthonormalized();
+ real_t det = orthonormalizedBasis.Determinant();
+ if (det < 0)
+ {
+ // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles.
+ orthonormalizedBasis = orthonormalizedBasis.Scaled(Vector3.NegOne);
+ }
+
+ return orthonormalizedBasis.Quat();
+ }
+
+ internal void SetQuantScale(Quat quat, Vector3 scale)
+ {
+ SetDiagonal(scale);
+ Rotate(quat);
+ }
+
+ private void Rotate(Quat quat)
+ {
+ this *= new Basis(quat);
+ }
+
+ private void SetDiagonal(Vector3 diagonal)
+ {
+ _x = new Vector3(diagonal.x, 0, 0);
+ _y = new Vector3(0, diagonal.y, 0);
+ _z = new Vector3(0, 0, diagonal.z);
+
+ }
+
public real_t Determinant()
{
return this[0, 0] * (this[1, 1] * this[2, 2] - this[2, 1] * this[1, 2]) -
diff --git a/modules/mono/glue/Managed/Files/Transform.cs b/modules/mono/glue/Managed/Files/Transform.cs
index e432d5b52c..068007d7f0 100644
--- a/modules/mono/glue/Managed/Files/Transform.cs
+++ b/modules/mono/glue/Managed/Files/Transform.cs
@@ -20,6 +20,25 @@ namespace Godot
return new Transform(basisInv, basisInv.Xform(-origin));
}
+ public Transform InterpolateWith(Transform transform, real_t c)
+ {
+ /* not sure if very "efficient" but good enough? */
+
+ Vector3 sourceScale = basis.Scale;
+ Quat sourceRotation = basis.RotationQuat();
+ Vector3 sourceLocation = origin;
+
+ Vector3 destinationScale = transform.basis.Scale;
+ Quat destinationRotation = transform.basis.RotationQuat();
+ Vector3 destinationLocation = transform.origin;
+
+ var interpolated = new Transform();
+ interpolated.basis.SetQuantScale(sourceRotation.Slerp(destinationRotation, c).Normalized(), sourceScale.LinearInterpolate(destinationScale, c));
+ interpolated.origin = sourceLocation.LinearInterpolate(destinationLocation, c);
+
+ return interpolated;
+ }
+
public Transform Inverse()
{
Basis basisTr = basis.Transposed();
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 3515eeeb60..b0ec3c4245 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -39,6 +39,7 @@
#include "unix/file_access_unix.h"
#include <emscripten.h>
+#include <png.h>
#include <stdlib.h>
#include "dom_keys.inc"
@@ -912,6 +913,57 @@ void OS_JavaScript::set_window_title(const String &p_title) {
/* clang-format on */
}
+void OS_JavaScript::set_icon(const Ref<Image> &p_icon) {
+
+ ERR_FAIL_COND(p_icon.is_null());
+ Ref<Image> icon = p_icon;
+ if (icon->is_compressed()) {
+ icon = icon->duplicate();
+ ERR_FAIL_COND(icon->decompress() != OK)
+ }
+ if (icon->get_format() != Image::FORMAT_RGBA8) {
+ if (icon == p_icon)
+ icon = icon->duplicate();
+ icon->convert(Image::FORMAT_RGBA8);
+ }
+
+ png_image png_meta;
+ memset(&png_meta, 0, sizeof png_meta);
+ png_meta.version = PNG_IMAGE_VERSION;
+ png_meta.width = icon->get_width();
+ png_meta.height = icon->get_height();
+ png_meta.format = PNG_FORMAT_RGBA;
+
+ PoolByteArray png;
+ size_t len;
+ PoolByteArray::Read r = icon->get_data().read();
+ ERR_FAIL_COND(!png_image_write_get_memory_size(png_meta, len, 0, r.ptr(), 0, NULL));
+
+ png.resize(len);
+ PoolByteArray::Write w = png.write();
+ ERR_FAIL_COND(!png_image_write_to_memory(&png_meta, w.ptr(), &len, 0, r.ptr(), 0, NULL));
+ w = PoolByteArray::Write();
+
+ r = png.read();
+ /* clang-format off */
+ EM_ASM_ARGS({
+ var PNG_PTR = $0;
+ var PNG_LEN = $1;
+
+ var png = new Blob([HEAPU8.slice(PNG_PTR, PNG_PTR + PNG_LEN)], { type: "image/png" });
+ var url = URL.createObjectURL(png);
+ var link = document.getElementById('-gd-engine-icon');
+ if (link === null) {
+ link = document.createElement('link');
+ link.rel = 'icon';
+ link.id = '-gd-engine-icon';
+ document.head.appendChild(link);
+ }
+ link.href = url;
+ }, r.ptr(), len);
+ /* clang-format on */
+}
+
String OS_JavaScript::get_executable_path() const {
return OS::get_executable_path();
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index f40fb8fc7e..ddcbf8c7c9 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -135,6 +135,7 @@ public:
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
virtual void set_window_title(const String &p_title);
+ virtual void set_icon(const Ref<Image> &p_icon);
String get_executable_path() const;
virtual Error shell_open(String p_uri);
virtual String get_name();
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 586533e817..5dfb1592e0 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -29,6 +29,7 @@ prog = env.add_program('#bin/godot', common_win + res_obj, PROGSUFFIX=env["PROGS
# Microsoft Visual Studio Project Generation
if env['vsproj']:
env.vs_srcs = env.vs_srcs + ["platform/windows/" + res_file]
+ env.vs_srcs = env.vs_srcs + ["platform/windows/godot.natvis"]
for x in common_win:
env.vs_srcs = env.vs_srcs + ["platform/windows/" + str(x)]
diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis
new file mode 100644
index 0000000000..01963035a1
--- /dev/null
+++ b/platform/windows/godot.natvis
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
+ <Type Name="Vector&lt;*&gt;">
+ <Expand>
+ <Item Name="size">(_cowdata &amp;&amp; _cowdata-&gt;_ptr) ? (((const unsigned int *)(_cowdata-&gt;_ptr))[-1]) : 0</Item>
+ <ArrayItems>
+ <Size>(_cowdata &amp;&amp; _cowdata-&gt;_ptr) ? (((const unsigned int *)(_cowdata-&gt;_ptr))[-1]) : 0</Size>
+ <ValuePointer>(_cowdata) ? (_cowdata-&gt;_ptr) : 0</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="PoolVector&lt;*&gt;">
+ <Expand>
+ <Item Name="size">alloc ? (alloc-&gt;size / sizeof($T1)) : 0</Item>
+ <ArrayItems>
+ <Size>alloc ? (alloc-&gt;size / sizeof($T1)) : 0</Size>
+ <ValuePointer>alloc ? (($T1 *)alloc-&gt;mem) : 0</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="Variant">
+ <DisplayString Condition="this-&gt;type == Variant::NIL">nil</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::BOOL">{_data._bool}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::INT">{_data._int}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::REAL">{_data._real}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::TRANSFORM2D">{_data._transform2d}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::AABB">{_data._aabb}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::BASIS">{_data._basis}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::TRANSFORM">{_data._transform}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::ARRAY">{*(Array *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::STRING &amp;&amp; ((String *)(&amp;_data._mem[0]))-&gt;_cowdata._ptr == 0">""</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::STRING &amp;&amp; ((String *)(&amp;_data._mem[0]))-&gt;_cowdata._ptr != 0">{((String *)(&amp;_data._mem[0]))-&gt;_cowdata._ptr,su}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::VECTOR2">{*(Vector2 *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::RECT2">{*(Rect2 *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::VECTOR3">{*(Vector3 *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::PLANE">{*(Plane *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::QUAT">{*(Quat *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::COLOR">{*(Color *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::NODE_PATH">{*(NodePath *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::_RID">{*(RID *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::OBJECT">{*(Object *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::DICTIONARY">{*(Dictionary *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::ARRAY">{*(Array *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::POOL_BYTE_ARRAY">{*(PoolByteArray *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::POOL_INT_ARRAY">{*(PoolIntArray *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::POOL_REAL_ARRAY">{*(PoolRealArray *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::POOL_STRING_ARRAY">{*(PoolStringArray *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::POOL_VECTOR2_ARRAY">{*(PoolVector2Array *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::POOL_VECTOR3_ARRAY">{*(PoolVector3Array *)_data._mem}</DisplayString>
+ <DisplayString Condition="this-&gt;type == Variant::POOL_COLOR_ARRAY">{*(PoolColorArray *)_data._mem}</DisplayString>
+
+ <StringView Condition="this-&gt;type == Variant::STRING &amp;&amp; ((String *)(&amp;_data._mem[0]))-&gt;_cowdata._ptr != 0">((String *)(&amp;_data._mem[0]))-&gt;_cowdata._ptr,su</StringView>
+
+ <Expand>
+ <Item Name="value" Condition="this-&gt;type == Variant::BOOL">_data._bool</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::INT">_data._int</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::REAL">_data._real</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::TRANSFORM2D">_data._transform2d</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::AABB">_data._aabb</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::BASIS">_data._basis</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::TRANSFORM">_data._transform</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::ARRAY">*(Array *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::STRING">*(String *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::VECTOR2">*(Vector2 *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::RECT2">*(Rect2 *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::VECTOR3">*(Vector3 *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::PLANE">*(Plane *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::QUAT">*(Quat *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::COLOR">*(Color *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::NODE_PATH">*(NodePath *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::_RID">*(RID *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::OBJECT">*(Object *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::DICTIONARY">*(Dictionary *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::ARRAY">*(Array *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::POOL_BYTE_ARRAY">*(PoolByteArray *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::POOL_INT_ARRAY">*(PoolIntArray *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::POOL_REAL_ARRAY">*(PoolRealArray *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::POOL_STRING_ARRAY">*(PoolStringArray *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::POOL_VECTOR2_ARRAY">*(PoolVector2Array *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::POOL_VECTOR3_ARRAY">*(PoolVector3Array *)_data._mem</Item>
+ <Item Name="value" Condition="this-&gt;type == Variant::POOL_COLOR_ARRAY">*(PoolColorArray *)_data._mem</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="String">
+ <DisplayString Condition="this-&gt;_cowdata._ptr == 0">empty</DisplayString>
+ <DisplayString Condition="this-&gt;_cowdata._ptr != 0">{this->_cowdata._ptr,su}</DisplayString>
+ <StringView Condition="this-&gt;_cowdata._ptr != 0">this->_cowdata._ptr,su</StringView>
+ </Type>
+
+ <Type Name="Vector2">
+ <DisplayString>{{{x},{y}}}</DisplayString>
+ <Expand>
+ <Item Name="x">x</Item>
+ <Item Name="y">y</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Vector3">
+ <DisplayString>{{{x},{y},{z}}}</DisplayString>
+ <Expand>
+ <Item Name="x">x</Item>
+ <Item Name="y">y</Item>
+ <Item Name="z">z</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Quat">
+ <DisplayString>Quat {{{x},{y},{z},{w}}}</DisplayString>
+ <Expand>
+ <Item Name="x">x</Item>
+ <Item Name="y">y</Item>
+ <Item Name="z">z</Item>
+ <Item Name="w">w</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Color">
+ <DisplayString>Color {{{r},{g},{b},{a}}}</DisplayString>
+ <Expand>
+ <Item Name="red">r</Item>
+ <Item Name="green">g</Item>
+ <Item Name="blue">b</Item>
+ <Item Name="alpha">a</Item>
+ </Expand>
+ </Type>
+</AutoVisualizer>