diff options
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); |