summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/variant/variant.cpp11
-rw-r--r--core/variant/variant.h1
-rw-r--r--doc/classes/ProjectSettings.xml2
-rw-r--r--drivers/gles3/storage/material_storage.cpp8
-rw-r--r--editor/editor_node.cpp4
-rw-r--r--main/main.cpp10
-rw-r--r--modules/gdscript/gdscript_vm.cpp82
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out2
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out2
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/read_only_dictionary.out2
-rw-r--r--platform/web/export/export_plugin.cpp199
-rw-r--r--platform/web/export/export_plugin.h17
-rw-r--r--scene/main/viewport.cpp4
-rw-r--r--scene/main/viewport.h1
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp8
15 files changed, 271 insertions, 82 deletions
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index fcbfdd4741..37eb16f9b2 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -3515,6 +3515,17 @@ bool Variant::is_shared() const {
return is_type_shared(type);
}
+bool Variant::is_read_only() const {
+ switch (type) {
+ case ARRAY:
+ return reinterpret_cast<const Array *>(_data._mem)->is_read_only();
+ case DICTIONARY:
+ return reinterpret_cast<const Dictionary *>(_data._mem)->is_read_only();
+ default:
+ return false;
+ }
+}
+
void Variant::_variant_call_error(const String &p_method, Callable::CallError &error) {
switch (error.error) {
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index ea6ae02c1e..93953c4e0e 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -349,6 +349,7 @@ public:
bool is_zero() const;
bool is_one() const;
bool is_null() const;
+ bool is_read_only() const;
// Make sure Variant is not implicitly cast when accessing it with bracket notation (GH-49469).
Variant &operator[](const Variant &p_key) = delete;
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 0d4d8bbebb..1a5946fe1f 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -344,7 +344,7 @@
This setting can be overridden using the [code]--frame-delay &lt;ms;&gt;[/code] command line argument.
</member>
<member name="application/run/low_processor_mode" type="bool" setter="" getter="" default="false">
- If [code]true[/code], enables low-processor usage mode. This setting only works on desktop platforms. The screen is not redrawn if nothing changes visually. This is meant for writing applications and editors, but is pretty useless (and can hurt performance) in most games.
+ If [code]true[/code], enables low-processor usage mode. The screen is not redrawn if nothing changes visually. This is meant for writing applications and editors, but is pretty useless (and can hurt performance) in most games.
</member>
<member name="application/run/low_processor_mode_sleep_usec" type="int" setter="" getter="" default="6900">
Amount of sleeping between frames when the low-processor usage mode is enabled (in microseconds). Higher values will result in lower CPU usage.
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index 1952502fb2..808e05e60a 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1966,13 +1966,9 @@ void MaterialStorage::global_shader_parameters_load_settings(bool p_load_texture
Variant value = d["value"];
if (gvtype >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
- //textire
- if (!p_load_textures) {
- continue;
- }
-
String path = value;
- if (path.is_empty()) {
+ // Don't load the textures, but still add the parameter so shaders compile correctly while loading.
+ if (!p_load_textures || path.is_empty()) {
value = RID();
} else {
Ref<Resource> resource = ResourceLoader::load(path);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index b9ac7b6d42..7ae566dd2c 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -3486,6 +3486,10 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_chan
}
}
+ if (singleton->editor_plugin_screen == p_editor) {
+ singleton->editor_plugin_screen = nullptr;
+ }
+
singleton->editor_table.erase(p_editor);
}
p_editor->make_visible(false);
diff --git a/main/main.cpp b/main/main.cpp
index eee634086e..7b61eba836 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -3182,6 +3182,7 @@ int Main::start() {
#ifdef TOOLS_ENABLED
String doc_tool_path;
+ bool doc_tool_implicit_cwd = false;
BitField<DocTools::GenerateFlags> gen_flags;
String _export_preset;
bool export_debug = false;
@@ -3252,6 +3253,7 @@ int Main::start() {
if (doc_tool_path.begins_with("-")) {
// Assuming other command line arg, so default to cwd.
doc_tool_path = ".";
+ doc_tool_implicit_cwd = true;
parsed_pair = false;
}
#ifdef MODULE_GDSCRIPT_ENABLED
@@ -3282,6 +3284,7 @@ int Main::start() {
// Handle case where no path is given to --doctool.
else if (args[i] == "--doctool") {
doc_tool_path = ".";
+ doc_tool_implicit_cwd = true;
}
#endif
}
@@ -3308,6 +3311,11 @@ int Main::start() {
{
Ref<DirAccess> da = DirAccess::open(doc_tool_path);
ERR_FAIL_COND_V_MSG(da.is_null(), EXIT_FAILURE, "Argument supplied to --doctool must be a valid directory path.");
+ // Ensure that doctool is running in the root dir, but only if
+ // user did not manually specify a path as argument.
+ if (doc_tool_implicit_cwd) {
+ ERR_FAIL_COND_V_MSG(!da->dir_exists("doc"), EXIT_FAILURE, "--doctool must be run from the Godot repository's root folder, or specify a path that points there.");
+ }
}
#ifndef MODULE_MONO_ENABLED
@@ -3636,7 +3644,7 @@ int Main::start() {
}
}
- if (doc_tool_path == ".") {
+ if (doc_tool_implicit_cwd) {
doc_tool_path = "./docs";
}
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 163ffcb35b..4e76965889 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -884,23 +884,27 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#endif
#ifdef DEBUG_ENABLED
if (!valid) {
- Object *obj = dst->get_validated_object();
- String v = index->operator String();
- bool read_only_property = false;
- if (obj) {
- read_only_property = ClassDB::has_property(obj->get_class_name(), v) && (ClassDB::get_property_setter(obj->get_class_name(), v) == StringName());
- }
- if (read_only_property) {
- err_text = vformat(R"(Cannot set value into property "%s" (on base "%s") because it is read-only.)", v, _get_var_type(dst));
+ if (dst->is_read_only()) {
+ err_text = "Invalid assignment on read-only value (on base: '" + _get_var_type(dst) + "').";
} else {
- if (!v.is_empty()) {
- v = "'" + v + "'";
- } else {
- v = "of type '" + _get_var_type(index) + "'";
+ Object *obj = dst->get_validated_object();
+ String v = index->operator String();
+ bool read_only_property = false;
+ if (obj) {
+ read_only_property = ClassDB::has_property(obj->get_class_name(), v) && (ClassDB::get_property_setter(obj->get_class_name(), v) == StringName());
}
- err_text = "Invalid assignment of property or key " + v + " with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'.";
- if (err_code == Variant::VariantSetError::SET_INDEXED_ERR) {
- err_text = "Invalid assignment of index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'.";
+ if (read_only_property) {
+ err_text = vformat(R"(Cannot set value into property "%s" (on base "%s") because it is read-only.)", v, _get_var_type(dst));
+ } else {
+ if (!v.is_empty()) {
+ v = "'" + v + "'";
+ } else {
+ v = "of type '" + _get_var_type(index) + "'";
+ }
+ err_text = "Invalid assignment of property or key " + v + " with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'.";
+ if (err_code == Variant::VariantSetError::SET_INDEXED_ERR) {
+ err_text = "Invalid assignment of index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'.";
+ }
}
}
OPCODE_BREAK;
@@ -926,13 +930,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
if (!valid) {
- String v = index->operator String();
- if (!v.is_empty()) {
- v = "'" + v + "'";
+ if (dst->is_read_only()) {
+ err_text = "Invalid assignment on read-only value (on base: '" + _get_var_type(dst) + "').";
} else {
- v = "of type '" + _get_var_type(index) + "'";
+ String v = index->operator String();
+ if (!v.is_empty()) {
+ v = "'" + v + "'";
+ } else {
+ v = "of type '" + _get_var_type(index) + "'";
+ }
+ err_text = "Invalid assignment of property or key " + v + " with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'.";
}
- err_text = "Invalid assignment of property or key " + v + " with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'.";
OPCODE_BREAK;
}
#endif
@@ -958,13 +966,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
if (oob) {
- String v = index->operator String();
- if (!v.is_empty()) {
- v = "'" + v + "'";
+ if (dst->is_read_only()) {
+ err_text = "Invalid assignment on read-only value (on base: '" + _get_var_type(dst) + "').";
} else {
- v = "of type '" + _get_var_type(index) + "'";
+ String v = index->operator String();
+ if (!v.is_empty()) {
+ v = "'" + v + "'";
+ } else {
+ v = "of type '" + _get_var_type(index) + "'";
+ }
+ err_text = "Out of bounds set index " + v + " (on base: '" + _get_var_type(dst) + "')";
}
- err_text = "Out of bounds set index " + v + " (on base: '" + _get_var_type(dst) + "')";
OPCODE_BREAK;
}
#endif
@@ -1092,15 +1104,19 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
if (!valid) {
- Object *obj = dst->get_validated_object();
- bool read_only_property = false;
- if (obj) {
- read_only_property = ClassDB::has_property(obj->get_class_name(), *index) && (ClassDB::get_property_setter(obj->get_class_name(), *index) == StringName());
- }
- if (read_only_property) {
- err_text = vformat(R"(Cannot set value into property "%s" (on base "%s") because it is read-only.)", String(*index), _get_var_type(dst));
+ if (dst->is_read_only()) {
+ err_text = "Invalid assignment on read-only value (on base: '" + _get_var_type(dst) + "').";
} else {
- err_text = "Invalid assignment of property or key '" + String(*index) + "' with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'.";
+ Object *obj = dst->get_validated_object();
+ bool read_only_property = false;
+ if (obj) {
+ read_only_property = ClassDB::has_property(obj->get_class_name(), *index) && (ClassDB::get_property_setter(obj->get_class_name(), *index) == StringName());
+ }
+ if (read_only_property) {
+ err_text = vformat(R"(Cannot set value into property "%s" (on base "%s") because it is read-only.)", String(*index), _get_var_type(dst));
+ } else {
+ err_text = "Invalid assignment of property or key '" + String(*index) + "' with value of type '" + _get_var_type(value) + "' on a base object of type '" + _get_var_type(dst) + "'.";
+ }
}
OPCODE_BREAK;
}
diff --git a/modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out b/modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out
index c524a1ae6b..350d5d1d45 100644
--- a/modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out
+++ b/modules/gdscript/tests/scripts/runtime/errors/constant_array_is_deep.out
@@ -3,4 +3,4 @@ GDTEST_RUNTIME_ERROR
>> on function: test()
>> runtime/errors/constant_array_is_deep.gd
>> 6
->> Invalid assignment of property or key '0' with value of type 'int' on a base object of type 'Dictionary'.
+>> Invalid assignment on read-only value (on base: 'Dictionary').
diff --git a/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out b/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out
index cf51b0262d..5f1f372b0a 100644
--- a/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out
+++ b/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_is_deep.out
@@ -3,4 +3,4 @@ GDTEST_RUNTIME_ERROR
>> on function: test()
>> runtime/errors/constant_dictionary_is_deep.gd
>> 6
->> Invalid assignment of index '0' (on base: 'Array') with value of type 'int'.
+>> Invalid assignment on read-only value (on base: 'Array').
diff --git a/modules/gdscript/tests/scripts/runtime/errors/read_only_dictionary.out b/modules/gdscript/tests/scripts/runtime/errors/read_only_dictionary.out
index da7ce58d73..f7d531e119 100644
--- a/modules/gdscript/tests/scripts/runtime/errors/read_only_dictionary.out
+++ b/modules/gdscript/tests/scripts/runtime/errors/read_only_dictionary.out
@@ -3,4 +3,4 @@ GDTEST_RUNTIME_ERROR
>> on function: test()
>> runtime/errors/read_only_dictionary.gd
>> 4
->> Invalid assignment of property or key 'a' with value of type 'int' on a base object of type 'Dictionary'.
+>> Invalid assignment on read-only value (on base: 'Dictionary').
diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index 92da7799e7..d42303ad25 100644
--- a/platform/web/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -585,32 +585,176 @@ bool EditorExportPlatformWeb::poll_export() {
}
}
- int prev = menu_options;
- menu_options = preset.is_valid();
+ HTTPServerState prev_server_state = server_state;
+ server_state = HTTP_SERVER_STATE_OFF;
if (server->is_listening()) {
- if (menu_options == 0) {
+ if (preset.is_null()) {
server->stop();
} else {
- menu_options += 1;
+ server_state = HTTP_SERVER_STATE_ON;
}
}
- return menu_options != prev;
+
+ return server_state != prev_server_state;
}
Ref<ImageTexture> EditorExportPlatformWeb::get_option_icon(int p_index) const {
- return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index);
+ Ref<ImageTexture> play_icon = EditorExportPlatform::get_option_icon(p_index);
+
+ switch (server_state) {
+ case HTTP_SERVER_STATE_OFF: {
+ switch (p_index) {
+ case 0:
+ case 1:
+ return play_icon;
+ }
+ } break;
+
+ case HTTP_SERVER_STATE_ON: {
+ switch (p_index) {
+ case 0:
+ return play_icon;
+ case 1:
+ return restart_icon;
+ case 2:
+ return stop_icon;
+ }
+ } break;
+ }
+
+ ERR_FAIL_V_MSG(nullptr, vformat(R"(EditorExportPlatformWeb option icon index "%s" is invalid.)", p_index));
}
int EditorExportPlatformWeb::get_options_count() const {
- return menu_options;
+ if (server_state == HTTP_SERVER_STATE_ON) {
+ return 3;
+ }
+ return 2;
+}
+
+String EditorExportPlatformWeb::get_option_label(int p_index) const {
+ String run_in_browser = TTR("Run in Browser");
+ String start_http_server = TTR("Start HTTP Server");
+ String reexport_project = TTR("Re-export Project");
+ String stop_http_server = TTR("Stop HTTP Server");
+
+ switch (server_state) {
+ case HTTP_SERVER_STATE_OFF: {
+ switch (p_index) {
+ case 0:
+ return run_in_browser;
+ case 1:
+ return start_http_server;
+ }
+ } break;
+
+ case HTTP_SERVER_STATE_ON: {
+ switch (p_index) {
+ case 0:
+ return run_in_browser;
+ case 1:
+ return reexport_project;
+ case 2:
+ return stop_http_server;
+ }
+ } break;
+ }
+
+ ERR_FAIL_V_MSG("", vformat(R"(EditorExportPlatformWeb option label index "%s" is invalid.)", p_index));
+}
+
+String EditorExportPlatformWeb::get_option_tooltip(int p_index) const {
+ String run_in_browser = TTR("Run exported HTML in the system's default browser.");
+ String start_http_server = TTR("Start the HTTP server.");
+ String reexport_project = TTR("Export project again to account for updates.");
+ String stop_http_server = TTR("Stop the HTTP server.");
+
+ switch (server_state) {
+ case HTTP_SERVER_STATE_OFF: {
+ switch (p_index) {
+ case 0:
+ return run_in_browser;
+ case 1:
+ return start_http_server;
+ }
+ } break;
+
+ case HTTP_SERVER_STATE_ON: {
+ switch (p_index) {
+ case 0:
+ return run_in_browser;
+ case 1:
+ return reexport_project;
+ case 2:
+ return stop_http_server;
+ }
+ } break;
+ }
+
+ ERR_FAIL_V_MSG("", vformat(R"(EditorExportPlatformWeb option tooltip index "%s" is invalid.)", p_index));
}
Error EditorExportPlatformWeb::run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) {
- if (p_option == 1) {
- server->stop();
- return OK;
+ const uint16_t bind_port = EDITOR_GET("export/web/http_port");
+ // Resolve host if needed.
+ const String bind_host = EDITOR_GET("export/web/http_host");
+ const bool use_tls = EDITOR_GET("export/web/use_tls");
+
+ switch (server_state) {
+ case HTTP_SERVER_STATE_OFF: {
+ switch (p_option) {
+ // Run in Browser.
+ case 0: {
+ Error err = _export_project(p_preset, p_debug_flags);
+ if (err != OK) {
+ return err;
+ }
+ err = _start_server(bind_host, bind_port, use_tls);
+ if (err != OK) {
+ return err;
+ }
+ return _launch_browser(bind_host, bind_port, use_tls);
+ } break;
+
+ // Start HTTP Server.
+ case 1: {
+ Error err = _export_project(p_preset, p_debug_flags);
+ if (err != OK) {
+ return err;
+ }
+ return _start_server(bind_host, bind_port, use_tls);
+ } break;
+ }
+ } break;
+
+ case HTTP_SERVER_STATE_ON: {
+ switch (p_option) {
+ // Run in Browser.
+ case 0: {
+ Error err = _export_project(p_preset, p_debug_flags);
+ if (err != OK) {
+ return err;
+ }
+ return _launch_browser(bind_host, bind_port, use_tls);
+ } break;
+
+ // Re-export Project.
+ case 1: {
+ return _export_project(p_preset, p_debug_flags);
+ } break;
+
+ // Stop HTTP Server.
+ case 2: {
+ return _stop_server();
+ } break;
+ }
+ } break;
}
+ ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat(R"(Trying to run EditorExportPlatformWeb, but option "%s" isn't known.)", p_option));
+}
+
+Error EditorExportPlatformWeb::_export_project(const Ref<EditorExportPreset> &p_preset, int p_debug_flags) {
const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("web");
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (!da->dir_exists(dest)) {
@@ -637,35 +781,40 @@ Error EditorExportPlatformWeb::run(const Ref<EditorExportPreset> &p_preset, int
DirAccess::remove_file_or_error(basepath + ".wasm");
DirAccess::remove_file_or_error(basepath + ".icon.png");
DirAccess::remove_file_or_error(basepath + ".apple-touch-icon.png");
- return err;
}
+ return err;
+}
- const uint16_t bind_port = EDITOR_GET("export/web/http_port");
- // Resolve host if needed.
- const String bind_host = EDITOR_GET("export/web/http_host");
+Error EditorExportPlatformWeb::_launch_browser(const String &p_bind_host, const uint16_t p_bind_port, const bool p_use_tls) {
+ OS::get_singleton()->shell_open(String((p_use_tls ? "https://" : "http://") + p_bind_host + ":" + itos(p_bind_port) + "/tmp_js_export.html"));
+ // FIXME: Find out how to clean up export files after running the successfully
+ // exported game. Might not be trivial.
+ return OK;
+}
+
+Error EditorExportPlatformWeb::_start_server(const String &p_bind_host, const uint16_t p_bind_port, const bool p_use_tls) {
IPAddress bind_ip;
- if (bind_host.is_valid_ip_address()) {
- bind_ip = bind_host;
+ if (p_bind_host.is_valid_ip_address()) {
+ bind_ip = p_bind_host;
} else {
- bind_ip = IP::get_singleton()->resolve_hostname(bind_host);
+ bind_ip = IP::get_singleton()->resolve_hostname(p_bind_host);
}
- ERR_FAIL_COND_V_MSG(!bind_ip.is_valid(), ERR_INVALID_PARAMETER, "Invalid editor setting 'export/web/http_host': '" + bind_host + "'. Try using '127.0.0.1'.");
+ ERR_FAIL_COND_V_MSG(!bind_ip.is_valid(), ERR_INVALID_PARAMETER, "Invalid editor setting 'export/web/http_host': '" + p_bind_host + "'. Try using '127.0.0.1'.");
- const bool use_tls = EDITOR_GET("export/web/use_tls");
const String tls_key = EDITOR_GET("export/web/tls_key");
const String tls_cert = EDITOR_GET("export/web/tls_certificate");
// Restart server.
server->stop();
- err = server->listen(bind_port, bind_ip, use_tls, tls_key, tls_cert);
+ Error err = server->listen(p_bind_port, bind_ip, p_use_tls, tls_key, tls_cert);
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), vformat(TTR("Error starting HTTP server: %d."), err));
- return err;
}
+ return err;
+}
- OS::get_singleton()->shell_open(String((use_tls ? "https://" : "http://") + bind_host + ":" + itos(bind_port) + "/tmp_js_export.html"));
- // FIXME: Find out how to clean up export files after running the successfully
- // exported game. Might not be trivial.
+Error EditorExportPlatformWeb::_stop_server() {
+ server->stop();
return OK;
}
@@ -691,8 +840,10 @@ EditorExportPlatformWeb::EditorExportPlatformWeb() {
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
if (theme.is_valid()) {
stop_icon = theme->get_icon(SNAME("Stop"), EditorStringName(EditorIcons));
+ restart_icon = theme->get_icon(SNAME("Reload"), EditorStringName(EditorIcons));
} else {
stop_icon.instantiate();
+ restart_icon.instantiate();
}
}
}
diff --git a/platform/web/export/export_plugin.h b/platform/web/export/export_plugin.h
index 952d03cdb4..9d3a1a7861 100644
--- a/platform/web/export/export_plugin.h
+++ b/platform/web/export/export_plugin.h
@@ -46,10 +46,16 @@
class EditorExportPlatformWeb : public EditorExportPlatform {
GDCLASS(EditorExportPlatformWeb, EditorExportPlatform);
+ enum HTTPServerState {
+ HTTP_SERVER_STATE_OFF,
+ HTTP_SERVER_STATE_ON,
+ };
+
Ref<ImageTexture> logo;
Ref<ImageTexture> run_icon;
Ref<ImageTexture> stop_icon;
- int menu_options = 0;
+ Ref<ImageTexture> restart_icon;
+ HTTPServerState server_state = HTTP_SERVER_STATE_OFF;
Ref<EditorHTTPServer> server;
@@ -96,6 +102,11 @@ class EditorExportPlatformWeb : public EditorExportPlatform {
Error _build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects);
Error _write_or_error(const uint8_t *p_content, int p_len, String p_path);
+ Error _export_project(const Ref<EditorExportPreset> &p_preset, int p_debug_flags);
+ Error _launch_browser(const String &p_bind_host, uint16_t p_bind_port, bool p_use_tls);
+ Error _start_server(const String &p_bind_host, uint16_t p_bind_port, bool p_use_tls);
+ Error _stop_server();
+
public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
@@ -112,8 +123,8 @@ public:
virtual bool poll_export() override;
virtual int get_options_count() const override;
- virtual String get_option_label(int p_index) const override { return p_index ? TTR("Stop HTTP Server") : TTR("Run in Browser"); }
- virtual String get_option_tooltip(int p_index) const override { return p_index ? TTR("Stop HTTP Server") : TTR("Run exported HTML in the system's default browser."); }
+ virtual String get_option_label(int p_index) const override;
+ virtual String get_option_tooltip(int p_index) const override;
virtual Ref<ImageTexture> get_option_icon(int p_index) const override;
virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) override;
virtual Ref<Texture2D> get_run_icon() const override;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 07e7273343..522dc74661 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1734,7 +1734,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.mouse_focus_mask.set_flag(button_mask);
} else {
gui.mouse_focus = gui_find_control(mpos);
- gui.last_mouse_focus = gui.mouse_focus;
if (!gui.mouse_focus) {
return;
@@ -2391,9 +2390,6 @@ void Viewport::_gui_remove_control(Control *p_control) {
gui.forced_mouse_focus = false;
gui.mouse_focus_mask.clear();
}
- if (gui.last_mouse_focus == p_control) {
- gui.last_mouse_focus = nullptr;
- }
if (gui.key_focus == p_control) {
gui.key_focus = nullptr;
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index c6a757acd0..394d48143c 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -345,7 +345,6 @@ private:
bool key_event_accepted = false;
HashMap<int, ObjectID> touch_focus;
Control *mouse_focus = nullptr;
- Control *last_mouse_focus = nullptr;
Control *mouse_click_grabber = nullptr;
BitField<MouseButtonMask> mouse_focus_mask;
Control *key_focus = nullptr;
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index 1c3076b128..a10c672379 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -1656,13 +1656,9 @@ void MaterialStorage::global_shader_parameters_load_settings(bool p_load_texture
Variant value = d["value"];
if (gvtype >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
- //textire
- if (!p_load_textures) {
- continue;
- }
-
String path = value;
- if (path.is_empty()) {
+ // Don't load the textures, but still add the parameter so shaders compile correctly while loading.
+ if (!p_load_textures || path.is_empty()) {
value = RID();
} else {
Ref<Resource> resource = ResourceLoader::load(path);