summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/extension/extension_api_dump.cpp2
-rw-r--r--core/extension/gdnative_interface.cpp2
-rw-r--r--core/io/json.cpp23
-rw-r--r--core/io/json.h6
-rw-r--r--core/io/stream_peer_gzip.cpp209
-rw-r--r--core/io/stream_peer_gzip.h76
-rw-r--r--core/register_core_types.cpp2
-rw-r--r--doc/classes/JSON.xml5
-rw-r--r--doc/classes/PhysicsServer2DExtension.xml2
-rw-r--r--doc/classes/PhysicsServer3DExtension.xml2
-rw-r--r--doc/classes/StreamPeerGZIP.xml42
-rw-r--r--editor/connections_dialog.cpp23
-rw-r--r--editor/editor_settings_dialog.cpp53
-rw-r--r--scene/2d/physics_body_2d.cpp16
-rw-r--r--scene/3d/physics_body_3d.cpp23
-rw-r--r--scene/3d/sprite_3d.cpp493
-rw-r--r--scene/3d/sprite_3d.h10
-rw-r--r--scene/gui/base_button.cpp2
-rw-r--r--scene/gui/menu_bar.cpp2
-rw-r--r--scene/main/http_request.cpp125
-rw-r--r--scene/main/http_request.h4
-rw-r--r--servers/extensions/physics_server_2d_extension.cpp2
-rw-r--r--servers/extensions/physics_server_2d_extension.h15
-rw-r--r--servers/extensions/physics_server_3d_extension.cpp2
-rw-r--r--servers/extensions/physics_server_3d_extension.h14
-rw-r--r--servers/physics_2d/godot_body_2d.cpp17
-rw-r--r--servers/physics_2d/godot_body_2d.h5
-rw-r--r--servers/physics_2d/godot_physics_server_2d.cpp4
-rw-r--r--servers/physics_2d/godot_physics_server_2d.h2
-rw-r--r--servers/physics_3d/godot_body_3d.cpp17
-rw-r--r--servers/physics_3d/godot_body_3d.h5
-rw-r--r--servers/physics_3d/godot_physics_server_3d.cpp4
-rw-r--r--servers/physics_3d/godot_physics_server_3d.h2
-rw-r--r--servers/physics_server_2d.h5
-rw-r--r--servers/physics_server_2d_wrap_mt.h2
-rw-r--r--servers/physics_server_3d.h5
-rw-r--r--servers/physics_server_3d_wrap_mt.h2
-rw-r--r--servers/register_server_types.cpp2
38 files changed, 700 insertions, 527 deletions
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 5cf951a93c..bda1a5cdc1 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -462,7 +462,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
d["indexing_return_type"] = index_type == Variant::NIL ? String("Variant") : Variant::get_type_name(index_type);
}
- d["is_keyed"] = Variant::ValidatedKeyedSetter(type);
+ d["is_keyed"] = Variant::is_keyed(type);
{
//members
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index 6c680e82c9..67dc55bdb7 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -884,7 +884,7 @@ static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const char *p_clas
MethodBind *mb = ClassDB::get_method(StringName(p_classname), StringName(p_methodname));
ERR_FAIL_COND_V(!mb, nullptr);
if (mb->get_hash() != p_hash) {
- ERR_PRINT_ONCE("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'.");
+ ERR_PRINT("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'.");
return nullptr;
}
// MethodBind *mb = ClassDB::get_method("Node", "get_name");
diff --git a/core/io/json.cpp b/core/io/json.cpp
index a685fcb718..7e267d35d4 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -56,6 +56,8 @@ String JSON::_make_indent(const String &p_indent, int p_size) {
}
String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision) {
+ ERR_FAIL_COND_V_MSG(p_cur_indent > Variant::MAX_RECURSION_DEPTH, "...", "JSON structure is too deep. Bailing.");
+
String colon = ":";
String end_statement = "";
@@ -357,17 +359,22 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to
return ERR_PARSE_ERROR;
}
-Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
+ if (p_depth > Variant::MAX_RECURSION_DEPTH) {
+ r_err_str = "JSON structure is too deep. Bailing.";
+ return ERR_OUT_OF_MEMORY;
+ }
+
if (token.type == TK_CURLY_BRACKET_OPEN) {
Dictionary d;
- Error err = _parse_object(d, p_str, index, p_len, line, r_err_str);
+ Error err = _parse_object(d, p_str, index, p_len, line, p_depth + 1, r_err_str);
if (err) {
return err;
}
value = d;
} else if (token.type == TK_BRACKET_OPEN) {
Array a;
- Error err = _parse_array(a, p_str, index, p_len, line, r_err_str);
+ Error err = _parse_array(a, p_str, index, p_len, line, p_depth + 1, r_err_str);
if (err) {
return err;
}
@@ -396,7 +403,7 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in
return OK;
}
-Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
Token token;
bool need_comma = false;
@@ -421,7 +428,7 @@ Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_
}
Variant v;
- err = _parse_value(v, token, p_str, index, p_len, line, r_err_str);
+ err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str);
if (err) {
return err;
}
@@ -434,7 +441,7 @@ Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_
return ERR_PARSE_ERROR;
}
-Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
bool at_key = true;
String key;
Token token;
@@ -483,7 +490,7 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index,
}
Variant v;
- err = _parse_value(v, token, p_str, index, p_len, line, r_err_str);
+ err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str);
if (err) {
return err;
}
@@ -514,7 +521,7 @@ Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_st
return err;
}
- err = _parse_value(r_ret, token, str, idx, len, r_err_line, r_err_str);
+ err = _parse_value(r_ret, token, str, idx, len, r_err_line, 0, r_err_str);
// Check if EOF is reached
// or it's a type of the next token.
diff --git a/core/io/json.h b/core/io/json.h
index 208d4ad625..829a5f922b 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -74,9 +74,9 @@ class JSON : public RefCounted {
static String _make_indent(const String &p_indent, int p_size);
static String _stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision = false);
static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str);
- static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
- static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
- static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
+ static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str);
+ static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str);
+ static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str);
static Error _parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line);
protected:
diff --git a/core/io/stream_peer_gzip.cpp b/core/io/stream_peer_gzip.cpp
new file mode 100644
index 0000000000..ca8be2d62e
--- /dev/null
+++ b/core/io/stream_peer_gzip.cpp
@@ -0,0 +1,209 @@
+/*************************************************************************/
+/* stream_peer_gzip.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "core/io/stream_peer_gzip.h"
+
+#include "core/io/zip_io.h"
+#include <zlib.h>
+
+void StreamPeerGZIP::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("start_compression", "use_deflate", "buffer_size"), &StreamPeerGZIP::start_compression, DEFVAL(false), DEFVAL(65535));
+ ClassDB::bind_method(D_METHOD("start_decompression", "use_deflate", "buffer_size"), &StreamPeerGZIP::start_decompression, DEFVAL(false), DEFVAL(65535));
+ ClassDB::bind_method(D_METHOD("finish"), &StreamPeerGZIP::finish);
+ ClassDB::bind_method(D_METHOD("clear"), &StreamPeerGZIP::clear);
+}
+
+StreamPeerGZIP::StreamPeerGZIP() {
+}
+
+StreamPeerGZIP::~StreamPeerGZIP() {
+ _close();
+}
+
+void StreamPeerGZIP::_close() {
+ if (ctx) {
+ z_stream *strm = (z_stream *)ctx;
+ if (compressing) {
+ deflateEnd(strm);
+ } else {
+ inflateEnd(strm);
+ }
+ memfree(strm);
+ ctx = nullptr;
+ }
+}
+
+void StreamPeerGZIP::clear() {
+ _close();
+ rb.clear();
+ buffer.clear();
+}
+
+Error StreamPeerGZIP::start_compression(bool p_is_deflate, int buffer_size) {
+ return _start(true, p_is_deflate, buffer_size);
+}
+
+Error StreamPeerGZIP::start_decompression(bool p_is_deflate, int buffer_size) {
+ return _start(false, p_is_deflate, buffer_size);
+}
+
+Error StreamPeerGZIP::_start(bool p_compress, bool p_is_deflate, int buffer_size) {
+ ERR_FAIL_COND_V(ctx != nullptr, ERR_ALREADY_IN_USE);
+ clear();
+ compressing = p_compress;
+ rb.resize(nearest_shift(buffer_size - 1));
+ buffer.resize(1024);
+
+ // Create ctx.
+ ctx = memalloc(sizeof(z_stream));
+ z_stream &strm = *(z_stream *)ctx;
+ strm.next_in = Z_NULL;
+ strm.avail_in = 0;
+ strm.zalloc = zipio_alloc;
+ strm.zfree = zipio_free;
+ strm.opaque = Z_NULL;
+ int window_bits = p_is_deflate ? 15 : (15 + 16);
+ int err = Z_OK;
+ int level = Z_DEFAULT_COMPRESSION;
+ if (compressing) {
+ err = deflateInit2(&strm, level, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
+ } else {
+ err = inflateInit2(&strm, window_bits);
+ }
+ ERR_FAIL_COND_V(err != Z_OK, FAILED);
+ return OK;
+}
+
+Error StreamPeerGZIP::_process(uint8_t *p_dst, int p_dst_size, const uint8_t *p_src, int p_src_size, int &r_consumed, int &r_out, bool p_close) {
+ ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED);
+ z_stream &strm = *(z_stream *)ctx;
+ strm.avail_in = p_src_size;
+ strm.avail_out = p_dst_size;
+ strm.next_in = (Bytef *)p_src;
+ strm.next_out = (Bytef *)p_dst;
+ int flush = p_close ? Z_FINISH : Z_NO_FLUSH;
+ if (compressing) {
+ int err = deflate(&strm, flush);
+ ERR_FAIL_COND_V(err != (p_close ? Z_STREAM_END : Z_OK), FAILED);
+ } else {
+ int err = inflate(&strm, flush);
+ ERR_FAIL_COND_V(err != Z_OK && err != Z_STREAM_END, FAILED);
+ }
+ r_out = p_dst_size - strm.avail_out;
+ r_consumed = p_src_size - strm.avail_in;
+ return OK;
+}
+
+Error StreamPeerGZIP::put_data(const uint8_t *p_data, int p_bytes) {
+ int wrote = 0;
+ Error err = put_partial_data(p_data, p_bytes, wrote);
+ if (err != OK) {
+ return err;
+ }
+ ERR_FAIL_COND_V(p_bytes != wrote, ERR_OUT_OF_MEMORY);
+ return OK;
+}
+
+Error StreamPeerGZIP::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
+ ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(p_bytes < 0, ERR_INVALID_PARAMETER);
+
+ // Ensure we have enough space in temporary buffer.
+ if (buffer.size() < p_bytes) {
+ buffer.resize(p_bytes);
+ }
+
+ r_sent = 0;
+ while (r_sent < p_bytes && rb.space_left() > 1024) { // Keep the ring buffer size meaningful.
+ int sent = 0;
+ int to_write = 0;
+ // Compress or decompress
+ Error err = _process(buffer.ptrw(), MIN(buffer.size(), rb.space_left()), p_data + r_sent, p_bytes - r_sent, sent, to_write);
+ if (err != OK) {
+ return err;
+ }
+ // When decompressing, we might need to do another round.
+ r_sent += sent;
+
+ // We can't write more than this buffer is full.
+ if (sent == 0 && to_write == 0) {
+ return OK;
+ }
+ if (to_write) {
+ // Copy to ring buffer.
+ int wrote = rb.write(buffer.ptr(), to_write);
+ ERR_FAIL_COND_V(wrote != to_write, ERR_BUG);
+ }
+ }
+ return OK;
+}
+
+Error StreamPeerGZIP::get_data(uint8_t *p_buffer, int p_bytes) {
+ int received = 0;
+ Error err = get_partial_data(p_buffer, p_bytes, received);
+ if (err != OK) {
+ return err;
+ }
+ ERR_FAIL_COND_V(p_bytes != received, ERR_UNAVAILABLE);
+ return OK;
+}
+
+Error StreamPeerGZIP::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) {
+ ERR_FAIL_COND_V(p_bytes < 0, ERR_INVALID_PARAMETER);
+
+ r_received = MIN(p_bytes, rb.data_left());
+ if (r_received == 0) {
+ return OK;
+ }
+ int received = rb.read(p_buffer, r_received);
+ ERR_FAIL_COND_V(received != r_received, ERR_BUG);
+ return OK;
+}
+
+int StreamPeerGZIP::get_available_bytes() const {
+ return rb.data_left();
+}
+
+Error StreamPeerGZIP::finish() {
+ ERR_FAIL_COND_V(!ctx || !compressing, ERR_UNAVAILABLE);
+ // Ensure we have enough space in temporary buffer.
+ if (buffer.size() < 1024) {
+ buffer.resize(1024); // 1024 should be more than enough.
+ }
+ int consumed = 0;
+ int to_write = 0;
+ Error err = _process(buffer.ptrw(), 1024, nullptr, 0, consumed, to_write, true); // compress
+ if (err != OK) {
+ return err;
+ }
+ int wrote = rb.write(buffer.ptr(), to_write);
+ ERR_FAIL_COND_V(wrote != to_write, ERR_OUT_OF_MEMORY);
+ return OK;
+}
diff --git a/core/io/stream_peer_gzip.h b/core/io/stream_peer_gzip.h
new file mode 100644
index 0000000000..5bafdbca9b
--- /dev/null
+++ b/core/io/stream_peer_gzip.h
@@ -0,0 +1,76 @@
+/*************************************************************************/
+/* stream_peer_gzip.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef STREAM_PEER_GZIP_H
+#define STREAM_PEER_GZIP_H
+
+#include "core/io/stream_peer.h"
+
+#include "core/core_bind.h"
+#include "core/io/compression.h"
+#include "core/templates/ring_buffer.h"
+
+class StreamPeerGZIP : public StreamPeer {
+ GDCLASS(StreamPeerGZIP, StreamPeer);
+
+private:
+ void *ctx = nullptr; // Will hold our z_stream instance.
+ bool compressing = true;
+
+ RingBuffer<uint8_t> rb;
+ Vector<uint8_t> buffer;
+
+ Error _process(uint8_t *p_dst, int p_dst_size, const uint8_t *p_src, int p_src_size, int &r_consumed, int &r_out, bool p_close = false);
+ void _close();
+ Error _start(bool p_compress, bool p_is_deflate, int buffer_size = 65535);
+
+protected:
+ static void _bind_methods();
+
+public:
+ Error start_compression(bool p_is_deflate, int buffer_size = 65535);
+ Error start_decompression(bool p_is_deflate, int buffer_size = 65535);
+
+ Error finish();
+ void clear();
+
+ virtual Error put_data(const uint8_t *p_data, int p_bytes) override;
+ virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override;
+
+ virtual Error get_data(uint8_t *p_buffer, int p_bytes) override;
+ virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override;
+
+ virtual int get_available_bytes() const override;
+
+ StreamPeerGZIP();
+ ~StreamPeerGZIP();
+};
+
+#endif // STREAM_PEER_GZIP_H
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 73bcdb84fd..bad53ab4e6 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -58,6 +58,7 @@
#include "core/io/resource_format_binary.h"
#include "core/io/resource_importer.h"
#include "core/io/resource_uid.h"
+#include "core/io/stream_peer_gzip.h"
#include "core/io/stream_peer_tls.h"
#include "core/io/tcp_server.h"
#include "core/io/translation_loader_po.h"
@@ -184,6 +185,7 @@ void register_core_types() {
GDREGISTER_ABSTRACT_CLASS(StreamPeer);
GDREGISTER_CLASS(StreamPeerExtension);
GDREGISTER_CLASS(StreamPeerBuffer);
+ GDREGISTER_CLASS(StreamPeerGZIP);
GDREGISTER_CLASS(StreamPeerTCP);
GDREGISTER_CLASS(TCPServer);
diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml
index 38ddca2727..125d016632 100644
--- a/doc/classes/JSON.xml
+++ b/doc/classes/JSON.xml
@@ -28,6 +28,11 @@
[codeblock]
var data = JSON.parse_string(json_string) # Returns null if parsing failed.
[/codeblock]
+ [b]Note:[/b] Both parse methods do not fully comply with the JSON specification:
+ - Trailing commas in arrays or objects are ignored, instead of causing a parser error.
+ - New line and tab characters are accepted in string literals, and are treated like their corresponding escape sequences [code]\n[/code] and [code]\t[/code].
+ - Numbers are parsed using [method String.to_float] which is generally more lax than the JSON specification.
+ - Certain errors, such as invalid Unicode sequences, do not cause a parser error. Instead, the string is cleansed and an error is logged to the console.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PhysicsServer2DExtension.xml b/doc/classes/PhysicsServer2DExtension.xml
index a63aa8a30f..518862bb28 100644
--- a/doc/classes/PhysicsServer2DExtension.xml
+++ b/doc/classes/PhysicsServer2DExtension.xml
@@ -602,7 +602,7 @@
<method name="_body_set_state_sync_callback" qualifiers="virtual">
<return type="void" />
<param index="0" name="body" type="RID" />
- <param index="1" name="callback" type="PhysicsServer2DExtensionStateCallback*" />
+ <param index="1" name="callable" type="Callable" />
<description>
</description>
</method>
diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml
index f42276ddd8..ab00f63359 100644
--- a/doc/classes/PhysicsServer3DExtension.xml
+++ b/doc/classes/PhysicsServer3DExtension.xml
@@ -575,7 +575,7 @@
<method name="_body_set_state_sync_callback" qualifiers="virtual">
<return type="void" />
<param index="0" name="body" type="RID" />
- <param index="1" name="callback" type="PhysicsServer3DExtensionStateCallback*" />
+ <param index="1" name="callable" type="Callable" />
<description>
</description>
</method>
diff --git a/doc/classes/StreamPeerGZIP.xml b/doc/classes/StreamPeerGZIP.xml
new file mode 100644
index 0000000000..71dd36160d
--- /dev/null
+++ b/doc/classes/StreamPeerGZIP.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="StreamPeerGZIP" inherits="StreamPeer" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Stream peer handling GZIP and deflate compression/decompresison.
+ </brief_description>
+ <description>
+ This class allows to compress or decompress data using GZIP/deflate in a streaming fashion. This is particularly useful when compressing or decompressing files that has to be sent through the network without having to allocate them all in memory.
+ After starting the stream via [method start_compression] (or [method start_decompression]), calling [method StreamPeer.put_partial_data] on this stream will compress (or decompress) the data, writing it to the internal buffer. Calling [method StreamPeer.get_available_bytes] will return the pending bytes in the internal buffer, and [method StreamPeer.get_partial_data] will retrieve the compressed (or decompressed) bytes from it. When the stream is over, you must call [method finish] to ensure the internal buffer is properly flushed (make sure to call [method StreamPeer.get_available_bytes] on last time to check if more data needs to be read after that).
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears this stream, resetting the internal state.
+ </description>
+ </method>
+ <method name="finish">
+ <return type="int" enum="Error" />
+ <description>
+ Finalizes the stream, compressing or decompressing any buffered chunk left.
+ </description>
+ </method>
+ <method name="start_compression">
+ <return type="int" enum="Error" />
+ <param index="0" name="use_deflate" type="bool" default="false" />
+ <param index="1" name="buffer_size" type="int" default="65535" />
+ <description>
+ Start the stream in compression mode with the given [param buffer_size], if [param use_deflate] is [code]true[/code] uses deflate instead of GZIP.
+ </description>
+ </method>
+ <method name="start_decompression">
+ <return type="int" enum="Error" />
+ <param index="0" name="use_deflate" type="bool" default="false" />
+ <param index="1" name="buffer_size" type="int" default="65535" />
+ <description>
+ Start the stream in decompression mode with the given [param buffer_size], if [param use_deflate] is [code]true[/code] uses deflate instead of GZIP.
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index c83011845b..236f3d7b08 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -238,6 +238,12 @@ void ConnectDialog::_notification(int p_what) {
String type_name = Variant::get_type_name((Variant::Type)type_list->get_item_id(i));
type_list->set_item_icon(i, get_theme_icon(type_name, SNAME("EditorIcons")));
}
+
+ Ref<StyleBox> style = get_theme_stylebox("normal", "LineEdit")->duplicate();
+ if (style.is_valid()) {
+ style->set_default_margin(SIDE_TOP, style->get_default_margin(SIDE_TOP) + 1.0);
+ from_signal->add_theme_style_override("normal", style);
+ }
} break;
}
}
@@ -465,30 +471,31 @@ ConnectDialog::ConnectDialog() {
vbc_right->add_margin_child(TTR("Unbind Signal Arguments:"), unbind_count);
- HBoxContainer *dstm_hb = memnew(HBoxContainer);
- vbc_left->add_margin_child(TTR("Receiver Method:"), dstm_hb);
-
dst_method = memnew(LineEdit);
dst_method->set_h_size_flags(Control::SIZE_EXPAND_FILL);
dst_method->connect("text_submitted", callable_mp(this, &ConnectDialog::_text_submitted));
- dstm_hb->add_child(dst_method);
+ vbc_left->add_margin_child(TTR("Receiver Method:"), dst_method);
advanced = memnew(CheckButton);
- dstm_hb->add_child(advanced);
+ vbc_left->add_child(advanced);
advanced->set_text(TTR("Advanced"));
+ advanced->set_h_size_flags(Control::SIZE_SHRINK_BEGIN | Control::SIZE_EXPAND);
advanced->connect("pressed", callable_mp(this, &ConnectDialog::_advanced_pressed));
+ HBoxContainer *hbox = memnew(HBoxContainer);
+ vbc_right->add_child(hbox);
+
deferred = memnew(CheckBox);
deferred->set_h_size_flags(0);
deferred->set_text(TTR("Deferred"));
deferred->set_tooltip_text(TTR("Defers the signal, storing it in a queue and only firing it at idle time."));
- vbc_right->add_child(deferred);
+ hbox->add_child(deferred);
one_shot = memnew(CheckBox);
one_shot->set_h_size_flags(0);
- one_shot->set_text(TTR("Oneshot"));
+ one_shot->set_text(TTR("One Shot"));
one_shot->set_tooltip_text(TTR("Disconnects the signal after its first emission."));
- vbc_right->add_child(one_shot);
+ hbox->add_child(one_shot);
cdbinds = memnew(ConnectDialogBinds);
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index 8062b6f756..48e746ac36 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -416,45 +416,50 @@ void EditorSettingsDialog::_update_shortcuts() {
List<String> slist;
EditorSettings::get_singleton()->get_shortcut_list(&slist);
+ slist.sort(); // Sort alphabetically.
const EditorPropertyNameProcessor::Style name_style = EditorPropertyNameProcessor::get_settings_style();
const EditorPropertyNameProcessor::Style tooltip_style = EditorPropertyNameProcessor::get_tooltip_style(name_style);
+ // Create all sections first.
for (const String &E : slist) {
Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(E);
- if (!sc->has_meta("original")) {
+ String section_name = E.get_slice("/", 0);
+
+ if (sections.has(section_name)) {
continue;
}
- // Shortcut Section
+ TreeItem *section = shortcuts->create_item(root);
- TreeItem *section;
- String section_name = E.get_slice("/", 0);
+ const String item_name = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, name_style);
+ const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style);
- if (sections.has(section_name)) {
- section = sections[section_name];
- } else {
- section = shortcuts->create_item(root);
-
- const String item_name = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, name_style);
- const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style);
-
- section->set_text(0, item_name);
- section->set_tooltip_text(0, tooltip);
- section->set_selectable(0, false);
- section->set_selectable(1, false);
- section->set_custom_bg_color(0, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
- section->set_custom_bg_color(1, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
-
- if (collapsed.has(item_name)) {
- section->set_collapsed(collapsed[item_name]);
- }
+ section->set_text(0, item_name);
+ section->set_tooltip_text(0, tooltip);
+ section->set_selectable(0, false);
+ section->set_selectable(1, false);
+ section->set_custom_bg_color(0, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
+ section->set_custom_bg_color(1, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
- sections[section_name] = section;
+ if (collapsed.has(item_name)) {
+ section->set_collapsed(collapsed[item_name]);
}
- // Shortcut Item
+ sections[section_name] = section;
+ }
+ // Add shortcuts to sections.
+ for (const String &E : slist) {
+ Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(E);
+ if (!sc->has_meta("original")) {
+ continue;
+ }
+
+ String section_name = E.get_slice("/", 0);
+ TreeItem *section = sections[section_name];
+
+ // Shortcut Item
if (!shortcut_filter.is_subsequence_ofn(sc->get_name())) {
continue;
}
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 7a3471777d..16686f4fe6 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -262,21 +262,16 @@ void AnimatableBody2D::_update_kinematic_motion() {
#endif
if (sync_to_physics) {
- PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
+ PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &AnimatableBody2D::_body_state_changed));
set_only_update_transform_changes(true);
set_notify_local_transform(true);
} else {
- PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr);
+ PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), Callable());
set_only_update_transform_changes(false);
set_notify_local_transform(false);
}
}
-void AnimatableBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) {
- AnimatableBody2D *body = static_cast<AnimatableBody2D *>(p_instance);
- body->_body_state_changed(p_state);
-}
-
void AnimatableBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
if (!sync_to_physics) {
return;
@@ -438,11 +433,6 @@ struct _RigidBody2DInOut {
int local_shape = 0;
};
-void RigidBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) {
- RigidBody2D *body = static_cast<RigidBody2D *>(p_instance);
- body->_body_state_changed(p_state);
-}
-
void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
set_block_transform_notify(true); // don't want notify (would feedback loop)
if (!freeze || freeze_mode != FREEZE_MODE_KINEMATIC) {
@@ -1079,7 +1069,7 @@ void RigidBody2D::_validate_property(PropertyInfo &p_property) const {
RigidBody2D::RigidBody2D() :
PhysicsBody2D(PhysicsServer2D::BODY_MODE_RIGID) {
- PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
+ PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &RigidBody2D::_body_state_changed));
}
RigidBody2D::~RigidBody2D() {
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 8cd9a8ac03..0eefb45c04 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -317,11 +317,6 @@ void AnimatableBody3D::_update_kinematic_motion() {
}
}
-void AnimatableBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
- AnimatableBody3D *body = (AnimatableBody3D *)p_instance;
- body->_body_state_changed(p_state);
-}
-
void AnimatableBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
linear_velocity = p_state->get_linear_velocity();
angular_velocity = p_state->get_angular_velocity();
@@ -373,7 +368,7 @@ void AnimatableBody3D::_bind_methods() {
AnimatableBody3D::AnimatableBody3D() :
StaticBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) {
- PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &AnimatableBody3D::_body_state_changed));
}
void RigidBody3D::_body_enter_tree(ObjectID p_id) {
@@ -488,11 +483,6 @@ struct _RigidBodyInOut {
int local_shape = 0;
};
-void RigidBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
- RigidBody3D *body = (RigidBody3D *)p_instance;
- body->_body_state_changed(p_state);
-}
-
void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
set_ignore_transform_notification(true);
set_global_transform(p_state->get_transform());
@@ -1139,7 +1129,7 @@ void RigidBody3D::_validate_property(PropertyInfo &p_property) const {
RigidBody3D::RigidBody3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) {
- PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &RigidBody3D::_body_state_changed));
}
RigidBody3D::~RigidBody3D() {
@@ -2900,11 +2890,6 @@ void PhysicalBone3D::_notification(int p_what) {
}
}
-void PhysicalBone3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
- PhysicalBone3D *bone = (PhysicalBone3D *)p_instance;
- bone->_body_state_changed(p_state);
-}
-
void PhysicalBone3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
if (!simulate_physics || !_internal_simulate_physics) {
return;
@@ -3422,7 +3407,7 @@ void PhysicalBone3D::_start_physics_simulation() {
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority());
- PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &PhysicalBone3D::_body_state_changed));
set_as_top_level(true);
_internal_simulate_physics = true;
}
@@ -3443,7 +3428,7 @@ void PhysicalBone3D::_stop_physics_simulation() {
PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), 1.0);
}
if (_internal_simulate_physics) {
- PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr);
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), Callable());
parent_skeleton->set_bone_global_pose_override(bone_id, Transform3D(), 0.0, false);
set_as_top_level(false);
_internal_simulate_physics = false;
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 074c54ba13..4b83bcdfc4 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -87,6 +87,182 @@ void SpriteBase3D::_notification(int p_what) {
}
}
+void SpriteBase3D::draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect, Rect2 p_src_rect) {
+ ERR_FAIL_COND(p_texture.is_null());
+
+ Rect2 final_rect;
+ Rect2 final_src_rect;
+ if (!p_texture->get_rect_region(p_dst_rect, p_src_rect, final_rect, final_src_rect)) {
+ return;
+ }
+
+ if (final_rect.size.x == 0 || final_rect.size.y == 0) {
+ return;
+ }
+
+ // 2D: 3D plane (axes match exactly when `axis == Vector3::AXIS_Z`):
+ // -X+ -X+
+ // - +
+ // Y +--------+ +--------+ +--------+ Y +--------+
+ // + | +--+ | | | (2) | | - | 0--1 |
+ // | |ab| | (1) | +--+ | (3) | 3--2 | | |ab| |
+ // | |cd| | --> | |ab| | --> | |cd| | <==> | |cd| |
+ // | +--+ | | |cd| | | |ab| | | 3--2 |
+ // | | | +--+ | | 0--1 | | |
+ // +--------+ +--------+ +--------+ +--------+
+
+ // (1) Y-wise shift `final_rect` within `p_dst_rect` so after inverting Y
+ // axis distances between top/bottom borders will be preserved (so for
+ // example AtlasTextures with vertical margins will look the same in 2D/3D).
+ final_rect.position.y = (p_dst_rect.position.y + p_dst_rect.size.y) - ((final_rect.position.y + final_rect.size.y) - p_dst_rect.position.y);
+
+ Color color = _get_color_accum();
+
+ real_t pixel_size = get_pixel_size();
+
+ // (2) Order vertices (0123) bottom-top in 2D / top-bottom in 3D.
+ Vector2 vertices[4] = {
+ (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
+ (final_rect.position + final_rect.size) * pixel_size,
+ (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
+ final_rect.position * pixel_size,
+ };
+
+ Vector2 src_tsize = p_texture->get_size();
+
+ // Properly setup UVs for impostor textures (AtlasTexture).
+ Ref<AtlasTexture> atlas_tex = p_texture;
+ if (atlas_tex != nullptr) {
+ src_tsize[0] = atlas_tex->get_atlas()->get_width();
+ src_tsize[1] = atlas_tex->get_atlas()->get_height();
+ }
+
+ // (3) Assign UVs (abcd) according to the vertices order (bottom-top in 2D / top-bottom in 3D).
+ Vector2 uvs[4] = {
+ final_src_rect.position / src_tsize,
+ (final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / src_tsize,
+ (final_src_rect.position + final_src_rect.size) / src_tsize,
+ (final_src_rect.position + Vector2(0, final_src_rect.size.y)) / src_tsize,
+ };
+
+ if (is_flipped_h()) {
+ SWAP(uvs[0], uvs[1]);
+ SWAP(uvs[2], uvs[3]);
+ }
+
+ if (is_flipped_v()) {
+ SWAP(uvs[0], uvs[3]);
+ SWAP(uvs[1], uvs[2]);
+ }
+
+ Vector3 normal;
+ int axis = get_axis();
+ normal[axis] = 1.0;
+
+ Plane tangent;
+ if (axis == Vector3::AXIS_X) {
+ tangent = Plane(0, 0, -1, 1);
+ } else {
+ tangent = Plane(1, 0, 0, 1);
+ }
+
+ int x_axis = ((axis + 1) % 3);
+ int y_axis = ((axis + 2) % 3);
+
+ if (axis != Vector3::AXIS_Z) {
+ SWAP(x_axis, y_axis);
+
+ for (int i = 0; i < 4; i++) {
+ //uvs[i] = Vector2(1.0,1.0)-uvs[i];
+ //SWAP(vertices[i].x,vertices[i].y);
+ if (axis == Vector3::AXIS_Y) {
+ vertices[i].y = -vertices[i].y;
+ } else if (axis == Vector3::AXIS_X) {
+ vertices[i].x = -vertices[i].x;
+ }
+ }
+ }
+
+ AABB aabb;
+
+ // Everything except position and UV is compressed.
+ uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
+ uint8_t *attribute_write_buffer = attribute_buffer.ptrw();
+
+ uint32_t v_normal;
+ {
+ Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
+
+ Vector2 res = n.octahedron_encode();
+ uint32_t value = 0;
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
+
+ v_normal = value;
+ }
+ uint32_t v_tangent;
+ {
+ Plane t = tangent;
+ Vector2 res = t.normal.octahedron_tangent_encode(t.d);
+ uint32_t value = 0;
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
+
+ v_tangent = value;
+ }
+
+ uint8_t v_color[4] = {
+ uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)),
+ uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)),
+ uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)),
+ uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0))
+ };
+
+ for (int i = 0; i < 4; i++) {
+ Vector3 vtx;
+ vtx[x_axis] = vertices[i][0];
+ vtx[y_axis] = vertices[i][1];
+ if (i == 0) {
+ aabb.position = vtx;
+ aabb.size = Vector3();
+ } else {
+ aabb.expand_to(vtx);
+ }
+
+ float v_uv[2] = { (float)uvs[i].x, (float)uvs[i].y };
+ memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8);
+
+ float v_vertex[3] = { (float)vtx.x, (float)vtx.y, (float)vtx.z };
+
+ memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3);
+ memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4);
+ memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4);
+ memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4);
+ }
+
+ RID mesh = get_mesh();
+ RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer);
+ RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer);
+
+ RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb);
+ set_aabb(aabb);
+
+ RID shader_rid;
+ StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), &shader_rid);
+ if (last_shader != shader_rid) {
+ RS::get_singleton()->material_set_shader(get_material(), shader_rid);
+ last_shader = shader_rid;
+ }
+ if (last_texture != p_texture->get_rid()) {
+ RS::get_singleton()->material_set_param(get_material(), "texture_albedo", p_texture->get_rid());
+ last_texture = p_texture->get_rid();
+ }
+ if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) {
+ RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority());
+ RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material());
+ }
+}
+
void SpriteBase3D::set_centered(bool p_center) {
centered = p_center;
_queue_redraw();
@@ -464,171 +640,17 @@ void Sprite3D::_draw() {
}
Size2 frame_size = base_rect.size / Size2(hframes, vframes);
- Point2 frame_offset = Point2(frame % hframes, frame / hframes);
- frame_offset *= frame_size;
+ Point2 frame_offset = Point2(frame % hframes, frame / hframes) * frame_size;
- Point2 dest_offset = get_offset();
+ Point2 dst_offset = get_offset();
if (is_centered()) {
- dest_offset -= frame_size / 2;
+ dst_offset -= frame_size / 2.0f;
}
Rect2 src_rect(base_rect.position + frame_offset, frame_size);
- Rect2 final_dst_rect(dest_offset, frame_size);
- Rect2 final_rect;
- Rect2 final_src_rect;
- if (!texture->get_rect_region(final_dst_rect, src_rect, final_rect, final_src_rect)) {
- return;
- }
-
- if (final_rect.size.x == 0 || final_rect.size.y == 0) {
- return;
- }
-
- Color color = _get_color_accum();
-
- real_t pixel_size = get_pixel_size();
-
- Vector2 vertices[4] = {
-
- (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
- (final_rect.position + final_rect.size) * pixel_size,
- (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
- final_rect.position * pixel_size,
-
- };
-
- Vector2 src_tsize = tsize;
-
- // Properly setup UVs for impostor textures (AtlasTexture).
- Ref<AtlasTexture> atlas_tex = texture;
- if (atlas_tex != nullptr) {
- src_tsize[0] = atlas_tex->get_atlas()->get_width();
- src_tsize[1] = atlas_tex->get_atlas()->get_height();
- }
-
- Vector2 uvs[4] = {
- final_src_rect.position / src_tsize,
- (final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / src_tsize,
- (final_src_rect.position + final_src_rect.size) / src_tsize,
- (final_src_rect.position + Vector2(0, final_src_rect.size.y)) / src_tsize,
- };
-
- if (is_flipped_h()) {
- SWAP(uvs[0], uvs[1]);
- SWAP(uvs[2], uvs[3]);
- }
-
- if (is_flipped_v()) {
- SWAP(uvs[0], uvs[3]);
- SWAP(uvs[1], uvs[2]);
- }
-
- Vector3 normal;
- int axis = get_axis();
- normal[axis] = 1.0;
-
- Plane tangent;
- if (axis == Vector3::AXIS_X) {
- tangent = Plane(0, 0, -1, 1);
- } else {
- tangent = Plane(1, 0, 0, 1);
- }
-
- int x_axis = ((axis + 1) % 3);
- int y_axis = ((axis + 2) % 3);
-
- if (axis != Vector3::AXIS_Z) {
- SWAP(x_axis, y_axis);
-
- for (int i = 0; i < 4; i++) {
- //uvs[i] = Vector2(1.0,1.0)-uvs[i];
- //SWAP(vertices[i].x,vertices[i].y);
- if (axis == Vector3::AXIS_Y) {
- vertices[i].y = -vertices[i].y;
- } else if (axis == Vector3::AXIS_X) {
- vertices[i].x = -vertices[i].x;
- }
- }
- }
-
- AABB aabb;
-
- // Everything except position and UV is compressed.
- uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
- uint8_t *attribute_write_buffer = attribute_buffer.ptrw();
-
- uint32_t v_normal;
- {
- Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
- Vector2 res = n.octahedron_encode();
- uint32_t value = 0;
- value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
- value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
-
- v_normal = value;
- }
- uint32_t v_tangent;
- {
- Plane t = tangent;
- Vector2 res = t.normal.octahedron_tangent_encode(t.d);
- uint32_t value = 0;
- value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
- value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
+ Rect2 dst_rect(dst_offset, frame_size);
- v_tangent = value;
- }
-
- uint8_t v_color[4] = {
- uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)),
- uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)),
- uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)),
- uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0))
- };
-
- for (int i = 0; i < 4; i++) {
- Vector3 vtx;
- vtx[x_axis] = vertices[i][0];
- vtx[y_axis] = vertices[i][1];
- if (i == 0) {
- aabb.position = vtx;
- aabb.size = Vector3();
- } else {
- aabb.expand_to(vtx);
- }
-
- float v_uv[2] = { (float)uvs[i].x, (float)uvs[i].y };
- memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8);
-
- float v_vertex[3] = { (float)vtx.x, (float)vtx.y, (float)vtx.z };
-
- memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3);
- memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4);
- memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4);
- memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4);
- }
-
- RID mesh = get_mesh();
- RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer);
- RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer);
-
- RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb);
- set_aabb(aabb);
-
- RID shader_rid;
- StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), &shader_rid);
- if (last_shader != shader_rid) {
- RS::get_singleton()->material_set_shader(get_material(), shader_rid);
- last_shader = shader_rid;
- }
- if (last_texture != texture->get_rid()) {
- RS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid());
- last_texture = texture->get_rid();
- }
- if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) {
- RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority());
- RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material());
- }
+ draw_texture_rect(texture, dst_rect, src_rect);
}
void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) {
@@ -831,158 +853,7 @@ void AnimatedSprite3D::_draw() {
Rect2 dst_rect(ofs, tsize);
- Rect2 final_rect;
- Rect2 final_src_rect;
- if (!texture->get_rect_region(dst_rect, src_rect, final_rect, final_src_rect)) {
- return;
- }
-
- if (final_rect.size.x == 0 || final_rect.size.y == 0) {
- return;
- }
-
- Color color = _get_color_accum();
-
- real_t pixel_size = get_pixel_size();
-
- Vector2 vertices[4] = {
-
- (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
- (final_rect.position + final_rect.size) * pixel_size,
- (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
- final_rect.position * pixel_size,
-
- };
-
- Vector2 src_tsize = tsize;
-
- // Properly setup UVs for impostor textures (AtlasTexture).
- Ref<AtlasTexture> atlas_tex = texture;
- if (atlas_tex != nullptr) {
- src_tsize[0] = atlas_tex->get_atlas()->get_width();
- src_tsize[1] = atlas_tex->get_atlas()->get_height();
- }
-
- Vector2 uvs[4] = {
- final_src_rect.position / src_tsize,
- (final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / src_tsize,
- (final_src_rect.position + final_src_rect.size) / src_tsize,
- (final_src_rect.position + Vector2(0, final_src_rect.size.y)) / src_tsize,
- };
-
- if (is_flipped_h()) {
- SWAP(uvs[0], uvs[1]);
- SWAP(uvs[2], uvs[3]);
- }
- if (is_flipped_v()) {
- SWAP(uvs[0], uvs[3]);
- SWAP(uvs[1], uvs[2]);
- }
-
- Vector3 normal;
- int axis = get_axis();
- normal[axis] = 1.0;
-
- Plane tangent;
- if (axis == Vector3::AXIS_X) {
- tangent = Plane(0, 0, -1, -1);
- } else {
- tangent = Plane(1, 0, 0, -1);
- }
-
- int x_axis = ((axis + 1) % 3);
- int y_axis = ((axis + 2) % 3);
-
- if (axis != Vector3::AXIS_Z) {
- SWAP(x_axis, y_axis);
-
- for (int i = 0; i < 4; i++) {
- //uvs[i] = Vector2(1.0,1.0)-uvs[i];
- //SWAP(vertices[i].x,vertices[i].y);
- if (axis == Vector3::AXIS_Y) {
- vertices[i].y = -vertices[i].y;
- } else if (axis == Vector3::AXIS_X) {
- vertices[i].x = -vertices[i].x;
- }
- }
- }
-
- AABB aabb;
-
- // Everything except position and UV is compressed.
- uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
- uint8_t *attribute_write_buffer = attribute_buffer.ptrw();
-
- uint32_t v_normal;
- {
- Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
- Vector2 res = n.octahedron_encode();
- uint32_t value = 0;
- value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
- value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
-
- v_normal = value;
- }
- uint32_t v_tangent;
- {
- Plane t = tangent;
- Vector2 res = t.normal.octahedron_tangent_encode(t.d);
- uint32_t value = 0;
- value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
- value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
- v_tangent = value;
- }
-
- uint8_t v_color[4] = {
- uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)),
- uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)),
- uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)),
- uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0))
- };
-
- for (int i = 0; i < 4; i++) {
- Vector3 vtx;
- vtx[x_axis] = vertices[i][0];
- vtx[y_axis] = vertices[i][1];
- if (i == 0) {
- aabb.position = vtx;
- aabb.size = Vector3();
- } else {
- aabb.expand_to(vtx);
- }
-
- float v_uv[2] = { (float)uvs[i].x, (float)uvs[i].y };
- memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8);
-
- float v_vertex[3] = { (float)vtx.x, (float)vtx.y, (float)vtx.z };
- memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3);
- memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4);
- memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4);
- memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4);
- }
-
- RID mesh = get_mesh();
- RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer);
- RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer);
-
- RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb);
- set_aabb(aabb);
-
- RID shader_rid;
- StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), &shader_rid);
- if (last_shader != shader_rid) {
- RS::get_singleton()->material_set_shader(get_material(), shader_rid);
- last_shader = shader_rid;
- }
- if (last_texture != texture->get_rid()) {
- RS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid());
- last_texture = texture->get_rid();
- }
- if (get_alpha_cut_mode() == ALPHA_CUT_DISABLED) {
- RS::get_singleton()->material_set_render_priority(get_material(), get_render_priority());
- RS::get_singleton()->mesh_surface_set_material(mesh, 0, get_material());
- }
+ draw_texture_rect(texture, dst_rect, src_rect);
}
void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const {
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 781a3f9173..edc48c7b71 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -80,6 +80,9 @@ private:
RID mesh;
RID material;
+ RID last_shader;
+ RID last_texture;
+
bool flags[FLAG_MAX] = {};
AlphaCutMode alpha_cut = ALPHA_CUT_DISABLED;
StandardMaterial3D::BillboardMode billboard_mode = StandardMaterial3D::BILLBOARD_DISABLED;
@@ -94,6 +97,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
virtual void _draw() = 0;
+ void draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect, Rect2 p_src_rect);
_FORCE_INLINE_ void set_aabb(const AABB &p_aabb) { aabb = p_aabb; }
_FORCE_INLINE_ RID &get_mesh() { return mesh; }
_FORCE_INLINE_ RID &get_material() { return material; }
@@ -167,9 +171,6 @@ class Sprite3D : public SpriteBase3D {
int vframes = 1;
int hframes = 1;
- RID last_shader;
- RID last_texture;
-
protected:
virtual void _draw() override;
static void _bind_methods();
@@ -225,9 +226,6 @@ class AnimatedSprite3D : public SpriteBase3D {
double _get_frame_duration();
void _reset_timeout();
- RID last_shader;
- RID last_texture;
-
protected:
virtual void _draw() override;
static void _bind_methods();
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index cf467ceafb..3d95677dcf 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -469,7 +469,7 @@ void BaseButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "Shortcut"), "set_shortcut", "get_shortcut");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "button_group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_RESOURCE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
BIND_ENUM_CONSTANT(DRAW_NORMAL);
BIND_ENUM_CONSTANT(DRAW_PRESSED);
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index d6bf84ea5a..75592a1b99 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -703,7 +703,7 @@ void MenuBar::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "start_index"), "set_start_index", "get_start_index");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "switch_on_hover"), "set_switch_on_hover", "is_switch_on_hover");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefer_global_menu"), "set_prefer_global_menu", "is_prefer_global_menu");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_RESOURCE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index bec378dd91..2c395ec07d 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -32,9 +32,6 @@
#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_tls, validate_tls);
}
@@ -48,6 +45,7 @@ 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;
@@ -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_TLS_HANDSHAKE_ERROR: {
- call_deferred(SNAME("_request_done"), RESULT_TLS_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray());
+ _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,7 +568,7 @@ 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() {
@@ -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);
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index 290bacd9d2..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"
@@ -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);
diff --git a/servers/extensions/physics_server_2d_extension.cpp b/servers/extensions/physics_server_2d_extension.cpp
index 36f3be2468..769315daa7 100644
--- a/servers/extensions/physics_server_2d_extension.cpp
+++ b/servers/extensions/physics_server_2d_extension.cpp
@@ -280,7 +280,7 @@ void PhysicsServer2DExtension::_bind_methods() {
GDVIRTUAL_BIND(_body_set_omit_force_integration, "body", "enable");
GDVIRTUAL_BIND(_body_is_omitting_force_integration, "body");
- GDVIRTUAL_BIND(_body_set_state_sync_callback, "body", "callback");
+ GDVIRTUAL_BIND(_body_set_state_sync_callback, "body", "callable");
GDVIRTUAL_BIND(_body_set_force_integration_callback, "body", "callable", "userdata");
GDVIRTUAL_BIND(_body_collide_shape, "body", "body_shape", "shape", "shape_xform", "motion", "results", "result_max", "result_count");
diff --git a/servers/extensions/physics_server_2d_extension.h b/servers/extensions/physics_server_2d_extension.h
index 3bd3d642c8..a6dbe35264 100644
--- a/servers/extensions/physics_server_2d_extension.h
+++ b/servers/extensions/physics_server_2d_extension.h
@@ -94,7 +94,6 @@ public:
EXBIND1RC(Vector2, get_contact_local_position, int)
EXBIND1RC(Vector2, get_contact_local_normal, int)
EXBIND1RC(int, get_contact_local_shape, int)
-
EXBIND1RC(RID, get_contact_collider, int)
EXBIND1RC(Vector2, get_contact_collider_position, int)
EXBIND1RC(ObjectID, get_contact_collider_id, int)
@@ -183,13 +182,7 @@ public:
typedef PhysicsServer2D::MotionResult PhysicsServer2DExtensionMotionResult;
-struct PhysicsServer2DExtensionStateCallback {
- void *instance = nullptr;
- void (*callback)(void *p_instance, PhysicsDirectBodyState2D *p_state);
-};
-
GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionMotionResult)
-GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionStateCallback)
class PhysicsServer2DExtension : public PhysicsServer2D {
GDCLASS(PhysicsServer2DExtension, PhysicsServer2D);
@@ -376,13 +369,7 @@ public:
EXBIND2(body_set_omit_force_integration, RID, bool)
EXBIND1RC(bool, body_is_omitting_force_integration, RID)
- GDVIRTUAL2(_body_set_state_sync_callback, RID, GDNativePtr<PhysicsServer2DExtensionStateCallback>)
- void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override {
- PhysicsServer2DExtensionStateCallback callback;
- callback.callback = p_callback;
- callback.instance = p_instance;
- GDVIRTUAL_REQUIRED_CALL(_body_set_state_sync_callback, p_body, &callback);
- }
+ EXBIND2(body_set_state_sync_callback, RID, const Callable &)
EXBIND3(body_set_force_integration_callback, RID, const Callable &, const Variant &)
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override {
diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp
index 800284dc60..4785fa33fb 100644
--- a/servers/extensions/physics_server_3d_extension.cpp
+++ b/servers/extensions/physics_server_3d_extension.cpp
@@ -284,7 +284,7 @@ void PhysicsServer3DExtension::_bind_methods() {
GDVIRTUAL_BIND(_body_set_omit_force_integration, "body", "enable");
GDVIRTUAL_BIND(_body_is_omitting_force_integration, "body");
- GDVIRTUAL_BIND(_body_set_state_sync_callback, "body", "callback");
+ GDVIRTUAL_BIND(_body_set_state_sync_callback, "body", "callable");
GDVIRTUAL_BIND(_body_set_force_integration_callback, "body", "callable", "userdata");
GDVIRTUAL_BIND(_body_set_ray_pickable, "body", "enable");
diff --git a/servers/extensions/physics_server_3d_extension.h b/servers/extensions/physics_server_3d_extension.h
index b6ed346a3d..f1e522aca8 100644
--- a/servers/extensions/physics_server_3d_extension.h
+++ b/servers/extensions/physics_server_3d_extension.h
@@ -192,14 +192,8 @@ public:
typedef PhysicsServer3D::MotionCollision PhysicsServer3DExtensionMotionCollision;
typedef PhysicsServer3D::MotionResult PhysicsServer3DExtensionMotionResult;
-struct PhysicsServer3DExtensionStateCallback {
- void *instance = nullptr;
- void (*callback)(void *p_instance, PhysicsDirectBodyState3D *p_state);
-};
-
GDVIRTUAL_NATIVE_PTR(PhysicsServer3DExtensionMotionCollision)
GDVIRTUAL_NATIVE_PTR(PhysicsServer3DExtensionMotionResult)
-GDVIRTUAL_NATIVE_PTR(PhysicsServer3DExtensionStateCallback)
class PhysicsServer3DExtension : public PhysicsServer3D {
GDCLASS(PhysicsServer3DExtension, PhysicsServer3D);
@@ -380,13 +374,7 @@ public:
EXBIND2(body_set_omit_force_integration, RID, bool)
EXBIND1RC(bool, body_is_omitting_force_integration, RID)
- GDVIRTUAL2(_body_set_state_sync_callback, RID, GDNativePtr<PhysicsServer3DExtensionStateCallback>)
- void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override {
- PhysicsServer3DExtensionStateCallback callback;
- callback.callback = p_callback;
- callback.instance = p_instance;
- GDVIRTUAL_REQUIRED_CALL(_body_set_state_sync_callback, p_body, &callback);
- }
+ EXBIND2(body_set_state_sync_callback, RID, const Callable &)
EXBIND3(body_set_force_integration_callback, RID, const Callable &, const Variant &)
EXBIND2(body_set_ray_pickable, RID, bool)
diff --git a/servers/physics_2d/godot_body_2d.cpp b/servers/physics_2d/godot_body_2d.cpp
index ef6a6b1ae2..90124cd991 100644
--- a/servers/physics_2d/godot_body_2d.cpp
+++ b/servers/physics_2d/godot_body_2d.cpp
@@ -615,7 +615,7 @@ void GodotBody2D::integrate_velocities(real_t p_step) {
return;
}
- if (fi_callback_data || body_state_callback) {
+ if (fi_callback_data || body_state_callback.get_object()) {
get_space()->body_add_to_state_query_list(&direct_state_query_list);
}
@@ -673,11 +673,12 @@ void GodotBody2D::wakeup_neighbours() {
}
void GodotBody2D::call_queries() {
+ Variant direct_state_variant = get_direct_state();
+
if (fi_callback_data) {
if (!fi_callback_data->callable.get_object()) {
set_force_integration_callback(Callable());
} else {
- Variant direct_state_variant = get_direct_state();
const Variant *vp[2] = { &direct_state_variant, &fi_callback_data->udata };
Callable::CallError ce;
@@ -691,8 +692,11 @@ void GodotBody2D::call_queries() {
}
}
- if (body_state_callback) {
- (body_state_callback)(body_state_callback_instance, get_direct_state());
+ if (body_state_callback.get_object()) {
+ const Variant *vp[1] = { &direct_state_variant };
+ Callable::CallError ce;
+ Variant rv;
+ body_state_callback.callp(vp, 1, rv, ce);
}
}
@@ -713,9 +717,8 @@ bool GodotBody2D::sleep_test(real_t p_step) {
}
}
-void GodotBody2D::set_state_sync_callback(void *p_instance, PhysicsServer2D::BodyStateCallback p_callback) {
- body_state_callback_instance = p_instance;
- body_state_callback = p_callback;
+void GodotBody2D::set_state_sync_callback(const Callable &p_callable) {
+ body_state_callback = p_callable;
}
void GodotBody2D::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
diff --git a/servers/physics_2d/godot_body_2d.h b/servers/physics_2d/godot_body_2d.h
index 409940d4f8..86d42ae7f8 100644
--- a/servers/physics_2d/godot_body_2d.h
+++ b/servers/physics_2d/godot_body_2d.h
@@ -137,8 +137,7 @@ class GodotBody2D : public GodotCollisionObject2D {
Vector<Contact> contacts; //no contacts by default
int contact_count = 0;
- void *body_state_callback_instance = nullptr;
- PhysicsServer2D::BodyStateCallback body_state_callback = nullptr;
+ Callable body_state_callback;
struct ForceIntegrationCallbackData {
Callable callable;
@@ -156,7 +155,7 @@ class GodotBody2D : public GodotCollisionObject2D {
friend class GodotPhysicsDirectBodyState2D; // i give up, too many functions to expose
public:
- void set_state_sync_callback(void *p_instance, PhysicsServer2D::BodyStateCallback p_callback);
+ void set_state_sync_callback(const Callable &p_callable);
void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
GodotPhysicsDirectBodyState2D *get_direct_state();
diff --git a/servers/physics_2d/godot_physics_server_2d.cpp b/servers/physics_2d/godot_physics_server_2d.cpp
index cec31bdc31..11f6bd9c1e 100644
--- a/servers/physics_2d/godot_physics_server_2d.cpp
+++ b/servers/physics_2d/godot_physics_server_2d.cpp
@@ -951,10 +951,10 @@ int GodotPhysicsServer2D::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
-void GodotPhysicsServer2D::body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) {
+void GodotPhysicsServer2D::body_set_state_sync_callback(RID p_body, const Callable &p_callable) {
GodotBody2D *body = body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
- body->set_state_sync_callback(p_instance, p_callback);
+ body->set_state_sync_callback(p_callable);
}
void GodotPhysicsServer2D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
diff --git a/servers/physics_2d/godot_physics_server_2d.h b/servers/physics_2d/godot_physics_server_2d.h
index 20e492d87a..c780ef3b66 100644
--- a/servers/physics_2d/godot_physics_server_2d.h
+++ b/servers/physics_2d/godot_physics_server_2d.h
@@ -243,7 +243,7 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
- virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override;
+ virtual void body_set_state_sync_callback(RID p_body, const Callable &p_callable) override;
virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override;
diff --git a/servers/physics_3d/godot_body_3d.cpp b/servers/physics_3d/godot_body_3d.cpp
index b632f7f461..19f065c319 100644
--- a/servers/physics_3d/godot_body_3d.cpp
+++ b/servers/physics_3d/godot_body_3d.cpp
@@ -674,7 +674,7 @@ void GodotBody3D::integrate_velocities(real_t p_step) {
return;
}
- if (fi_callback_data || body_state_callback) {
+ if (fi_callback_data || body_state_callback.get_object()) {
get_space()->body_add_to_state_query_list(&direct_state_query_list);
}
@@ -756,11 +756,12 @@ void GodotBody3D::wakeup_neighbours() {
}
void GodotBody3D::call_queries() {
+ Variant direct_state_variant = get_direct_state();
+
if (fi_callback_data) {
if (!fi_callback_data->callable.get_object()) {
set_force_integration_callback(Callable());
} else {
- Variant direct_state_variant = get_direct_state();
const Variant *vp[2] = { &direct_state_variant, &fi_callback_data->udata };
Callable::CallError ce;
@@ -770,8 +771,11 @@ void GodotBody3D::call_queries() {
}
}
- if (body_state_callback_instance) {
- (body_state_callback)(body_state_callback_instance, get_direct_state());
+ if (body_state_callback.get_object()) {
+ const Variant *vp[1] = { &direct_state_variant };
+ Callable::CallError ce;
+ Variant rv;
+ body_state_callback.callp(vp, 1, rv, ce);
}
}
@@ -792,9 +796,8 @@ bool GodotBody3D::sleep_test(real_t p_step) {
}
}
-void GodotBody3D::set_state_sync_callback(void *p_instance, PhysicsServer3D::BodyStateCallback p_callback) {
- body_state_callback_instance = p_instance;
- body_state_callback = p_callback;
+void GodotBody3D::set_state_sync_callback(const Callable &p_callable) {
+ body_state_callback = p_callable;
}
void GodotBody3D::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
diff --git a/servers/physics_3d/godot_body_3d.h b/servers/physics_3d/godot_body_3d.h
index 2153ca4e91..412cbebc7d 100644
--- a/servers/physics_3d/godot_body_3d.h
+++ b/servers/physics_3d/godot_body_3d.h
@@ -131,8 +131,7 @@ class GodotBody3D : public GodotCollisionObject3D {
Vector<Contact> contacts; //no contacts by default
int contact_count = 0;
- void *body_state_callback_instance = nullptr;
- PhysicsServer3D::BodyStateCallback body_state_callback = nullptr;
+ Callable body_state_callback;
struct ForceIntegrationCallbackData {
Callable callable;
@@ -150,7 +149,7 @@ class GodotBody3D : public GodotCollisionObject3D {
friend class GodotPhysicsDirectBodyState3D; // i give up, too many functions to expose
public:
- void set_state_sync_callback(void *p_instance, PhysicsServer3D::BodyStateCallback p_callback);
+ void set_state_sync_callback(const Callable &p_callable);
void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
GodotPhysicsDirectBodyState3D *get_direct_state();
diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp
index b028c00a31..7f2ec72921 100644
--- a/servers/physics_3d/godot_physics_server_3d.cpp
+++ b/servers/physics_3d/godot_physics_server_3d.cpp
@@ -877,10 +877,10 @@ int GodotPhysicsServer3D::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
-void GodotPhysicsServer3D::body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) {
+void GodotPhysicsServer3D::body_set_state_sync_callback(RID p_body, const Callable &p_callable) {
GodotBody3D *body = body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
- body->set_state_sync_callback(p_instance, p_callback);
+ body->set_state_sync_callback(p_callable);
}
void GodotPhysicsServer3D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
diff --git a/servers/physics_3d/godot_physics_server_3d.h b/servers/physics_3d/godot_physics_server_3d.h
index b429f23a0c..6dc9330caf 100644
--- a/servers/physics_3d/godot_physics_server_3d.h
+++ b/servers/physics_3d/godot_physics_server_3d.h
@@ -242,7 +242,7 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
- virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override;
+ virtual void body_set_state_sync_callback(RID p_body, const Callable &p_callable) override;
virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) override;
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index d9572e6594..bd57a6a375 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -470,10 +470,7 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0;
virtual bool body_is_omitting_force_integration(RID p_body) const = 0;
- // Callback for C++ use only.
- typedef void (*BodyStateCallback)(void *p_instance, PhysicsDirectBodyState2D *p_state);
- virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) = 0;
-
+ virtual void body_set_state_sync_callback(RID p_body, const Callable &p_callable) = 0;
virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0;
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) = 0;
diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h
index d080aac438..1353d8de6d 100644
--- a/servers/physics_server_2d_wrap_mt.h
+++ b/servers/physics_server_2d_wrap_mt.h
@@ -249,7 +249,7 @@ public:
FUNC2(body_set_omit_force_integration, RID, bool);
FUNC1RC(bool, body_is_omitting_force_integration, RID);
- FUNC3(body_set_state_sync_callback, RID, void *, BodyStateCallback);
+ FUNC2(body_set_state_sync_callback, RID, const Callable &);
FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &);
bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override {
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 6ad5e26815..2151d84e40 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -508,10 +508,7 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0;
virtual bool body_is_omitting_force_integration(RID p_body) const = 0;
- // Callback for C++ use only.
- typedef void (*BodyStateCallback)(void *p_instance, PhysicsDirectBodyState3D *p_state);
- virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) = 0;
-
+ virtual void body_set_state_sync_callback(RID p_body, const Callable &p_callable) = 0;
virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) = 0;
diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h
index ed4546b240..9b07e19e50 100644
--- a/servers/physics_server_3d_wrap_mt.h
+++ b/servers/physics_server_3d_wrap_mt.h
@@ -252,7 +252,7 @@ public:
FUNC2(body_set_omit_force_integration, RID, bool);
FUNC1RC(bool, body_is_omitting_force_integration, RID);
- FUNC3(body_set_state_sync_callback, RID, void *, BodyStateCallback);
+ FUNC2(body_set_state_sync_callback, RID, const Callable &);
FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &);
FUNC2(body_set_ray_pickable, RID, bool);
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index b9667f338c..55d6a7d934 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -145,7 +145,6 @@ void register_server_types() {
GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionShapeResult, "RID rid;ObjectID collider_id;Object *collider;int shape");
GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionShapeRestInfo, "Vector2 point;Vector2 normal;RID rid;ObjectID collider_id;int shape;Vector2 linear_velocity");
GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionMotionResult, "Vector2 travel;Vector2 remainder;Vector2 collision_point;Vector2 collision_normal;Vector2 collider_velocity;real_t collision_depth;real_t collision_safe_fraction;real_t collision_unsafe_fraction;int collision_local_shape;ObjectID collider_id;RID collider;int collider_shape");
- GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionStateCallback, "void *instance;void (*callback)(void *p_instance, PhysicsDirectBodyState2D *p_state)");
GDREGISTER_CLASS(PhysicsServer3DManager);
Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3DManager", PhysicsServer3DManager::get_singleton(), "PhysicsServer3DManager"));
@@ -161,7 +160,6 @@ void register_server_types() {
GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionShapeRestInfo, "Vector3 point;Vector3 normal;RID rid;ObjectID collider_id;int shape;Vector3 linear_velocity");
GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionMotionCollision, "Vector3 position;Vector3 normal;Vector3 collider_velocity;real_t depth;int local_shape;ObjectID collider_id;RID collider;int collider_shape");
GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionMotionResult, "Vector3 travel;Vector3 remainder;real_t collision_safe_fraction;real_t collision_unsafe_fraction;PhysicsServer3DExtensionMotionCollision collisions[32];int collision_count");
- GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionStateCallback, "void *instance;void (*callback)(void *p_instance, PhysicsDirectBodyState3D *p_state)");
GDREGISTER_ABSTRACT_CLASS(NavigationServer2D);
GDREGISTER_ABSTRACT_CLASS(NavigationServer3D);