summaryrefslogtreecommitdiff
path: root/scene/main
diff options
context:
space:
mode:
Diffstat (limited to 'scene/main')
-rw-r--r--scene/main/canvas_item.cpp64
-rw-r--r--scene/main/canvas_item.h24
-rw-r--r--scene/main/http_request.cpp149
-rw-r--r--scene/main/http_request.h14
-rw-r--r--scene/main/missing_node.cpp4
-rw-r--r--scene/main/missing_node.h2
-rw-r--r--scene/main/multiplayer_api.cpp8
-rw-r--r--scene/main/multiplayer_peer.cpp16
-rw-r--r--scene/main/multiplayer_peer.h8
-rw-r--r--scene/main/node.cpp181
-rw-r--r--scene/main/node.h23
-rw-r--r--scene/main/scene_tree.cpp191
-rw-r--r--scene/main/scene_tree.h16
-rw-r--r--scene/main/shader_globals_override.cpp4
-rw-r--r--scene/main/shader_globals_override.h2
-rw-r--r--scene/main/timer.cpp4
-rw-r--r--scene/main/timer.h2
-rw-r--r--scene/main/viewport.cpp112
-rw-r--r--scene/main/viewport.h5
-rw-r--r--scene/main/window.cpp132
-rw-r--r--scene/main/window.h6
21 files changed, 498 insertions, 469 deletions
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 65e7ba3e67..b8f7897f48 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -369,6 +369,13 @@ void CanvasItem::queue_redraw() {
MessageQueue::get_singleton()->push_callable(callable_mp(this, &CanvasItem::_redraw_callback));
}
+void CanvasItem::move_to_front() {
+ if (!get_parent()) {
+ return;
+ }
+ get_parent()->move_child(this, -1);
+}
+
void CanvasItem::set_modulate(const Color &p_modulate) {
if (modulate == p_modulate) {
return;
@@ -897,6 +904,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("hide"), &CanvasItem::hide);
ClassDB::bind_method(D_METHOD("queue_redraw"), &CanvasItem::queue_redraw);
+ ClassDB::bind_method(D_METHOD("move_to_front"), &CanvasItem::move_to_front);
ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &CanvasItem::set_as_top_level);
ClassDB::bind_method(D_METHOD("is_set_as_top_level"), &CanvasItem::is_set_as_top_level);
@@ -978,8 +986,8 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat);
ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat);
- ClassDB::bind_method(D_METHOD("set_clip_children", "enable"), &CanvasItem::set_clip_children);
- ClassDB::bind_method(D_METHOD("is_clipping_children"), &CanvasItem::is_clipping_children);
+ ClassDB::bind_method(D_METHOD("set_clip_children_mode", "mode"), &CanvasItem::set_clip_children_mode);
+ ClassDB::bind_method(D_METHOD("get_clip_children_mode"), &CanvasItem::get_clip_children_mode);
GDVIRTUAL_BIND(_draw);
@@ -989,7 +997,7 @@ void CanvasItem::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_children"), "set_clip_children", "is_clipping_children");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "clip_children", PROPERTY_HINT_ENUM, "Disabled,Clip Only, Clip + Draw"), "set_clip_children_mode", "get_clip_children_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
ADD_GROUP("Texture", "texture_");
@@ -1027,6 +1035,11 @@ void CanvasItem::_bind_methods() {
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_ENABLED);
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MIRROR);
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MAX);
+
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_DISABLED);
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_ONLY);
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_AND_DRAW);
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_MAX);
}
Transform2D CanvasItem::get_canvas_transform() const {
@@ -1084,7 +1097,7 @@ int CanvasItem::get_canvas_layer() const {
}
}
-void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
+void CanvasItem::_refresh_texture_filter_cache() {
if (!is_inside_tree()) {
return;
}
@@ -1099,6 +1112,14 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
} else {
texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter);
}
+}
+
+void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
+ if (!is_inside_tree()) {
+ return;
+ }
+ _refresh_texture_filter_cache();
+
RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache);
queue_redraw();
@@ -1125,7 +1146,7 @@ CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
return texture_filter;
}
-void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
+void CanvasItem::_refresh_texture_repeat_cache() {
if (!is_inside_tree()) {
return;
}
@@ -1140,6 +1161,14 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
} else {
texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat);
}
+}
+
+void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
+ if (!is_inside_tree()) {
+ return;
+ }
+ _refresh_texture_repeat_cache();
+
RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
queue_redraw();
if (p_propagate) {
@@ -1161,26 +1190,39 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
notify_property_list_changed();
}
-void CanvasItem::set_clip_children(bool p_enabled) {
- if (clip_children == p_enabled) {
+void CanvasItem::set_clip_children_mode(ClipChildrenMode p_clip_mode) {
+ ERR_FAIL_COND(p_clip_mode >= CLIP_CHILDREN_MAX);
+
+ if (clip_children_mode == p_clip_mode) {
return;
}
- clip_children = p_enabled;
+ clip_children_mode = p_clip_mode;
if (Object::cast_to<CanvasGroup>(this) != nullptr) {
//avoid accidental bugs, make this not work on CanvasGroup
return;
}
- RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), clip_children ? RS::CANVAS_GROUP_MODE_OPAQUE : RS::CANVAS_GROUP_MODE_DISABLED);
+
+ RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CanvasGroupMode(clip_children_mode));
}
-bool CanvasItem::is_clipping_children() const {
- return clip_children;
+CanvasItem::ClipChildrenMode CanvasItem::get_clip_children_mode() const {
+ return clip_children_mode;
}
CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
return texture_repeat;
}
+CanvasItem::TextureFilter CanvasItem::get_texture_filter_in_tree() {
+ _refresh_texture_filter_cache();
+ return (TextureFilter)texture_filter_cache;
+}
+
+CanvasItem::TextureRepeat CanvasItem::get_texture_repeat_in_tree() {
+ _refresh_texture_repeat_cache();
+ return (TextureRepeat)texture_repeat_cache;
+}
+
CanvasItem::CanvasItem() :
xform_change(this) {
canvas_item = RenderingServer::get_singleton()->canvas_item_create();
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 1abb4edec9..565ea930ce 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -66,8 +66,16 @@ public:
TEXTURE_REPEAT_MAX,
};
+ enum ClipChildrenMode {
+ CLIP_CHILDREN_DISABLED,
+ CLIP_CHILDREN_ONLY,
+ CLIP_CHILDREN_AND_DRAW,
+ CLIP_CHILDREN_MAX,
+ };
+
private:
- mutable SelfList<Node> xform_change;
+ mutable SelfList<Node>
+ xform_change;
RID canvas_item;
StringName canvas_group;
@@ -85,7 +93,6 @@ private:
Window *window = nullptr;
bool visible = true;
bool parent_visible_in_tree = false;
- bool clip_children = false;
bool pending_update = false;
bool top_level = false;
bool drawing = false;
@@ -95,6 +102,8 @@ private:
bool notify_local_transform = false;
bool notify_transform = false;
+ ClipChildrenMode clip_children_mode = CLIP_CHILDREN_DISABLED;
+
RS::CanvasItemTextureFilter texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
RS::CanvasItemTextureRepeat texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
TextureFilter texture_filter = TEXTURE_FILTER_PARENT_NODE;
@@ -121,7 +130,9 @@ private:
static CanvasItem *current_item_drawn;
friend class Viewport;
+ void _refresh_texture_repeat_cache();
void _update_texture_repeat_changed(bool p_propagate);
+ void _refresh_texture_filter_cache();
void _update_texture_filter_changed(bool p_propagate);
protected:
@@ -198,9 +209,10 @@ public:
void hide();
void queue_redraw();
+ void move_to_front();
- void set_clip_children(bool p_enabled);
- bool is_clipping_children() const;
+ void set_clip_children_mode(ClipChildrenMode p_clip_mode);
+ ClipChildrenMode get_clip_children_mode() const;
virtual void set_light_mask(int p_light_mask);
int get_light_mask() const;
@@ -309,6 +321,9 @@ public:
virtual void set_texture_repeat(TextureRepeat p_texture_repeat);
TextureRepeat get_texture_repeat() const;
+ TextureFilter get_texture_filter_in_tree();
+ TextureRepeat get_texture_repeat_in_tree();
+
// Used by control nodes to retrieve the parent's anchorable area
virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); };
@@ -320,6 +335,7 @@ public:
VARIANT_ENUM_CAST(CanvasItem::TextureFilter)
VARIANT_ENUM_CAST(CanvasItem::TextureRepeat)
+VARIANT_ENUM_CAST(CanvasItem::ClipChildrenMode)
class CanvasTexture : public Texture2D {
GDCLASS(CanvasTexture, Texture2D);
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 9a23bc65bf..2c395ec07d 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -32,15 +32,12 @@
#include "core/io/compression.h"
#include "scene/main/timer.h"
-void HTTPRequest::_redirect_request(const String &p_new_url) {
-}
-
Error HTTPRequest::_request() {
- return client->connect_to_host(url, port, use_ssl, validate_ssl);
+ return client->connect_to_host(url, port, use_tls, validate_tls);
}
Error HTTPRequest::_parse_url(const String &p_url) {
- use_ssl = false;
+ use_tls = false;
request_string = "";
port = 80;
request_sent = false;
@@ -48,18 +45,19 @@ Error HTTPRequest::_parse_url(const String &p_url) {
body_len = -1;
body.clear();
downloaded.set(0);
+ final_body_size.set(0);
redirections = 0;
String scheme;
Error err = p_url.parse_url(scheme, url, port, request_string);
ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing URL: " + p_url + ".");
if (scheme == "https://") {
- use_ssl = true;
+ use_tls = true;
} else if (scheme != "http://") {
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Invalid URL scheme: " + scheme + ".");
}
if (port == 0) {
- port = use_ssl ? 443 : 80;
+ port = use_tls ? 443 : 80;
}
if (request_string.is_empty()) {
request_string = "/";
@@ -98,7 +96,7 @@ String HTTPRequest::get_header_value(const PackedStringArray &p_headers, const S
return value;
}
-Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const String &p_request_data) {
+Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_tls_validate_domain, HTTPClient::Method p_method, const String &p_request_data) {
// Copy the string into a raw buffer.
Vector<uint8_t> raw_data;
@@ -110,10 +108,10 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h
memcpy(w, charstr.ptr(), len);
}
- return request_raw(p_url, p_custom_headers, p_ssl_validate_domain, p_method, raw_data);
+ return request_raw(p_url, p_custom_headers, p_tls_validate_domain, p_method, raw_data);
}
-Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const Vector<uint8_t> &p_request_data_raw) {
+Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_custom_headers, bool p_tls_validate_domain, HTTPClient::Method p_method, const Vector<uint8_t> &p_request_data_raw) {
ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(requesting, ERR_BUSY, "HTTPRequest is processing a request. Wait for completion or cancel it before attempting a new one.");
@@ -129,7 +127,7 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust
return err;
}
- validate_ssl = p_ssl_validate_domain;
+ validate_tls = p_tls_validate_domain;
headers = p_custom_headers;
@@ -153,7 +151,7 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust
client->set_blocking_mode(false);
err = _request();
if (err != OK) {
- call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
return ERR_CANT_CONNECT;
}
@@ -169,7 +167,7 @@ void HTTPRequest::_thread_func(void *p_userdata) {
Error err = hr->_request();
if (err != OK) {
- hr->call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
+ hr->_defer_done(RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
} else {
while (!hr->thread_request_quit.is_set()) {
bool exit = hr->_update_connection();
@@ -198,6 +196,7 @@ void HTTPRequest::cancel_request() {
}
file.unref();
+ decompressor.unref();
client->close();
body.clear();
got_response = false;
@@ -208,7 +207,7 @@ void HTTPRequest::cancel_request() {
bool HTTPRequest::_handle_response(bool *ret_value) {
if (!client->has_response()) {
- call_deferred(SNAME("_request_done"), RESULT_NO_RESPONSE, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_NO_RESPONSE, 0, PackedStringArray(), PackedByteArray());
*ret_value = true;
return true;
}
@@ -219,6 +218,9 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
client->get_response_headers(&rheaders);
response_headers.clear();
downloaded.set(0);
+ final_body_size.set(0);
+ decompressor.unref();
+
for (const String &E : rheaders) {
response_headers.push_back(E);
}
@@ -227,7 +229,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
// Handle redirect.
if (max_redirects >= 0 && redirections >= max_redirects) {
- call_deferred(SNAME("_request_done"), RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray());
*ret_value = true;
return true;
}
@@ -259,6 +261,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
body_len = -1;
body.clear();
downloaded.set(0);
+ final_body_size.set(0);
redirections = new_redirs;
*ret_value = false;
return true;
@@ -266,13 +269,26 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
}
}
+ // Check if we need to start streaming decompression.
+ String content_encoding;
+ if (accept_gzip) {
+ content_encoding = get_header_value(response_headers, "Content-Encoding").to_lower();
+ }
+ if (content_encoding == "gzip") {
+ decompressor.instantiate();
+ decompressor->start_decompression(false, get_download_chunk_size() * 2);
+ } else if (content_encoding == "deflate") {
+ decompressor.instantiate();
+ decompressor->start_decompression(true, get_download_chunk_size() * 2);
+ }
+
return false;
}
bool HTTPRequest::_update_connection() {
switch (client->get_status()) {
case HTTPClient::STATUS_DISCONNECTED: {
- call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
return true; // End it, since it's disconnected.
} break;
case HTTPClient::STATUS_RESOLVING: {
@@ -281,7 +297,7 @@ bool HTTPRequest::_update_connection() {
return false;
} break;
case HTTPClient::STATUS_CANT_RESOLVE: {
- call_deferred(SNAME("_request_done"), RESULT_CANT_RESOLVE, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_CANT_RESOLVE, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
@@ -291,7 +307,7 @@ bool HTTPRequest::_update_connection() {
return false;
} break; // Connecting to IP.
case HTTPClient::STATUS_CANT_CONNECT: {
- call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
@@ -306,16 +322,16 @@ bool HTTPRequest::_update_connection() {
return ret_value;
}
- call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_SUCCESS, response_code, response_headers, PackedByteArray());
return true;
}
if (body_len < 0) {
// Chunked transfer is done.
- call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body);
+ _defer_done(RESULT_SUCCESS, response_code, response_headers, body);
return true;
}
- call_deferred(SNAME("_request_done"), RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray());
return true;
// Request might have been done.
} else {
@@ -324,7 +340,7 @@ bool HTTPRequest::_update_connection() {
int size = request_data.size();
Error err = client->request(method, request_string, headers, size > 0 ? request_data.ptr() : nullptr, size);
if (err != OK) {
- call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
return true;
}
@@ -347,7 +363,7 @@ bool HTTPRequest::_update_connection() {
}
if (!client->is_response_chunked() && client->get_response_body_length() == 0) {
- call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_SUCCESS, response_code, response_headers, PackedByteArray());
return true;
}
@@ -356,14 +372,14 @@ bool HTTPRequest::_update_connection() {
body_len = client->get_response_body_length();
if (body_size_limit >= 0 && body_len > body_size_limit) {
- call_deferred(SNAME("_request_done"), RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
return true;
}
if (!download_to_file.is_empty()) {
file = FileAccess::open(download_to_file, FileAccess::WRITE);
if (file.is_null()) {
- call_deferred(SNAME("_request_done"), RESULT_DOWNLOAD_FILE_CANT_OPEN, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_DOWNLOAD_FILE_CANT_OPEN, response_code, response_headers, PackedByteArray());
return true;
}
}
@@ -375,14 +391,33 @@ bool HTTPRequest::_update_connection() {
}
PackedByteArray chunk = client->read_response_body_chunk();
+ downloaded.add(chunk.size());
+
+ // Decompress chunk if needed.
+ if (decompressor.is_valid()) {
+ Error err = decompressor->put_data(chunk.ptr(), chunk.size());
+ if (err == OK) {
+ chunk.resize(decompressor->get_available_bytes());
+ err = decompressor->get_data(chunk.ptrw(), chunk.size());
+ }
+ if (err != OK) {
+ _defer_done(RESULT_BODY_DECOMPRESS_FAILED, response_code, response_headers, PackedByteArray());
+ return true;
+ }
+ }
+ final_body_size.add(chunk.size());
+
+ if (body_size_limit >= 0 && final_body_size.get() > body_size_limit) {
+ _defer_done(RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
+ return true;
+ }
if (chunk.size()) {
- downloaded.add(chunk.size());
if (file.is_valid()) {
const uint8_t *r = chunk.ptr();
file->store_buffer(r, chunk.size());
if (file->get_error() != OK) {
- call_deferred(SNAME("_request_done"), RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray());
+ _defer_done(RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray());
return true;
}
} else {
@@ -390,19 +425,14 @@ bool HTTPRequest::_update_connection() {
}
}
- if (body_size_limit >= 0 && downloaded.get() > body_size_limit) {
- call_deferred(SNAME("_request_done"), RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
- return true;
- }
-
if (body_len >= 0) {
if (downloaded.get() == body_len) {
- call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body);
+ _defer_done(RESULT_SUCCESS, response_code, response_headers, body);
return true;
}
} else if (client->get_status() == HTTPClient::STATUS_DISCONNECTED) {
// We read till EOF, with no errors. Request is done.
- call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body);
+ _defer_done(RESULT_SUCCESS, response_code, response_headers, body);
return true;
}
@@ -410,11 +440,11 @@ bool HTTPRequest::_update_connection() {
} break; // Request resulted in body: break which must be read.
case HTTPClient::STATUS_CONNECTION_ERROR: {
- call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
- case HTTPClient::STATUS_SSL_HANDSHAKE_ERROR: {
- call_deferred(SNAME("_request_done"), RESULT_SSL_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray());
+ case HTTPClient::STATUS_TLS_HANDSHAKE_ERROR: {
+ _defer_done(RESULT_TLS_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
}
@@ -422,41 +452,13 @@ bool HTTPRequest::_update_connection() {
ERR_FAIL_V(false);
}
+void HTTPRequest::_defer_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) {
+ call_deferred(SNAME("_request_done"), p_status, p_code, p_headers, p_data);
+}
+
void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) {
cancel_request();
- // Determine if the request body is compressed.
- bool is_compressed;
- String content_encoding = get_header_value(p_headers, "Content-Encoding").to_lower();
- Compression::Mode mode;
- if (content_encoding == "gzip") {
- mode = Compression::Mode::MODE_GZIP;
- is_compressed = true;
- } else if (content_encoding == "deflate") {
- mode = Compression::Mode::MODE_DEFLATE;
- is_compressed = true;
- } else {
- is_compressed = false;
- }
-
- if (accept_gzip && is_compressed && p_data.size() > 0) {
- // Decompress request body
- PackedByteArray decompressed;
- int result = Compression::decompress_dynamic(&decompressed, body_size_limit, p_data.ptr(), p_data.size(), mode);
- if (result == OK) {
- emit_signal(SNAME("request_completed"), p_status, p_code, p_headers, decompressed);
- return;
- } else if (result == -5) {
- WARN_PRINT("Decompressed size of HTTP response body exceeded body_size_limit");
- p_status = RESULT_BODY_SIZE_LIMIT_EXCEEDED;
- // Just return the raw data if we failed to decompress it.
- } else {
- WARN_PRINT("Failed to decompress HTTP response body");
- p_status = RESULT_BODY_DECOMPRESS_FAILED;
- // Just return the raw data if we failed to decompress it.
- }
- }
-
emit_signal(SNAME("request_completed"), p_status, p_code, p_headers, p_data);
}
@@ -566,12 +568,12 @@ double HTTPRequest::get_timeout() {
void HTTPRequest::_timeout() {
cancel_request();
- call_deferred(SNAME("_request_done"), RESULT_TIMEOUT, 0, PackedStringArray(), PackedByteArray());
+ _defer_done(RESULT_TIMEOUT, 0, PackedStringArray(), PackedByteArray());
}
void HTTPRequest::_bind_methods() {
- ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "ssl_validate_domain", "method", "request_data"), &HTTPRequest::request, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String()));
- ClassDB::bind_method(D_METHOD("request_raw", "url", "custom_headers", "ssl_validate_domain", "method", "request_data_raw"), &HTTPRequest::request_raw, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(PackedByteArray()));
+ ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "tls_validate_domain", "method", "request_data"), &HTTPRequest::request, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String()));
+ ClassDB::bind_method(D_METHOD("request_raw", "url", "custom_headers", "tls_validate_domain", "method", "request_data_raw"), &HTTPRequest::request_raw, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(PackedByteArray()));
ClassDB::bind_method(D_METHOD("cancel_request"), &HTTPRequest::cancel_request);
ClassDB::bind_method(D_METHOD("get_http_client_status"), &HTTPRequest::get_http_client_status);
@@ -594,7 +596,6 @@ void HTTPRequest::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_downloaded_bytes"), &HTTPRequest::get_downloaded_bytes);
ClassDB::bind_method(D_METHOD("get_body_size"), &HTTPRequest::get_body_size);
- ClassDB::bind_method(D_METHOD("_redirect_request"), &HTTPRequest::_redirect_request);
ClassDB::bind_method(D_METHOD("_request_done"), &HTTPRequest::_request_done);
ClassDB::bind_method(D_METHOD("set_timeout", "timeout"), &HTTPRequest::set_timeout);
@@ -621,7 +622,7 @@ void HTTPRequest::_bind_methods() {
BIND_ENUM_CONSTANT(RESULT_CANT_CONNECT);
BIND_ENUM_CONSTANT(RESULT_CANT_RESOLVE);
BIND_ENUM_CONSTANT(RESULT_CONNECTION_ERROR);
- BIND_ENUM_CONSTANT(RESULT_SSL_HANDSHAKE_ERROR);
+ BIND_ENUM_CONSTANT(RESULT_TLS_HANDSHAKE_ERROR);
BIND_ENUM_CONSTANT(RESULT_NO_RESPONSE);
BIND_ENUM_CONSTANT(RESULT_BODY_SIZE_LIMIT_EXCEEDED);
BIND_ENUM_CONSTANT(RESULT_BODY_DECOMPRESS_FAILED);
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index 4b32188377..80445684b0 100644
--- a/scene/main/http_request.h
+++ b/scene/main/http_request.h
@@ -32,6 +32,7 @@
#define HTTP_REQUEST_H
#include "core/io/http_client.h"
+#include "core/io/stream_peer_gzip.h"
#include "core/os/thread.h"
#include "core/templates/safe_refcount.h"
#include "scene/main/node.h"
@@ -48,7 +49,7 @@ public:
RESULT_CANT_CONNECT,
RESULT_CANT_RESOLVE,
RESULT_CONNECTION_ERROR,
- RESULT_SSL_HANDSHAKE_ERROR,
+ RESULT_TLS_HANDSHAKE_ERROR,
RESULT_NO_RESPONSE,
RESULT_BODY_SIZE_LIMIT_EXCEEDED,
RESULT_BODY_DECOMPRESS_FAILED,
@@ -67,8 +68,8 @@ private:
String url;
int port = 80;
Vector<String> headers;
- bool validate_ssl = false;
- bool use_ssl = false;
+ bool validate_tls = false;
+ bool use_tls = false;
HTTPClient::Method method;
Vector<uint8_t> request_data;
@@ -84,10 +85,12 @@ private:
String download_to_file;
+ Ref<StreamPeerGZIP> decompressor;
Ref<FileAccess> file;
int body_len = -1;
SafeNumeric<int> downloaded;
+ SafeNumeric<int> final_body_size;
int body_size_limit = -1;
int redirections = 0;
@@ -113,6 +116,7 @@ private:
Thread thread;
+ void _defer_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data);
void _request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data);
static void _thread_func(void *p_userdata);
@@ -121,8 +125,8 @@ protected:
static void _bind_methods();
public:
- Error request(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_ssl_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const String &p_request_data = ""); //connects to a full url and perform request
- Error request_raw(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_ssl_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const Vector<uint8_t> &p_request_data_raw = Vector<uint8_t>()); //connects to a full url and perform request
+ Error request(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_tls_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const String &p_request_data = ""); //connects to a full url and perform request
+ Error request_raw(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_tls_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const Vector<uint8_t> &p_request_data_raw = Vector<uint8_t>()); //connects to a full url and perform request
void cancel_request();
HTTPClient::Status get_http_client_status() const;
diff --git a/scene/main/missing_node.cpp b/scene/main/missing_node.cpp
index 395fdad9e4..7ce527fd9c 100644
--- a/scene/main/missing_node.cpp
+++ b/scene/main/missing_node.cpp
@@ -74,9 +74,9 @@ bool MissingNode::is_recording_properties() const {
return recording_properties;
}
-TypedArray<String> MissingNode::get_configuration_warnings() const {
+PackedStringArray MissingNode::get_configuration_warnings() const {
// The mere existence of this node is warning.
- TypedArray<String> ret;
+ PackedStringArray ret;
ret.push_back(vformat(RTR("This node was saved as class type '%s', which was no longer available when this scene was loaded."), original_class));
ret.push_back(RTR("Data from the original node is kept as a placeholder until this type of node is available again. It can hence be safely re-saved without risk of data loss."));
return ret;
diff --git a/scene/main/missing_node.h b/scene/main/missing_node.h
index d200fbb47f..0003f71f29 100644
--- a/scene/main/missing_node.h
+++ b/scene/main/missing_node.h
@@ -55,7 +55,7 @@ public:
void set_recording_properties(bool p_enable);
bool is_recording_properties() const;
- virtual TypedArray<String> get_configuration_warnings() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
MissingNode();
};
diff --git a/scene/main/multiplayer_api.cpp b/scene/main/multiplayer_api.cpp
index 2d2103f031..7e2c82c88d 100644
--- a/scene/main/multiplayer_api.cpp
+++ b/scene/main/multiplayer_api.cpp
@@ -372,7 +372,7 @@ Error MultiplayerAPIExtension::rpcp(Object *p_obj, int p_peer_id, const StringNa
for (int i = 0; i < p_argcount; i++) {
args.push_back(*p_arg[i]);
}
- int ret;
+ int ret = FAILED;
if (GDVIRTUAL_CALL(_rpc, p_peer_id, p_obj, p_method, args, ret)) {
return (Error)ret;
}
@@ -380,7 +380,7 @@ Error MultiplayerAPIExtension::rpcp(Object *p_obj, int p_peer_id, const StringNa
}
int MultiplayerAPIExtension::get_remote_sender_id() {
- int id;
+ int id = 0;
if (GDVIRTUAL_CALL(_get_remote_sender_id, id)) {
return id;
}
@@ -388,7 +388,7 @@ int MultiplayerAPIExtension::get_remote_sender_id() {
}
Error MultiplayerAPIExtension::object_configuration_add(Object *p_object, Variant p_config) {
- int err;
+ int err = ERR_UNAVAILABLE;
if (GDVIRTUAL_CALL(_object_configuration_add, p_object, p_config, err)) {
return (Error)err;
}
@@ -396,7 +396,7 @@ Error MultiplayerAPIExtension::object_configuration_add(Object *p_object, Varian
}
Error MultiplayerAPIExtension::object_configuration_remove(Object *p_object, Variant p_config) {
- int err;
+ int err = ERR_UNAVAILABLE;
if (GDVIRTUAL_CALL(_object_configuration_remove, p_object, p_config, err)) {
return (Error)err;
}
diff --git a/scene/main/multiplayer_peer.cpp b/scene/main/multiplayer_peer.cpp
index 9b63118f7c..462dc1babb 100644
--- a/scene/main/multiplayer_peer.cpp
+++ b/scene/main/multiplayer_peer.cpp
@@ -78,6 +78,10 @@ bool MultiplayerPeer::is_refusing_new_connections() const {
return refuse_connections;
}
+bool MultiplayerPeer::is_server_relay_supported() const {
+ return false;
+}
+
void MultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &MultiplayerPeer::set_transfer_channel);
ClassDB::bind_method(D_METHOD("get_transfer_channel"), &MultiplayerPeer::get_transfer_channel);
@@ -86,6 +90,8 @@ void MultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &MultiplayerPeer::set_target_peer);
ClassDB::bind_method(D_METHOD("get_packet_peer"), &MultiplayerPeer::get_packet_peer);
+ ClassDB::bind_method(D_METHOD("get_packet_channel"), &MultiplayerPeer::get_packet_channel);
+ ClassDB::bind_method(D_METHOD("get_packet_mode"), &MultiplayerPeer::get_packet_mode);
ClassDB::bind_method(D_METHOD("poll"), &MultiplayerPeer::poll);
@@ -96,6 +102,8 @@ void MultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_refuse_new_connections", "enable"), &MultiplayerPeer::set_refuse_new_connections);
ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &MultiplayerPeer::is_refusing_new_connections);
+ ClassDB::bind_method(D_METHOD("is_server_relay_supported"), &MultiplayerPeer::is_server_relay_supported);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_connections"), "set_refuse_new_connections", "is_refusing_new_connections");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_mode", PROPERTY_HINT_ENUM, "Unreliable,Unreliable Ordered,Reliable"), "set_transfer_mode", "get_transfer_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_channel", PROPERTY_HINT_RANGE, "0,255,1"), "set_transfer_channel", "get_transfer_channel");
@@ -177,6 +185,14 @@ bool MultiplayerPeerExtension::is_refusing_new_connections() const {
return MultiplayerPeer::is_refusing_new_connections();
}
+bool MultiplayerPeerExtension::is_server_relay_supported() const {
+ bool can_relay;
+ if (GDVIRTUAL_CALL(_is_server_relay_supported, can_relay)) {
+ return can_relay;
+ }
+ return MultiplayerPeer::is_server_relay_supported();
+}
+
void MultiplayerPeerExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size");
GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size");
diff --git a/scene/main/multiplayer_peer.h b/scene/main/multiplayer_peer.h
index ab7483ece5..63ce66871e 100644
--- a/scene/main/multiplayer_peer.h
+++ b/scene/main/multiplayer_peer.h
@@ -74,10 +74,13 @@ public:
virtual TransferMode get_transfer_mode() const;
virtual void set_refuse_new_connections(bool p_enable);
virtual bool is_refusing_new_connections() const;
+ virtual bool is_server_relay_supported() const;
virtual void set_target_peer(int p_peer_id) = 0;
virtual int get_packet_peer() const = 0;
+ virtual TransferMode get_packet_mode() const = 0;
+ virtual int get_packet_channel() const = 0;
virtual bool is_server() const = 0;
@@ -123,12 +126,17 @@ public:
virtual bool is_refusing_new_connections() const override;
GDVIRTUAL0RC(bool, _is_refusing_new_connections); // Optional.
+ virtual bool is_server_relay_supported() const override;
+ GDVIRTUAL0RC(bool, _is_server_relay_supported); // Optional.
+
EXBIND1(set_transfer_channel, int);
EXBIND0RC(int, get_transfer_channel);
EXBIND1(set_transfer_mode, TransferMode);
EXBIND0RC(TransferMode, get_transfer_mode);
EXBIND1(set_target_peer, int);
EXBIND0RC(int, get_packet_peer);
+ EXBIND0RC(TransferMode, get_packet_mode);
+ EXBIND0RC(int, get_packet_channel);
EXBIND0RC(bool, is_server);
EXBIND0(poll);
EXBIND0RC(int, get_unique_id);
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 289e963077..2ea45df309 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -322,53 +322,62 @@ void Node::_propagate_exit_tree() {
data.depth = -1;
}
-void Node::move_child(Node *p_child, int p_pos) {
+void Node::move_child(Node *p_child, int p_index) {
ERR_FAIL_NULL(p_child);
ERR_FAIL_COND_MSG(p_child->data.parent != this, "Child is not a child of this node.");
// We need to check whether node is internal and move it only in the relevant node range.
if (p_child->_is_internal_front()) {
- ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_front, vformat("Invalid new child position: %d. Child is internal.", p_pos));
- _move_child(p_child, p_pos);
+ if (p_index < 0) {
+ p_index += data.internal_children_front;
+ }
+ ERR_FAIL_INDEX_MSG(p_index, data.internal_children_front, vformat("Invalid new child index: %d. Child is internal.", p_index));
+ _move_child(p_child, p_index);
} else if (p_child->_is_internal_back()) {
- ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_back, vformat("Invalid new child position: %d. Child is internal.", p_pos));
- _move_child(p_child, data.children.size() - data.internal_children_back + p_pos);
+ if (p_index < 0) {
+ p_index += data.internal_children_back;
+ }
+ ERR_FAIL_INDEX_MSG(p_index, data.internal_children_back, vformat("Invalid new child index: %d. Child is internal.", p_index));
+ _move_child(p_child, data.children.size() - data.internal_children_back + p_index);
} else {
- ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child position: %d.", p_pos));
- _move_child(p_child, p_pos + data.internal_children_front);
+ if (p_index < 0) {
+ p_index += get_child_count(false);
+ }
+ ERR_FAIL_INDEX_MSG(p_index, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child index: %d.", p_index));
+ _move_child(p_child, p_index + data.internal_children_front);
}
}
-void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
+void Node::_move_child(Node *p_child, int p_index, bool p_ignore_end) {
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, move_child() failed. Consider using call_deferred(\"move_child\") instead (or \"popup\" if this is from a popup).");
// Specifying one place beyond the end
- // means the same as moving to the last position
+ // means the same as moving to the last index
if (!p_ignore_end) { // p_ignore_end is a little hack to make back internal children work properly.
if (p_child->_is_internal_front()) {
- if (p_pos == data.internal_children_front) {
- p_pos--;
+ if (p_index == data.internal_children_front) {
+ p_index--;
}
} else if (p_child->_is_internal_back()) {
- if (p_pos == data.children.size()) {
- p_pos--;
+ if (p_index == data.children.size()) {
+ p_index--;
}
} else {
- if (p_pos == data.children.size() - data.internal_children_back) {
- p_pos--;
+ if (p_index == data.children.size() - data.internal_children_back) {
+ p_index--;
}
}
}
- if (p_child->data.pos == p_pos) {
+ if (p_child->data.index == p_index) {
return; //do nothing
}
- int motion_from = MIN(p_pos, p_child->data.pos);
- int motion_to = MAX(p_pos, p_child->data.pos);
+ int motion_from = MIN(p_index, p_child->data.index);
+ int motion_to = MAX(p_index, p_child->data.index);
- data.children.remove_at(p_child->data.pos);
- data.children.insert(p_pos, p_child);
+ data.children.remove_at(p_child->data.index);
+ data.children.insert(p_index, p_child);
if (data.tree) {
data.tree->tree_changed();
@@ -377,7 +386,7 @@ void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
data.blocked++;
//new pos first
for (int i = motion_from; i <= motion_to; i++) {
- data.children[i]->data.pos = i;
+ data.children[i]->data.index = i;
}
// notification second
move_child_notify(p_child);
@@ -389,21 +398,6 @@ void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
data.blocked--;
}
-void Node::raise() {
- if (!data.parent) {
- return;
- }
-
- // Internal children move within a different index range.
- if (_is_internal_front()) {
- data.parent->move_child(this, data.parent->data.internal_children_front - 1);
- } else if (_is_internal_back()) {
- data.parent->move_child(this, data.parent->data.internal_children_back - 1);
- } else {
- data.parent->move_child(this, data.parent->get_child_count(false) - 1);
- }
-}
-
void Node::_propagate_groups_dirty() {
for (const KeyValue<StringName, GroupData> &E : data.grouped) {
if (E.value.group) {
@@ -1030,11 +1024,9 @@ String increase_numeric_string(const String &s) {
void Node::_generate_serial_child_name(const Node *p_child, StringName &name) const {
if (name == StringName()) {
- //no name and a new name is needed, create one.
+ // No name and a new name is needed, create one.
name = p_child->get_class();
- // Adjust casing according to project setting.
- name = adjust_name_casing(name);
}
//quickly test if proposed name exists
@@ -1112,7 +1104,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
//add a child node quickly, without name validation
p_child->data.name = p_name;
- p_child->data.pos = data.children.size();
+ p_child->data.index = data.children.size();
data.children.push_back(p_child);
p_child->data.parent = this;
@@ -1131,7 +1123,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
add_child_notify(p_child);
}
-void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_internal) {
+void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_internal) {
ERR_FAIL_NULL(p_child);
ERR_FAIL_COND_MSG(p_child == this, vformat("Can't add child '%s' to itself.", p_child->get_name())); // adding to itself!
ERR_FAIL_COND_MSG(p_child->data.parent, vformat("Can't add child '%s' to '%s', already has a parent '%s'.", p_child->get_name(), get_name(), p_child->data.parent->get_name())); //Fail if node has a parent
@@ -1140,7 +1132,7 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_i
#endif
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_node() failed. Consider using call_deferred(\"add_child\", child) instead.");
- _validate_child_name(p_child, p_legible_unique_name);
+ _validate_child_name(p_child, p_force_readable_name);
_add_child_nocheck(p_child, p_child->data.name);
if (p_internal == INTERNAL_MODE_FRONT) {
@@ -1154,7 +1146,7 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_i
}
}
-void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) {
+void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) {
ERR_FAIL_NULL(p_sibling);
ERR_FAIL_NULL(data.parent);
ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself!
@@ -1167,7 +1159,7 @@ void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) {
internal = INTERNAL_MODE_BACK;
}
- data.parent->add_child(p_sibling, p_legible_unique_name, internal);
+ data.parent->add_child(p_sibling, p_force_readable_name, internal);
data.parent->_move_child(p_sibling, get_index() + 1);
}
@@ -1179,9 +1171,9 @@ void Node::remove_child(Node *p_child) {
Node **children = data.children.ptrw();
int idx = -1;
- if (p_child->data.pos >= 0 && p_child->data.pos < child_count) {
- if (children[p_child->data.pos] == p_child) {
- idx = p_child->data.pos;
+ if (p_child->data.index >= 0 && p_child->data.index < child_count) {
+ if (children[p_child->data.index] == p_child) {
+ idx = p_child->data.index;
}
}
@@ -1217,12 +1209,12 @@ void Node::remove_child(Node *p_child) {
children = data.children.ptrw();
for (int i = idx; i < child_count; i++) {
- children[i]->data.pos = i;
+ children[i]->data.index = i;
children[i]->notification(NOTIFICATION_MOVED_IN_PARENT);
}
p_child->data.parent = nullptr;
- p_child->data.pos = -1;
+ p_child->data.index = -1;
if (data.inside_tree) {
p_child->_propagate_after_exit_tree();
@@ -1417,14 +1409,14 @@ TypedArray<Node> Node::find_children(const String &p_pattern, const String &p_ty
if (cptr[i]->is_class(p_type)) {
ret.append(cptr[i]);
} else if (cptr[i]->get_script_instance()) {
- Ref<Script> script = cptr[i]->get_script_instance()->get_script();
- while (script.is_valid()) {
- if ((ScriptServer::is_global_class(p_type) && ScriptServer::get_global_class_path(p_type) == script->get_path()) || p_type == script->get_path()) {
+ Ref<Script> scr = cptr[i]->get_script_instance()->get_script();
+ while (scr.is_valid()) {
+ if ((ScriptServer::is_global_class(p_type) && ScriptServer::get_global_class_path(p_type) == scr->get_path()) || p_type == scr->get_path()) {
ret.append(cptr[i]);
break;
}
- script = script->get_base_script();
+ scr = scr->get_base_script();
}
}
@@ -1472,26 +1464,16 @@ bool Node::is_greater_than(const Node *p_node) const {
ERR_FAIL_COND_V(data.depth < 0, false);
ERR_FAIL_COND_V(p_node->data.depth < 0, false);
-#ifdef NO_ALLOCA
-
- Vector<int> this_stack;
- Vector<int> that_stack;
- this_stack.resize(data.depth);
- that_stack.resize(p_node->data.depth);
-
-#else
int *this_stack = (int *)alloca(sizeof(int) * data.depth);
int *that_stack = (int *)alloca(sizeof(int) * p_node->data.depth);
-#endif
-
const Node *n = this;
int idx = data.depth - 1;
while (n) {
ERR_FAIL_INDEX_V(idx, data.depth, false);
- this_stack[idx--] = n->data.pos;
+ this_stack[idx--] = n->data.index;
n = n->data.parent;
}
ERR_FAIL_COND_V(idx != -1, false);
@@ -1499,7 +1481,7 @@ bool Node::is_greater_than(const Node *p_node) const {
idx = p_node->data.depth - 1;
while (n) {
ERR_FAIL_INDEX_V(idx, p_node->data.depth, false);
- that_stack[idx--] = n->data.pos;
+ that_stack[idx--] = n->data.index;
n = n->data.parent;
}
@@ -1910,9 +1892,9 @@ int Node::get_index(bool p_include_internal) const {
ERR_FAIL_COND_V_MSG(!p_include_internal && (_is_internal_front() || _is_internal_back()), -1, "Node is internal. Can't get index with 'include_internal' being false.");
if (data.parent && !p_include_internal) {
- return data.pos - data.parent->data.internal_children_front;
+ return data.index - data.parent->data.internal_children_front;
}
- return data.pos;
+ return data.index;
}
Ref<Tween> Node::create_tween() {
@@ -1922,43 +1904,6 @@ Ref<Tween> Node::create_tween() {
return tween;
}
-void Node::remove_and_skip() {
- ERR_FAIL_COND(!data.parent);
-
- Node *new_owner = get_owner();
-
- List<Node *> children;
-
- while (true) {
- bool clear = true;
- for (int i = 0; i < data.children.size(); i++) {
- Node *c_node = data.children[i];
- if (!c_node->get_owner()) {
- continue;
- }
-
- remove_child(c_node);
- c_node->_propagate_replace_owner(this, nullptr);
- children.push_back(c_node);
- clear = false;
- break;
- }
-
- if (clear) {
- break;
- }
- }
-
- while (!children.is_empty()) {
- Node *c_node = children.front()->get();
- data.parent->add_child(c_node);
- c_node->_propagate_replace_owner(nullptr, new_owner);
- children.pop_front();
- }
-
- data.parent->remove_child(this);
-}
-
void Node::set_scene_file_path(const String &p_scene_file_path) {
data.scene_file_path = p_scene_file_path;
}
@@ -2174,9 +2119,9 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c
if (p_flags & DUPLICATE_SCRIPTS) {
bool is_valid = false;
- Variant script = N->get()->get(script_property_name, &is_valid);
+ Variant scr = N->get()->get(script_property_name, &is_valid);
if (is_valid) {
- current_node->set(script_property_name, script);
+ current_node->set(script_property_name, scr);
}
}
@@ -2444,12 +2389,12 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) {
}
Node *parent = data.parent;
- int pos_in_parent = data.pos;
+ int index_in_parent = data.index;
if (data.parent) {
parent->remove_child(this);
parent->add_child(p_node);
- parent->move_child(p_node, pos_in_parent);
+ parent->move_child(p_node, index_in_parent);
}
while (get_child_count()) {
@@ -2683,21 +2628,19 @@ void Node::clear_internal_tree_resource_paths() {
}
}
-TypedArray<String> Node::get_configuration_warnings() const {
- TypedArray<String> ret;
+PackedStringArray Node::get_configuration_warnings() const {
+ PackedStringArray ret;
Vector<String> warnings;
if (GDVIRTUAL_CALL(_get_configuration_warnings, warnings)) {
- for (int i = 0; i < warnings.size(); i++) {
- ret.push_back(warnings[i]);
- }
+ ret.append_array(warnings);
}
return ret;
}
String Node::get_configuration_warnings_as_string() const {
- TypedArray<String> warnings = get_configuration_warnings();
+ PackedStringArray warnings = get_configuration_warnings();
String all_warnings = String();
for (int i = 0; i < warnings.size(); i++) {
if (i > 0) {
@@ -2705,7 +2648,7 @@ String Node::get_configuration_warnings_as_string() const {
}
// Format as a bullet point list to make multiple warnings easier to distinguish
// from each other.
- all_warnings += String::utf8("• ") + String(warnings[i]);
+ all_warnings += String::utf8("• ") + warnings[i];
}
return all_warnings;
}
@@ -2787,11 +2730,11 @@ void Node::_bind_methods() {
GLOBAL_DEF("editor/node_naming/name_casing", NAME_CASING_PASCAL_CASE);
ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_casing", PropertyInfo(Variant::INT, "editor/node_naming/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"));
- ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "legible_unique_name"), &Node::add_sibling, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "force_readable_name"), &Node::add_sibling, DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_name", "name"), &Node::set_name);
ClassDB::bind_method(D_METHOD("get_name"), &Node::get_name);
- ClassDB::bind_method(D_METHOD("add_child", "node", "legible_unique_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("add_child", "node", "force_readable_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0));
ClassDB::bind_method(D_METHOD("remove_child", "node"), &Node::remove_child);
ClassDB::bind_method(D_METHOD("get_child_count", "include_internal"), &Node::get_child_count, DEFVAL(false)); // Note that the default value bound for include_internal is false, while the method is declared with true. This is because internal nodes are irrelevant for GDSCript.
ClassDB::bind_method(D_METHOD("get_children", "include_internal"), &Node::_get_children, DEFVAL(false));
@@ -2814,12 +2757,10 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_to_group", "group", "persistent"), &Node::add_to_group, DEFVAL(false));
ClassDB::bind_method(D_METHOD("remove_from_group", "group"), &Node::remove_from_group);
ClassDB::bind_method(D_METHOD("is_in_group", "group"), &Node::is_in_group);
- ClassDB::bind_method(D_METHOD("move_child", "child_node", "to_position"), &Node::move_child);
+ ClassDB::bind_method(D_METHOD("move_child", "child_node", "to_index"), &Node::move_child);
ClassDB::bind_method(D_METHOD("get_groups"), &Node::_get_groups);
- ClassDB::bind_method(D_METHOD("raise"), &Node::raise);
ClassDB::bind_method(D_METHOD("set_owner", "owner"), &Node::set_owner);
ClassDB::bind_method(D_METHOD("get_owner"), &Node::get_owner);
- ClassDB::bind_method(D_METHOD("remove_and_skip"), &Node::remove_and_skip);
ClassDB::bind_method(D_METHOD("get_index", "include_internal"), &Node::get_index, DEFVAL(false));
ClassDB::bind_method(D_METHOD("print_tree"), &Node::print_tree);
ClassDB::bind_method(D_METHOD("print_tree_pretty"), &Node::print_tree_pretty);
diff --git a/scene/main/node.h b/scene/main/node.h
index ae6a997579..c8c8c395ce 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -91,6 +91,7 @@ private:
SceneTree::Group *group = nullptr;
};
+ // This Data struct is to avoid namespace pollution in derived classes.
struct Data {
String scene_file_path;
Ref<SceneState> instance_state;
@@ -104,7 +105,7 @@ private:
int internal_children_front = 0;
int internal_children_back = 0;
- int pos = -1;
+ int index = -1;
int depth = -1;
int blocked = 0; // Safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed.
StringName name;
@@ -186,8 +187,8 @@ private:
Error _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Error _rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.pos < data.parent->data.internal_children_front; }
- _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.pos >= data.parent->data.children.size() - data.parent->data.internal_children_back; }
+ _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.index < data.parent->data.internal_children_front; }
+ _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.index >= data.parent->data.children.size() - data.parent->data.internal_children_back; }
friend class SceneTree;
@@ -303,8 +304,8 @@ public:
StringName get_name() const;
void set_name(const String &p_name);
- void add_child(Node *p_child, bool p_legible_unique_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED);
- void add_sibling(Node *p_sibling, bool p_legible_unique_name = false);
+ void add_child(Node *p_child, bool p_force_readable_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED);
+ void add_sibling(Node *p_sibling, bool p_force_readable_name = false);
void remove_child(Node *p_child);
int get_child_count(bool p_include_internal = true) const;
@@ -346,9 +347,8 @@ public:
void get_groups(List<GroupInfo> *p_groups) const;
int get_persistent_group_count() const;
- void move_child(Node *p_child, int p_pos);
- void _move_child(Node *p_child, int p_pos, bool p_ignore_end = false);
- void raise();
+ void move_child(Node *p_child, int p_index);
+ void _move_child(Node *p_child, int p_index, bool p_ignore_end = false);
void set_owner(Node *p_owner);
Node *get_owner() const;
@@ -357,7 +357,6 @@ public:
void set_unique_name_in_owner(bool p_enabled);
bool is_unique_name_in_owner() const;
- void remove_and_skip();
int get_index(bool p_include_internal = true) const;
Ref<Tween> create_tween();
@@ -479,7 +478,7 @@ public:
_FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; }
- virtual TypedArray<String> get_configuration_warnings() const;
+ virtual PackedStringArray get_configuration_warnings() const;
String get_configuration_warnings_as_string() const;
void update_configuration_warnings();
@@ -531,4 +530,8 @@ Error Node::rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args)
return rpcp(p_peer_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
+// Add these macro to your class's 'get_configuration_warnings' function to have warnings show up in the scene tree inspector.
+#define DEPRECATED_NODE_WARNING warnings.push_back(RTR("This node is marked as deprecated and will be removed in future versions.\nPlease check the Godot documentation for information about migration."));
+#define EXPERIMENTAL_NODE_WARNING warnings.push_back(RTR("This node is marked as experimental and may be subject to removal or major changes in future versions."));
+
#endif // NODE_H
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 25c9b33ff9..5ff9a29792 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -44,6 +44,7 @@
#include "node.h"
#include "scene/animation/tween.h"
#include "scene/debugger/scene_debugger.h"
+#include "scene/gui/control.h"
#include "scene/main/multiplayer_api.h"
#include "scene/main/viewport.h"
#include "scene/resources/environment.h"
@@ -105,10 +106,10 @@ bool SceneTreeTimer::is_ignore_time_scale() {
}
void SceneTreeTimer::release_connections() {
- List<Connection> connections;
- get_all_signal_connections(&connections);
+ List<Connection> signal_connections;
+ get_all_signal_connections(&signal_connections);
- for (const Connection &connection : connections) {
+ for (const Connection &connection : signal_connections) {
disconnect(connection.signal.get_name(), connection.callable);
}
}
@@ -207,15 +208,15 @@ void SceneTree::_update_group_order(Group &g, bool p_use_priority) {
return;
}
- Node **nodes = g.nodes.ptrw();
- int node_count = g.nodes.size();
+ Node **gr_nodes = g.nodes.ptrw();
+ int gr_node_count = g.nodes.size();
if (p_use_priority) {
SortArray<Node *, Node::ComparatorWithPriority> node_sort;
- node_sort.sort(nodes, node_count);
+ node_sort.sort(gr_nodes, gr_node_count);
} else {
SortArray<Node *, Node::Comparator> node_sort;
- node_sort.sort(nodes, node_count);
+ node_sort.sort(gr_nodes, gr_node_count);
}
g.changed = false;
}
@@ -253,36 +254,36 @@ void SceneTree::call_group_flagsp(uint32_t p_call_flags, const StringName &p_gro
_update_group_order(g);
Vector<Node *> nodes_copy = g.nodes;
- Node **nodes = nodes_copy.ptrw();
- int node_count = nodes_copy.size();
+ Node **gr_nodes = nodes_copy.ptrw();
+ int gr_node_count = nodes_copy.size();
call_lock++;
if (p_call_flags & GROUP_CALL_REVERSE) {
- for (int i = node_count - 1; i >= 0; i--) {
- if (call_lock && call_skip.has(nodes[i])) {
+ for (int i = gr_node_count - 1; i >= 0; i--) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
Callable::CallError ce;
- nodes[i]->callp(p_function, p_args, p_argcount, ce);
+ gr_nodes[i]->callp(p_function, p_args, p_argcount, ce);
} else {
- MessageQueue::get_singleton()->push_callp(nodes[i], p_function, p_args, p_argcount);
+ MessageQueue::get_singleton()->push_callp(gr_nodes[i], p_function, p_args, p_argcount);
}
}
} else {
- for (int i = 0; i < node_count; i++) {
- if (call_lock && call_skip.has(nodes[i])) {
+ for (int i = 0; i < gr_node_count; i++) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
Callable::CallError ce;
- nodes[i]->callp(p_function, p_args, p_argcount, ce);
+ gr_nodes[i]->callp(p_function, p_args, p_argcount, ce);
} else {
- MessageQueue::get_singleton()->push_callp(nodes[i], p_function, p_args, p_argcount);
+ MessageQueue::get_singleton()->push_callp(gr_nodes[i], p_function, p_args, p_argcount);
}
}
}
@@ -306,34 +307,34 @@ void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_gr
_update_group_order(g);
Vector<Node *> nodes_copy = g.nodes;
- Node **nodes = nodes_copy.ptrw();
- int node_count = nodes_copy.size();
+ Node **gr_nodes = nodes_copy.ptrw();
+ int gr_node_count = nodes_copy.size();
call_lock++;
if (p_call_flags & GROUP_CALL_REVERSE) {
- for (int i = node_count - 1; i >= 0; i--) {
- if (call_lock && call_skip.has(nodes[i])) {
+ for (int i = gr_node_count - 1; i >= 0; i--) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
- nodes[i]->notification(p_notification);
+ gr_nodes[i]->notification(p_notification);
} else {
- MessageQueue::get_singleton()->push_notification(nodes[i], p_notification);
+ MessageQueue::get_singleton()->push_notification(gr_nodes[i], p_notification);
}
}
} else {
- for (int i = 0; i < node_count; i++) {
- if (call_lock && call_skip.has(nodes[i])) {
+ for (int i = 0; i < gr_node_count; i++) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
- nodes[i]->notification(p_notification);
+ gr_nodes[i]->notification(p_notification);
} else {
- MessageQueue::get_singleton()->push_notification(nodes[i], p_notification);
+ MessageQueue::get_singleton()->push_notification(gr_nodes[i], p_notification);
}
}
}
@@ -357,34 +358,34 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group
_update_group_order(g);
Vector<Node *> nodes_copy = g.nodes;
- Node **nodes = nodes_copy.ptrw();
- int node_count = nodes_copy.size();
+ Node **gr_nodes = nodes_copy.ptrw();
+ int gr_node_count = nodes_copy.size();
call_lock++;
if (p_call_flags & GROUP_CALL_REVERSE) {
- for (int i = node_count - 1; i >= 0; i--) {
- if (call_lock && call_skip.has(nodes[i])) {
+ for (int i = gr_node_count - 1; i >= 0; i--) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
- nodes[i]->set(p_name, p_value);
+ gr_nodes[i]->set(p_name, p_value);
} else {
- MessageQueue::get_singleton()->push_set(nodes[i], p_name, p_value);
+ MessageQueue::get_singleton()->push_set(gr_nodes[i], p_name, p_value);
}
}
} else {
- for (int i = 0; i < node_count; i++) {
- if (call_lock && call_skip.has(nodes[i])) {
+ for (int i = 0; i < gr_node_count; i++) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
- nodes[i]->set(p_name, p_value);
+ gr_nodes[i]->set(p_name, p_value);
} else {
- MessageQueue::get_singleton()->push_set(nodes[i], p_name, p_value);
+ MessageQueue::get_singleton()->push_set(gr_nodes[i], p_name, p_value);
}
}
}
@@ -510,7 +511,7 @@ bool SceneTree::process(double p_time) {
return _quit;
}
-void SceneTree::process_timers(float p_delta, bool p_physics_frame) {
+void SceneTree::process_timers(double p_delta, bool p_physics_frame) {
List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element
for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
@@ -542,7 +543,7 @@ void SceneTree::process_timers(float p_delta, bool p_physics_frame) {
}
}
-void SceneTree::process_tweens(float p_delta, bool p_physics) {
+void SceneTree::process_tweens(double p_delta, bool p_physics) {
// This methods works similarly to how SceneTreeTimers are handled.
List<Ref<Tween>>::Element *L = tweens.back();
@@ -722,22 +723,6 @@ float SceneTree::get_debug_paths_width() const {
return debug_paths_width;
}
-void SceneTree::set_debug_navigation_color(const Color &p_color) {
- debug_navigation_color = p_color;
-}
-
-Color SceneTree::get_debug_navigation_color() const {
- return debug_navigation_color;
-}
-
-void SceneTree::set_debug_navigation_disabled_color(const Color &p_color) {
- debug_navigation_disabled_color = p_color;
-}
-
-Color SceneTree::get_debug_navigation_disabled_color() const {
- return debug_navigation_disabled_color;
-}
-
Ref<Material> SceneTree::get_debug_paths_material() {
if (debug_paths_material.is_valid()) {
return debug_paths_material;
@@ -755,40 +740,6 @@ Ref<Material> SceneTree::get_debug_paths_material() {
return debug_paths_material;
}
-Ref<Material> SceneTree::get_debug_navigation_material() {
- if (navigation_material.is_valid()) {
- return navigation_material;
- }
-
- Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
- line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- line_material->set_albedo(get_debug_navigation_color());
-
- navigation_material = line_material;
-
- return navigation_material;
-}
-
-Ref<Material> SceneTree::get_debug_navigation_disabled_material() {
- if (navigation_disabled_material.is_valid()) {
- return navigation_disabled_material;
- }
-
- Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
- line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- line_material->set_albedo(get_debug_navigation_disabled_color());
-
- navigation_disabled_material = line_material;
-
- return navigation_disabled_material;
-}
-
Ref<Material> SceneTree::get_debug_collision_material() {
if (collision_material.is_valid()) {
return collision_material;
@@ -896,13 +847,13 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
//performance is not lost because only if something is added/removed the vector is copied.
Vector<Node *> nodes_copy = g.nodes;
- int node_count = nodes_copy.size();
- Node **nodes = nodes_copy.ptrw();
+ int gr_node_count = nodes_copy.size();
+ Node **gr_nodes = nodes_copy.ptrw();
call_lock++;
- for (int i = 0; i < node_count; i++) {
- Node *n = nodes[i];
+ for (int i = 0; i < gr_node_count; i++) {
+ Node *n = gr_nodes[i];
if (call_lock && call_skip.has(n)) {
continue;
}
@@ -915,7 +866,7 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
}
n->notification(p_notification);
- //ERR_FAIL_COND(node_count != g.nodes.size());
+ //ERR_FAIL_COND(gr_node_count != g.nodes.size());
}
call_lock--;
@@ -940,17 +891,19 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
//performance is not lost because only if something is added/removed the vector is copied.
Vector<Node *> nodes_copy = g.nodes;
- int node_count = nodes_copy.size();
- Node **nodes = nodes_copy.ptrw();
+ int gr_node_count = nodes_copy.size();
+ Node **gr_nodes = nodes_copy.ptrw();
call_lock++;
- for (int i = node_count - 1; i >= 0; i--) {
+ Vector<ObjectID> no_context_node_ids; // Nodes may be deleted due to this shortcut input.
+
+ for (int i = gr_node_count - 1; i >= 0; i--) {
if (p_viewport->is_input_handled()) {
break;
}
- Node *n = nodes[i];
+ Node *n = gr_nodes[i];
if (call_lock && call_skip.has(n)) {
continue;
}
@@ -963,9 +916,22 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
case CALL_INPUT_TYPE_INPUT:
n->_call_input(p_input);
break;
- case CALL_INPUT_TYPE_SHORTCUT_INPUT:
+ case CALL_INPUT_TYPE_SHORTCUT_INPUT: {
+ const Control *c = Object::cast_to<Control>(n);
+ if (c) {
+ // If calling shortcut input on a control, ensure it respects the shortcut context.
+ // Shortcut context (based on focus) only makes sense for controls (UI), so don't need to worry about it for nodes
+ if (c->get_shortcut_context() == nullptr) {
+ no_context_node_ids.append(n->get_instance_id());
+ continue;
+ }
+ if (!c->is_focus_owner_in_shortcut_context()) {
+ continue;
+ }
+ }
n->_call_shortcut_input(p_input);
break;
+ }
case CALL_INPUT_TYPE_UNHANDLED_INPUT:
n->_call_unhandled_input(p_input);
break;
@@ -975,6 +941,13 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
}
}
+ for (const ObjectID &id : no_context_node_ids) {
+ Node *n = Object::cast_to<Node>(ObjectDB::get_instance(id));
+ if (n) {
+ n->_call_shortcut_input(p_input);
+ }
+ }
+
call_lock--;
if (call_lock == 0) {
call_skip.clear();
@@ -1135,19 +1108,20 @@ void SceneTree::_change_scene(Node *p_to) {
if (p_to) {
current_scene = p_to;
root->add_child(p_to);
+ root->update_mouse_cursor_shape();
}
}
-Error SceneTree::change_scene(const String &p_path) {
+Error SceneTree::change_scene_to_file(const String &p_path) {
Ref<PackedScene> new_scene = ResourceLoader::load(p_path);
if (new_scene.is_null()) {
return ERR_CANT_OPEN;
}
- return change_scene_to(new_scene);
+ return change_scene_to_packed(new_scene);
}
-Error SceneTree::change_scene_to(const Ref<PackedScene> &p_scene) {
+Error SceneTree::change_scene_to_packed(const Ref<PackedScene> &p_scene) {
Node *new_scene = nullptr;
if (p_scene.is_valid()) {
new_scene = p_scene->instantiate();
@@ -1161,7 +1135,7 @@ Error SceneTree::change_scene_to(const Ref<PackedScene> &p_scene) {
Error SceneTree::reload_current_scene() {
ERR_FAIL_COND_V(!current_scene, ERR_UNCONFIGURED);
String fname = current_scene->get_scene_file_path();
- return change_scene(fname);
+ return change_scene_to_file(fname);
}
void SceneTree::add_current_scene(Node *p_current) {
@@ -1310,8 +1284,8 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_current_scene", "child_node"), &SceneTree::set_current_scene);
ClassDB::bind_method(D_METHOD("get_current_scene"), &SceneTree::get_current_scene);
- ClassDB::bind_method(D_METHOD("change_scene", "path"), &SceneTree::change_scene);
- ClassDB::bind_method(D_METHOD("change_scene_to", "packed_scene"), &SceneTree::change_scene_to);
+ ClassDB::bind_method(D_METHOD("change_scene_to_file", "path"), &SceneTree::change_scene_to_file);
+ ClassDB::bind_method(D_METHOD("change_scene_to_packed", "packed_scene"), &SceneTree::change_scene_to_packed);
ClassDB::bind_method(D_METHOD("reload_current_scene"), &SceneTree::reload_current_scene);
@@ -1366,7 +1340,7 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) {
}
void SceneTree::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
- if (p_function == "change_scene") {
+ if (p_function == "change_scene_to_file") {
Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
List<String> directories;
directories.push_back(dir_access->get_current_dir());
@@ -1404,8 +1378,6 @@ SceneTree::SceneTree() {
debug_collision_contact_color = GLOBAL_DEF("debug/shapes/collision/contact_color", Color(1.0, 0.2, 0.1, 0.8));
debug_paths_color = GLOBAL_DEF("debug/shapes/paths/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
debug_paths_width = GLOBAL_DEF("debug/shapes/paths/geometry_width", 2.0);
- debug_navigation_color = GLOBAL_DEF("debug/shapes/navigation/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
- debug_navigation_disabled_color = GLOBAL_DEF("debug/shapes/navigation/disabled_geometry_color", Color(1.0, 0.7, 0.1, 0.4));
collision_debug_contacts = GLOBAL_DEF("debug/shapes/collision/max_contacts_displayed", 10000);
ProjectSettings::get_singleton()->set_custom_property_info("debug/shapes/collision/max_contacts_displayed", PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1")); // No negative
@@ -1441,6 +1413,9 @@ SceneTree::SceneTree() {
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa_3d", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")));
root->set_msaa_3d(Viewport::MSAA(msaa_mode_3d));
+ const bool transparent_background = GLOBAL_DEF("rendering/transparent_background", false);
+ root->set_transparent_background(transparent_background);
+
const int ssaa_mode = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/screen_space_aa", 0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/screen_space_aa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"));
root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 45653001ca..a460e40597 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -180,8 +180,8 @@ private:
void node_added(Node *p_node);
void node_removed(Node *p_node);
void node_renamed(Node *p_node);
- void process_timers(float p_delta, bool p_physics_frame);
- void process_tweens(float p_delta, bool p_physics_frame);
+ void process_timers(double p_delta, bool p_physics_frame);
+ void process_tweens(double p_delta, bool p_physics_frame);
Group *add_to_group(const StringName &p_group, Node *p_node);
void remove_from_group(const StringName &p_group, Node *p_node);
@@ -334,15 +334,7 @@ public:
void set_debug_paths_width(float p_width);
float get_debug_paths_width() const;
- void set_debug_navigation_color(const Color &p_color);
- Color get_debug_navigation_color() const;
-
- void set_debug_navigation_disabled_color(const Color &p_color);
- Color get_debug_navigation_disabled_color() const;
-
Ref<Material> get_debug_paths_material();
- Ref<Material> get_debug_navigation_material();
- Ref<Material> get_debug_navigation_disabled_material();
Ref<Material> get_debug_collision_material();
Ref<ArrayMesh> get_debug_contact_mesh();
@@ -366,8 +358,8 @@ public:
void set_current_scene(Node *p_scene);
Node *get_current_scene() const;
- Error change_scene(const String &p_path);
- Error change_scene_to(const Ref<PackedScene> &p_scene);
+ Error change_scene_to_file(const String &p_path);
+ Error change_scene_to_packed(const Ref<PackedScene> &p_scene);
Error reload_current_scene();
Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true, bool p_process_in_physics = false, bool p_ignore_time_scale = false);
diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp
index 13034c5447..455b8c6866 100644
--- a/scene/main/shader_globals_override.cpp
+++ b/scene/main/shader_globals_override.cpp
@@ -271,8 +271,8 @@ void ShaderGlobalsOverride::_notification(int p_what) {
}
}
-TypedArray<String> ShaderGlobalsOverride::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray ShaderGlobalsOverride::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!active) {
warnings.push_back(RTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene."));
diff --git a/scene/main/shader_globals_override.h b/scene/main/shader_globals_override.h
index af99bf9aa7..f3d0074f28 100644
--- a/scene/main/shader_globals_override.h
+++ b/scene/main/shader_globals_override.h
@@ -58,7 +58,7 @@ protected:
static void _bind_methods();
public:
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
ShaderGlobalsOverride();
};
diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp
index bb9359ef59..210b60171a 100644
--- a/scene/main/timer.cpp
+++ b/scene/main/timer.cpp
@@ -180,8 +180,8 @@ void Timer::_set_process(bool p_process, bool p_force) {
processing = p_process;
}
-TypedArray<String> Timer::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray Timer::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (wait_time < 0.05 - CMP_EPSILON) {
warnings.push_back(RTR("Very low timer wait times (< 0.05 seconds) may behave in significantly different ways depending on the rendered or physics frame rate.\nConsider using a script's process loop instead of relying on a Timer for very low wait times."));
diff --git a/scene/main/timer.h b/scene/main/timer.h
index 8785d31a8a..53503e31b2 100644
--- a/scene/main/timer.h
+++ b/scene/main/timer.h
@@ -73,7 +73,7 @@ public:
double get_time_left() const;
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
void set_timer_process_callback(TimerProcessCallback p_callback);
TimerProcessCallback get_timer_process_callback() const;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index fe4a171d81..ad40346c36 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -60,8 +60,8 @@
#include "servers/rendering/rendering_server_globals.h"
void ViewportTexture::setup_local_to_scene() {
- Node *local_scene = get_local_scene();
- if (!local_scene) {
+ Node *loc_scene = get_local_scene();
+ if (!loc_scene) {
return;
}
@@ -71,7 +71,7 @@ void ViewportTexture::setup_local_to_scene() {
vp = nullptr;
- Node *vpn = local_scene->get_node(path);
+ Node *vpn = loc_scene->get_node(path);
ERR_FAIL_COND_MSG(!vpn, "ViewportTexture: Path to node is invalid.");
vp = Object::cast_to<Viewport>(vpn);
@@ -499,6 +499,13 @@ void Viewport::_notification(int p_what) {
// exit event if the change in focus results in the mouse exiting
// the window.
} break;
+
+ case NOTIFICATION_PREDELETE: {
+ if (gui_parent) {
+ gui_parent->gui.tooltip_popup = nullptr;
+ gui_parent->gui.tooltip_label = nullptr;
+ }
+ } break;
}
}
@@ -628,19 +635,19 @@ void Viewport::_process_picking() {
PhysicsDirectSpaceState2D::ShapeResult res[64];
for (const CanvasLayer *E : canvas_layers) {
- Transform2D canvas_transform;
+ Transform2D canvas_layer_transform;
ObjectID canvas_layer_id;
if (E) {
// A descendant CanvasLayer.
- canvas_transform = E->get_transform();
+ canvas_layer_transform = E->get_transform();
canvas_layer_id = E->get_instance_id();
} else {
// This Viewport's builtin canvas.
- canvas_transform = get_canvas_transform();
+ canvas_layer_transform = get_canvas_transform();
canvas_layer_id = ObjectID();
}
- Vector2 point = canvas_transform.affine_inverse().xform(pos);
+ Vector2 point = canvas_layer_transform.affine_inverse().xform(pos);
PhysicsDirectSpaceState2D::PointParameters point_params;
point_params.position = point;
@@ -795,11 +802,20 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override,
stretch_transform = p_stretch_transform;
to_screen_rect = p_to_screen_rect;
- if (p_allocated) {
- RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
- } else {
- RS::get_singleton()->viewport_set_size(viewport, 0, 0);
- }
+#ifndef _3D_DISABLED
+ if (!use_xr) {
+#endif
+
+ if (p_allocated) {
+ RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
+ } else {
+ RS::get_singleton()->viewport_set_size(viewport, 0, 0);
+ }
+
+#ifndef _3D_DISABLED
+ } // if (!use_xr)
+#endif
+
_update_global_transform();
update_configuration_warnings();
@@ -813,6 +829,19 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override,
}
Size2i Viewport::_get_size() const {
+#ifndef _3D_DISABLED
+ if (use_xr) {
+ if (XRServer::get_singleton() != nullptr) {
+ Ref<XRInterface> xr_interface = XRServer::get_singleton()->get_primary_interface();
+ if (xr_interface.is_valid() && xr_interface->is_initialized()) {
+ Size2 xr_size = xr_interface->get_render_target_size();
+ return (Size2i)xr_size;
+ }
+ }
+ return Size2i();
+ }
+#endif // _3D_DISABLED
+
return size;
}
@@ -1133,8 +1162,6 @@ void Viewport::_gui_cancel_tooltip() {
}
if (gui.tooltip_popup) {
gui.tooltip_popup->queue_delete();
- gui.tooltip_popup = nullptr;
- gui.tooltip_label = nullptr;
}
}
@@ -1197,8 +1224,6 @@ void Viewport::_gui_show_tooltip() {
// Remove previous popup if we change something.
if (gui.tooltip_popup) {
memdelete(gui.tooltip_popup);
- gui.tooltip_popup = nullptr;
- gui.tooltip_label = nullptr;
}
if (!tooltip_owner) {
@@ -1230,6 +1255,7 @@ void Viewport::_gui_show_tooltip() {
panel->set_flag(Window::FLAG_POPUP, false);
panel->set_wrap_controls(true);
panel->add_child(base_tooltip);
+ panel->gui_parent = this;
gui.tooltip_popup = panel;
@@ -1378,10 +1404,6 @@ Control *Viewport::gui_find_control(const Point2 &p_global) {
}
Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform) {
- if (Object::cast_to<Viewport>(p_node)) {
- return nullptr;
- }
-
if (!p_node->is_visible()) {
return nullptr; // Canvas item hidden, discard.
}
@@ -1465,7 +1487,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.key_event_accepted = false;
Point2 mpos = mb->get_position();
- gui.last_mouse_pos = mpos;
if (mb->is_pressed()) {
Size2 pos = mpos;
if (gui.mouse_focus_mask != MouseButton::NONE) {
@@ -1555,7 +1576,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.drag_preview_id = ObjectID();
}
_propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
- // Change mouse accordingly.
+ get_base_window()->update_mouse_cursor_shape();
}
_gui_cancel_tooltip();
@@ -1576,7 +1597,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.dragging = false;
gui.drag_mouse_over = nullptr;
_propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
- // Change mouse accordingly.
+ get_base_window()->update_mouse_cursor_shape();
}
gui.mouse_focus_mask &= ~mouse_button_to_mask(mb->get_button_index()); // Remove from mask.
@@ -1619,8 +1640,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.key_event_accepted = false;
Point2 mpos = mm->get_position();
- gui.last_mouse_pos = mpos;
-
// Drag & drop.
if (!gui.drag_attempted && gui.mouse_focus && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
gui.drag_accum += mm->get_relative();
@@ -2104,7 +2123,7 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) {
p_control->set_as_top_level(true);
p_control->set_position(gui.last_mouse_pos);
p_base->get_root_parent_control()->add_child(p_control); // Add as child of viewport.
- p_control->raise();
+ p_control->move_to_front();
gui.drag_preview_id = p_control->get_instance_id();
}
@@ -2734,6 +2753,11 @@ void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ev = p_event;
}
+ Ref<InputEventMouse> me = ev;
+ if (me.is_valid()) {
+ gui.last_mouse_pos = me->get_position();
+ }
+
if (is_embedding_subwindows() && _sub_windows_forward_input(ev)) {
set_input_as_handled();
return;
@@ -2778,7 +2802,7 @@ void Viewport::push_unhandled_input(const Ref<InputEvent> &p_event, bool p_local
}
// Shortcut Input.
- if (Object::cast_to<InputEventKey>(*ev) != nullptr || Object::cast_to<InputEventShortcut>(*ev) != nullptr) {
+ if (Object::cast_to<InputEventKey>(*ev) != nullptr || Object::cast_to<InputEventShortcut>(*ev) != nullptr || Object::cast_to<InputEventJoypadButton>(*ev) != nullptr) {
get_tree()->_call_input_pause(shortcut_input_group, SceneTree::CALL_INPUT_TYPE_SHORTCUT_INPUT, ev, this);
}
@@ -2851,8 +2875,8 @@ Variant Viewport::gui_get_drag_data() const {
return gui.drag_data;
}
-TypedArray<String> Viewport::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+PackedStringArray Viewport::get_configuration_warnings() const {
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (size.x <= 1 || size.y <= 1) {
warnings.push_back(RTR("The Viewport size must be greater than or equal to 2 pixels on both dimensions to render anything."));
@@ -3613,9 +3637,20 @@ void Viewport::_propagate_exit_world_3d(Node *p_node) {
}
void Viewport::set_use_xr(bool p_use_xr) {
- use_xr = p_use_xr;
+ if (use_xr != p_use_xr) {
+ use_xr = p_use_xr;
- RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
+ RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
+
+ if (!use_xr) {
+ // Set viewport to previous size when exiting XR.
+ if (size_allocated) {
+ RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
+ } else {
+ RS::get_singleton()->viewport_set_size(viewport, 0, 0);
+ }
+ }
+ }
}
bool Viewport::is_using_xr() {
@@ -3691,6 +3726,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_global_canvas_transform", "xform"), &Viewport::set_global_canvas_transform);
ClassDB::bind_method(D_METHOD("get_global_canvas_transform"), &Viewport::get_global_canvas_transform);
ClassDB::bind_method(D_METHOD("get_final_transform"), &Viewport::get_final_transform);
+ ClassDB::bind_method(D_METHOD("get_screen_transform"), &Viewport::get_screen_transform);
ClassDB::bind_method(D_METHOD("get_visible_rect"), &Viewport::get_visible_rect);
ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background);
@@ -4018,16 +4054,10 @@ Viewport::Viewport() {
ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::FLOAT, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
#ifndef _3D_DISABLED
- Viewport::Scaling3DMode scaling_3d_mode = (Viewport::Scaling3DMode)(int)GLOBAL_GET("rendering/scaling_3d/mode");
- set_scaling_3d_mode(scaling_3d_mode);
-
+ set_scaling_3d_mode((Viewport::Scaling3DMode)(int)GLOBAL_GET("rendering/scaling_3d/mode"));
set_scaling_3d_scale(GLOBAL_GET("rendering/scaling_3d/scale"));
-
- float fsr_sharpness = GLOBAL_GET("rendering/scaling_3d/fsr_sharpness");
- set_fsr_sharpness(fsr_sharpness);
-
- float texture_mipmap_bias = GLOBAL_GET("rendering/textures/default_filters/texture_mipmap_bias");
- set_texture_mipmap_bias(texture_mipmap_bias);
+ set_fsr_sharpness((float)GLOBAL_GET("rendering/scaling_3d/fsr_sharpness"));
+ set_texture_mipmap_bias((float)GLOBAL_GET("rendering/textures/default_filters/texture_mipmap_bias"));
#endif // _3D_DISABLED
set_sdf_oversize(sdf_oversize); // Set to server.
@@ -4103,7 +4133,7 @@ Transform2D SubViewport::_stretch_transform() {
Transform2D transform = Transform2D();
Size2i view_size_2d_override = _get_size_2d_override();
if (size_2d_override_stretch && view_size_2d_override.width > 0 && view_size_2d_override.height > 0) {
- Size2 scale = _get_size() / view_size_2d_override;
+ Size2 scale = Size2(_get_size()) / Size2(view_size_2d_override);
transform.scale(scale);
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index afea3ea56c..6f67649ea3 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -208,6 +208,7 @@ private:
friend class ViewportTexture;
Viewport *parent = nullptr;
+ Viewport *gui_parent = nullptr; // Whose gui.tooltip_popup it is.
AudioListener2D *audio_listener_2d = nullptr;
Camera2D *camera_2d = nullptr;
@@ -568,7 +569,7 @@ public:
bool is_input_disabled() const;
Vector2 get_mouse_position() const;
- virtual void warp_mouse(const Vector2 &p_position);
+ void warp_mouse(const Vector2 &p_position);
void set_physics_object_picking(bool p_enable);
bool get_physics_object_picking();
@@ -581,7 +582,7 @@ public:
void gui_release_focus();
Control *gui_get_focus_owner();
- TypedArray<String> get_configuration_warnings() const override;
+ PackedStringArray get_configuration_warnings() const override;
void set_debug_draw(DebugDraw p_debug_draw);
DebugDraw get_debug_draw() const;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 25e0a9978c..ebb11ecee8 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -157,26 +157,18 @@ void Window::set_flag(Flags p_flag, bool p_enabled) {
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-#ifdef TOOLS_ENABLED
- if ((p_flag != FLAG_POPUP) || !(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
}
-#else
- DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
-#endif
}
}
bool Window::get_flag(Flags p_flag) const {
ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-#ifdef TOOLS_ENABLED
- if ((p_flag != FLAG_POPUP) || !(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id);
}
-#else
- flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id);
-#endif
}
return flags[p_flag];
}
@@ -232,6 +224,14 @@ bool Window::is_embedded() const {
return _get_embedder() != nullptr;
}
+bool Window::is_in_edited_scene_root() const {
+#ifdef TOOLS_ENABLED
+ return (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this));
+#else
+ return false;
+#endif
+}
+
void Window::_make_window() {
ERR_FAIL_COND(window_id != DisplayServer::INVALID_WINDOW_ID);
@@ -259,15 +259,12 @@ void Window::_make_window() {
#endif
DisplayServer::get_singleton()->window_set_title(tr_title, window_id);
DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
- } else {
+
+ if (is_in_edited_scene_root()) {
DisplayServer::get_singleton()->window_set_exclusive(window_id, false);
+ } else {
+ DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
}
-#else
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
-#endif
_update_window_size();
@@ -389,9 +386,24 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
_propagate_window_notification(this, NOTIFICATION_WM_DPI_CHANGE);
emit_signal(SNAME("dpi_changed"));
} break;
+ case DisplayServer::WINDOW_EVENT_TITLEBAR_CHANGE: {
+ emit_signal(SNAME("titlebar_changed"));
+ } break;
}
}
+void Window::update_mouse_cursor_shape() {
+ // The default shape is set in Viewport::_gui_input_event. To instantly
+ // see the shape in the viewport we need to trigger a mouse motion event.
+ Ref<InputEventMouseMotion> mm;
+ Vector2 pos = get_mouse_position();
+ Transform2D xform = get_global_canvas_transform().affine_inverse();
+ mm.instantiate();
+ mm->set_position(pos);
+ mm->set_global_position(xform.xform(pos));
+ push_input(mm);
+}
+
void Window::show() {
set_visible(true);
}
@@ -450,14 +462,10 @@ void Window::set_visible(bool p_visible) {
//update transient exclusive
if (transient_parent) {
if (exclusive && visible) {
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child.");
transient_parent->exclusive_child = this;
}
-#else
- transient_parent->exclusive_child = this;
-#endif
} else {
if (transient_parent->exclusive_child == this) {
transient_parent->exclusive_child = nullptr;
@@ -504,13 +512,9 @@ void Window::_make_transient() {
window->transient_children.insert(this);
if (is_inside_tree() && is_visible() && exclusive) {
if (transient_parent->exclusive_child == nullptr) {
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
transient_parent->exclusive_child = this;
}
-#else
- transient_parent->exclusive_child = this;
-#endif
} else if (transient_parent->exclusive_child != this) {
ERR_PRINT("Making child transient exclusive, but parent has another exclusive child");
}
@@ -553,27 +557,19 @@ void Window::set_exclusive(bool p_exclusive) {
exclusive = p_exclusive;
if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) {
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
- } else {
+ if (is_in_edited_scene_root()) {
DisplayServer::get_singleton()->window_set_exclusive(window_id, false);
+ } else {
+ DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
}
-#else
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
-#endif
}
if (transient_parent) {
if (p_exclusive && is_inside_tree() && is_visible()) {
ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child.");
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
transient_parent->exclusive_child = this;
}
-#else
- transient_parent->exclusive_child = this;
-#endif
} else {
if (transient_parent->exclusive_child == this) {
transient_parent->exclusive_child = nullptr;
@@ -648,9 +644,9 @@ void Window::_update_window_size() {
DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id);
}
- DisplayServer::get_singleton()->window_set_size(size, window_id);
DisplayServer::get_singleton()->window_set_max_size(max_size_valid ? max_size : Size2i(), window_id);
DisplayServer::get_singleton()->window_set_min_size(size_limit, window_id);
+ DisplayServer::get_singleton()->window_set_size(size, window_id);
}
//update the viewport
@@ -663,7 +659,7 @@ void Window::_update_viewport_size() {
Size2i final_size;
Size2i final_size_override;
Rect2i attach_to_screen_rect(Point2i(), size);
- Transform2D stretch_transform;
+ Transform2D stretch_transform_new;
float font_oversampling = 1.0;
if (content_scale_mode == CONTENT_SCALE_MODE_DISABLED || content_scale_size.x == 0 || content_scale_size.y == 0) {
@@ -671,8 +667,8 @@ void Window::_update_viewport_size() {
final_size = size;
final_size_override = Size2(size) / content_scale_factor;
- stretch_transform = Transform2D();
- stretch_transform.scale(Size2(content_scale_factor, content_scale_factor));
+ stretch_transform_new = Transform2D();
+ stretch_transform_new.scale(Size2(content_scale_factor, content_scale_factor));
} else {
//actual screen video mode
Size2 video_mode = size;
@@ -749,7 +745,7 @@ void Window::_update_viewport_size() {
font_oversampling = (screen_size.x / viewport_size.x) * content_scale_factor;
Size2 scale = Vector2(screen_size) / Vector2(final_size_override);
- stretch_transform.scale(scale);
+ stretch_transform_new.scale(scale);
} break;
case CONTENT_SCALE_MODE_VIEWPORT: {
@@ -761,7 +757,7 @@ void Window::_update_viewport_size() {
}
bool allocate = is_inside_tree() && visible && (window_id != DisplayServer::INVALID_WINDOW_ID || embedder != nullptr);
- _set_size(final_size, final_size_override, attach_to_screen_rect, stretch_transform, allocate);
+ _set_size(final_size, final_size_override, attach_to_screen_rect, stretch_transform_new, allocate);
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
RenderingServer::get_singleton()->viewport_attach_to_screen(get_viewport_rid(), attach_to_screen_rect, window_id);
@@ -998,18 +994,6 @@ DisplayServer::WindowID Window::get_window_id() const {
return window_id;
}
-void Window::warp_mouse(const Vector2 &p_position) {
- Transform2D xform = get_screen_transform();
- Vector2 gpos = xform.xform(p_position);
-
- if (transient_parent && !transient_parent->is_embedding_subwindows()) {
- Transform2D window_trans = Transform2D().translated(get_position() + (transient_parent->get_visible_rect().size - transient_parent->get_real_size()));
- gpos = window_trans.xform(gpos);
- }
-
- Input::get_singleton()->warp_mouse(gpos);
-}
-
void Window::set_wrap_controls(bool p_enable) {
wrap_controls = p_enable;
if (wrap_controls) {
@@ -1165,7 +1149,7 @@ void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio
Rect2 parent_rect;
if (is_embedded()) {
- parent_rect = get_parent_viewport()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
@@ -1191,7 +1175,7 @@ void Window::popup_centered(const Size2i &p_minsize) {
Rect2 parent_rect;
if (is_embedded()) {
- parent_rect = get_parent_viewport()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
@@ -1219,7 +1203,7 @@ void Window::popup_centered_ratio(float p_ratio) {
Rect2 parent_rect;
if (is_embedded()) {
- parent_rect = get_parent_viewport()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
@@ -1272,6 +1256,19 @@ void Window::popup(const Rect2i &p_screen_rect) {
set_transient(true);
set_visible(true);
+
+ Rect2i parent_rect;
+ if (is_embedded()) {
+ parent_rect = _get_embedder()->get_visible_rect();
+ } else {
+ int screen_id = DisplayServer::get_singleton()->window_get_current_screen(get_window_id());
+ parent_rect = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id);
+ }
+ if (parent_rect != Rect2i() && !parent_rect.intersects(Rect2i(position, size))) {
+ ERR_PRINT(vformat("Window %d spawned at invalid position: %s.", get_window_id(), position));
+ set_position((parent_rect.size - size) / 2);
+ }
+
_post_popup();
notification(NOTIFICATION_POST_POPUP);
}
@@ -1294,17 +1291,17 @@ bool Window::has_focus() const {
Rect2i Window::get_usable_parent_rect() const {
ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
- Rect2i parent;
+ Rect2i parent_rect;
if (is_embedded()) {
- parent = _get_embedder()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
const Window *w = is_visible() ? this : get_parent_visible_window();
//find a parent that can contain us
ERR_FAIL_COND_V(!w, Rect2());
- parent = DisplayServer::get_singleton()->screen_get_usable_rect(DisplayServer::get_singleton()->window_get_current_screen(w->get_window_id()));
+ parent_rect = DisplayServer::get_singleton()->screen_get_usable_rect(DisplayServer::get_singleton()->window_get_current_screen(w->get_window_id()));
}
- return parent;
+ return parent_rect;
}
void Window::add_child_notify(Node *p_child) {
@@ -1572,9 +1569,9 @@ Window::LayoutDirection Window::get_layout_direction() const {
bool Window::is_layout_rtl() const {
if (layout_dir == LAYOUT_DIRECTION_INHERITED) {
- Window *parent = Object::cast_to<Window>(get_parent());
- if (parent) {
- return parent->is_layout_rtl();
+ Window *parent_w = Object::cast_to<Window>(get_parent());
+ if (parent_w) {
+ return parent_w->is_layout_rtl();
} else {
if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) {
return true;
@@ -1806,6 +1803,7 @@ void Window::_bind_methods() {
ADD_SIGNAL(MethodInfo("visibility_changed"));
ADD_SIGNAL(MethodInfo("about_to_popup"));
ADD_SIGNAL(MethodInfo("theme_changed"));
+ ADD_SIGNAL(MethodInfo("titlebar_changed"));
BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
BIND_CONSTANT(NOTIFICATION_THEME_CHANGED);
diff --git a/scene/main/window.h b/scene/main/window.h
index 8113117103..03597b309a 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -220,6 +220,8 @@ public:
void set_visible(bool p_visible);
bool is_visible() const;
+ void update_mouse_cursor_shape();
+
void show();
void hide();
@@ -232,6 +234,8 @@ public:
void set_clamp_to_embedder(bool p_enable);
bool is_clamped_to_embedder() const;
+ bool is_in_edited_scene_root() const;
+
bool can_draw() const;
void set_ime_active(bool p_active);
@@ -254,8 +258,6 @@ public:
void set_use_font_oversampling(bool p_oversampling);
bool is_using_font_oversampling() const;
- void warp_mouse(const Vector2 &p_position) override;
-
void set_wrap_controls(bool p_enable);
bool is_wrapping_controls() const;
void child_controls_changed();