diff options
175 files changed, 2538 insertions, 2218 deletions
diff --git a/.gitignore b/.gitignore index 00d87b6bf6..5b3414fe7e 100644 --- a/.gitignore +++ b/.gitignore @@ -390,3 +390,6 @@ gcov.css # https://clangd.llvm.org/ cache folder .clangd/ .cache/ + +# Generated by unit tests files +tests/data/*.translation diff --git a/SConstruct b/SConstruct index b6c98eea77..b539dc59b7 100644 --- a/SConstruct +++ b/SConstruct @@ -91,6 +91,7 @@ env_base.__class__.add_program = methods.add_program env_base.__class__.CommandNoCache = methods.CommandNoCache env_base.__class__.Run = methods.Run env_base.__class__.disable_warnings = methods.disable_warnings +env_base.__class__.force_optimization_on_debug = methods.force_optimization_on_debug env_base.__class__.module_check_dependencies = methods.module_check_dependencies env_base["x86_libtheora_opt_gcc"] = False diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 242a2f3638..1f028702f6 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -1786,13 +1786,13 @@ void Thread::_start_func(void *ud) { // We must check if we are in case b). int target_param_count = 0; int target_default_arg_count = 0; - Ref<Script> script = t->target_instance->get_script(); + Ref<Script> script = t->target_callable.get_object()->get_script(); if (script.is_valid()) { - MethodInfo mi = script->get_method_info(t->target_method); + MethodInfo mi = script->get_method_info(t->target_callable.get_method()); target_param_count = mi.arguments.size(); target_default_arg_count = mi.default_arguments.size(); } else { - MethodBind *method = ClassDB::get_method(t->target_instance->get_class_name(), t->target_method); + MethodBind *method = ClassDB::get_method(t->target_callable.get_object()->get_class_name(), t->target_callable.get_method()); target_param_count = method->get_argument_count(); target_default_arg_count = method->get_default_argument_count(); } @@ -1801,41 +1801,21 @@ void Thread::_start_func(void *ud) { } } - ::Thread::set_name(t->target_method); + ::Thread::set_name(t->target_callable.get_method()); - t->ret = t->target_instance->call(t->target_method, arg, argc, ce); + t->target_callable.call(arg, argc, t->ret, ce); if (ce.error != Callable::CallError::CALL_OK) { - String reason; - switch (ce.error) { - case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: { - reason = "Invalid Argument #" + itos(ce.argument); - } break; - case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { - reason = "Too Many Arguments"; - } break; - case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: { - reason = "Too Few Arguments"; - } break; - case Callable::CallError::CALL_ERROR_INVALID_METHOD: { - reason = "Method Not Found"; - } break; - default: { - } - } - - ERR_FAIL_MSG("Could not call function '" + t->target_method.operator String() + "' to start thread " + t->get_id() + ": " + reason + "."); + ERR_FAIL_MSG("Could not call function '" + t->target_callable.get_method().operator String() + "' to start thread " + t->get_id() + ": " + Variant::get_callable_error_text(t->target_callable, arg, argc, ce) + "."); } } -Error Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, Priority p_priority) { +Error Thread::start(const Callable &p_callable, const Variant &p_userdata, Priority p_priority) { ERR_FAIL_COND_V_MSG(active.is_set(), ERR_ALREADY_IN_USE, "Thread already started."); - ERR_FAIL_COND_V(!p_instance, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(p_method == StringName(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_callable.is_null(), ERR_INVALID_PARAMETER); ERR_FAIL_INDEX_V(p_priority, PRIORITY_MAX, ERR_INVALID_PARAMETER); ret = Variant(); - target_method = p_method; - target_instance = p_instance; + target_callable = p_callable; userdata = p_userdata; active.set(); @@ -1861,15 +1841,14 @@ Variant Thread::wait_to_finish() { thread.wait_to_finish(); Variant r = ret; active.clear(); - target_method = StringName(); - target_instance = nullptr; + target_callable = Callable(); userdata = Variant(); return r; } void Thread::_bind_methods() { - ClassDB::bind_method(D_METHOD("start", "instance", "method", "userdata", "priority"), &Thread::start, DEFVAL(Variant()), DEFVAL(PRIORITY_NORMAL)); + ClassDB::bind_method(D_METHOD("start", "callable", "userdata", "priority"), &Thread::start, DEFVAL(Variant()), DEFVAL(PRIORITY_NORMAL)); ClassDB::bind_method(D_METHOD("get_id"), &Thread::get_id); ClassDB::bind_method(D_METHOD("is_active"), &Thread::is_active); ClassDB::bind_method(D_METHOD("wait_to_finish"), &Thread::wait_to_finish); @@ -2221,7 +2200,7 @@ Object *Engine::get_singleton_object(const StringName &p_name) const { void Engine::register_singleton(const StringName &p_name, Object *p_object) { ERR_FAIL_COND_MSG(has_singleton(p_name), "Singleton already registered: " + String(p_name)); - ERR_FAIL_COND_MSG(p_name.operator String().is_valid_identifier(), "Singleton name is not a valid identifier: " + String(p_name)); + ERR_FAIL_COND_MSG(!String(p_name).is_valid_identifier(), "Singleton name is not a valid identifier: " + p_name); ::Engine::Singleton s; s.class_name = p_name; s.name = p_name; diff --git a/core/core_bind.h b/core/core_bind.h index a5d5a7c8ce..84a284f948 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -539,8 +539,7 @@ protected: Variant ret; Variant userdata; SafeFlag active; - Object *target_instance = nullptr; - StringName target_method; + Callable target_callable; ::Thread thread; static void _bind_methods(); static void _start_func(void *ud); @@ -553,7 +552,7 @@ public: PRIORITY_MAX }; - Error start(Object *p_instance, const StringName &p_method, const Variant &p_userdata = Variant(), Priority p_priority = PRIORITY_NORMAL); + Error start(const Callable &p_callable, const Variant &p_userdata = Variant(), Priority p_priority = PRIORITY_NORMAL); String get_id() const; bool is_active() const; Variant wait_to_finish(); diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index 50b2099236..c2a9d30fff 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -1557,9 +1557,13 @@ bool InputEventShortcut::is_pressed() const { } String InputEventShortcut::as_text() const { + ERR_FAIL_COND_V(shortcut.is_null(), "None"); + return vformat(RTR("Input Event with Shortcut=%s"), shortcut->get_as_text()); } String InputEventShortcut::to_string() { + ERR_FAIL_COND_V(shortcut.is_null(), "None"); + return vformat("InputEventShortcut: shortcut=%s", shortcut->get_as_text()); } diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 8bec80a99e..1ec4299093 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -467,7 +467,7 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() { // ///// UI Text Input Shortcuts ///// inputs = List<Ref<InputEvent>>(); - inputs.push_back(InputEventKey::create_reference(KEY_SPACE | KEY_MASK_CMD)); + inputs.push_back(InputEventKey::create_reference(KEY_SPACE | KEY_MASK_CTRL)); default_builtin_cache.insert("ui_text_completion_query", inputs); inputs = List<Ref<InputEvent>>(); diff --git a/core/io/image.cpp b/core/io/image.cpp index 3112dd217f..c70f4b86bd 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -2506,7 +2506,7 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po clipped_src_rect.position.y = ABS(p_dest.y); } - if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) { + if (clipped_src_rect.has_no_area()) { return; } @@ -2561,7 +2561,7 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co clipped_src_rect.position.y = ABS(p_dest.y); } - if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) { + if (clipped_src_rect.has_no_area()) { return; } @@ -2615,7 +2615,7 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const P clipped_src_rect.position.y = ABS(p_dest.y); } - if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) { + if (clipped_src_rect.has_no_area()) { return; } @@ -2664,7 +2664,7 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c clipped_src_rect.position.y = ABS(p_dest.y); } - if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) { + if (clipped_src_rect.has_no_area()) { return; } diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index 8da44fd290..87d2b66e5b 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -138,6 +138,7 @@ Error PacketPeer::_get_packet_error() const { void PacketPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &PacketPeer::_bnd_get_var, DEFVAL(false)); ClassDB::bind_method(D_METHOD("put_var", "var", "full_objects"), &PacketPeer::put_var, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_packet"), &PacketPeer::_get_packet); ClassDB::bind_method(D_METHOD("put_packet", "buffer"), &PacketPeer::_put_packet); ClassDB::bind_method(D_METHOD("get_packet_error"), &PacketPeer::_get_packet_error); @@ -151,6 +152,51 @@ void PacketPeer::_bind_methods() { /***************/ +int PacketPeerExtension::get_available_packet_count() const { + int count; + if (GDVIRTUAL_CALL(_get_available_packet_count, count)) { + return count; + } + WARN_PRINT_ONCE("PacketPeerExtension::_get_available_packet_count is unimplemented!"); + return -1; +} + +Error PacketPeerExtension::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + int err; + if (GDVIRTUAL_CALL(_get_packet, r_buffer, &r_buffer_size, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("PacketPeerExtension::_get_packet_native is unimplemented!"); + return FAILED; +} + +Error PacketPeerExtension::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + int err; + if (GDVIRTUAL_CALL(_put_packet, p_buffer, p_buffer_size, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("PacketPeerExtension::_put_packet_native is unimplemented!"); + return FAILED; +} + +int PacketPeerExtension::get_max_packet_size() const { + int size; + if (GDVIRTUAL_CALL(_get_max_packet_size, size)) { + return size; + } + WARN_PRINT_ONCE("PacketPeerExtension::_get_max_packet_size is unimplemented!"); + return 0; +} + +void PacketPeerExtension::_bind_methods() { + GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size"); + GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size"); + GDVIRTUAL_BIND(_get_available_packet_count); + GDVIRTUAL_BIND(_get_max_packet_size); +} + +/***************/ + void PacketPeerStream::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream_peer", "peer"), &PacketPeerStream::set_stream_peer); ClassDB::bind_method(D_METHOD("get_stream_peer"), &PacketPeerStream::get_stream_peer); diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h index 9a345af3d0..bc1f4aaabf 100644 --- a/core/io/packet_peer.h +++ b/core/io/packet_peer.h @@ -35,6 +35,10 @@ #include "core/object/class_db.h" #include "core/templates/ring_buffer.h" +#include "core/object/gdvirtual.gen.inc" +#include "core/object/script_language.h" +#include "core/variant/native_ptr.h" + class PacketPeer : public RefCounted { GDCLASS(PacketPeer, RefCounted); @@ -73,6 +77,25 @@ public: ~PacketPeer() {} }; +class PacketPeerExtension : public PacketPeer { + GDCLASS(PacketPeerExtension, PacketPeer); + +protected: + static void _bind_methods(); + +public: + virtual int get_available_packet_count() const override; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; + virtual int get_max_packet_size() const override; + + /* GDExtension */ + GDVIRTUAL0RC(int, _get_available_packet_count); + GDVIRTUAL2R(int, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>); + GDVIRTUAL2R(int, _put_packet, GDNativeConstPtr<const uint8_t>, int); + GDVIRTUAL0RC(int, _get_max_packet_size); +}; + class PacketPeerStream : public PacketPeer { GDCLASS(PacketPeerStream, PacketPeer); diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp index 97d683f415..290a71043c 100644 --- a/core/io/resource_uid.cpp +++ b/core/io/resource_uid.cpp @@ -126,8 +126,7 @@ String ResourceUID::get_id_path(ID p_id) const { MutexLock l(mutex); ERR_FAIL_COND_V(!unique_ids.has(p_id), String()); const CharString &cs = unique_ids[p_id].cs; - String s(cs.ptr()); - return s; + return String::utf8(cs.ptr()); } void ResourceUID::remove_id(ID p_id) { MutexLock l(mutex); diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp index 27f8d4e88f..8ab025dda1 100644 --- a/core/io/stream_peer.cpp +++ b/core/io/stream_peer.cpp @@ -410,6 +410,63 @@ void StreamPeer::_bind_methods() { //////////////////////////////// +int StreamPeerExtension::get_available_bytes() const { + int count; + if (GDVIRTUAL_CALL(_get_available_bytes, count)) { + return count; + } + WARN_PRINT_ONCE("StreamPeerExtension::_get_available_bytes is unimplemented!"); + return -1; +} + +Error StreamPeerExtension::get_data(uint8_t *r_buffer, int p_bytes) { + int err; + int received = 0; + if (GDVIRTUAL_CALL(_get_data, r_buffer, p_bytes, &received, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("StreamPeerExtension::_get_data is unimplemented!"); + return FAILED; +} + +Error StreamPeerExtension::get_partial_data(uint8_t *r_buffer, int p_bytes, int &r_received) { + int err; + if (GDVIRTUAL_CALL(_get_partial_data, r_buffer, p_bytes, &r_received, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("StreamPeerExtension::_get_partial_data is unimplemented!"); + return FAILED; +} + +Error StreamPeerExtension::put_data(const uint8_t *p_data, int p_bytes) { + int err; + int sent = 0; + if (GDVIRTUAL_CALL(_put_data, p_data, p_bytes, &sent, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("StreamPeerExtension::_put_data is unimplemented!"); + return FAILED; +} + +Error StreamPeerExtension::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) { + int err; + if (GDVIRTUAL_CALL(_put_data, p_data, p_bytes, &r_sent, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("StreamPeerExtension::_put_partial_data is unimplemented!"); + return FAILED; +} + +void StreamPeerExtension::_bind_methods() { + GDVIRTUAL_BIND(_get_data, "r_buffer", "r_bytes", "r_received"); + GDVIRTUAL_BIND(_get_partial_data, "r_buffer", "r_bytes", "r_received"); + GDVIRTUAL_BIND(_put_data, "p_data", "p_bytes", "r_sent"); + GDVIRTUAL_BIND(_put_partial_data, "p_data", "p_bytes", "r_sent"); + GDVIRTUAL_BIND(_get_available_bytes); +} + +//////////////////////////////// + void StreamPeerBuffer::_bind_methods() { ClassDB::bind_method(D_METHOD("seek", "position"), &StreamPeerBuffer::seek); ClassDB::bind_method(D_METHOD("get_size"), &StreamPeerBuffer::get_size); diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h index effc3850af..89432951c5 100644 --- a/core/io/stream_peer.h +++ b/core/io/stream_peer.h @@ -33,6 +33,10 @@ #include "core/object/ref_counted.h" +#include "core/object/gdvirtual.gen.inc" +#include "core/object/script_language.h" +#include "core/variant/native_ptr.h" + class StreamPeer : public RefCounted { GDCLASS(StreamPeer, RefCounted); OBJ_CATEGORY("Networking"); @@ -58,6 +62,7 @@ public: virtual int get_available_bytes() const = 0; + /* helpers */ void set_big_endian(bool p_big_endian); bool is_big_endian_enabled() const; @@ -92,6 +97,26 @@ public: StreamPeer() {} }; +class StreamPeerExtension : public StreamPeer { + GDCLASS(StreamPeerExtension, StreamPeer); + +protected: + static void _bind_methods(); + +public: + 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; + + GDVIRTUAL3R(int, _put_data, GDNativeConstPtr<const uint8_t>, int, GDNativePtr<int>); + GDVIRTUAL3R(int, _put_partial_data, GDNativeConstPtr<const uint8_t>, int, GDNativePtr<int>); + GDVIRTUAL3R(int, _get_data, GDNativePtr<uint8_t>, int, GDNativePtr<int>); + GDVIRTUAL3R(int, _get_partial_data, GDNativePtr<uint8_t>, int, GDNativePtr<int>); + GDVIRTUAL0RC(int, _get_available_bytes); +}; + class StreamPeerBuffer : public StreamPeer { GDCLASS(StreamPeerBuffer, StreamPeer); diff --git a/core/multiplayer/multiplayer_peer.cpp b/core/multiplayer/multiplayer_peer.cpp index 40847102d8..3c33948e2f 100644 --- a/core/multiplayer/multiplayer_peer.cpp +++ b/core/multiplayer/multiplayer_peer.cpp @@ -53,6 +53,30 @@ uint32_t MultiplayerPeer::generate_unique_id() const { return hash; } +void MultiplayerPeer::set_transfer_channel(int p_channel) { + transfer_channel = p_channel; +} + +int MultiplayerPeer::get_transfer_channel() const { + return transfer_channel; +} + +void MultiplayerPeer::set_transfer_mode(Multiplayer::TransferMode p_mode) { + transfer_mode = p_mode; +} + +Multiplayer::TransferMode MultiplayerPeer::get_transfer_mode() const { + return transfer_mode; +} + +void MultiplayerPeer::set_refuse_new_connections(bool p_enable) { + refuse_connections = p_enable; +} + +bool MultiplayerPeer::is_refusing_new_connections() const { + return refuse_connections; +} + void MultiplayerPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &MultiplayerPeer::set_transfer_channel); ClassDB::bind_method(D_METHOD("get_transfer_channel"), &MultiplayerPeer::get_transfer_channel); @@ -88,3 +112,160 @@ void MultiplayerPeer::_bind_methods() { ADD_SIGNAL(MethodInfo("connection_succeeded")); ADD_SIGNAL(MethodInfo("connection_failed")); } + +/*************/ + +int MultiplayerPeerExtension::get_available_packet_count() const { + int count; + if (GDVIRTUAL_CALL(_get_available_packet_count, count)) { + return count; + } + WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_available_packet_count is unimplemented!"); + return -1; +} + +Error MultiplayerPeerExtension::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + int err; + if (GDVIRTUAL_CALL(_get_packet, r_buffer, &r_buffer_size, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_packet_native is unimplemented!"); + return FAILED; +} + +Error MultiplayerPeerExtension::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + int err; + if (GDVIRTUAL_CALL(_put_packet, p_buffer, p_buffer_size, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("MultiplayerPeerExtension::_put_packet_native is unimplemented!"); + return FAILED; +} + +int MultiplayerPeerExtension::get_max_packet_size() const { + int size; + if (GDVIRTUAL_CALL(_get_max_packet_size, size)) { + return size; + } + WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_max_packet_size is unimplemented!"); + return 0; +} + +void MultiplayerPeerExtension::set_transfer_channel(int p_channel) { + if (GDVIRTUAL_CALL(_set_transfer_channel, p_channel)) { + return; + } + MultiplayerPeer::set_transfer_channel(p_channel); +} + +int MultiplayerPeerExtension::get_transfer_channel() const { + int channel; + if (GDVIRTUAL_CALL(_get_transfer_channel, channel)) { + return channel; + } + return MultiplayerPeer::get_transfer_channel(); +} + +void MultiplayerPeerExtension::set_transfer_mode(Multiplayer::TransferMode p_mode) { + if (GDVIRTUAL_CALL(_set_transfer_mode, p_mode)) { + return; + } + MultiplayerPeer::set_transfer_mode(p_mode); +} + +Multiplayer::TransferMode MultiplayerPeerExtension::get_transfer_mode() const { + int mode; + if (GDVIRTUAL_CALL(_get_transfer_mode, mode)) { + return (Multiplayer::TransferMode)mode; + } + return MultiplayerPeer::get_transfer_mode(); +} + +void MultiplayerPeerExtension::set_target_peer(int p_peer_id) { + if (GDVIRTUAL_CALL(_set_target_peer, p_peer_id)) { + return; + } + WARN_PRINT_ONCE("MultiplayerPeerExtension::_set_target_peer is unimplemented!"); +} + +int MultiplayerPeerExtension::get_packet_peer() const { + int peer; + if (GDVIRTUAL_CALL(_get_packet_peer, peer)) { + return peer; + } + WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_packet_peer is unimplemented!"); + return 0; +} + +bool MultiplayerPeerExtension::is_server() const { + bool server; + if (GDVIRTUAL_CALL(_is_server, server)) { + return server; + } + WARN_PRINT_ONCE("MultiplayerPeerExtension::_is_server is unimplemented!"); + return false; +} + +void MultiplayerPeerExtension::poll() { + int err; + if (GDVIRTUAL_CALL(_poll, err)) { + return; + } + WARN_PRINT_ONCE("MultiplayerPeerExtension::_poll is unimplemented!"); +} + +int MultiplayerPeerExtension::get_unique_id() const { + int id; + if (GDVIRTUAL_CALL(_get_unique_id, id)) { + return id; + } + WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_unique_id is unimplemented!"); + return 0; +} + +void MultiplayerPeerExtension::set_refuse_new_connections(bool p_enable) { + if (GDVIRTUAL_CALL(_set_refuse_new_connections, p_enable)) { + return; + } + MultiplayerPeer::set_refuse_new_connections(p_enable); +} + +bool MultiplayerPeerExtension::is_refusing_new_connections() const { + bool refusing; + if (GDVIRTUAL_CALL(_is_refusing_new_connections, refusing)) { + return refusing; + } + return MultiplayerPeer::is_refusing_new_connections(); +} + +MultiplayerPeer::ConnectionStatus MultiplayerPeerExtension::get_connection_status() const { + int status; + if (GDVIRTUAL_CALL(_get_connection_status, status)) { + return (ConnectionStatus)status; + } + WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_connection_status is unimplemented!"); + return CONNECTION_DISCONNECTED; +} + +void MultiplayerPeerExtension::_bind_methods() { + GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size"); + GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size"); + GDVIRTUAL_BIND(_get_available_packet_count); + GDVIRTUAL_BIND(_get_max_packet_size); + + GDVIRTUAL_BIND(_set_transfer_channel, "p_channel"); + GDVIRTUAL_BIND(_get_transfer_channel); + + GDVIRTUAL_BIND(_set_transfer_mode, "p_mode"); + GDVIRTUAL_BIND(_get_transfer_mode); + + GDVIRTUAL_BIND(_set_target_peer, "p_peer"); + + GDVIRTUAL_BIND(_get_packet_peer); + GDVIRTUAL_BIND(_is_server); + GDVIRTUAL_BIND(_poll); + GDVIRTUAL_BIND(_get_unique_id); + GDVIRTUAL_BIND(_set_refuse_new_connections, "p_enable"); + GDVIRTUAL_BIND(_is_refusing_new_connections); + GDVIRTUAL_BIND(_get_connection_status); +} diff --git a/core/multiplayer/multiplayer_peer.h b/core/multiplayer/multiplayer_peer.h index ba00c3b41b..126ba9e645 100644 --- a/core/multiplayer/multiplayer_peer.h +++ b/core/multiplayer/multiplayer_peer.h @@ -34,12 +34,21 @@ #include "core/io/packet_peer.h" #include "core/multiplayer/multiplayer.h" +#include "core/object/gdvirtual.gen.inc" +#include "core/object/script_language.h" +#include "core/variant/native_ptr.h" + class MultiplayerPeer : public PacketPeer { GDCLASS(MultiplayerPeer, PacketPeer); protected: static void _bind_methods(); +private: + int transfer_channel = 0; + Multiplayer::TransferMode transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; + bool refuse_connections = false; + public: enum { TARGET_PEER_BROADCAST = 0, @@ -52,10 +61,13 @@ public: CONNECTION_CONNECTED, }; - virtual void set_transfer_channel(int p_channel) = 0; - virtual int get_transfer_channel() const = 0; - virtual void set_transfer_mode(Multiplayer::TransferMode p_mode) = 0; - virtual Multiplayer::TransferMode get_transfer_mode() const = 0; + virtual void set_transfer_channel(int p_channel); + virtual int get_transfer_channel() const; + virtual void set_transfer_mode(Multiplayer::TransferMode p_mode); + virtual Multiplayer::TransferMode get_transfer_mode() const; + virtual void set_refuse_new_connections(bool p_enable); + virtual bool is_refusing_new_connections() const; + virtual void set_target_peer(int p_peer_id) = 0; virtual int get_packet_peer() const = 0; @@ -66,15 +78,67 @@ public: virtual int get_unique_id() const = 0; - virtual void set_refuse_new_connections(bool p_enable) = 0; - virtual bool is_refusing_new_connections() const = 0; - virtual ConnectionStatus get_connection_status() const = 0; + uint32_t generate_unique_id() const; MultiplayerPeer() {} }; -VARIANT_ENUM_CAST(MultiplayerPeer::ConnectionStatus) +VARIANT_ENUM_CAST(MultiplayerPeer::ConnectionStatus); + +class MultiplayerPeerExtension : public MultiplayerPeer { + GDCLASS(MultiplayerPeerExtension, MultiplayerPeer); + +protected: + static void _bind_methods(); + +public: + /* PacketPeer */ + virtual int get_available_packet_count() const override; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; + virtual int get_max_packet_size() const override; + + /* MultiplayerPeer */ + virtual void set_transfer_channel(int p_channel) override; + virtual int get_transfer_channel() const override; + virtual void set_transfer_mode(Multiplayer::TransferMode p_mode) override; + virtual Multiplayer::TransferMode get_transfer_mode() const override; + virtual void set_target_peer(int p_peer_id) override; + + virtual int get_packet_peer() const override; + + virtual bool is_server() const override; + + virtual void poll() override; + + virtual int get_unique_id() const override; + + virtual void set_refuse_new_connections(bool p_enable) override; + virtual bool is_refusing_new_connections() const override; + + virtual ConnectionStatus get_connection_status() const override; + + /* PacketPeer GDExtension */ + GDVIRTUAL0RC(int, _get_available_packet_count); + GDVIRTUAL2R(int, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>); + GDVIRTUAL2R(int, _put_packet, GDNativeConstPtr<const uint8_t>, int); + GDVIRTUAL0RC(int, _get_max_packet_size); + + /* MultiplayerPeer GDExtension */ + GDVIRTUAL1(_set_transfer_channel, int); + GDVIRTUAL0RC(int, _get_transfer_channel); + GDVIRTUAL1(_set_transfer_mode, int); + GDVIRTUAL0RC(int, _get_transfer_mode); + GDVIRTUAL1(_set_target_peer, int); + GDVIRTUAL0RC(int, _get_packet_peer); + GDVIRTUAL0RC(bool, _is_server); + GDVIRTUAL0R(int, _poll); + GDVIRTUAL0RC(int, _get_unique_id); + GDVIRTUAL1(_set_refuse_new_connections, bool); + GDVIRTUAL0RC(bool, _is_refusing_new_connections); + GDVIRTUAL0RC(int, _get_connection_status); +}; #endif // NETWORKED_MULTIPLAYER_PEER_H diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 3a037f9dd1..e33c21cc00 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -169,11 +169,13 @@ void register_core_types() { GDREGISTER_VIRTUAL_CLASS(IP); GDREGISTER_VIRTUAL_CLASS(StreamPeer); + GDREGISTER_CLASS(StreamPeerExtension); GDREGISTER_CLASS(StreamPeerBuffer); GDREGISTER_CLASS(StreamPeerTCP); GDREGISTER_CLASS(TCPServer); GDREGISTER_VIRTUAL_CLASS(PacketPeer); + GDREGISTER_CLASS(PacketPeerExtension); GDREGISTER_CLASS(PacketPeerStream); GDREGISTER_CLASS(PacketPeerUDP); GDREGISTER_CLASS(UDPServer); @@ -197,6 +199,7 @@ void register_core_types() { ResourceLoader::add_resource_format_loader(resource_format_loader_crypto); GDREGISTER_VIRTUAL_CLASS(MultiplayerPeer); + GDREGISTER_VIRTUAL_CLASS(MultiplayerPeerExtension); GDREGISTER_VIRTUAL_CLASS(MultiplayerReplicator); GDREGISTER_CLASS(MultiplayerAPI); GDREGISTER_CLASS(MainLoop); diff --git a/core/string/translation.cpp b/core/string/translation.cpp index cb7d924556..5c0eb388f5 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -875,6 +875,11 @@ void Translation::add_plural_message(const StringName &p_src_text, const Vector< } StringName Translation::get_message(const StringName &p_src_text, const StringName &p_context) const { + StringName ret; + if (GDVIRTUAL_CALL(_get_message, p_src_text, p_context, ret)) { + return ret; + } + if (p_context != StringName()) { WARN_PRINT("Translation class doesn't handle context. Using context in get_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles context, such as TranslationPO class"); } @@ -888,6 +893,11 @@ StringName Translation::get_message(const StringName &p_src_text, const StringNa } StringName Translation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const { + StringName ret; + if (GDVIRTUAL_CALL(_get_plural_message, p_src_text, p_plural_text, p_n, p_context, ret)) { + return ret; + } + WARN_PRINT("Translation class doesn't handle plural messages. Calling get_plural_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles plurals, such as TranslationPO class"); return get_message(p_src_text); } @@ -923,6 +933,9 @@ void Translation::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_messages"), &Translation::_set_messages); ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages); + GDVIRTUAL_BIND(_get_plural_message, "src_message", "src_plural_message", "n", "context"); + GDVIRTUAL_BIND(_get_message, "src_message", "context"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "messages", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_messages", "_get_messages"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "locale"), "set_locale", "get_locale"); } diff --git a/core/string/translation.h b/core/string/translation.h index 4f179ac0fe..6aec0bb8ea 100644 --- a/core/string/translation.h +++ b/core/string/translation.h @@ -32,6 +32,8 @@ #define TRANSLATION_H #include "core/io/resource.h" +#include "core/object/gdvirtual.gen.inc" +#include "core/object/script_language.h" class Translation : public Resource { GDCLASS(Translation, Resource); @@ -48,6 +50,9 @@ class Translation : public Resource { protected: static void _bind_methods(); + GDVIRTUAL2RC(StringName, _get_message, StringName, StringName); + GDVIRTUAL4RC(StringName, _get_plural_message, StringName, StringName, int, StringName); + public: void set_locale(const String &p_locale); _FORCE_INLINE_ String get_locale() const { return locale; } diff --git a/core/variant/native_ptr.h b/core/variant/native_ptr.h index b4ec0df7d6..b7e8d92f62 100644 --- a/core/variant/native_ptr.h +++ b/core/variant/native_ptr.h @@ -117,6 +117,7 @@ GDVIRTUAL_NATIVE_PTR(char16_t) GDVIRTUAL_NATIVE_PTR(char32_t) GDVIRTUAL_NATIVE_PTR(wchar_t) GDVIRTUAL_NATIVE_PTR(uint8_t) +GDVIRTUAL_NATIVE_PTR(uint8_t *) GDVIRTUAL_NATIVE_PTR(int8_t) GDVIRTUAL_NATIVE_PTR(uint16_t) GDVIRTUAL_NATIVE_PTR(int16_t) diff --git a/doc/classes/AnimatableBody2D.xml b/doc/classes/AnimatableBody2D.xml index e58f4bd692..bc169cf9c9 100644 --- a/doc/classes/AnimatableBody2D.xml +++ b/doc/classes/AnimatableBody2D.xml @@ -11,7 +11,7 @@ <tutorials> </tutorials> <members> - <member name="sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false"> + <member name="sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="true"> If [code]true[/code], the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method PhysicsBody2D.move_and_collide]. </member> </members> diff --git a/doc/classes/AnimatableBody3D.xml b/doc/classes/AnimatableBody3D.xml index 71a48a5aa6..86cff38c51 100644 --- a/doc/classes/AnimatableBody3D.xml +++ b/doc/classes/AnimatableBody3D.xml @@ -14,7 +14,7 @@ <link title="3D Voxel Demo">https://godotengine.org/asset-library/asset/676</link> </tutorials> <members> - <member name="sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false"> + <member name="sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="true"> If [code]true[/code], the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method PhysicsBody3D.move_and_collide]. </member> </members> diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml index 882aa8bd71..35702070be 100644 --- a/doc/classes/CharacterBody2D.xml +++ b/doc/classes/CharacterBody2D.xml @@ -133,11 +133,11 @@ <member name="floor_max_angle" type="float" setter="set_floor_max_angle" getter="get_floor_max_angle" default="0.785398"> Maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. The default value equals 45 degrees. </member> - <member name="floor_snap_length" type="float" setter="set_floor_snap_length" getter="get_floor_snap_length" default="0.0"> + <member name="floor_snap_length" type="float" setter="set_floor_snap_length" getter="get_floor_snap_length" default="1.0"> Sets a snapping distance. When set to a value different from [code]0.0[/code], the body is kept attached to slopes when calling [method move_and_slide]. The snapping vector is determined by the given distance along the opposite direction of the [member up_direction]. As long as the snapping vector is in contact with the ground and the body moves against `up_direction`, the body will remain attached to the surface. Snapping is not applied if the body moves along `up_direction`, so it will be able to detach from the ground when jumping. </member> - <member name="floor_stop_on_slope" type="bool" setter="set_floor_stop_on_slope_enabled" getter="is_floor_stop_on_slope_enabled" default="false"> + <member name="floor_stop_on_slope" type="bool" setter="set_floor_stop_on_slope_enabled" getter="is_floor_stop_on_slope_enabled" default="true"> If [code]true[/code], the body will not slide on floor's slopes when you include gravity in [code]linear_velocity[/code] when calling [method move_and_slide] and the body is standing still. </member> <member name="free_mode_min_slide_angle" type="float" setter="set_free_mode_min_slide_angle" getter="get_free_mode_min_slide_angle" default="0.261799"> diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml index f13796bfe7..66d9940b60 100644 --- a/doc/classes/CharacterBody3D.xml +++ b/doc/classes/CharacterBody3D.xml @@ -146,7 +146,7 @@ Sets a snapping distance. When set to a value different from [code]0.0[/code], the body is kept attached to slopes when calling [method move_and_slide]. The snapping vector is determined by the given distance along the opposite direction of the [member up_direction]. As long as the snapping vector is in contact with the ground and the body moves against `up_direction`, the body will remain attached to the surface. Snapping is not applied if the body moves along `up_direction`, so it will be able to detach from the ground when jumping. </member> - <member name="floor_stop_on_slope" type="bool" setter="set_floor_stop_on_slope_enabled" getter="is_floor_stop_on_slope_enabled" default="false"> + <member name="floor_stop_on_slope" type="bool" setter="set_floor_stop_on_slope_enabled" getter="is_floor_stop_on_slope_enabled" default="true"> If [code]true[/code], the body will not slide on slopes when you include gravity in [code]linear_velocity[/code] when calling [method move_and_slide] and the body is standing still. </member> <member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3(0, 0, 0)"> diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index 571ffd592a..f33016cc6c 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -5,6 +5,7 @@ </brief_description> <description> Displays a color picker widget. Useful for selecting a color from an RGB/RGBA colorspace. + [b]Note:[/b] This control is the color picker widget itself. You can use a [ColorPickerButton] instead if you need a button that brings up a [ColorPicker] in a pop-up. </description> <tutorials> <link title="Tween Demo">https://godotengine.org/asset-library/asset/146</link> diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml index dcef1c55f7..1cdfbd760e 100644 --- a/doc/classes/ColorPickerButton.xml +++ b/doc/classes/ColorPickerButton.xml @@ -6,6 +6,7 @@ <description> Encapsulates a [ColorPicker] making it accessible by pressing a button. Pressing the button will toggle the [ColorPicker] visibility. See also [BaseButton] which contains common properties and methods associated with this node. + [b]Note:[/b] By default, the button may not be wide enough for the color preview swatch to be visible. Make sure to set [member Control.rect_min_size] to a big enough value to give the button enough space. </description> <tutorials> <link title="GUI Drag And Drop Demo">https://godotengine.org/asset-library/asset/133</link> diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index 834b5a41db..83e3f5b05a 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -82,6 +82,24 @@ Returns the scroll offset due to [member caret_column], as a number of characters. </description> </method> + <method name="get_selection_from_column" qualifiers="const"> + <return type="int" /> + <description> + Returns the selection begin column. + </description> + </method> + <method name="get_selection_to_column" qualifiers="const"> + <return type="int" /> + <description> + Returns the selection end column. + </description> + </method> + <method name="has_selection" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if the user has selected text. + </description> + </method> <method name="insert_text_at_caret"> <return type="void" /> <argument index="0" name="text" type="String" /> diff --git a/doc/classes/MultiplayerPeer.xml b/doc/classes/MultiplayerPeer.xml index a9c2a941f8..15517f7c2f 100644 --- a/doc/classes/MultiplayerPeer.xml +++ b/doc/classes/MultiplayerPeer.xml @@ -53,14 +53,14 @@ </method> </methods> <members> - <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" default="true"> + <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" default="false"> If [code]true[/code], this [MultiplayerPeer] refuses new connections. </member> <member name="transfer_channel" type="int" setter="set_transfer_channel" getter="get_transfer_channel" default="0"> The channel to use to send packets. Many network APIs such as ENet and WebRTC allow the creation of multiple independent channels which behaves, in a way, like separate connections. This means that reliable data will only block delivery of other packets on that channel, and ordering will only be in respect to the channel the packet is being sent on. Using different channels to send [b]different and independent[/b] state updates is a common way to optimize network usage and decrease latency in fast-paced games. [b]Note:[/b] The default channel ([code]0[/code]) actually works as 3 separate channels (one for each [enum TransferMode]) so that [constant TRANSFER_MODE_RELIABLE] and [constant TRANSFER_MODE_ORDERED] does not interact with each other by default. Refer to the specific network API documentation (e.g. ENet or WebRTC) to learn how to set up channels correctly. </member> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" enum="TransferMode" default="0"> + <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" enum="TransferMode" default="2"> The manner in which to send packets to the [code]target_peer[/code]. See [enum TransferMode]. </member> </members> diff --git a/doc/classes/MultiplayerPeerExtension.xml b/doc/classes/MultiplayerPeerExtension.xml new file mode 100644 index 0000000000..d9c173a4a1 --- /dev/null +++ b/doc/classes/MultiplayerPeerExtension.xml @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="MultiplayerPeerExtension" inherits="MultiplayerPeer" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="_get_available_packet_count" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_connection_status" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_max_packet_size" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_packet" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="r_buffer" type="const void*" /> + <argument index="1" name="r_buffer_size" type="int32_t*" /> + <description> + </description> + </method> + <method name="_get_packet_peer" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_transfer_channel" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_transfer_mode" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_unique_id" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_is_refusing_new_connections" qualifiers="virtual const"> + <return type="bool" /> + <description> + </description> + </method> + <method name="_is_server" qualifiers="virtual const"> + <return type="bool" /> + <description> + </description> + </method> + <method name="_poll" qualifiers="virtual"> + <return type="int" /> + <description> + </description> + </method> + <method name="_put_packet" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_buffer" type="const void*" /> + <argument index="1" name="p_buffer_size" type="int" /> + <description> + </description> + </method> + <method name="_set_refuse_new_connections" qualifiers="virtual"> + <return type="void" /> + <argument index="0" name="p_enable" type="bool" /> + <description> + </description> + </method> + <method name="_set_target_peer" qualifiers="virtual"> + <return type="void" /> + <argument index="0" name="p_peer" type="int" /> + <description> + </description> + </method> + <method name="_set_transfer_channel" qualifiers="virtual"> + <return type="void" /> + <argument index="0" name="p_channel" type="int" /> + <description> + </description> + </method> + <method name="_set_transfer_mode" qualifiers="virtual"> + <return type="void" /> + <argument index="0" name="p_mode" type="int" /> + <description> + </description> + </method> + </methods> +</class> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index e2ac8568c9..9d0d185c42 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -49,6 +49,7 @@ [/codeblocks] See [method execute] if you wish to run an external command and retrieve the results. [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. + [b]Note:[/b] On macOS, sandboxed applications are limited to run only embedded helper executables, specified during export. </description> </method> <method name="delay_msec" qualifiers="const"> @@ -119,6 +120,7 @@ [/csharp] [/codeblocks] [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. + [b]Note:[/b] On macOS, sandboxed applications are limited to run only embedded helper executables, specified during export. </description> </method> <method name="find_keycode_from_string" qualifiers="const"> diff --git a/doc/classes/PacketPeerExtension.xml b/doc/classes/PacketPeerExtension.xml new file mode 100644 index 0000000000..6804053484 --- /dev/null +++ b/doc/classes/PacketPeerExtension.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="PacketPeerExtension" inherits="PacketPeer" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="_get_available_packet_count" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_max_packet_size" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_packet" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="r_buffer" type="const void*" /> + <argument index="1" name="r_buffer_size" type="int32_t*" /> + <description> + </description> + </method> + <method name="_put_packet" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_buffer" type="const void*" /> + <argument index="1" name="p_buffer_size" type="int" /> + <description> + </description> + </method> + </methods> +</class> diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml index ee28500838..e108ab6298 100644 --- a/doc/classes/PhysicsBody2D.xml +++ b/doc/classes/PhysicsBody2D.xml @@ -25,11 +25,12 @@ </method> <method name="move_and_collide"> <return type="KinematicCollision2D" /> - <argument index="0" name="rel_vec" type="Vector2" /> + <argument index="0" name="linear_velocity" type="Vector2" /> <argument index="1" name="test_only" type="bool" default="false" /> <argument index="2" name="safe_margin" type="float" default="0.08" /> <description> - Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision2D], which contains information about the collision. + Moves the body along the vector [code]linear_velocity[/code]. This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. + The body will stop if it collides. Returns a [KinematicCollision2D], which contains information about the collision. If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given. [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details). </description> @@ -44,11 +45,12 @@ <method name="test_move"> <return type="bool" /> <argument index="0" name="from" type="Transform2D" /> - <argument index="1" name="rel_vec" type="Vector2" /> + <argument index="1" name="linear_velocity" type="Vector2" /> <argument index="2" name="collision" type="KinematicCollision2D" default="null" /> <argument index="3" name="safe_margin" type="float" default="0.08" /> <description> - Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur. + Checks for collisions without moving the body. This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. + Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [code]linear_velocity[/code]. Returns [code]true[/code] if a collision would occur. [code]collision[/code] is an optional object of type [KinematicCollision2D], which contains additional information about the collision (should there be one). [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details). </description> diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml index 174e49ea2d..8718c0caa2 100644 --- a/doc/classes/PhysicsBody3D.xml +++ b/doc/classes/PhysicsBody3D.xml @@ -32,12 +32,13 @@ </method> <method name="move_and_collide"> <return type="KinematicCollision3D" /> - <argument index="0" name="rel_vec" type="Vector3" /> + <argument index="0" name="linear_velocity" type="Vector3" /> <argument index="1" name="test_only" type="bool" default="false" /> <argument index="2" name="safe_margin" type="float" default="0.001" /> <argument index="3" name="max_collisions" type="int" default="1" /> <description> - Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision. + Moves the body along the vector [code]linear_velocity[/code]. This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. + The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision. If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given. [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details). [code]max_collisions[/code] allows to retrieve more than one collision result. @@ -61,12 +62,13 @@ <method name="test_move"> <return type="bool" /> <argument index="0" name="from" type="Transform3D" /> - <argument index="1" name="rel_vec" type="Vector3" /> + <argument index="1" name="linear_velocity" type="Vector3" /> <argument index="2" name="collision" type="KinematicCollision3D" default="null" /> <argument index="3" name="safe_margin" type="float" default="0.001" /> <argument index="4" name="max_collisions" type="int" default="1" /> <description> - Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur. + Checks for collisions without moving the body. This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. + Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [code]linear_velocity[/code]. Returns [code]true[/code] if a collision would occur. [code]collision[/code] is an optional object of type [KinematicCollision3D], which contains additional information about the collision (should there be one). [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details). [code]max_collisions[/code] allows to retrieve more than one collision result. diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml index 7e5d7ca704..791a04e4c2 100644 --- a/doc/classes/PhysicsServer2D.xml +++ b/doc/classes/PhysicsServer2D.xml @@ -851,8 +851,6 @@ <constant name="SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS" value="6" enum="SpaceParameter"> Constant to set/get the default solver bias for all physics constraints. A solver bias is a factor controlling how much two objects "rebound", after violating a constraint, to avoid leaving them in that state because of numerical imprecision. </constant> - <constant name="SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH" value="7" enum="SpaceParameter"> - </constant> <constant name="SHAPE_WORLD_BOUNDARY" value="0" enum="ShapeType"> This is the constant for creating world boundary shapes. A world boundary shape is an [i]infinite[/i] line with an origin point, and a normal. Thus, it can be used for front/behind checks. </constant> @@ -928,8 +926,8 @@ <constant name="BODY_MODE_DYNAMIC" value="2" enum="BodyMode"> Constant for dynamic bodies. In this mode, a body can be pushed by other bodies and has forces applied. </constant> - <constant name="BODY_MODE_DYNAMIC_LOCKED" value="3" enum="BodyMode"> - Constant for locked dynamic bodies. In this mode, a body is dynamic but can not rotate, and only its linear velocity is affected by external forces. + <constant name="BODY_MODE_DYNAMIC_LINEAR" value="3" enum="BodyMode"> + Constant for linear dynamic bodies. In this mode, a body is dynamic but can not rotate, and only its linear velocity is affected by external forces. </constant> <constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter"> Constant to set/get a body's bounce factor. diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index 9f48c36b62..1d1ca54dbb 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -1278,8 +1278,8 @@ <constant name="BODY_MODE_DYNAMIC" value="2" enum="BodyMode"> Constant for dynamic bodies. In this mode, a body can be pushed by other bodies and has forces applied. </constant> - <constant name="BODY_MODE_DYNAMIC_LOCKED" value="3" enum="BodyMode"> - Constant for locked dynamic bodies. In this mode, a body is dynamic but can not rotate, and only its linear velocity is affected by external forces. + <constant name="BODY_MODE_DYNAMIC_LINEAR" value="3" enum="BodyMode"> + Constant for linear dynamic bodies. In this mode, a body is dynamic but can not rotate, and only its linear velocity is affected by external forces. </constant> <constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter"> Constant to set/get a body's bounce factor. @@ -1361,8 +1361,6 @@ <constant name="SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS" value="7" enum="SpaceParameter"> Constant to set/get the default solver bias for all physics constraints. A solver bias is a factor controlling how much two objects "rebound", after violating a constraint, to avoid leaving them in that state because of numerical imprecision. </constant> - <constant name="SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH" value="8" enum="SpaceParameter"> - </constant> <constant name="BODY_AXIS_LINEAR_X" value="1" enum="BodyAxis"> </constant> <constant name="BODY_AXIS_LINEAR_Y" value="2" enum="BodyAxis"> diff --git a/doc/classes/RigidDynamicBody2D.xml b/doc/classes/RigidDynamicBody2D.xml index 059379242b..9baed392eb 100644 --- a/doc/classes/RigidDynamicBody2D.xml +++ b/doc/classes/RigidDynamicBody2D.xml @@ -5,11 +5,10 @@ </brief_description> <description> This node implements simulated 2D physics. You do not control a RigidDynamicBody2D directly. Instead, you apply forces to it (gravity, impulses, etc.) and the physics simulation calculates the resulting movement based on its mass, friction, and other physical properties. - A RigidDynamicBody2D has 4 behavior [member mode]s: Dynamic, Static, DynamicLocked, and Kinematic. + You can switch the body's behavior using [member lock_rotation], [member freeze], and [member freeze_mode]. [b]Note:[/b] You should not change a RigidDynamicBody2D's [code]position[/code] or [code]linear_velocity[/code] every frame or even very often. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state. Please also keep in mind that physics bodies manage their own transform which overwrites the ones you set. So any direct or indirect transformation (including scaling of the node or its parent) will be visible in the editor only, and immediately reset at runtime. If you need to override the default physics behavior or add a transformation at runtime, you can write a custom force integration. See [member custom_integrator]. - The center of mass is always located at the node's origin without taking into account the [CollisionShape2D] centroid offsets. </description> <tutorials> <link title="2D Physics Platformer Demo">https://godotengine.org/asset-library/asset/119</link> @@ -120,6 +119,15 @@ <member name="custom_integrator" type="bool" setter="set_use_custom_integrator" getter="is_using_custom_integrator" default="false"> If [code]true[/code], internal force integration is disabled for this body. Aside from collision response, the body will only move as determined by the [method _integrate_forces] function. </member> + <member name="freeze" type="bool" setter="set_freeze_enabled" getter="is_freeze_enabled" default="false"> + If [code]true[/code], the body is frozen. Gravity and forces are not applied anymore. + See [member freeze_mode] to set the body's behavior when frozen. + For a body that is always frozen, use [StaticBody2D] or [AnimatableBody2D] instead. + </member> + <member name="freeze_mode" type="int" setter="set_freeze_mode" getter="get_freeze_mode" enum="RigidDynamicBody2D.FreezeMode" default="0"> + The body's freeze mode. Can be used to set the body's behavior when [member freeze] is enabled. See [enum FreezeMode] for possible values. + For a body that is always frozen, use [StaticBody2D] or [AnimatableBody2D] instead. + </member> <member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0"> Multiplies the gravity applied to the body. The body's gravity is calculated from the [b]Default Gravity[/b] value in [b]Project > Project Settings > Physics > 2d[/b] and/or any additional gravity vector applied by [Area2D]s. </member> @@ -134,13 +142,12 @@ <member name="linear_velocity" type="Vector2" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector2(0, 0)"> The body's linear velocity. </member> + <member name="lock_rotation" type="bool" setter="set_lock_rotation_enabled" getter="is_lock_rotation_enabled" default="false"> + If [code]true[/code], the body cannot rotate. Gravity and forces only apply linear movement. + </member> <member name="mass" type="float" setter="set_mass" getter="get_mass" default="1.0"> The body's mass. </member> - <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="RigidDynamicBody2D.Mode" default="0"> - The body's mode. See [enum Mode] for possible values. - For a body that uses only Static or Kinematic mode, use [StaticBody2D] or [AnimatableBody2D] instead. - </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> The physics material override for the body. If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one. @@ -198,17 +205,11 @@ </signal> </signals> <constants> - <constant name="MODE_DYNAMIC" value="0" enum="Mode"> - Dynamic body mode. This is the default mode of a rigid body. It is affected by forces, and can move, rotate, and be affected by user code. - </constant> - <constant name="MODE_STATIC" value="1" enum="Mode"> - Static body mode. The body behaves like a [StaticBody2D], and must be moved by code. - </constant> - <constant name="MODE_DYNAMIC_LOCKED" value="2" enum="Mode"> - Locked dynamic body mode. Similar to [constant MODE_DYNAMIC], but the body can not rotate. + <constant name="FREEZE_MODE_STATIC" value="0" enum="FreezeMode"> + Static body freeze mode (default). The body is not affected by gravity and forces. It can be only moved by user code and doesn't collide with other bodies along its path. </constant> - <constant name="MODE_KINEMATIC" value="3" enum="Mode"> - Kinematic body mode. The body behaves like a [AnimatableBody2D], and must be moved by code. + <constant name="FREEZE_MODE_KINEMATIC" value="1" enum="FreezeMode"> + Kinematic body freeze mode. Similar to [constant FREEZE_MODE_STATIC], but collides with other bodies along its path when moved. Useful for a frozen body that needs to be animated. </constant> <constant name="CENTER_OF_MASS_MODE_AUTO" value="0" enum="CenterOfMassMode"> In this mode, the body's center of mass is calculated automatically based on its shapes. diff --git a/doc/classes/RigidDynamicBody3D.xml b/doc/classes/RigidDynamicBody3D.xml index 9b6bcd840b..7d1c7fecfa 100644 --- a/doc/classes/RigidDynamicBody3D.xml +++ b/doc/classes/RigidDynamicBody3D.xml @@ -5,10 +5,9 @@ </brief_description> <description> This is the node that implements full 3D physics. This means that you do not control a RigidDynamicBody3D directly. Instead, you can apply forces to it (gravity, impulses, etc.), and the physics simulation will calculate the resulting movement, collision, bouncing, rotating, etc. - A RigidDynamicBody3D has 4 behavior [member mode]s: Dynamic, Static, DynamicLocked, and Kinematic. + You can switch the body's behavior using [member lock_rotation], [member freeze], and [member freeze_mode]. [b]Note:[/b] Don't change a RigidDynamicBody3D's position every frame or very often. Sporadic changes work fine, but physics runs at a different granularity (fixed Hz) than usual rendering (process callback) and maybe even in a separate thread, so changing this from a process loop may result in strange behavior. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state. If you need to override the default physics behavior, you can write a custom force integration function. See [member custom_integrator]. - With Bullet physics (the default), the center of mass is the RigidDynamicBody3D center. With GodotPhysics, the center of mass is the average of the [CollisionShape3D] centers. </description> <tutorials> <link title="Physics introduction">https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link> @@ -123,6 +122,15 @@ <member name="custom_integrator" type="bool" setter="set_use_custom_integrator" getter="is_using_custom_integrator" default="false"> If [code]true[/code], internal force integration will be disabled (like gravity or air friction) for this body. Other than collision response, the body will only move as determined by the [method _integrate_forces] function, if defined. </member> + <member name="freeze" type="bool" setter="set_freeze_enabled" getter="is_freeze_enabled" default="false"> + If [code]true[/code], the body is frozen. Gravity and forces are not applied anymore. + See [member freeze_mode] to set the body's behavior when frozen. + For a body that is always frozen, use [StaticBody3D] or [AnimatableBody3D] instead. + </member> + <member name="freeze_mode" type="int" setter="set_freeze_mode" getter="get_freeze_mode" enum="RigidDynamicBody3D.FreezeMode" default="0"> + The body's freeze mode. Can be used to set the body's behavior when [member freeze] is enabled. See [enum FreezeMode] for possible values. + For a body that is always frozen, use [StaticBody3D] or [AnimatableBody3D] instead. + </member> <member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0"> This is multiplied by the global 3D gravity setting found in [b]Project > Project Settings > Physics > 3d[/b] to produce RigidDynamicBody3D's gravity. For example, a value of 1 will be normal gravity, 2 will apply double gravity, and 0.5 will apply half gravity to this object. </member> @@ -137,13 +145,12 @@ <member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3(0, 0, 0)"> The body's linear velocity. Can be used sporadically, but [b]don't set this every frame[/b], because physics may run in another thread and runs at a different granularity. Use [method _integrate_forces] as your process loop for precise control of the body state. </member> + <member name="lock_rotation" type="bool" setter="set_lock_rotation_enabled" getter="is_lock_rotation_enabled" default="false"> + If [code]true[/code], the body cannot rotate. Gravity and forces only apply linear movement. + </member> <member name="mass" type="float" setter="set_mass" getter="get_mass" default="1.0"> The body's mass. </member> - <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="RigidDynamicBody3D.Mode" default="0"> - The body's mode. See [enum Mode] for possible values. - For a body that uses only Static or Kinematic mode, use [StaticBody3D] or [AnimatableBody3D] instead. - </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> The physics material override for the body. If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one. @@ -203,17 +210,11 @@ </signal> </signals> <constants> - <constant name="MODE_DYNAMIC" value="0" enum="Mode"> - Dynamic body mode. This is the default mode of a rigid body. It is affected by forces, and can move, rotate, and be affected by user code. - </constant> - <constant name="MODE_STATIC" value="1" enum="Mode"> - Static body mode. The body behaves like a [StaticBody3D], and can only move by user code. - </constant> - <constant name="MODE_DYNAMIC_LOCKED" value="2" enum="Mode"> - Locked dynamic body mode. Similar to [constant MODE_DYNAMIC], but the body can not rotate. + <constant name="FREEZE_MODE_STATIC" value="0" enum="FreezeMode"> + Static body freeze mode (default). The body is not affected by gravity and forces. It can be only moved by user code and doesn't collide with other bodies along its path. </constant> - <constant name="MODE_KINEMATIC" value="3" enum="Mode"> - Kinematic body mode. The body behaves like a [AnimatableBody3D], and can only move by user code. + <constant name="FREEZE_MODE_KINEMATIC" value="1" enum="FreezeMode"> + Kinematic body freeze mode. Similar to [constant FREEZE_MODE_STATIC], but collides with other bodies along its path when moved. Useful for a frozen body that needs to be animated. </constant> <constant name="CENTER_OF_MASS_MODE_AUTO" value="0" enum="CenterOfMassMode"> In this mode, the body's center of mass is calculated automatically based on its shapes. diff --git a/doc/classes/StreamPeerExtension.xml b/doc/classes/StreamPeerExtension.xml new file mode 100644 index 0000000000..93fda8cf5d --- /dev/null +++ b/doc/classes/StreamPeerExtension.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="StreamPeerExtension" inherits="StreamPeer" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="_get_available_bytes" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_data" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="r_buffer" type="uint8_t*" /> + <argument index="1" name="r_bytes" type="int" /> + <argument index="2" name="r_received" type="int32_t*" /> + <description> + </description> + </method> + <method name="_get_partial_data" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="r_buffer" type="uint8_t*" /> + <argument index="1" name="r_bytes" type="int" /> + <argument index="2" name="r_received" type="int32_t*" /> + <description> + </description> + </method> + <method name="_put_data" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_data" type="const void*" /> + <argument index="1" name="p_bytes" type="int" /> + <argument index="2" name="r_sent" type="int32_t*" /> + <description> + </description> + </method> + <method name="_put_partial_data" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_data" type="const void*" /> + <argument index="1" name="p_bytes" type="int" /> + <argument index="2" name="r_sent" type="int32_t*" /> + <description> + </description> + </method> + </methods> +</class> diff --git a/doc/classes/Thread.xml b/doc/classes/Thread.xml index 9c9119c664..ae5c0761b1 100644 --- a/doc/classes/Thread.xml +++ b/doc/classes/Thread.xml @@ -27,12 +27,11 @@ </method> <method name="start"> <return type="int" enum="Error" /> - <argument index="0" name="instance" type="Object" /> - <argument index="1" name="method" type="StringName" /> - <argument index="2" name="userdata" type="Variant" default="null" /> - <argument index="3" name="priority" type="int" enum="Thread.Priority" default="1" /> + <argument index="0" name="callable" type="Callable" /> + <argument index="1" name="userdata" type="Variant" default="null" /> + <argument index="2" name="priority" type="int" enum="Thread.Priority" default="1" /> <description> - Starts a new [Thread] that runs [code]method[/code] on object [code]instance[/code] with [code]userdata[/code] passed as an argument. Even if no userdata is passed, [code]method[/code] must accept one argument and it will be null. The [code]priority[/code] of the [Thread] can be changed by passing a value from the [enum Priority] enum. + Starts a new [Thread] that calls [code]callable[/code] with [code]userdata[/code] passed as an argument. Even if no userdata is passed, [code]method[/code] must accept one argument and it will be null. The [code]priority[/code] of the [Thread] can be changed by passing a value from the [enum Priority] enum. Returns [constant OK] on success, or [constant ERR_CANT_CREATE] on failure. </description> </method> diff --git a/doc/classes/Translation.xml b/doc/classes/Translation.xml index c27d6f5667..2a0695d42e 100644 --- a/doc/classes/Translation.xml +++ b/doc/classes/Translation.xml @@ -11,6 +11,24 @@ <link title="Locales">https://docs.godotengine.org/en/latest/tutorials/i18n/locales.html</link> </tutorials> <methods> + <method name="_get_message" qualifiers="virtual const"> + <return type="StringName" /> + <argument index="0" name="src_message" type="StringName" /> + <argument index="1" name="context" type="StringName" /> + <description> + Virtual method to override [method get_message]. + </description> + </method> + <method name="_get_plural_message" qualifiers="virtual const"> + <return type="StringName" /> + <argument index="0" name="src_message" type="StringName" /> + <argument index="1" name="src_plural_message" type="StringName" /> + <argument index="2" name="n" type="int" /> + <argument index="3" name="context" type="StringName" /> + <description> + Virtual method to override [method get_plural_message]. + </description> + </method> <method name="add_message"> <return type="void" /> <argument index="0" name="src_message" type="StringName" /> diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index ab857dc3ad..d6650c3319 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -147,7 +147,7 @@ void ScriptEditorDebugger::update_tabs() { } void ScriptEditorDebugger::clear_style() { - tabs->add_theme_style_override("panel", nullptr); + tabs->remove_theme_style_override("panel"); } void ScriptEditorDebugger::save_node(ObjectID p_id, const String &p_file) { diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp index 5df392b91e..f91dedf25d 100644 --- a/editor/editor_dir_dialog.cpp +++ b/editor/editor_dir_dialog.cpp @@ -44,6 +44,7 @@ void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p p_item->set_metadata(0, p_dir->get_path()); p_item->set_icon(0, tree->get_theme_icon(SNAME("Folder"), SNAME("EditorIcons"))); + p_item->set_icon_modulate(0, tree->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"))); if (!p_item->get_parent()) { p_item->set_text(0, "res://"); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index e719797e03..9a79e1f942 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1757,13 +1757,15 @@ void EditorNode::restart_editor() { void EditorNode::_save_all_scenes() { for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { Node *scene = editor_data.get_edited_scene_root(i); - if (scene && scene->get_filename() != "") { + if (scene && scene->get_filename() != "" && DirAccess::exists(scene->get_filename().get_base_dir())) { if (i != editor_data.get_edited_scene()) { _save_scene(scene->get_filename(), i); } else { _save_scene_with_preview(scene->get_filename()); } - } // else: ignore new scenes + } else { + show_warning(TTR("Could not save one or more scenes!"), TTR("Save All Scenes")); + } } _save_default_environment(); @@ -2484,20 +2486,22 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { case SCENE_TAB_CLOSE: case FILE_SAVE_SCENE: { int scene_idx = (p_option == FILE_SAVE_SCENE) ? -1 : tab_closing; - Node *scene = editor_data.get_edited_scene_root(scene_idx); if (scene && scene->get_filename() != "") { - if (scene_idx != editor_data.get_edited_scene()) { - _save_scene_with_preview(scene->get_filename(), scene_idx); - } else { - _save_scene_with_preview(scene->get_filename()); - } + if (DirAccess::exists(scene->get_filename().get_base_dir())) { + if (scene_idx != editor_data.get_edited_scene()) { + _save_scene_with_preview(scene->get_filename(), scene_idx); + } else { + _save_scene_with_preview(scene->get_filename()); + } - if (scene_idx != -1) { - _discard_changes(); + if (scene_idx != -1) { + _discard_changes(); + } + save_layout(); + } else { + show_save_accept(vformat(TTR("%s no longer exists! Please specify a new save location."), scene->get_filename().get_base_dir()), TTR("OK")); } - save_layout(); - break; } [[fallthrough]]; @@ -4150,6 +4154,13 @@ void EditorNode::show_accept(const String &p_text, const String &p_title) { accept->popup_centered(); } +void EditorNode::show_save_accept(const String &p_text, const String &p_title) { + current_option = -1; + save_accept->get_ok_button()->set_text(p_title); + save_accept->set_text(p_text); + save_accept->popup_centered(); +} + void EditorNode::show_warning(const String &p_text, const String &p_title) { if (warning->is_inside_tree()) { warning->set_text(p_text); @@ -6263,6 +6274,10 @@ EditorNode::EditorNode() { gui_base->add_child(accept); accept->connect("confirmed", callable_mp(this, &EditorNode::_menu_confirm_current)); + save_accept = memnew(AcceptDialog); + gui_base->add_child(save_accept); + save_accept->connect("confirmed", callable_mp(this, &EditorNode::_menu_option), make_binds((int)MenuOptions::FILE_SAVE_AS_SCENE)); + project_export = memnew(ProjectExportDialog); gui_base->add_child(project_export); diff --git a/editor/editor_node.h b/editor/editor_node.h index 2e8b850c7b..d1f4cf8452 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -308,6 +308,7 @@ private: ConfirmationDialog *pick_main_scene; Button *select_current_scene_button; AcceptDialog *accept; + AcceptDialog *save_accept; EditorAbout *about; AcceptDialog *warning; @@ -814,6 +815,7 @@ public: Ref<Texture2D> get_class_icon(const String &p_class, const String &p_fallback = "Object") const; void show_accept(const String &p_text, const String &p_title); + void show_save_accept(const String &p_text, const String &p_title); void show_warning(const String &p_text, const String &p_title = TTR("Warning!")); void _copy_warning(const String &p_str); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index afeba4f6fb..1890814da9 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -191,6 +191,59 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) { } } +void EditorSpinSlider::_value_input_gui_input(const Ref<InputEvent> &p_event) { + Ref<InputEventKey> k = p_event; + if (k.is_valid() && k->is_pressed()) { + double step = get_step(); + double real_step = step; + if (step < 1) { + double divisor = 1.0 / get_step(); + + if (trunc(divisor) == divisor) { + step = 1.0; + } + } + + if (k->is_ctrl_pressed()) { + step *= 100.0; + } else if (k->is_shift_pressed()) { + step *= 10.0; + } else if (k->is_alt_pressed()) { + step *= 0.1; + } + + uint32_t code = k->get_keycode(); + switch (code) { + case KEY_UP: { + _evaluate_input_text(); + + double last_value = get_value(); + set_value(last_value + step); + double new_value = get_value(); + + if (new_value < CLAMP(last_value + step, get_min(), get_max())) { + set_value(last_value + real_step); + } + + value_input->set_text(get_text_value()); + } break; + case KEY_DOWN: { + _evaluate_input_text(); + + double last_value = get_value(); + set_value(last_value - step); + double new_value = get_value(); + + if (new_value > CLAMP(last_value - step, get_min(), get_max())) { + set_value(last_value - real_step); + } + + value_input->set_text(get_text_value()); + } break; + } + } +} + void EditorSpinSlider::_update_value_input_stylebox() { if (!value_input) { return; @@ -585,11 +638,13 @@ void EditorSpinSlider::_ensure_input_popup() { value_input_popup->connect("popup_hide", callable_mp(this, &EditorSpinSlider::_value_input_closed)); value_input->connect("text_submitted", callable_mp(this, &EditorSpinSlider::_value_input_submitted)); value_input->connect("focus_exited", callable_mp(this, &EditorSpinSlider::_value_focus_exited)); + value_input->connect("gui_input", callable_mp(this, &EditorSpinSlider::_value_input_gui_input)); if (is_inside_tree()) { _update_value_input_stylebox(); } } + EditorSpinSlider::EditorSpinSlider() { flat = false; grabbing_spinner_attempt = false; diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h index 1bf8e8eef9..7e10764491 100644 --- a/editor/editor_spin_slider.h +++ b/editor/editor_spin_slider.h @@ -71,6 +71,7 @@ class EditorSpinSlider : public Range { void _value_input_closed(); void _value_input_submitted(const String &); void _value_focus_exited(); + void _value_input_gui_input(const Ref<InputEvent> &p_event); bool hide_slider; bool flat; diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index b646b3361d..cb88e9d75e 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -743,7 +743,7 @@ void ExportTemplateManager::_notification(int p_what) { current_missing_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor"))); current_installed_label->add_theme_color_override("font_color", get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"))); - mirror_options_button->set_icon(get_theme_icon(SNAME("GuiTabMenu"), SNAME("EditorIcons"))); + mirror_options_button->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); } break; case NOTIFICATION_VISIBILITY_CHANGED: { diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index 49fcac512b..686a35e442 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -129,8 +129,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven add_point_pos += blend_space->get_min_space(); if (snap->is_pressed()) { - add_point_pos.x = Math::snapped(add_point_pos.x, blend_space->get_snap().x); - add_point_pos.y = Math::snapped(add_point_pos.y, blend_space->get_snap().y); + add_point_pos = add_point_pos.snapped(blend_space->get_snap()); } } @@ -215,8 +214,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven Vector2 point = blend_space->get_blend_point_position(selected_point); point += drag_ofs; if (snap->is_pressed()) { - point.x = Math::snapped(point.x, blend_space->get_snap().x); - point.y = Math::snapped(point.y, blend_space->get_snap().y); + point = point.snapped(blend_space->get_snap()); } updating = true; @@ -467,8 +465,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { if (dragging_selected && selected_point == point_idx) { point += drag_ofs; if (snap->is_pressed()) { - point.x = Math::snapped(point.x, blend_space->get_snap().x); - point.y = Math::snapped(point.y, blend_space->get_snap().y); + point = point.snapped(blend_space->get_snap()); } } point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); @@ -503,8 +500,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { if (dragging_selected && selected_point == i) { point += drag_ofs; if (snap->is_pressed()) { - point.x = Math::snapped(point.x, blend_space->get_snap().x); - point.y = Math::snapped(point.y, blend_space->get_snap().y); + point = point.snapped(blend_space->get_snap()); } } point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); @@ -702,8 +698,7 @@ void AnimationNodeBlendSpace2DEditor::_update_edited_point_pos() { if (dragging_selected) { pos += drag_ofs; if (snap->is_pressed()) { - pos.x = Math::snapped(pos.x, blend_space->get_snap().x); - pos.y = Math::snapped(pos.y, blend_space->get_snap().y); + pos = pos.snapped(blend_space->get_snap()); } } updating = true; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index faa3b58dbb..66a1719ff3 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4898,8 +4898,7 @@ void CanvasItemEditor::_focus_selection(int p_op) { if (p_op == VIEW_CENTER_TO_SELECTION) { center = rect.get_center(); Vector2 offset = viewport->get_size() / 2 - editor->get_scene_root()->get_global_canvas_transform().xform(center); - view_offset.x -= Math::round(offset.x / zoom); - view_offset.y -= Math::round(offset.y / zoom); + view_offset -= (offset / zoom).round(); update_viewport(); } else { // VIEW_FRAME_TO_SELECTION diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index d52a633fed..fdd4baaf7d 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -6280,7 +6280,7 @@ void Node3DEditor::update_grid() { // Gets a orthogonal or perspective position correctly (for the grid comparison) const Vector3 camera_position = get_editor_viewport(0)->camera->get_position(); - if (!grid_init_draw || (camera_position - grid_camera_last_update_position).length() >= 10.0f) { + if (!grid_init_draw || grid_camera_last_update_position.distance_squared_to(camera_position) >= 100.0f) { _finish_grid(); _init_grid(); grid_init_draw = true; diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index 13f7908170..bb0c270baa 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -510,7 +510,14 @@ void Path3DEditorPlugin::_close_curve() { if (c->get_point_count() < 2) { return; } - c->add_point(c->get_point_position(0), c->get_point_in(0), c->get_point_out(0)); + if (c->get_point_position(0) == c->get_point_position(c->get_point_count() - 1)) { + return; + } + UndoRedo *ur = editor->get_undo_redo(); + ur->create_action(TTR("Close Curve")); + ur->add_do_method(c.ptr(), "add_point", c->get_point_position(0), c->get_point_in(0), c->get_point_out(0), -1); + ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count()); + ur->commit_action(); } void Path3DEditorPlugin::_handle_option_pressed(int p_option) { diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index cfb2d63bc7..ce90d61616 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -50,7 +50,7 @@ void draw_margin_line(Control *edit_draw, Vector2 from, Vector2 to) { EditorNode::get_singleton()->get_theme_base()->get_theme_color(SNAME("mono_color"), SNAME("Editor")).inverted() * Color(1, 1, 1, 0.5), Math::round(2 * EDSCALE)); - while ((to - from).length_squared() > 200) { + while (from.distance_squared_to(to) > 200) { edit_draw->draw_line( from, from + line, @@ -674,8 +674,7 @@ void TextureRegionEditor::_zoom_on_position(float p_zoom, Point2 p_position) { draw_zoom = p_zoom; Point2 ofs = p_position; ofs = ofs / prev_zoom - ofs / draw_zoom; - draw_ofs.x = Math::round(draw_ofs.x + ofs.x); - draw_ofs.y = Math::round(draw_ofs.y + ofs.y); + draw_ofs = (draw_ofs + ofs).round(); edit_draw->update(); } diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp index 801ee0eac2..d26d0ec39d 100644 --- a/editor/plugins/theme_editor_preview.cpp +++ b/editor/plugins/theme_editor_preview.cpp @@ -126,8 +126,8 @@ void ThemeEditorPreview::_draw_picker_overlay() { highlight_label_rect.size.x += margin_left + margin_right; highlight_label_rect.size.y += margin_top + margin_bottom; - highlight_label_rect.position.x = CLAMP(highlight_label_rect.position.x, 0.0, picker_overlay->get_size().width); - highlight_label_rect.position.y = CLAMP(highlight_label_rect.position.y, 0.0, picker_overlay->get_size().height); + highlight_label_rect.position = highlight_label_rect.position.clamp(Vector2(), picker_overlay->get_size()); + picker_overlay->draw_style_box(theme_cache.preview_picker_label, highlight_label_rect); Point2 label_pos = highlight_label_rect.position; diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index ea7ca787c8..216c5f7c7d 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -622,7 +622,7 @@ void GenericTilePolygonEditor::_notification(int p_what) { button_delete->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveDelete"), SNAME("EditorIcons"))); button_center_view->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CenterView"), SNAME("EditorIcons"))); button_pixel_snap->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Snap"), SNAME("EditorIcons"))); - button_advanced_menu->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("GuiTabMenu"), SNAME("EditorIcons"))); + button_advanced_menu->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); break; } } diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 8b5b576369..a248f23517 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -1041,7 +1041,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i TypedArray<Vector2i> to_check; if (source.source_id == TileSet::INVALID_SOURCE) { Rect2i rect = tile_map->get_used_rect(); - if (rect.size.x <= 0 || rect.size.y <= 0) { + if (rect.has_no_area()) { rect = Rect2i(p_coords, Vector2i(1, 1)); } for (int x = boundaries.position.x; x < boundaries.get_end().x; x++) { diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 76a05449db..1f1408016b 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -87,7 +87,7 @@ void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get_property_list p_list->push_back(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D")); p_list->push_back(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "")); p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, "")); - p_list->push_back(PropertyInfo(Variant::VECTOR2I, "tile_size", PROPERTY_HINT_NONE, "")); + p_list->push_back(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, "")); } void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_bind_methods() { @@ -1946,6 +1946,11 @@ void TileSetAtlasSourceEditor::_tile_set_atlas_source_changed() { tile_set_atlas_source_changed_needs_update = true; } +void TileSetAtlasSourceEditor::_tile_proxy_object_changed(String p_what) { + tile_set_atlas_source_changed_needs_update = false; // Avoid updating too many things. + _update_atlas_view(); +} + void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(String p_what) { if (p_what == "texture" && !atlas_source_proxy_object->get("texture").is_null()) { confirm_auto_create_tiles->popup_centered(); @@ -2206,7 +2211,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { middle_vbox_container->add_child(tile_inspector_label); tile_proxy_object = memnew(AtlasTileProxyObject(this)); - tile_proxy_object->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view).unbind(1)); + tile_proxy_object->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_proxy_object_changed)); tile_inspector = memnew(EditorInspector); tile_inspector->set_undo_redo(undo_redo); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h index 501416c340..6448b55feb 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.h +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h @@ -264,6 +264,7 @@ private: AcceptDialog *confirm_auto_create_tiles; void _tile_set_atlas_source_changed(); + void _tile_proxy_object_changed(String p_what); void _atlas_source_proxy_object_changed(String p_what); void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 4bc0905163..5ce88949ef 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -848,7 +848,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { break; } Ref<MultiNodeEdit> mne = memnew(MultiNodeEdit); - for (const Map<Node *, Object *>::Element *E = EditorNode::get_singleton()->get_editor_selection()->get_selection().front(); E; E = E->next()) { + for (const Map<Node *, Object *>::Element *E = editor_selection->get_selection().front(); E; E = E->next()) { mne->add_node(root->get_path_to(E->key())); } @@ -2101,11 +2101,11 @@ void SceneTreeDock::_update_script_button() { if (!profile_allow_script_editing) { button_create_script->hide(); button_detach_script->hide(); - } else if (EditorNode::get_singleton()->get_editor_selection()->get_selection().size() == 0) { + } else if (editor_selection->get_selection().size() == 0) { button_create_script->hide(); button_detach_script->hide(); - } else if (EditorNode::get_singleton()->get_editor_selection()->get_selection().size() == 1) { - Node *n = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list()[0]; + } else if (editor_selection->get_selection().size() == 1) { + Node *n = editor_selection->get_selected_node_list()[0]; if (n->get_script().is_null()) { button_create_script->show(); button_detach_script->hide(); @@ -2128,10 +2128,12 @@ void SceneTreeDock::_update_script_button() { } void SceneTreeDock::_selection_changed() { - int selection_size = EditorNode::get_singleton()->get_editor_selection()->get_selection().size(); + int selection_size = editor_selection->get_selection().size(); if (selection_size > 1) { //automatically turn on multi-edit _tool_selected(TOOL_MULTI_EDIT); + } else if (selection_size == 1) { + editor->push_item(editor_selection->get_selection().front()->key()); } else if (selection_size == 0) { editor->push_item(nullptr); } diff --git a/main/main.cpp b/main/main.cpp index fc24010e7b..d512c41e7a 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2689,8 +2689,9 @@ void Main::cleanup(bool p_force) { rendering_server->global_variables_clear(); if (xr_server) { - // cleanup now before we pull the rug from underneath... - memdelete(xr_server); + // Now that we're unregistering properly in plugins we need to keep access to xr_server for a little longer + // We do however unset our primary interface + xr_server->set_primary_interface(Ref<XRInterface>()); } unregister_driver_types(); @@ -2706,6 +2707,10 @@ void Main::cleanup(bool p_force) { unregister_scene_types(); unregister_server_types(); + if (xr_server) { + memdelete(xr_server); + } + if (audio_server) { audio_server->finish(); memdelete(audio_server); diff --git a/methods.py b/methods.py index 50b413a0e6..0e71adb40d 100644 --- a/methods.py +++ b/methods.py @@ -56,6 +56,17 @@ def disable_warnings(self): self.Append(CXXFLAGS=["-w"]) +def force_optimization_on_debug(self): + # 'self' is the environment + if self["target"] != "debug": + return + + if self.msvc: + self.Append(CCFLAGS=["/O2"]) + else: + self.Append(CCFLAGS=["-O3"]) + + def add_module_version_string(self, s): self.module_version_string += "." + s diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 0d2cd1f5a0..7b20fad28c 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -303,6 +303,7 @@ RigidBodyBullet::~RigidBodyBullet() { void RigidBodyBullet::init_kinematic_utilities() { kinematic_utilities = memnew(KinematicUtilities(this)); + reload_kinematic_shapes(); } void RigidBodyBullet::destroy_kinematic_utilities() { @@ -529,26 +530,23 @@ void RigidBodyBullet::set_mode(PhysicsServer3D::BodyMode p_mode) { can_integrate_forces = false; destroy_kinematic_utilities(); // The mode change is relevant to its mass + mode = p_mode; switch (p_mode) { case PhysicsServer3D::BODY_MODE_KINEMATIC: - mode = PhysicsServer3D::BODY_MODE_KINEMATIC; reload_axis_lock(); _internal_set_mass(0); init_kinematic_utilities(); break; case PhysicsServer3D::BODY_MODE_STATIC: - mode = PhysicsServer3D::BODY_MODE_STATIC; reload_axis_lock(); _internal_set_mass(0); break; case PhysicsServer3D::BODY_MODE_DYNAMIC: - mode = PhysicsServer3D::BODY_MODE_DYNAMIC; reload_axis_lock(); _internal_set_mass(0 == mass ? 1 : mass); scratch_space_override_modificator(); break; - case PhysicsServer3D::MODE_DYNAMIC_LOCKED: - mode = PhysicsServer3D::MODE_DYNAMIC_LOCKED; + case PhysicsServer3D::MODE_DYNAMIC_LINEAR: reload_axis_lock(); _internal_set_mass(0 == mass ? 1 : mass); scratch_space_override_modificator(); @@ -721,7 +719,7 @@ bool RigidBodyBullet::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const { void RigidBodyBullet::reload_axis_lock() { btBody->setLinearFactor(btVector3(btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z)))); - if (PhysicsServer3D::MODE_DYNAMIC_LOCKED == mode) { + if (PhysicsServer3D::MODE_DYNAMIC_LINEAR == mode) { /// When character angular is always locked btBody->setAngularFactor(btVector3(0., 0., 0.)); } else { @@ -1016,7 +1014,7 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) { // Rigidbody is dynamic if and only if mass is non Zero, otherwise static const bool isDynamic = p_mass != 0.f; if (isDynamic) { - if (PhysicsServer3D::BODY_MODE_DYNAMIC != mode && PhysicsServer3D::MODE_DYNAMIC_LOCKED != mode) { + if (PhysicsServer3D::BODY_MODE_DYNAMIC != mode && PhysicsServer3D::MODE_DYNAMIC_LINEAR != mode) { return; } diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index a9a811c445..0cfd658bd5 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -947,7 +947,6 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p if (!p_body->get_kinematic_utilities()) { p_body->init_kinematic_utilities(); - p_body->reload_kinematic_shapes(); } btVector3 initial_recover_motion(0, 0, 0); @@ -1089,7 +1088,6 @@ int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform3D if (!p_body->get_kinematic_utilities()) { p_body->init_kinematic_utilities(); - p_body->reload_kinematic_shapes(); } btVector3 recover_motion(0, 0, 0); diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index cbe41a1310..229e1e2724 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -37,16 +37,16 @@ // Static helper functions. inline static bool is_snapable(const Vector3 &p_point1, const Vector3 &p_point2, real_t p_distance) { - return (p_point1 - p_point2).length_squared() < p_distance * p_distance; + return p_point2.distance_squared_to(p_point1) < p_distance * p_distance; } -inline static Vector2 interpolate_segment_uv(const Vector2 p_segement_points[2], const Vector2 p_uvs[2], const Vector2 &p_interpolation_point) { - float segment_length = (p_segement_points[1] - p_segement_points[0]).length(); - if (p_segement_points[0].is_equal_approx(p_segement_points[1])) { +inline static Vector2 interpolate_segment_uv(const Vector2 p_segment_points[2], const Vector2 p_uvs[2], const Vector2 &p_interpolation_point) { + if (p_segment_points[0].is_equal_approx(p_segment_points[1])) { return p_uvs[0]; } - float distance = (p_interpolation_point - p_segement_points[0]).length(); + float segment_length = p_segment_points[0].distance_to(p_segment_points[1]); + float distance = p_segment_points[0].distance_to(p_interpolation_point); float fraction = distance / segment_length; return p_uvs[0].lerp(p_uvs[1], fraction); @@ -162,7 +162,7 @@ inline static bool is_triangle_degenerate(const Vector2 p_vertices[3], real_t p_ return det < p_vertex_snap2; } -inline static bool are_segements_parallel(const Vector2 p_segment1_points[2], const Vector2 p_segment2_points[2], float p_vertex_snap2) { +inline static bool are_segments_parallel(const Vector2 p_segment1_points[2], const Vector2 p_segment2_points[2], float p_vertex_snap2) { Vector2 segment1 = p_segment1_points[1] - p_segment1_points[0]; Vector2 segment2 = p_segment2_points[1] - p_segment2_points[0]; real_t segment1_length2 = segment1.dot(segment1); @@ -596,7 +596,7 @@ bool CSGBrushOperation::MeshMerge::_bvh_inside(FaceBVH *facebvhptr, int p_max_de _add_distance(intersectionsA, intersectionsB, current_face.from_b, 0); } } else if (ray_intersects_triangle(face_center, face_normal, current_points, CMP_EPSILON, intersection_point)) { - real_t distance = (intersection_point - face_center).length(); + real_t distance = face_center.distance_to(intersection_point); _add_distance(intersectionsA, intersectionsB, current_face.from_b, distance); } } @@ -781,7 +781,7 @@ void CSGBrushOperation::MeshMerge::add_face(const Vector3 p_points[], const Vect int CSGBrushOperation::Build2DFaces::_get_point_idx(const Vector2 &p_point) { for (int vertex_idx = 0; vertex_idx < vertices.size(); ++vertex_idx) { - if ((p_point - vertices[vertex_idx].point).length_squared() < vertex_snap2) { + if (vertices[vertex_idx].point.distance_squared_to(p_point) < vertex_snap2) { return vertex_idx; } } @@ -911,7 +911,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_ vertices[outer_edge_idx[1]].point, vertices[p_segment_indices[closest_idx]].point }; - if (are_segements_parallel(edge1, edge2, vertex_snap2)) { + if (are_segments_parallel(edge1, edge2, vertex_snap2)) { if (!degenerate_points.find(outer_edge_idx[0])) { degenerate_points.push_back(outer_edge_idx[0]); } @@ -961,7 +961,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_ // Check if point is existing face vertex. bool existing = false; for (int i = 0; i < 3; ++i) { - if ((point_2D - face_vertices[i].point).length_squared() < vertex_snap2) { + if (face_vertices[i].point.distance_squared_to(point_2D) < vertex_snap2) { existing = true; break; } @@ -978,7 +978,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_ }; Vector2 closest_point = Geometry2D::get_closest_point_to_segment(point_2D, edge_points); - if ((closest_point - point_2D).length_squared() < vertex_snap2) { + if (point_2D.distance_squared_to(closest_point) < vertex_snap2) { int opposite_vertex_idx = face.vertex_idx[(face_edge_idx + 2) % 3]; // If new vertex snaps to degenerate vertex, just delete this face. @@ -1041,7 +1041,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s bool on_edge = false; for (int edge_point_idx = 0; edge_point_idx < 2; ++edge_point_idx) { intersection_point = Geometry2D::get_closest_point_to_segment(p_segment_points[edge_point_idx], edge_points); - if ((intersection_point - p_segment_points[edge_point_idx]).length_squared() < vertex_snap2) { + if (p_segment_points[edge_point_idx].distance_squared_to(intersection_point) < vertex_snap2) { on_edge = true; break; } @@ -1050,13 +1050,13 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s // Else check if the segment intersects the edge. if (on_edge || Geometry2D::segment_intersects_segment(p_segment_points[0], p_segment_points[1], edge_points[0], edge_points[1], &intersection_point)) { // Check if intersection point is an edge point. - if ((intersection_point - edge_points[0]).length_squared() < vertex_snap2 || - (intersection_point - edge_points[1]).length_squared() < vertex_snap2) { + if ((edge_points[0].distance_squared_to(intersection_point) < vertex_snap2) || + (edge_points[1].distance_squared_to(intersection_point) < vertex_snap2)) { continue; } // Check if edge exists, by checking if the intersecting segment is parallel to the edge. - if (are_segements_parallel(p_segment_points, edge_points, vertex_snap2)) { + if (are_segments_parallel(p_segment_points, edge_points, vertex_snap2)) { continue; } @@ -1078,7 +1078,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s // If opposite point is on the segment, add its index to segment indices too. Vector2 closest_point = Geometry2D::get_closest_point_to_segment(vertices[opposite_vertex_idx].point, p_segment_points); - if ((closest_point - vertices[opposite_vertex_idx].point).length_squared() < vertex_snap2) { + if (vertices[opposite_vertex_idx].point.distance_squared_to(closest_point) < vertex_snap2) { _add_vertex_idx_sorted(r_segment_indices, opposite_vertex_idx); } @@ -1132,7 +1132,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) { // Check if point is existing face vertex. for (int i = 0; i < 3; ++i) { - if ((p_point - face_vertices[i].point).length_squared() < vertex_snap2) { + if (face_vertices[i].point.distance_squared_to(p_point) < vertex_snap2) { return face.vertex_idx[i]; } } @@ -1150,7 +1150,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) { }; Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, edge_points); - if ((closest_point - p_point).length_squared() < vertex_snap2) { + if (p_point.distance_squared_to(closest_point) < vertex_snap2) { on_edge = true; // Add the point as a new vertex. @@ -1172,8 +1172,8 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) { Vector2 split_edge1[2] = { vertices[new_vertex_idx].point, edge_points[0] }; Vector2 split_edge2[2] = { vertices[new_vertex_idx].point, edge_points[1] }; Vector2 new_edge[2] = { vertices[new_vertex_idx].point, vertices[opposite_vertex_idx].point }; - if (are_segements_parallel(split_edge1, new_edge, vertex_snap2) && - are_segements_parallel(split_edge2, new_edge, vertex_snap2)) { + if (are_segments_parallel(split_edge1, new_edge, vertex_snap2) && + are_segments_parallel(split_edge2, new_edge, vertex_snap2)) { break; } diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 452fb32d9d..e4297a593e 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -1732,6 +1732,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { int extrusion_face_count = shape_sides * 2; int end_count = 0; int shape_face_count = shape_faces.size() / 3; + real_t curve_length = 1.0; switch (mode) { case MODE_DEPTH: extrusions = 1; @@ -1744,7 +1745,12 @@ CSGBrush *CSGPolygon3D::_build_brush() { } break; case MODE_PATH: { - extrusions = Math::ceil(1.0 * curve->get_point_count() / path_interval); + curve_length = curve->get_baked_length(); + if (path_interval_type == PATH_INTERVAL_DISTANCE) { + extrusions = MAX(1, Math::ceil(curve_length / path_interval)) + 1; + } else { + extrusions = Math::ceil(1.0 * curve->get_point_count() / path_interval); + } if (!path_joined) { end_count = 2; extrusions -= 1; @@ -1767,212 +1773,245 @@ CSGBrush *CSGPolygon3D::_build_brush() { smooth.resize(face_count); materials.resize(face_count); invert.resize(face_count); + int faces_removed = 0; - Vector3 *facesw = faces.ptrw(); - Vector2 *uvsw = uvs.ptrw(); - bool *smoothw = smooth.ptrw(); - Ref<Material> *materialsw = materials.ptrw(); - bool *invertw = invert.ptrw(); - - int face = 0; - Transform3D base_xform; - Transform3D current_xform; - Transform3D previous_xform; - double u_step = 1.0 / extrusions; - double v_step = 1.0 / shape_sides; - double spin_step = Math::deg2rad(spin_degrees / spin_sides); - double extrusion_step = 1.0 / extrusions; - if (mode == MODE_PATH) { - if (path_joined) { - extrusion_step = 1.0 / (extrusions - 1); - } - extrusion_step *= curve->get_baked_length(); - } + { + Vector3 *facesw = faces.ptrw(); + Vector2 *uvsw = uvs.ptrw(); + bool *smoothw = smooth.ptrw(); + Ref<Material> *materialsw = materials.ptrw(); + bool *invertw = invert.ptrw(); - if (mode == MODE_PATH) { - if (!path_local) { - base_xform = path->get_global_transform(); + int face = 0; + Transform3D base_xform; + Transform3D current_xform; + Transform3D previous_xform; + Transform3D previous_previous_xform; + double u_step = 1.0 / extrusions; + if (path_u_distance > 0.0) { + u_step *= curve_length / path_u_distance; + } + double v_step = 1.0 / shape_sides; + double spin_step = Math::deg2rad(spin_degrees / spin_sides); + double extrusion_step = 1.0 / extrusions; + if (mode == MODE_PATH) { + if (path_joined) { + extrusion_step = 1.0 / (extrusions - 1); + } + extrusion_step *= curve_length; } - Vector3 current_point = curve->interpolate_baked(0); - Vector3 next_point = curve->interpolate_baked(extrusion_step); - Vector3 current_up = Vector3(0, 1, 0); - Vector3 direction = next_point - current_point; + if (mode == MODE_PATH) { + if (!path_local) { + base_xform = path->get_global_transform(); + } - if (path_joined) { - Vector3 last_point = curve->interpolate_baked(curve->get_baked_length()); - direction = next_point - last_point; - } + Vector3 current_point = curve->interpolate_baked(0); + Vector3 next_point = curve->interpolate_baked(extrusion_step); + Vector3 current_up = Vector3(0, 1, 0); + Vector3 direction = next_point - current_point; - switch (path_rotation) { - case PATH_ROTATION_POLYGON: - direction = Vector3(0, 0, -1); - break; - case PATH_ROTATION_PATH: - break; - case PATH_ROTATION_PATH_FOLLOW: - current_up = curve->interpolate_baked_up_vector(0); - break; + if (path_joined) { + Vector3 last_point = curve->interpolate_baked(curve->get_baked_length()); + direction = next_point - last_point; + } + + switch (path_rotation) { + case PATH_ROTATION_POLYGON: + direction = Vector3(0, 0, -1); + break; + case PATH_ROTATION_PATH: + break; + case PATH_ROTATION_PATH_FOLLOW: + current_up = curve->interpolate_baked_up_vector(0); + break; + } + + Transform3D facing = Transform3D().looking_at(direction, current_up); + current_xform = base_xform.translated(current_point) * facing; } - Transform3D facing = Transform3D().looking_at(direction, current_up); - current_xform = base_xform.translated(current_point) * facing; - } + // Create the mesh. + if (end_count > 0) { + // Add front end face. + for (int face_idx = 0; face_idx < shape_face_count; face_idx++) { + for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) { + // We need to reverse the rotation of the shape face vertices. + int index = shape_faces[face_idx * 3 + 2 - face_vertex_idx]; + Point2 p = shape_polygon[index]; + Point2 uv = (p - shape_rect.position) / shape_rect.size; + + // Use the left side of the bottom half of the y-inverted texture. + uv.x = uv.x / 2; + uv.y = 1 - (uv.y / 2); + + facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0)); + uvsw[face * 3 + face_vertex_idx] = uv; + } - // Create the mesh. - if (end_count > 0) { - // Add front end face. - for (int face_idx = 0; face_idx < shape_face_count; face_idx++) { - for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) { - // We need to reverse the rotation of the shape face vertices. - int index = shape_faces[face_idx * 3 + 2 - face_vertex_idx]; - Point2 p = shape_polygon[index]; - Point2 uv = (p - shape_rect.position) / shape_rect.size; - - // Use the left side of the bottom half of the y-inverted texture. - uv.x = uv.x / 2; - uv.y = 1 - (uv.y / 2); - - facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0)); - uvsw[face * 3 + face_vertex_idx] = uv; + smoothw[face] = false; + materialsw[face] = material; + invertw[face] = invert_faces; + face++; } - - smoothw[face] = false; - materialsw[face] = material; - invertw[face] = invert_faces; - face++; } - } - // Add extrusion faces. - for (int x0 = 0; x0 < extrusions; x0++) { - previous_xform = current_xform; - - switch (mode) { - case MODE_DEPTH: { - current_xform.translate(Vector3(0, 0, -depth)); - } break; - case MODE_SPIN: { - current_xform.rotate(Vector3(0, 1, 0), spin_step); - } break; - case MODE_PATH: { - double previous_offset = x0 * extrusion_step; - double current_offset = (x0 + 1) * extrusion_step; - double next_offset = (x0 + 2) * extrusion_step; - if (x0 == extrusions - 1) { - if (path_joined) { - current_offset = 0; - next_offset = extrusion_step; + real_t angle_simplify_dot = Math::cos(Math::deg2rad(path_simplify_angle)); + Vector3 previous_simplify_dir = Vector3(0, 0, 0); + int faces_combined = 0; + + // Add extrusion faces. + for (int x0 = 0; x0 < extrusions; x0++) { + previous_previous_xform = previous_xform; + previous_xform = current_xform; + + switch (mode) { + case MODE_DEPTH: { + current_xform.translate(Vector3(0, 0, -depth)); + } break; + case MODE_SPIN: { + current_xform.rotate(Vector3(0, 1, 0), spin_step); + } break; + case MODE_PATH: { + double previous_offset = x0 * extrusion_step; + double current_offset = (x0 + 1) * extrusion_step; + double next_offset = (x0 + 2) * extrusion_step; + if (x0 == extrusions - 1) { + if (path_joined) { + current_offset = 0; + next_offset = extrusion_step; + } else { + next_offset = current_offset; + } + } + + Vector3 previous_point = curve->interpolate_baked(previous_offset); + Vector3 current_point = curve->interpolate_baked(current_offset); + Vector3 next_point = curve->interpolate_baked(next_offset); + Vector3 current_up = Vector3(0, 1, 0); + Vector3 direction = next_point - previous_point; + Vector3 current_dir = (current_point - previous_point).normalized(); + + // If the angles are similar, remove the previous face and replace it with this one. + if (path_simplify_angle > 0.0 && x0 > 0 && previous_simplify_dir.dot(current_dir) > angle_simplify_dot) { + faces_combined += 1; + previous_xform = previous_previous_xform; + face -= extrusion_face_count; + faces_removed += extrusion_face_count; } else { - next_offset = current_offset; + faces_combined = 0; + previous_simplify_dir = current_dir; } - } - Vector3 previous_point = curve->interpolate_baked(previous_offset); - Vector3 current_point = curve->interpolate_baked(current_offset); - Vector3 next_point = curve->interpolate_baked(next_offset); - Vector3 current_up = Vector3(0, 1, 0); - Vector3 direction = next_point - previous_point; + switch (path_rotation) { + case PATH_ROTATION_POLYGON: + direction = Vector3(0, 0, -1); + break; + case PATH_ROTATION_PATH: + break; + case PATH_ROTATION_PATH_FOLLOW: + current_up = curve->interpolate_baked_up_vector(current_offset); + break; + } - switch (path_rotation) { - case PATH_ROTATION_POLYGON: - direction = Vector3(0, 0, -1); - break; - case PATH_ROTATION_PATH: - break; - case PATH_ROTATION_PATH_FOLLOW: - current_up = curve->interpolate_baked_up_vector(current_offset); - break; - } + Transform3D facing = Transform3D().looking_at(direction, current_up); + current_xform = base_xform.translated(current_point) * facing; + } break; + } - Transform3D facing = Transform3D().looking_at(direction, current_up); - current_xform = base_xform.translated(current_point) * facing; - } break; - } + double u0 = (x0 - faces_combined) * u_step; + double u1 = ((x0 + 1) * u_step); + if (mode == MODE_PATH && !path_continuous_u) { + u0 = 0.0; + u1 = 1.0; + } - double u0 = x0 * u_step; - double u1 = ((x0 + 1) * u_step); - if (mode == MODE_PATH && !path_continuous_u) { - u0 = 0.0; - u1 = 1.0; - } + for (int y0 = 0; y0 < shape_sides; y0++) { + int y1 = (y0 + 1) % shape_sides; + // Use the top half of the texture. + double v0 = (y0 * v_step) / 2; + double v1 = ((y0 + 1) * v_step) / 2; - for (int y0 = 0; y0 < shape_sides; y0++) { - int y1 = (y0 + 1) % shape_sides; - // Use the top half of the texture. - double v0 = (y0 * v_step) / 2; - double v1 = ((y0 + 1) * v_step) / 2; - - Vector3 v[4] = { - previous_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)), - current_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)), - current_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)), - previous_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)), - }; - - Vector2 u[4] = { - Vector2(u0, v0), - Vector2(u1, v0), - Vector2(u1, v1), - Vector2(u0, v1), - }; - - // Face 1 - facesw[face * 3 + 0] = v[0]; - facesw[face * 3 + 1] = v[1]; - facesw[face * 3 + 2] = v[2]; - - uvsw[face * 3 + 0] = u[0]; - uvsw[face * 3 + 1] = u[1]; - uvsw[face * 3 + 2] = u[2]; - - smoothw[face] = smooth_faces; - invertw[face] = invert_faces; - materialsw[face] = material; - - face++; - - // Face 2 - facesw[face * 3 + 0] = v[2]; - facesw[face * 3 + 1] = v[3]; - facesw[face * 3 + 2] = v[0]; - - uvsw[face * 3 + 0] = u[2]; - uvsw[face * 3 + 1] = u[3]; - uvsw[face * 3 + 2] = u[0]; - - smoothw[face] = smooth_faces; - invertw[face] = invert_faces; - materialsw[face] = material; - - face++; - } - } + Vector3 v[4] = { + previous_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)), + current_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)), + current_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)), + previous_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)), + }; - if (end_count > 1) { - // Add back end face. - for (int face_idx = 0; face_idx < shape_face_count; face_idx++) { - for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) { - int index = shape_faces[face_idx * 3 + face_vertex_idx]; - Point2 p = shape_polygon[index]; - Point2 uv = (p - shape_rect.position) / shape_rect.size; + Vector2 u[4] = { + Vector2(u0, v0), + Vector2(u1, v0), + Vector2(u1, v1), + Vector2(u0, v1), + }; - // Use the x-inverted ride side of the bottom half of the y-inverted texture. - uv.x = 1 - uv.x / 2; - uv.y = 1 - (uv.y / 2); + // Face 1 + facesw[face * 3 + 0] = v[0]; + facesw[face * 3 + 1] = v[1]; + facesw[face * 3 + 2] = v[2]; - facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0)); - uvsw[face * 3 + face_vertex_idx] = uv; + uvsw[face * 3 + 0] = u[0]; + uvsw[face * 3 + 1] = u[1]; + uvsw[face * 3 + 2] = u[2]; + + smoothw[face] = smooth_faces; + invertw[face] = invert_faces; + materialsw[face] = material; + + face++; + + // Face 2 + facesw[face * 3 + 0] = v[2]; + facesw[face * 3 + 1] = v[3]; + facesw[face * 3 + 2] = v[0]; + + uvsw[face * 3 + 0] = u[2]; + uvsw[face * 3 + 1] = u[3]; + uvsw[face * 3 + 2] = u[0]; + + smoothw[face] = smooth_faces; + invertw[face] = invert_faces; + materialsw[face] = material; + + face++; } + } + + if (end_count > 1) { + // Add back end face. + for (int face_idx = 0; face_idx < shape_face_count; face_idx++) { + for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) { + int index = shape_faces[face_idx * 3 + face_vertex_idx]; + Point2 p = shape_polygon[index]; + Point2 uv = (p - shape_rect.position) / shape_rect.size; - smoothw[face] = false; - materialsw[face] = material; - invertw[face] = invert_faces; - face++; + // Use the x-inverted ride side of the bottom half of the y-inverted texture. + uv.x = 1 - uv.x / 2; + uv.y = 1 - (uv.y / 2); + + facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0)); + uvsw[face * 3 + face_vertex_idx] = uv; + } + + smoothw[face] = false; + materialsw[face] = material; + invertw[face] = invert_faces; + face++; + } } + + face_count -= faces_removed; + ERR_FAIL_COND_V_MSG(face != face_count, brush, "Bug: Failed to create the CSGPolygon mesh correctly."); } - ERR_FAIL_COND_V_MSG(face != face_count, brush, "Bug: Failed to create the CSGPolygon mesh correctly."); + if (faces_removed > 0) { + faces.resize(face_count * 3); + uvs.resize(face_count * 3); + smooth.resize(face_count); + materials.resize(face_count); + invert.resize(face_count); + } brush->build_from_faces(faces, uvs, smooth, materials, invert); @@ -2031,9 +2070,15 @@ void CSGPolygon3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_path_node", "path"), &CSGPolygon3D::set_path_node); ClassDB::bind_method(D_METHOD("get_path_node"), &CSGPolygon3D::get_path_node); + ClassDB::bind_method(D_METHOD("set_path_interval_type", "interval_type"), &CSGPolygon3D::set_path_interval_type); + ClassDB::bind_method(D_METHOD("get_path_interval_type"), &CSGPolygon3D::get_path_interval_type); + ClassDB::bind_method(D_METHOD("set_path_interval", "interval"), &CSGPolygon3D::set_path_interval); ClassDB::bind_method(D_METHOD("get_path_interval"), &CSGPolygon3D::get_path_interval); + ClassDB::bind_method(D_METHOD("set_path_simplify_angle", "degrees"), &CSGPolygon3D::set_path_simplify_angle); + ClassDB::bind_method(D_METHOD("get_path_simplify_angle"), &CSGPolygon3D::get_path_simplify_angle); + ClassDB::bind_method(D_METHOD("set_path_rotation", "path_rotation"), &CSGPolygon3D::set_path_rotation); ClassDB::bind_method(D_METHOD("get_path_rotation"), &CSGPolygon3D::get_path_rotation); @@ -2043,6 +2088,9 @@ void CSGPolygon3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_path_continuous_u", "enable"), &CSGPolygon3D::set_path_continuous_u); ClassDB::bind_method(D_METHOD("is_path_continuous_u"), &CSGPolygon3D::is_path_continuous_u); + ClassDB::bind_method(D_METHOD("set_path_u_distance", "distance"), &CSGPolygon3D::set_path_u_distance); + ClassDB::bind_method(D_METHOD("get_path_u_distance"), &CSGPolygon3D::get_path_u_distance); + ClassDB::bind_method(D_METHOD("set_path_joined", "enable"), &CSGPolygon3D::set_path_joined); ClassDB::bind_method(D_METHOD("is_path_joined"), &CSGPolygon3D::is_path_joined); @@ -2061,10 +2109,13 @@ void CSGPolygon3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees"); ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path3D"), "set_path_node", "get_path_node"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.1,1.0,0.05,exp"), "set_path_interval", "get_path_interval"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "path_interval_type", PROPERTY_HINT_ENUM, "Distance,Subdivide"), "set_path_interval_type", "get_path_interval_type"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.01,1.0,0.01,exp,or_greater"), "set_path_interval", "get_path_interval"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_simplify_angle", PROPERTY_HINT_RANGE, "0.0,180.0,0.1,exp"), "set_path_simplify_angle", "get_path_simplify_angle"); ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_continuous_u"), "set_path_continuous_u", "is_path_continuous_u"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_u_distance", PROPERTY_HINT_RANGE, "0.0,10.0,0.01,or_greater"), "set_path_u_distance", "get_path_u_distance"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_joined"), "set_path_joined", "is_path_joined"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); @@ -2076,6 +2127,9 @@ void CSGPolygon3D::_bind_methods() { BIND_ENUM_CONSTANT(PATH_ROTATION_POLYGON); BIND_ENUM_CONSTANT(PATH_ROTATION_PATH); BIND_ENUM_CONSTANT(PATH_ROTATION_PATH_FOLLOW); + + BIND_ENUM_CONSTANT(PATH_INTERVAL_DISTANCE); + BIND_ENUM_CONSTANT(PATH_INTERVAL_SUBDIVIDE); } void CSGPolygon3D::set_polygon(const Vector<Vector2> &p_polygon) { @@ -2119,6 +2173,16 @@ bool CSGPolygon3D::is_path_continuous_u() const { return path_continuous_u; } +void CSGPolygon3D::set_path_u_distance(real_t p_path_u_distance) { + path_u_distance = p_path_u_distance; + _make_dirty(); + update_gizmos(); +} + +real_t CSGPolygon3D::get_path_u_distance() const { + return path_u_distance; +} + void CSGPolygon3D::set_spin_degrees(const float p_spin_degrees) { ERR_FAIL_COND(p_spin_degrees < 0.01 || p_spin_degrees > 360); spin_degrees = p_spin_degrees; @@ -2151,8 +2215,17 @@ NodePath CSGPolygon3D::get_path_node() const { return path_node; } +void CSGPolygon3D::set_path_interval_type(PathIntervalType p_interval_type) { + path_interval_type = p_interval_type; + _make_dirty(); + update_gizmos(); +} + +CSGPolygon3D::PathIntervalType CSGPolygon3D::get_path_interval_type() const { + return path_interval_type; +} + void CSGPolygon3D::set_path_interval(float p_interval) { - ERR_FAIL_COND_MSG(p_interval <= 0 || p_interval > 1, "Path interval must be greater than 0 and less than or equal to 1.0."); path_interval = p_interval; _make_dirty(); update_gizmos(); @@ -2162,6 +2235,16 @@ float CSGPolygon3D::get_path_interval() const { return path_interval; } +void CSGPolygon3D::set_path_simplify_angle(float p_angle) { + path_simplify_angle = p_angle; + _make_dirty(); + update_gizmos(); +} + +float CSGPolygon3D::get_path_simplify_angle() const { + return path_simplify_angle; +} + void CSGPolygon3D::set_path_rotation(PathRotation p_rotation) { path_rotation = p_rotation; _make_dirty(); @@ -2229,10 +2312,13 @@ CSGPolygon3D::CSGPolygon3D() { spin_degrees = 360; spin_sides = 8; smooth_faces = false; + path_interval_type = PATH_INTERVAL_DISTANCE; path_interval = 1.0; + path_simplify_angle = 0.0; path_rotation = PATH_ROTATION_PATH_FOLLOW; path_local = false; path_continuous_u = true; + path_u_distance = 1.0; path_joined = false; path = nullptr; } diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index 5cf371665e..c85cce776b 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -336,6 +336,11 @@ public: MODE_PATH }; + enum PathIntervalType { + PATH_INTERVAL_DISTANCE, + PATH_INTERVAL_SUBDIVIDE + }; + enum PathRotation { PATH_ROTATION_POLYGON, PATH_ROTATION_PATH, @@ -356,7 +361,9 @@ private: int spin_sides; NodePath path_node; + PathIntervalType path_interval_type; float path_interval; + float path_simplify_angle; PathRotation path_rotation; bool path_local; @@ -364,6 +371,7 @@ private: bool smooth_faces; bool path_continuous_u; + real_t path_u_distance; bool path_joined; bool _is_editable_3d_polygon() const; @@ -396,9 +404,15 @@ public: void set_path_node(const NodePath &p_path); NodePath get_path_node() const; + void set_path_interval_type(PathIntervalType p_interval_type); + PathIntervalType get_path_interval_type() const; + void set_path_interval(float p_interval); float get_path_interval() const; + void set_path_simplify_angle(float p_angle); + float get_path_simplify_angle() const; + void set_path_rotation(PathRotation p_rotation); PathRotation get_path_rotation() const; @@ -408,6 +422,9 @@ public: void set_path_continuous_u(bool p_enable); bool is_path_continuous_u() const; + void set_path_u_distance(real_t p_path_u_distance); + real_t get_path_u_distance() const; + void set_path_joined(bool p_enable); bool is_path_joined() const; @@ -422,5 +439,6 @@ public: VARIANT_ENUM_CAST(CSGPolygon3D::Mode) VARIANT_ENUM_CAST(CSGPolygon3D::PathRotation) +VARIANT_ENUM_CAST(CSGPolygon3D::PathIntervalType) #endif // CSG_SHAPE_H diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml index 5d56e56de9..ecbb7962d1 100644 --- a/modules/csg/doc_classes/CSGPolygon3D.xml +++ b/modules/csg/doc_classes/CSGPolygon3D.xml @@ -24,6 +24,9 @@ <member name="path_interval" type="float" setter="set_path_interval" getter="get_path_interval"> When [member mode] is [constant MODE_PATH], the path interval or ratio of path points to extrusions. </member> + <member name="path_interval_type" type="int" setter="set_path_interval_type" getter="get_path_interval_type" enum="CSGPolygon3D.PathIntervalType"> + When [member mode] is [constant MODE_PATH], this will determine if the interval should be by distance ([constant PATH_INTERVAL_DISTANCE]) or subdivision fractions ([constant PATH_INTERVAL_SUBDIVIDE]). + </member> <member name="path_joined" type="bool" setter="set_path_joined" getter="is_path_joined"> When [member mode] is [constant MODE_PATH], if [code]true[/code] the ends of the path are joined, by adding an extrusion between the last and first points of the path. </member> @@ -36,6 +39,12 @@ <member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon3D.PathRotation"> When [member mode] is [constant MODE_PATH], the [enum PathRotation] method used to rotate the [member polygon] as it is extruded. </member> + <member name="path_simplify_angle" type="float" setter="set_path_simplify_angle" getter="get_path_simplify_angle"> + When [member mode] is [constant MODE_PATH], extrusions that are less than this angle, will be merged together to reduce polygon count. + </member> + <member name="path_u_distance" type="float" setter="set_path_u_distance" getter="get_path_u_distance"> + When [member mode] is [constant MODE_PATH], this is the distance along the path, in meters, the texture coordinates will tile. When set to 0, texture coordinates will match geometry exactly with no tiling. + </member> <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array(0, 0, 0, 1, 1, 1, 1, 0)"> The point array that defines the 2D polygon that is extruded. </member> @@ -70,5 +79,11 @@ <constant name="PATH_ROTATION_PATH_FOLLOW" value="2" enum="PathRotation"> The [member polygon] shape follows the path and its rotations around the path axis. </constant> + <constant name="PATH_INTERVAL_DISTANCE" value="0" enum="PathIntervalType"> + When [member mode] is set to [constant MODE_PATH], [member path_interval] will determine the distance, in meters, each interval of the path will extrude. + </constant> + <constant name="PATH_INTERVAL_SUBDIVIDE" value="1" enum="PathIntervalType"> + When [member mode] is set to [constant MODE_PATH], [member path_interval] will subdivide the polygons along the path. + </constant> </constants> </class> diff --git a/modules/enet/doc_classes/ENetMultiplayerPeer.xml b/modules/enet/doc_classes/ENetMultiplayerPeer.xml index 456b390dbb..f9659c092a 100644 --- a/modules/enet/doc_classes/ENetMultiplayerPeer.xml +++ b/modules/enet/doc_classes/ENetMultiplayerPeer.xml @@ -77,10 +77,8 @@ <member name="host" type="ENetConnection" setter="" getter="get_host"> The underlying [ENetConnection] created after [method create_client] and [method create_server]. </member> - <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" /> <member name="server_relay" type="bool" setter="set_server_relay_enabled" getter="is_server_relay_enabled" default="true"> Enable or disable the server feature that notifies clients of other peers' connection/disconnection, and relays messages between them. When this option is [code]false[/code], clients won't be automatically notified of other peers and won't be able to send them packets through the server. </member> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="TransferMode" default="2" /> </members> </class> diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp index afd31207f6..52eb46f070 100644 --- a/modules/enet/enet_multiplayer_peer.cpp +++ b/modules/enet/enet_multiplayer_peer.cpp @@ -33,22 +33,6 @@ #include "core/io/marshalls.h" #include "core/os/os.h" -void ENetMultiplayerPeer::set_transfer_channel(int p_channel) { - transfer_channel = p_channel; -} - -int ENetMultiplayerPeer::get_transfer_channel() const { - return transfer_channel; -} - -void ENetMultiplayerPeer::set_transfer_mode(Multiplayer::TransferMode p_mode) { - transfer_mode = p_mode; -} - -Multiplayer::TransferMode ENetMultiplayerPeer::get_transfer_mode() const { - return transfer_mode; -} - void ENetMultiplayerPeer::set_target_peer(int p_peer) { target_peer = p_peer; } @@ -62,6 +46,7 @@ int ENetMultiplayerPeer::get_packet_peer() const { Error ENetMultiplayerPeer::create_server(int p_port, int p_max_clients, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth) { ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); + set_refuse_new_connections(false); Ref<ENetConnection> host; host.instantiate(); Error err = host->create_host_bound(bind_ip, p_port, p_max_clients, 0, p_max_channels > 0 ? p_max_channels + SYSCH_MAX : 0, p_out_bandwidth); @@ -70,7 +55,6 @@ Error ENetMultiplayerPeer::create_server(int p_port, int p_max_clients, int p_ma } active_mode = MODE_SERVER; - refuse_connections = false; unique_id = 1; connection_status = CONNECTION_CONNECTED; hosts[0] = host; @@ -79,6 +63,7 @@ Error ENetMultiplayerPeer::create_server(int p_port, int p_max_clients, int p_ma Error ENetMultiplayerPeer::create_client(const String &p_address, int p_port, int p_channel_count, int p_in_bandwidth, int p_out_bandwidth, int p_local_port) { ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); + set_refuse_new_connections(false); Ref<ENetConnection> host; host.instantiate(); Error err; @@ -102,7 +87,6 @@ Error ENetMultiplayerPeer::create_client(const String &p_address, int p_port, in // Need to wait for CONNECT event. connection_status = CONNECTION_CONNECTING; active_mode = MODE_CLIENT; - refuse_connections = false; peers[1] = peer; hosts[0] = host; @@ -113,7 +97,6 @@ Error ENetMultiplayerPeer::create_mesh(int p_id) { ERR_FAIL_COND_V_MSG(p_id <= 0, ERR_INVALID_PARAMETER, "The unique ID must be greater then 0"); ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); active_mode = MODE_MESH; - refuse_connections = false; unique_id = p_id; connection_status = CONNECTION_CONNECTED; return OK; @@ -145,7 +128,7 @@ bool ENetMultiplayerPeer::_poll_server() { } switch (ret) { case ENetConnection::EVENT_CONNECT: { - if (refuse_connections) { + if (is_refusing_new_connections()) { event.peer->reset(); return false; } @@ -173,7 +156,7 @@ bool ENetMultiplayerPeer::_poll_server() { emit_signal(SNAME("peer_disconnected"), id); peers.erase(id); - if (!server_relay) { + if (server_relay) { _notify_peers(id, false); } return false; @@ -423,6 +406,7 @@ void ENetMultiplayerPeer::close_connection(uint32_t wait_usec) { hosts.clear(); unique_id = 0; connection_status = CONNECTION_DISCONNECTED; + set_refuse_new_connections(false); } int ENetMultiplayerPeer::get_available_packet_count() const { @@ -451,10 +435,11 @@ Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size int packet_flags = 0; int channel = SYSCH_RELIABLE; + int transfer_channel = get_transfer_channel(); if (transfer_channel > 0) { channel = SYSCH_MAX + transfer_channel - 1; } else { - switch (transfer_mode) { + switch (get_transfer_mode()) { case Multiplayer::TRANSFER_MODE_UNRELIABLE: { packet_flags = ENET_PACKET_FLAG_UNSEQUENCED; channel = SYSCH_UNRELIABLE; @@ -545,19 +530,15 @@ int ENetMultiplayerPeer::get_unique_id() const { return unique_id; } -void ENetMultiplayerPeer::set_refuse_new_connections(bool p_enable) { - refuse_connections = p_enable; +void ENetMultiplayerPeer::set_refuse_new_connections(bool p_enabled) { #ifdef GODOT_ENET if (_is_active()) { for (KeyValue<int, Ref<ENetConnection>> &E : hosts) { - E.value->refuse_new_connections(p_enable); + E.value->refuse_new_connections(p_enabled); } } #endif -} - -bool ENetMultiplayerPeer::is_refusing_new_connections() const { - return refuse_connections; + MultiplayerPeer::set_refuse_new_connections(p_enabled); } void ENetMultiplayerPeer::set_server_relay_enabled(bool p_enabled) { diff --git a/modules/enet/enet_multiplayer_peer.h b/modules/enet/enet_multiplayer_peer.h index b5316b8292..7a60e2359c 100644 --- a/modules/enet/enet_multiplayer_peer.h +++ b/modules/enet/enet_multiplayer_peer.h @@ -65,10 +65,7 @@ private: uint32_t unique_id = 0; int target_peer = 0; - int transfer_channel = 0; - Multiplayer::TransferMode transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; - bool refuse_connections = false; bool server_relay = true; ConnectionStatus connection_status = CONNECTION_DISCONNECTED; @@ -101,40 +98,31 @@ protected: static void _bind_methods(); public: - virtual void set_transfer_channel(int p_channel) override; - virtual int get_transfer_channel() const override; - - virtual void set_transfer_mode(Multiplayer::TransferMode p_mode) override; - virtual Multiplayer::TransferMode get_transfer_mode() const override; virtual void set_target_peer(int p_peer) override; - virtual int get_packet_peer() const override; - Error create_server(int p_port, int p_max_clients = 32, int p_max_channels = 0, int p_in_bandwidth = 0, int p_out_bandwidth = 0); - Error create_client(const String &p_address, int p_port, int p_channel_count = 0, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_local_port = 0); - Error create_mesh(int p_id); - Error add_mesh_peer(int p_id, Ref<ENetConnection> p_host); - - void close_connection(uint32_t wait_usec = 100); - - void disconnect_peer(int p_peer, bool now = false); - virtual void poll() override; - virtual bool is_server() const override; + // Overriden so we can instrument the DTLSServer when needed. + virtual void set_refuse_new_connections(bool p_enabled) override; - virtual int get_available_packet_count() const override; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; + virtual ConnectionStatus get_connection_status() const override; + + virtual int get_unique_id() const override; virtual int get_max_packet_size() const override; + virtual int get_available_packet_count() const override; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; - virtual ConnectionStatus get_connection_status() const override; + Error create_server(int p_port, int p_max_clients = 32, int p_max_channels = 0, int p_in_bandwidth = 0, int p_out_bandwidth = 0); + Error create_client(const String &p_address, int p_port, int p_channel_count = 0, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_local_port = 0); + Error create_mesh(int p_id); + Error add_mesh_peer(int p_id, Ref<ENetConnection> p_host); - virtual void set_refuse_new_connections(bool p_enable) override; - virtual bool is_refusing_new_connections() const override; + void close_connection(uint32_t wait_usec = 100); - virtual int get_unique_id() const override; + void disconnect_peer(int p_peer, bool now = false); void set_bind_ip(const IPAddress &p_ip); void set_server_relay_enabled(bool p_enabled); diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub index 21ee39f3ed..94bda04d12 100644 --- a/modules/gdnative/SCsub +++ b/modules/gdnative/SCsub @@ -16,7 +16,6 @@ env_gdnative.Prepend(CPPPATH=["#modules/gdnative/include/"]) Export("env_gdnative") -SConscript("net/SCsub") SConscript("pluginscript/SCsub") SConscript("videodecoder/SCsub") SConscript("text/SCsub") diff --git a/modules/gdnative/config.py b/modules/gdnative/config.py index fa985501b5..026a84a70f 100644 --- a/modules/gdnative/config.py +++ b/modules/gdnative/config.py @@ -10,14 +10,9 @@ def get_doc_classes(): return [ "GDNative", "GDNativeLibrary", - "MultiplayerPeerGDNative", "NativeScript", - "PacketPeerGDNative", "PluginScript", - "StreamPeerGDNative", "VideoStreamGDNative", - "WebRTCPeerConnectionGDNative", - "WebRTCDataChannelGDNative", ] diff --git a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml b/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml deleted file mode 100644 index 40f3121525..0000000000 --- a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiplayerPeerGDNative" inherits="MultiplayerPeer" version="4.0"> - <brief_description> - </brief_description> - <description> - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/gdnative/doc_classes/PacketPeerGDNative.xml b/modules/gdnative/doc_classes/PacketPeerGDNative.xml deleted file mode 100644 index 32863f8422..0000000000 --- a/modules/gdnative/doc_classes/PacketPeerGDNative.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="PacketPeerGDNative" inherits="PacketPeer" version="4.0"> - <brief_description> - </brief_description> - <description> - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/gdnative/doc_classes/StreamPeerGDNative.xml b/modules/gdnative/doc_classes/StreamPeerGDNative.xml deleted file mode 100644 index a505de2106..0000000000 --- a/modules/gdnative/doc_classes/StreamPeerGDNative.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="StreamPeerGDNative" inherits="StreamPeer" version="4.0"> - <brief_description> - </brief_description> - <description> - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/gdnative/doc_classes/WebRTCDataChannelGDNative.xml b/modules/gdnative/doc_classes/WebRTCDataChannelGDNative.xml deleted file mode 100644 index ddf354763c..0000000000 --- a/modules/gdnative/doc_classes/WebRTCDataChannelGDNative.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="WebRTCDataChannelGDNative" inherits="WebRTCDataChannel" version="4.0"> - <brief_description> - </brief_description> - <description> - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/gdnative/doc_classes/WebRTCPeerConnectionGDNative.xml b/modules/gdnative/doc_classes/WebRTCPeerConnectionGDNative.xml deleted file mode 100644 index 821779a0ff..0000000000 --- a/modules/gdnative/doc_classes/WebRTCPeerConnectionGDNative.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="WebRTCPeerConnectionGDNative" inherits="WebRTCPeerConnection" version="4.0"> - <brief_description> - </brief_description> - <description> - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 66d2dc267d..627883886c 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -5105,97 +5105,6 @@ ] }, { - "name": "net", - "type": "NET", - "version": { - "major": 4, - "minor": 0 - }, - "next": null, - "api": [ - { - "name": "godot_net_bind_stream_peer", - "return_type": "void", - "arguments": [ - [ - "godot_object *", - "p_obj" - ], - [ - "const godot_net_stream_peer *", - "p_interface" - ] - ] - }, - { - "name": "godot_net_bind_packet_peer", - "return_type": "void", - "arguments": [ - [ - "godot_object *", - "p_obj" - ], - [ - "const godot_net_packet_peer *", - "p_interface" - ] - ] - }, - { - "name": "godot_net_bind_multiplayer_peer", - "return_type": "void", - "arguments": [ - [ - "godot_object *", - "p_obj" - ], - [ - "const godot_net_multiplayer_peer *", - "p_interface" - ] - ] - }, - { - "name": "godot_net_set_webrtc_library", - "return_type": "godot_error", - "arguments": [ - [ - "const godot_net_webrtc_library *", - "p_library" - ] - ] - }, - { - "name": "godot_net_bind_webrtc_peer_connection", - "return_type": "void", - "arguments": [ - [ - "godot_object *", - "p_obj" - ], - [ - "const godot_net_webrtc_peer_connection *", - "p_interface" - ] - ] - }, - { - "name": "godot_net_bind_webrtc_data_channel", - "return_type": "void", - "arguments": [ - [ - "godot_object *", - "p_obj" - ], - [ - "const godot_net_webrtc_data_channel *", - "p_interface" - ] - ] - } - ] - }, - { "name": "text", "type": "TEXT", "version": { diff --git a/modules/gdnative/gdnative_builders.py b/modules/gdnative/gdnative_builders.py index 181fd71b82..4986b173cf 100644 --- a/modules/gdnative/gdnative_builders.py +++ b/modules/gdnative/gdnative_builders.py @@ -20,7 +20,6 @@ def _build_gdnative_api_struct_header(api): "#include <gdnative/gdnative.h>", "#include <android/godot_android.h>", "#include <nativescript/godot_nativescript.h>", - "#include <net/godot_net.h>", "#include <pluginscript/godot_pluginscript.h>", "#include <videodecoder/godot_videodecoder.h>", "#include <text/godot_text.h>", diff --git a/modules/gdnative/include/net/godot_net.h b/modules/gdnative/include/net/godot_net.h deleted file mode 100644 index 3fb7b9e1cc..0000000000 --- a/modules/gdnative/include/net/godot_net.h +++ /dev/null @@ -1,122 +0,0 @@ -/*************************************************************************/ -/* godot_net.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 GODOT_NATIVENET_H -#define GODOT_NATIVENET_H - -#include <gdnative/gdnative.h> - -#ifdef __cplusplus -extern "C" { -#endif - -// For future versions of the API we should only add new functions at the end of the structure and use the -// version info to detect whether a call is available - -// Use these to populate version in your plugin -#define GODOT_NET_API_MAJOR 3 -#define GODOT_NET_API_MINOR 1 - -typedef struct { - godot_gdnative_api_version version; /* version of our API */ - godot_object *data; /* User reference */ - - /* This is StreamPeer */ - godot_error (*get_data)(void *user, uint8_t *p_buffer, int p_bytes); - godot_error (*get_partial_data)(void *user, uint8_t *p_buffer, int p_bytes, int *r_received); - godot_error (*put_data)(void *user, const uint8_t *p_data, int p_bytes); - godot_error (*put_partial_data)(void *user, const uint8_t *p_data, int p_bytes, int *r_sent); - - int (*get_available_bytes)(const void *user); - - void *next; /* For extension? */ -} godot_net_stream_peer; - -/* Binds a StreamPeerGDNative to the provided interface */ -void godot_net_bind_stream_peer(godot_object *p_obj, const godot_net_stream_peer *p_interface); - -typedef struct { - godot_gdnative_api_version version; /* version of our API */ - - godot_object *data; /* User reference */ - - /* This is PacketPeer */ - godot_error (*get_packet)(void *, const uint8_t **, int *); - godot_error (*put_packet)(void *, const uint8_t *, int); - godot_int (*get_available_packet_count)(const void *); - godot_int (*get_max_packet_size)(const void *); - - void *next; /* For extension? */ -} godot_net_packet_peer; - -/* Binds a PacketPeerGDNative to the provided interface */ -void GDAPI godot_net_bind_packet_peer(godot_object *p_obj, const godot_net_packet_peer *); - -typedef struct { - godot_gdnative_api_version version; /* version of our API */ - - godot_object *data; /* User reference */ - - /* This is PacketPeer */ - godot_error (*get_packet)(void *, const uint8_t **, int *); - godot_error (*put_packet)(void *, const uint8_t *, int); - godot_int (*get_available_packet_count)(const void *); - godot_int (*get_max_packet_size)(const void *); - - /* This is MultiplayerPeer */ - void (*set_transfer_channel)(void *, godot_int); - godot_int (*get_transfer_channel)(void *); - void (*set_transfer_mode)(void *, godot_int); - godot_int (*get_transfer_mode)(const void *); - // 0 = broadcast, 1 = server, <0 = all but abs(value) - void (*set_target_peer)(void *, godot_int); - godot_int (*get_packet_peer)(const void *); - godot_bool (*is_server)(const void *); - void (*poll)(void *); - // Must be > 0, 1 is for server - int32_t (*get_unique_id)(const void *); - void (*set_refuse_new_connections)(void *, godot_bool); - godot_bool (*is_refusing_new_connections)(const void *); - godot_int (*get_connection_status)(const void *); - - void *next; /* For extension? Or maybe not... */ -} godot_net_multiplayer_peer; - -/* Binds a MultiplayerPeerGDNative to the provided interface */ -void GDAPI godot_net_bind_multiplayer_peer(godot_object *p_obj, const godot_net_multiplayer_peer *); - -#ifdef __cplusplus -} -#endif - -// WebRTC Bindings -#include "net/godot_webrtc.h" - -#endif /* GODOT_NATIVENET_H */ diff --git a/modules/gdnative/include/net/godot_webrtc.h b/modules/gdnative/include/net/godot_webrtc.h deleted file mode 100644 index 52006e56ec..0000000000 --- a/modules/gdnative/include/net/godot_webrtc.h +++ /dev/null @@ -1,123 +0,0 @@ -/*************************************************************************/ -/* godot_webrtc.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 GODOT_NATIVEWEBRTC_H -#define GODOT_NATIVEWEBRTC_H - -#include <gdnative/gdnative.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#define GODOT_NET_WEBRTC_API_MAJOR 4 -#define GODOT_NET_WEBRTC_API_MINOR 0 - -/* Library Interface (used to set default GDNative WebRTC implementation */ -typedef struct { - godot_gdnative_api_version version; /* version of our API */ - - /* Called when the library is unset as default interface via godot_net_set_webrtc_library */ - void (*unregistered)(); - - /* Used by WebRTCPeerConnection create when GDNative is the default implementation. */ - /* Takes a pointer to WebRTCPeerConnectionGDNative, should bind and return OK, failure if binding was unsuccessful. */ - godot_error (*create_peer_connection)(godot_object *); - - void *next; /* For extension */ -} godot_net_webrtc_library; - -/* WebRTCPeerConnection interface */ -typedef struct { - godot_gdnative_api_version version; /* version of our API */ - - godot_object *data; /* User reference */ - - /* This is WebRTCPeerConnection */ - godot_int (*get_connection_state)(const void *); - - godot_error (*initialize)(void *, const godot_dictionary *); - godot_object *(*create_data_channel)(void *, const char *p_channel_name, const godot_dictionary *); - godot_error (*create_offer)(void *); - godot_error (*create_answer)(void *); /* unused for now, should be done automatically on set_local_description */ - godot_error (*set_remote_description)(void *, const char *, const char *); - godot_error (*set_local_description)(void *, const char *, const char *); - godot_error (*add_ice_candidate)(void *, const char *, int, const char *); - godot_error (*poll)(void *); - void (*close)(void *); - - void *next; /* For extension? */ -} godot_net_webrtc_peer_connection; - -/* WebRTCDataChannel interface */ -typedef struct { - godot_gdnative_api_version version; /* version of our API */ - - godot_object *data; /* User reference */ - - /* This is PacketPeer */ - godot_error (*get_packet)(void *, const uint8_t **, int *); - godot_error (*put_packet)(void *, const uint8_t *, int); - godot_int (*get_available_packet_count)(const void *); - godot_int (*get_max_packet_size)(const void *); - - /* This is WebRTCDataChannel */ - void (*set_write_mode)(void *, godot_int); - godot_int (*get_write_mode)(const void *); - bool (*was_string_packet)(const void *); - - godot_int (*get_ready_state)(const void *); - const char *(*get_label)(const void *); - bool (*is_ordered)(const void *); - int (*get_id)(const void *); - int (*get_max_packet_life_time)(const void *); - int (*get_max_retransmits)(const void *); - const char *(*get_protocol)(const void *); - bool (*is_negotiated)(const void *); - int (*get_buffered_amount)(const void *); - - godot_error (*poll)(void *); - void (*close)(void *); - - void *next; /* For extension? */ -} godot_net_webrtc_data_channel; - -/* Set the default GDNative library */ -godot_error GDAPI godot_net_set_webrtc_library(const godot_net_webrtc_library *); -/* Binds a WebRTCPeerConnectionGDNative to the provided interface */ -void GDAPI godot_net_bind_webrtc_peer_connection(godot_object *p_obj, const godot_net_webrtc_peer_connection *); -/* Binds a WebRTCDataChannelGDNative to the provided interface */ -void GDAPI godot_net_bind_webrtc_data_channel(godot_object *p_obj, const godot_net_webrtc_data_channel *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/modules/gdnative/net/SCsub b/modules/gdnative/net/SCsub deleted file mode 100644 index b76500c003..0000000000 --- a/modules/gdnative/net/SCsub +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_gdnative") - -env_net = env_gdnative.Clone() - -has_webrtc = env_net["module_webrtc_enabled"] -if has_webrtc: - env_net.Append(CPPDEFINES=["WEBRTC_GDNATIVE_ENABLED"]) - -env_net.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.cpp b/modules/gdnative/net/multiplayer_peer_gdnative.cpp deleted file mode 100644 index 575d5f5060..0000000000 --- a/modules/gdnative/net/multiplayer_peer_gdnative.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/*************************************************************************/ -/* multiplayer_peer_gdnative.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 "multiplayer_peer_gdnative.h" - -MultiplayerPeerGDNative::MultiplayerPeerGDNative() { - interface = nullptr; -} - -MultiplayerPeerGDNative::~MultiplayerPeerGDNative() { -} - -void MultiplayerPeerGDNative::set_native_multiplayer_peer(const godot_net_multiplayer_peer *p_interface) { - interface = p_interface; -} - -Error MultiplayerPeerGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size); -} - -Error MultiplayerPeerGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size); -} - -int MultiplayerPeerGDNative::get_max_packet_size() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_max_packet_size(interface->data); -} - -int MultiplayerPeerGDNative::get_available_packet_count() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_available_packet_count(interface->data); -} - -/* MultiplayerPeer */ -void MultiplayerPeerGDNative::set_transfer_channel(int p_channel) { - ERR_FAIL_COND(interface == nullptr); - return interface->set_transfer_channel(interface->data, p_channel); -} - -int MultiplayerPeerGDNative::get_transfer_channel() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_transfer_channel(interface->data); -} - -void MultiplayerPeerGDNative::set_transfer_mode(Multiplayer::TransferMode p_mode) { - ERR_FAIL_COND(interface == nullptr); - interface->set_transfer_mode(interface->data, (godot_int)p_mode); -} - -Multiplayer::TransferMode MultiplayerPeerGDNative::get_transfer_mode() const { - ERR_FAIL_COND_V(interface == nullptr, Multiplayer::TRANSFER_MODE_UNRELIABLE); - return (Multiplayer::TransferMode)interface->get_transfer_mode(interface->data); -} - -void MultiplayerPeerGDNative::set_target_peer(int p_peer_id) { - ERR_FAIL_COND(interface == nullptr); - interface->set_target_peer(interface->data, p_peer_id); -} - -int MultiplayerPeerGDNative::get_packet_peer() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_packet_peer(interface->data); -} - -bool MultiplayerPeerGDNative::is_server() const { - ERR_FAIL_COND_V(interface == nullptr, false); - return interface->is_server(interface->data); -} - -void MultiplayerPeerGDNative::poll() { - ERR_FAIL_COND(interface == nullptr); - interface->poll(interface->data); -} - -int MultiplayerPeerGDNative::get_unique_id() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_unique_id(interface->data); -} - -void MultiplayerPeerGDNative::set_refuse_new_connections(bool p_enable) { - ERR_FAIL_COND(interface == nullptr); - interface->set_refuse_new_connections(interface->data, p_enable); -} - -bool MultiplayerPeerGDNative::is_refusing_new_connections() const { - ERR_FAIL_COND_V(interface == nullptr, true); - return interface->is_refusing_new_connections(interface->data); -} - -MultiplayerPeer::ConnectionStatus MultiplayerPeerGDNative::get_connection_status() const { - ERR_FAIL_COND_V(interface == nullptr, CONNECTION_DISCONNECTED); - return (ConnectionStatus)interface->get_connection_status(interface->data); -} - -void MultiplayerPeerGDNative::_bind_methods() { - ADD_PROPERTY_DEFAULT("transfer_channel", 0); - ADD_PROPERTY_DEFAULT("transfer_mode", Multiplayer::TRANSFER_MODE_UNRELIABLE); - ADD_PROPERTY_DEFAULT("refuse_new_connections", true); -} - -extern "C" { - -void GDAPI godot_net_bind_multiplayer_peer(godot_object *p_obj, const godot_net_multiplayer_peer *p_impl) { - ((MultiplayerPeerGDNative *)p_obj)->set_native_multiplayer_peer(p_impl); -} -} diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.h b/modules/gdnative/net/multiplayer_peer_gdnative.h deleted file mode 100644 index 33e424d284..0000000000 --- a/modules/gdnative/net/multiplayer_peer_gdnative.h +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************/ -/* multiplayer_peer_gdnative.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 MULTIPLAYER_PEER_GDNATIVE_H -#define MULTIPLAYER_PEER_GDNATIVE_H - -#include "core/multiplayer/multiplayer_peer.h" -#include "modules/gdnative/gdnative.h" -#include "modules/gdnative/include/net/godot_net.h" - -class MultiplayerPeerGDNative : public MultiplayerPeer { - GDCLASS(MultiplayerPeerGDNative, MultiplayerPeer); - -protected: - static void _bind_methods(); - const godot_net_multiplayer_peer *interface; - -public: - MultiplayerPeerGDNative(); - ~MultiplayerPeerGDNative(); - - /* Sets the interface implementation from GDNative */ - void set_native_multiplayer_peer(const godot_net_multiplayer_peer *p_impl); - - /* Specific to PacketPeer */ - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; - virtual int get_max_packet_size() const override; - virtual int get_available_packet_count() const override; - - /* Specific to MultiplayerPeer */ - virtual void set_transfer_channel(int p_channel) override; - virtual int get_transfer_channel() const override; - virtual void set_transfer_mode(Multiplayer::TransferMode p_mode) override; - virtual Multiplayer::TransferMode get_transfer_mode() const override; - virtual void set_target_peer(int p_peer_id) override; - - virtual int get_packet_peer() const override; - - virtual bool is_server() const override; - - virtual void poll() override; - - virtual int get_unique_id() const override; - - virtual void set_refuse_new_connections(bool p_enable) override; - virtual bool is_refusing_new_connections() const override; - - virtual ConnectionStatus get_connection_status() const override; -}; - -#endif // MULTIPLAYER_PEER_GDNATIVE_H diff --git a/modules/gdnative/net/packet_peer_gdnative.cpp b/modules/gdnative/net/packet_peer_gdnative.cpp deleted file mode 100644 index 3bcdfed8ff..0000000000 --- a/modules/gdnative/net/packet_peer_gdnative.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/*************************************************************************/ -/* packet_peer_gdnative.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 "packet_peer_gdnative.h" - -PacketPeerGDNative::PacketPeerGDNative() { - interface = nullptr; -} - -PacketPeerGDNative::~PacketPeerGDNative() { -} - -void PacketPeerGDNative::set_native_packet_peer(const godot_net_packet_peer *p_impl) { - interface = p_impl; -} - -void PacketPeerGDNative::_bind_methods() { -} - -Error PacketPeerGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size); -} - -Error PacketPeerGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size); -} - -int PacketPeerGDNative::get_max_packet_size() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_max_packet_size(interface->data); -} - -int PacketPeerGDNative::get_available_packet_count() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_available_packet_count(interface->data); -} - -extern "C" { - -void GDAPI godot_net_bind_packet_peer(godot_object *p_obj, const godot_net_packet_peer *p_impl) { - ((PacketPeerGDNative *)p_obj)->set_native_packet_peer(p_impl); -} -} diff --git a/modules/gdnative/net/packet_peer_gdnative.h b/modules/gdnative/net/packet_peer_gdnative.h deleted file mode 100644 index 29013f9367..0000000000 --- a/modules/gdnative/net/packet_peer_gdnative.h +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************/ -/* packet_peer_gdnative.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 PACKET_PEER_GDNATIVE_H -#define PACKET_PEER_GDNATIVE_H - -#include "core/io/packet_peer.h" -#include "modules/gdnative/gdnative.h" -#include "modules/gdnative/include/net/godot_net.h" - -class PacketPeerGDNative : public PacketPeer { - GDCLASS(PacketPeerGDNative, PacketPeer); - -protected: - static void _bind_methods(); - const godot_net_packet_peer *interface; - -public: - PacketPeerGDNative(); - ~PacketPeerGDNative(); - - /* Sets the interface implementation from GDNative */ - void set_native_packet_peer(const godot_net_packet_peer *p_impl); - - /* Specific to PacketPeer */ - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; - virtual int get_max_packet_size() const override; - virtual int get_available_packet_count() const override; -}; - -#endif // PACKET_PEER_GDNATIVE_H diff --git a/modules/gdnative/net/register_types.cpp b/modules/gdnative/net/register_types.cpp deleted file mode 100644 index 46c383e5ae..0000000000 --- a/modules/gdnative/net/register_types.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/*************************************************************************/ -/* register_types.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 "register_types.h" -#include "multiplayer_peer_gdnative.h" -#include "packet_peer_gdnative.h" -#include "stream_peer_gdnative.h" - -void register_net_types() { - GDREGISTER_CLASS(MultiplayerPeerGDNative); - GDREGISTER_CLASS(PacketPeerGDNative); - GDREGISTER_CLASS(StreamPeerGDNative); -} - -void unregister_net_types() { -} diff --git a/modules/gdnative/net/register_types.h b/modules/gdnative/net/register_types.h deleted file mode 100644 index c99c6f6fbf..0000000000 --- a/modules/gdnative/net/register_types.h +++ /dev/null @@ -1,37 +0,0 @@ -/*************************************************************************/ -/* register_types.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 NET_REGISTER_TYPES_H -#define NET_REGISTER_TYPES_H - -void register_net_types(); -void unregister_net_types(); - -#endif // NET_REGISTER_TYPES_H diff --git a/modules/gdnative/net/stream_peer_gdnative.cpp b/modules/gdnative/net/stream_peer_gdnative.cpp deleted file mode 100644 index 72ab72323d..0000000000 --- a/modules/gdnative/net/stream_peer_gdnative.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/*************************************************************************/ -/* stream_peer_gdnative.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 "stream_peer_gdnative.h" - -StreamPeerGDNative::StreamPeerGDNative() { - interface = nullptr; -} - -StreamPeerGDNative::~StreamPeerGDNative() { -} - -void StreamPeerGDNative::set_native_stream_peer(const godot_net_stream_peer *p_interface) { - interface = p_interface; -} - -void StreamPeerGDNative::_bind_methods() { -} - -Error StreamPeerGDNative::put_data(const uint8_t *p_data, int p_bytes) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)(interface->put_data(interface->data, p_data, p_bytes)); -} - -Error StreamPeerGDNative::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)(interface->put_partial_data(interface->data, p_data, p_bytes, &r_sent)); -} - -Error StreamPeerGDNative::get_data(uint8_t *p_buffer, int p_bytes) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)(interface->get_data(interface->data, p_buffer, p_bytes)); -} - -Error StreamPeerGDNative::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)(interface->get_partial_data(interface->data, p_buffer, p_bytes, &r_received)); -} - -int StreamPeerGDNative::get_available_bytes() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_available_bytes(interface->data); -} - -extern "C" { - -void GDAPI godot_net_bind_stream_peer(godot_object *p_obj, const godot_net_stream_peer *p_interface) { - ((StreamPeerGDNative *)p_obj)->set_native_stream_peer(p_interface); -} -} diff --git a/modules/gdnative/net/stream_peer_gdnative.h b/modules/gdnative/net/stream_peer_gdnative.h deleted file mode 100644 index dd5abceb83..0000000000 --- a/modules/gdnative/net/stream_peer_gdnative.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************/ -/* stream_peer_gdnative.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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_GDNATIVE_H -#define STREAM_PEER_GDNATIVE_H - -#include "core/io/stream_peer.h" -#include "modules/gdnative/gdnative.h" -#include "modules/gdnative/include/net/godot_net.h" - -class StreamPeerGDNative : public StreamPeer { - GDCLASS(StreamPeerGDNative, StreamPeer); - -protected: - static void _bind_methods(); - const godot_net_stream_peer *interface; - -public: - StreamPeerGDNative(); - ~StreamPeerGDNative(); - - /* Sets the interface implementation from GDNative */ - void set_native_stream_peer(const godot_net_stream_peer *p_interface); - - /* Specific to StreamPeer */ - Error put_data(const uint8_t *p_data, int p_bytes) override; - Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override; - Error get_data(uint8_t *p_buffer, int p_bytes) override; - Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override; - int get_available_bytes() const override; -}; - -#endif // STREAM_PEER_GDNATIVE_H diff --git a/modules/gdnative/net/webrtc_gdnative.cpp b/modules/gdnative/net/webrtc_gdnative.cpp deleted file mode 100644 index 76ccbad009..0000000000 --- a/modules/gdnative/net/webrtc_gdnative.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************/ -/* webrtc_gdnative.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 "modules/gdnative/gdnative.h" -#include "modules/gdnative/include/net/godot_net.h" - -#ifdef WEBRTC_GDNATIVE_ENABLED -#include "modules/webrtc/webrtc_data_channel_gdnative.h" -#include "modules/webrtc/webrtc_peer_connection_gdnative.h" -#endif - -extern "C" { - -void GDAPI godot_net_bind_webrtc_peer_connection(godot_object *p_obj, const godot_net_webrtc_peer_connection *p_impl) { -#ifdef WEBRTC_GDNATIVE_ENABLED - ((WebRTCPeerConnectionGDNative *)p_obj)->set_native_webrtc_peer_connection(p_impl); -#endif -} - -void GDAPI godot_net_bind_webrtc_data_channel(godot_object *p_obj, const godot_net_webrtc_data_channel *p_impl) { -#ifdef WEBRTC_GDNATIVE_ENABLED - ((WebRTCDataChannelGDNative *)p_obj)->set_native_webrtc_data_channel(p_impl); -#endif -} - -godot_error GDAPI godot_net_set_webrtc_library(const godot_net_webrtc_library *p_lib) { -#ifdef WEBRTC_GDNATIVE_ENABLED - return (godot_error)WebRTCPeerConnectionGDNative::set_default_library(p_lib); -#else - return (godot_error)ERR_UNAVAILABLE; -#endif -} -} diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index e4c2b20224..a4ab5663ef 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -35,7 +35,6 @@ #include "gdnative.h" #include "nativescript/register_types.h" -#include "net/register_types.h" #include "pluginscript/register_types.h" #include "videodecoder/register_types.h" @@ -265,7 +264,6 @@ void register_gdnative_types() { GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall); - register_net_types(); register_nativescript_types(); register_pluginscript_types(); register_videodecoder_types(); @@ -329,7 +327,6 @@ void unregister_gdnative_types() { unregister_videodecoder_types(); unregister_pluginscript_types(); unregister_nativescript_types(); - unregister_net_types(); memdelete(GDNativeCallRegistry::singleton); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 2f8a054b2a..044ac4b661 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -637,7 +637,7 @@ static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String } static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_annotation, int p_argument, const String p_quote_style, Map<String, ScriptCodeCompletionOption> &r_result) { - if (p_annotation->name == "@export_range" || p_annotation->name == "@export_exp_range") { + if (p_annotation->name == "@export_range") { if (p_argument == 3 || p_argument == 4) { // Slider hint. ScriptCodeCompletionOption slider1("or_greater", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 9ea9fc61de..6186d0edee 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -88,9 +88,9 @@ static String _get_var_type(const Variant *p_var) { Object *bobj = p_var->get_validated_object_with_check(was_freed); if (!bobj) { if (was_freed) { - basestr = "null instance"; - } else { basestr = "previously freed"; + } else { + basestr = "null instance"; } } else { basestr = bobj->get_class(); @@ -1233,7 +1233,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GD_ERR_BREAK(to_type < 0 || to_type >= Variant::VARIANT_MAX); #ifdef DEBUG_ENABLED - if (src->get_type() == Variant::OBJECT && !src->operator ObjectID().is_ref_counted() && ObjectDB::get_instance(src->operator ObjectID()) == nullptr) { + if (src->operator Object *() && !src->get_validated_object()) { err_text = "Trying to cast a freed object."; OPCODE_BREAK; } @@ -1263,7 +1263,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GD_ERR_BREAK(!nc); #ifdef DEBUG_ENABLED - if (src->get_type() == Variant::OBJECT && !src->operator ObjectID().is_ref_counted() && ObjectDB::get_instance(src->operator ObjectID()) == nullptr) { + if (src->operator Object *() && !src->get_validated_object()) { err_text = "Trying to cast a freed object."; OPCODE_BREAK; } @@ -1295,7 +1295,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GD_ERR_BREAK(!base_type); #ifdef DEBUG_ENABLED - if (src->get_type() == Variant::OBJECT && !src->operator ObjectID().is_ref_counted() && ObjectDB::get_instance(src->operator ObjectID()) == nullptr) { + if (src->operator Object *() && !src->get_validated_object()) { err_text = "Trying to cast a freed object."; OPCODE_BREAK; } diff --git a/modules/gltf/doc_classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml index 91df7d8014..b4f03cd1ed 100644 --- a/modules/gltf/doc_classes/GLTFLight.xml +++ b/modules/gltf/doc_classes/GLTFLight.xml @@ -7,17 +7,25 @@ <tutorials> </tutorials> <members> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0, 0, 0, 1)"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> + The [Color] of the light. Defaults to white. A black color causes the light to have no effect. </member> <member name="inner_cone_angle" type="float" setter="set_inner_cone_angle" getter="get_inner_cone_angle" default="0.0"> + The inner angle of the cone in a spotlight. Must be less than or equal to the outer cone angle. + Within this angle, the light is at full brightness. Between the inner and outer cone angles, there is a transition from full brightness to zero brightness. When creating a Godot [SpotLight3D], the ratio between the inner and outer cone angles is used to calculate the attenuation of the light. </member> - <member name="intensity" type="float" setter="set_intensity" getter="get_intensity" default="0.0"> + <member name="intensity" type="float" setter="set_intensity" getter="get_intensity" default="1.0"> + The intensity of the light. This is expressed in candelas (lumens per steradian) for point and spot lights, and lux (lumens per m²) for directional lights. When creating a Godot light, this value is converted to a unitless multiplier. </member> <member name="light_type" type="String" setter="set_light_type" getter="get_light_type" default=""""> + The type of the light. The values accepted by Godot are "point", "spot", and "directional", which correspond to Godot's [OmniLight3D], [SpotLight3D], and [DirectionalLight3D] respectively. </member> - <member name="outer_cone_angle" type="float" setter="set_outer_cone_angle" getter="get_outer_cone_angle" default="0.0"> + <member name="outer_cone_angle" type="float" setter="set_outer_cone_angle" getter="get_outer_cone_angle" default="0.785398"> + The outer angle of the cone in a spotlight. Must be greater than or equal to the inner angle. + At this angle, the light drops off to zero brightness. Between the inner and outer cone angles, there is a transition from full brightness to zero brightness. If this angle is a half turn, then the spotlight emits in all directions. When creating a Godot [SpotLight3D], the outer cone angle is used as the angle of the spotlight. </member> - <member name="range" type="float" setter="set_range" getter="get_range" default="0.0"> + <member name="range" type="float" setter="set_range" getter="get_range" default="inf"> + The range of the light, beyond which the light has no effect. GLTF lights with no range defined behave like physical lights (which have infinite range). When creating a Godot light, the range is clamped to 4096. </member> </members> </class> diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index df2856ec7c..a92eb88edb 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -3757,10 +3757,7 @@ void GLTFDocument::spec_gloss_to_metal_base_color(const Color &p_specular_factor r_base_color.g = Math::lerp(base_color_from_diffuse.g, base_color_from_specular.g, r_metallic * r_metallic); r_base_color.b = Math::lerp(base_color_from_diffuse.b, base_color_from_specular.b, r_metallic * r_metallic); r_base_color.a = p_diffuse.a; - r_base_color.r = CLAMP(r_base_color.r, 0.0f, 1.0f); - r_base_color.g = CLAMP(r_base_color.g, 0.0f, 1.0f); - r_base_color.b = CLAMP(r_base_color.b, 0.0f, 1.0f); - r_base_color.a = CLAMP(r_base_color.a, 0.0f, 1.0f); + r_base_color = r_base_color.clamp(); } GLTFNodeIndex GLTFDocument::_find_highest_node(Ref<GLTFState> state, const Vector<GLTFNodeIndex> &subset) { @@ -5074,7 +5071,7 @@ Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent, const float range = CLAMP(l->range, 0, 4096); // Doubling the range will double the effective brightness, so we need double attenuation (half brightness). // We want to have double intensity give double brightness, so we need half the attenuation. - const float attenuation = range / intensity; + const float attenuation = range / (intensity * 2048); if (l->light_type == "point") { OmniLight3D *light = memnew(OmniLight3D); light->set_param(OmniLight3D::PARAM_ATTENUATION, attenuation); @@ -5150,13 +5147,13 @@ GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_lig OmniLight3D *light = cast_to<OmniLight3D>(p_light); l->range = light->get_param(OmniLight3D::PARAM_RANGE); float attenuation = p_light->get_param(OmniLight3D::PARAM_ATTENUATION); - l->intensity = l->range / attenuation; + l->intensity = l->range / (attenuation * 2048); } else if (cast_to<SpotLight3D>(p_light)) { l->light_type = "spot"; SpotLight3D *light = cast_to<SpotLight3D>(p_light); l->range = light->get_param(SpotLight3D::PARAM_RANGE); float attenuation = light->get_param(SpotLight3D::PARAM_ATTENUATION); - l->intensity = l->range / attenuation; + l->intensity = l->range / (attenuation * 2048); l->outer_cone_angle = Math::deg2rad(light->get_param(SpotLight3D::PARAM_SPOT_ANGLE)); // This equation is the inverse of the import equation (which has a desmos link). diff --git a/modules/gltf/gltf_light.h b/modules/gltf/gltf_light.h index 079fb18151..62a20d2f16 100644 --- a/modules/gltf/gltf_light.h +++ b/modules/gltf/gltf_light.h @@ -42,12 +42,12 @@ protected: static void _bind_methods(); private: - Color color; - float intensity = 0.0f; + Color color = Color(1.0f, 1.0f, 1.0f); + float intensity = 1.0f; String light_type; - float range = 0.0f; + float range = INFINITY; float inner_cone_angle = 0.0f; - float outer_cone_angle = 0.0f; + float outer_cone_angle = Math_TAU / 8.0f; public: Color get_color(); diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 487e6deac0..116c0e00f9 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -377,10 +377,7 @@ int GridMap::get_cell_item_orientation(const Vector3i &p_position) const { } Vector3i GridMap::world_to_map(const Vector3 &p_world_position) const { - Vector3 map_position = p_world_position / cell_size; - map_position.x = floor(map_position.x); - map_position.y = floor(map_position.y); - map_position.z = floor(map_position.z); + Vector3 map_position = (p_world_position / cell_size).floor(); return Vector3i(map_position); } diff --git a/modules/mobile_vr/register_types.cpp b/modules/mobile_vr/register_types.cpp index 47d1fe482c..233c16531a 100644 --- a/modules/mobile_vr/register_types.cpp +++ b/modules/mobile_vr/register_types.cpp @@ -32,15 +32,30 @@ #include "mobile_vr_interface.h" +Ref<MobileVRInterface> mobile_vr; + void register_mobile_vr_types() { GDREGISTER_CLASS(MobileVRInterface); if (XRServer::get_singleton()) { - Ref<MobileVRInterface> mobile_vr; mobile_vr.instantiate(); XRServer::get_singleton()->add_interface(mobile_vr); } } void unregister_mobile_vr_types() { + if (mobile_vr.is_valid()) { + // uninitialise our interface if it is initialised + if (mobile_vr->is_initialized()) { + mobile_vr->uninitialize(); + } + + // unregister our interface from the XR server + if (XRServer::get_singleton()) { + XRServer::get_singleton()->remove_interface(mobile_vr); + } + + // and release + mobile_vr.unref(); + } } diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 6cc7ddb424..af7c54dd5b 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -3511,10 +3511,10 @@ int CSharpScript::get_member_line(const StringName &p_member) const { } Multiplayer::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_member) const { - if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute))) { + if (p_member->has_attribute(CACHED_CLASS(AnyAttribute))) { return Multiplayer::RPC_MODE_ANY; } - if (p_member->has_attribute(CACHED_CLASS(PuppetAttribute))) { + if (p_member->has_attribute(CACHED_CLASS(AuthorityAttribute))) { return Multiplayer::RPC_MODE_AUTHORITY; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs index 2dedba2be3..1da91ea867 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs @@ -3,8 +3,8 @@ using System; namespace Godot { [AttributeUsage(AttributeTargets.Method)] - public class RemoteAttribute : Attribute { } + public class AnyAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method)] - public class PuppetAttribute : Attribute { } + public class AuthorityAttribute : Attribute { } } diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp index 8b215a66c2..34e845a589 100644 --- a/modules/mono/mono_gd/gd_mono_cache.cpp +++ b/modules/mono/mono_gd/gd_mono_cache.cpp @@ -140,8 +140,8 @@ void CachedData::clear_godot_api_cache() { field_ExportAttribute_hintString = nullptr; class_SignalAttribute = nullptr; class_ToolAttribute = nullptr; - class_RemoteAttribute = nullptr; - class_PuppetAttribute = nullptr; + class_AnyAttribute = nullptr; + class_AuthorityAttribute = nullptr; class_GodotMethodAttribute = nullptr; field_GodotMethodAttribute_methodName = nullptr; class_ScriptPathAttribute = nullptr; @@ -265,8 +265,8 @@ void update_godot_api_cache() { CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString")); CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute)); CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute)); - CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute)); - CACHE_CLASS_AND_CHECK(PuppetAttribute, GODOT_API_CLASS(PuppetAttribute)); + CACHE_CLASS_AND_CHECK(AnyAttribute, GODOT_API_CLASS(AnyAttribute)); + CACHE_CLASS_AND_CHECK(AuthorityAttribute, GODOT_API_CLASS(AuthorityAttribute)); CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute)); CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName")); CACHE_CLASS_AND_CHECK(ScriptPathAttribute, GODOT_API_CLASS(ScriptPathAttribute)); diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h index fd28bbda14..e60a4d5279 100644 --- a/modules/mono/mono_gd/gd_mono_cache.h +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -111,8 +111,8 @@ struct CachedData { GDMonoField *field_ExportAttribute_hintString; GDMonoClass *class_SignalAttribute; GDMonoClass *class_ToolAttribute; - GDMonoClass *class_RemoteAttribute; - GDMonoClass *class_PuppetAttribute; + GDMonoClass *class_AnyAttribute; + GDMonoClass *class_AuthorityAttribute; GDMonoClass *class_GodotMethodAttribute; GDMonoField *field_GodotMethodAttribute_methodName; GDMonoClass *class_ScriptPathAttribute; diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 3150ca0bc8..962bf79150 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -664,7 +664,7 @@ void NavMap::sync() { } else { other1 = other_edge_p1.lerp(other_edge_p2, (1.0 - projected_p1_ratio) / (projected_p2_ratio - projected_p1_ratio)); } - if ((self1 - other1).length() > edge_connection_margin) { + if (other1.distance_to(self1) > edge_connection_margin) { continue; } @@ -675,7 +675,7 @@ void NavMap::sync() { } else { other2 = other_edge_p1.lerp(other_edge_p2, (0.0 - projected_p1_ratio) / (projected_p2_ratio - projected_p1_ratio)); } - if ((self2 - other2).length() > edge_connection_margin) { + if (other2.distance_to(self2) > edge_connection_margin) { continue; } diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub index 1fdc8fe1b3..4820cf7608 100644 --- a/modules/raycast/SCsub +++ b/modules/raycast/SCsub @@ -79,6 +79,7 @@ if env["builtin_embree"]: env.Append(LIBS=["psapi"]) env_thirdparty = env_raycast.Clone() + env_thirdparty.force_optimization_on_debug() env_thirdparty.disable_warnings() env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index ef1411fb3b..c93f353cea 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -3573,6 +3573,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re shaped_text_shape(p_shaped_line); } + sd->text_trimmed = false; sd->overrun_trim_data.ellipsis_glyph_buf.clear(); bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 8a1bd93c65..1323aa80ce 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -2683,6 +2683,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, re shaped_text_shape(p_shaped_line); } + sd->text_trimmed = false; sd->overrun_trim_data.ellipsis_glyph_buf.clear(); bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS; diff --git a/modules/webrtc/SCsub b/modules/webrtc/SCsub index 31b8a73bf2..e6b9959840 100644 --- a/modules/webrtc/SCsub +++ b/modules/webrtc/SCsub @@ -4,11 +4,6 @@ Import("env") Import("env_modules") env_webrtc = env_modules.Clone() -use_gdnative = env_webrtc["module_gdnative_enabled"] - -if use_gdnative: # GDNative is retained in Javascript for export compatibility - env_webrtc.Append(CPPDEFINES=["WEBRTC_GDNATIVE_ENABLED"]) - env_webrtc.Prepend(CPPPATH=["#modules/gdnative/include/"]) if env["platform"] == "javascript": # Our JavaScript/C++ interface. diff --git a/modules/webrtc/config.py b/modules/webrtc/config.py index 3281415f38..4ad918833a 100644 --- a/modules/webrtc/config.py +++ b/modules/webrtc/config.py @@ -11,6 +11,8 @@ def get_doc_classes(): "WebRTCPeerConnection", "WebRTCDataChannel", "WebRTCMultiplayerPeer", + "WebRTCPeerConnectionExtension", + "WebRTCDataChannelExtension", ] diff --git a/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml new file mode 100644 index 0000000000..26a4391b83 --- /dev/null +++ b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="WebRTCDataChannelExtension" inherits="WebRTCDataChannel" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="_close" qualifiers="virtual"> + <return type="void" /> + <description> + </description> + </method> + <method name="_get_available_packet_count" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_buffered_amount" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_id" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_label" qualifiers="virtual const"> + <return type="String" /> + <description> + </description> + </method> + <method name="_get_max_packet_life_time" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_max_packet_size" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_max_retransmits" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_packet" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="r_buffer" type="const void*" /> + <argument index="1" name="r_buffer_size" type="int32_t*" /> + <description> + </description> + </method> + <method name="_get_protocol" qualifiers="virtual const"> + <return type="String" /> + <description> + </description> + </method> + <method name="_get_ready_state" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_write_mode" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_is_negotiated" qualifiers="virtual const"> + <return type="bool" /> + <description> + </description> + </method> + <method name="_is_ordered" qualifiers="virtual const"> + <return type="bool" /> + <description> + </description> + </method> + <method name="_poll" qualifiers="virtual"> + <return type="int" /> + <description> + </description> + </method> + <method name="_put_packet" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_buffer" type="const void*" /> + <argument index="1" name="p_buffer_size" type="int" /> + <description> + </description> + </method> + <method name="_set_write_mode" qualifiers="virtual"> + <return type="void" /> + <argument index="0" name="p_write_mode" type="int" /> + <description> + </description> + </method> + <method name="_was_string_packet" qualifiers="virtual const"> + <return type="bool" /> + <description> + </description> + </method> + </methods> +</class> diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml index 09556fa7cb..a8360a4d45 100644 --- a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml +++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml @@ -68,8 +68,4 @@ </description> </method> </methods> - <members> - <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" /> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="TransferMode" default="2" /> - </members> </class> diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml new file mode 100644 index 0000000000..d296fcd6e7 --- /dev/null +++ b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="WebRTCPeerConnectionExtension" inherits="WebRTCPeerConnection" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="_add_ice_candidate" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_sdp_mid_name" type="String" /> + <argument index="1" name="p_sdp_mline_index" type="int" /> + <argument index="2" name="p_sdp_name" type="String" /> + <description> + </description> + </method> + <method name="_close" qualifiers="virtual"> + <return type="void" /> + <description> + </description> + </method> + <method name="_create_data_channel" qualifiers="virtual"> + <return type="Object" /> + <argument index="0" name="p_label" type="String" /> + <argument index="1" name="p_config" type="Dictionary" /> + <description> + </description> + </method> + <method name="_create_offer" qualifiers="virtual"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_connection_state" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_initialize" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_config" type="Dictionary" /> + <description> + </description> + </method> + <method name="_poll" qualifiers="virtual"> + <return type="int" /> + <description> + </description> + </method> + <method name="_set_local_description" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_type" type="String" /> + <argument index="1" name="p_sdp" type="String" /> + <description> + </description> + </method> + <method name="_set_remote_description" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_type" type="String" /> + <argument index="1" name="p_sdp" type="String" /> + <description> + </description> + </method> + <method name="make_default"> + <return type="void" /> + <description> + </description> + </method> + </methods> +</class> diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp index 63ecc03a4c..8110e4a048 100644 --- a/modules/webrtc/register_types.cpp +++ b/modules/webrtc/register_types.cpp @@ -31,17 +31,11 @@ #include "register_types.h" #include "core/config/project_settings.h" #include "webrtc_data_channel.h" +#include "webrtc_multiplayer_peer.h" #include "webrtc_peer_connection.h" -#ifdef JAVASCRIPT_ENABLED -#include "emscripten.h" -#include "webrtc_peer_connection_js.h" -#endif -#ifdef WEBRTC_GDNATIVE_ENABLED -#include "webrtc_data_channel_gdnative.h" -#include "webrtc_peer_connection_gdnative.h" -#endif -#include "webrtc_multiplayer_peer.h" +#include "webrtc_data_channel_extension.h" +#include "webrtc_peer_connection_extension.h" void register_webrtc_types() { #define _SET_HINT(NAME, _VAL_, _MAX_) \ @@ -50,18 +44,12 @@ void register_webrtc_types() { _SET_HINT(WRTC_IN_BUF, 64, 4096); -#ifdef JAVASCRIPT_ENABLED - WebRTCPeerConnectionJS::make_default(); -#elif defined(WEBRTC_GDNATIVE_ENABLED) - WebRTCPeerConnectionGDNative::make_default(); -#endif - ClassDB::register_custom_instance_class<WebRTCPeerConnection>(); -#ifdef WEBRTC_GDNATIVE_ENABLED - GDREGISTER_CLASS(WebRTCPeerConnectionGDNative); - GDREGISTER_CLASS(WebRTCDataChannelGDNative); -#endif + GDREGISTER_CLASS(WebRTCPeerConnectionExtension); + GDREGISTER_VIRTUAL_CLASS(WebRTCDataChannel); + GDREGISTER_CLASS(WebRTCDataChannelExtension); + GDREGISTER_CLASS(WebRTCMultiplayerPeer); } diff --git a/modules/webrtc/webrtc_data_channel_extension.cpp b/modules/webrtc/webrtc_data_channel_extension.cpp new file mode 100644 index 0000000000..ae346f6d8e --- /dev/null +++ b/modules/webrtc/webrtc_data_channel_extension.cpp @@ -0,0 +1,215 @@ +/*************************************************************************/ +/* webrtc_data_channel_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "webrtc_data_channel_extension.h" + +void WebRTCDataChannelExtension::_bind_methods() { + ADD_PROPERTY_DEFAULT("write_mode", WRITE_MODE_BINARY); + + GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size"); + GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size"); + GDVIRTUAL_BIND(_get_available_packet_count); + GDVIRTUAL_BIND(_get_max_packet_size); + + GDVIRTUAL_BIND(_poll); + GDVIRTUAL_BIND(_close); + + GDVIRTUAL_BIND(_set_write_mode, "p_write_mode"); + GDVIRTUAL_BIND(_get_write_mode); + + GDVIRTUAL_BIND(_was_string_packet); + GDVIRTUAL_BIND(_get_ready_state); + GDVIRTUAL_BIND(_get_label); + GDVIRTUAL_BIND(_is_ordered); + GDVIRTUAL_BIND(_get_id); + GDVIRTUAL_BIND(_get_max_packet_life_time); + GDVIRTUAL_BIND(_get_max_retransmits); + GDVIRTUAL_BIND(_get_protocol); + GDVIRTUAL_BIND(_is_negotiated); + GDVIRTUAL_BIND(_get_buffered_amount); +} + +int WebRTCDataChannelExtension::get_available_packet_count() const { + int count; + if (GDVIRTUAL_CALL(_get_available_packet_count, count)) { + return count; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_available_packet_count is unimplemented!"); + return -1; +} + +Error WebRTCDataChannelExtension::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + int err; + if (GDVIRTUAL_CALL(_get_packet, r_buffer, &r_buffer_size, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_packet_native is unimplemented!"); + return FAILED; +} + +Error WebRTCDataChannelExtension::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + int err; + if (GDVIRTUAL_CALL(_put_packet, p_buffer, p_buffer_size, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_put_packet_native is unimplemented!"); + return FAILED; +} + +int WebRTCDataChannelExtension::get_max_packet_size() const { + int size; + if (GDVIRTUAL_CALL(_get_max_packet_size, size)) { + return size; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_max_packet_size is unimplemented!"); + return 0; +} + +Error WebRTCDataChannelExtension::poll() { + int err; + if (GDVIRTUAL_CALL(_poll, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_poll is unimplemented!"); + return ERR_UNCONFIGURED; +} + +void WebRTCDataChannelExtension::close() { + if (GDVIRTUAL_CALL(_close)) { + return; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_close is unimplemented!"); +} + +void WebRTCDataChannelExtension::set_write_mode(WriteMode p_mode) { + if (GDVIRTUAL_CALL(_set_write_mode, p_mode)) { + return; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_set_write_mode is unimplemented!"); +} + +WebRTCDataChannel::WriteMode WebRTCDataChannelExtension::get_write_mode() const { + int mode; + if (GDVIRTUAL_CALL(_get_write_mode, mode)) { + return (WriteMode)mode; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_write_mode is unimplemented!"); + return WRITE_MODE_BINARY; +} + +bool WebRTCDataChannelExtension::was_string_packet() const { + bool was_string; + if (GDVIRTUAL_CALL(_was_string_packet, was_string)) { + return was_string; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_was_string_packet is unimplemented!"); + return false; +} + +WebRTCDataChannel::ChannelState WebRTCDataChannelExtension::get_ready_state() const { + int state; + if (GDVIRTUAL_CALL(_get_ready_state, state)) { + return (ChannelState)state; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_ready_state is unimplemented!"); + return STATE_CLOSED; +} + +String WebRTCDataChannelExtension::get_label() const { + String label; + if (GDVIRTUAL_CALL(_get_label, label)) { + return label; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_label is unimplemented!"); + return label; +} + +bool WebRTCDataChannelExtension::is_ordered() const { + bool ordered; + if (GDVIRTUAL_CALL(_is_ordered, ordered)) { + return ordered; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_is_ordered is unimplemented!"); + return false; +} + +int WebRTCDataChannelExtension::get_id() const { + int id; + if (GDVIRTUAL_CALL(_get_id, id)) { + return id; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_id is unimplemented!"); + return -1; +} + +int WebRTCDataChannelExtension::get_max_packet_life_time() const { + int lifetime; + if (GDVIRTUAL_CALL(_get_max_packet_life_time, lifetime)) { + return lifetime; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_max_packet_life_time is unimplemented!"); + return -1; +} + +int WebRTCDataChannelExtension::get_max_retransmits() const { + int retransmits; + if (GDVIRTUAL_CALL(_get_max_retransmits, retransmits)) { + return retransmits; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_max_retransmits is unimplemented!"); + return -1; +} + +String WebRTCDataChannelExtension::get_protocol() const { + String protocol; + if (GDVIRTUAL_CALL(_get_protocol, protocol)) { + return protocol; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_protocol is unimplemented!"); + return protocol; +} + +bool WebRTCDataChannelExtension::is_negotiated() const { + bool negotiated; + if (GDVIRTUAL_CALL(_is_negotiated, negotiated)) { + return negotiated; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_is_negotiated is unimplemented!"); + return false; +} + +int WebRTCDataChannelExtension::get_buffered_amount() const { + int amount; + if (GDVIRTUAL_CALL(_get_buffered_amount, amount)) { + return amount; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_buffered_amount is unimplemented!"); + return -1; +} diff --git a/modules/webrtc/webrtc_data_channel_gdnative.h b/modules/webrtc/webrtc_data_channel_extension.h index 5c80edd48c..eec96b4c62 100644 --- a/modules/webrtc/webrtc_data_channel_gdnative.h +++ b/modules/webrtc/webrtc_data_channel_extension.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* webrtc_data_channel_gdnative.h */ +/* webrtc_data_channel_extension.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,26 +28,22 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef WEBRTC_DATA_CHANNEL_GDNATIVE_H -#define WEBRTC_DATA_CHANNEL_GDNATIVE_H +#ifndef WEBRTC_DATA_CHANNEL_EXTENSION_H +#define WEBRTC_DATA_CHANNEL_EXTENSION_H -#ifdef WEBRTC_GDNATIVE_ENABLED - -#include "modules/gdnative/include/net/godot_net.h" #include "webrtc_data_channel.h" -class WebRTCDataChannelGDNative : public WebRTCDataChannel { - GDCLASS(WebRTCDataChannelGDNative, WebRTCDataChannel); +#include "core/object/gdvirtual.gen.inc" +#include "core/object/script_language.h" +#include "core/variant/native_ptr.h" + +class WebRTCDataChannelExtension : public WebRTCDataChannel { + GDCLASS(WebRTCDataChannelExtension, WebRTCDataChannel); protected: static void _bind_methods(); -private: - const godot_net_webrtc_data_channel *interface; - public: - void set_native_webrtc_data_channel(const godot_net_webrtc_data_channel *p_impl); - virtual void set_write_mode(WriteMode mode) override; virtual WriteMode get_write_mode() const override; virtual bool was_string_packet() const override; @@ -72,10 +68,31 @@ public: virtual int get_max_packet_size() const override; - WebRTCDataChannelGDNative(); - ~WebRTCDataChannelGDNative(); -}; + /** GDExtension **/ + GDVIRTUAL0RC(int, _get_available_packet_count); + GDVIRTUAL2R(int, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>); + GDVIRTUAL2R(int, _put_packet, GDNativeConstPtr<const uint8_t>, int); + GDVIRTUAL0RC(int, _get_max_packet_size); -#endif // WEBRTC_GDNATIVE_ENABLED + GDVIRTUAL0R(int, _poll); + GDVIRTUAL0(_close); + + GDVIRTUAL1(_set_write_mode, int); + GDVIRTUAL0RC(int, _get_write_mode); + + GDVIRTUAL0RC(bool, _was_string_packet); + + GDVIRTUAL0RC(int, _get_ready_state); + GDVIRTUAL0RC(String, _get_label); + GDVIRTUAL0RC(bool, _is_ordered); + GDVIRTUAL0RC(int, _get_id); + GDVIRTUAL0RC(int, _get_max_packet_life_time); + GDVIRTUAL0RC(int, _get_max_retransmits); + GDVIRTUAL0RC(String, _get_protocol); + GDVIRTUAL0RC(bool, _is_negotiated); + GDVIRTUAL0RC(int, _get_buffered_amount); + + WebRTCDataChannelExtension() {} +}; -#endif // WEBRTC_DATA_CHANNEL_GDNATIVE_H +#endif // WEBRTC_DATA_CHANNEL_EXTENSION_H diff --git a/modules/webrtc/webrtc_data_channel_gdnative.cpp b/modules/webrtc/webrtc_data_channel_gdnative.cpp deleted file mode 100644 index 10a3367557..0000000000 --- a/modules/webrtc/webrtc_data_channel_gdnative.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/*************************************************************************/ -/* webrtc_data_channel_gdnative.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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. */ -/*************************************************************************/ - -#ifdef WEBRTC_GDNATIVE_ENABLED - -#include "webrtc_data_channel_gdnative.h" - -#include "core/io/resource_loader.h" -#include "modules/gdnative/nativescript/nativescript.h" - -void WebRTCDataChannelGDNative::_bind_methods() { - ADD_PROPERTY_DEFAULT("write_mode", WRITE_MODE_BINARY); -} - -WebRTCDataChannelGDNative::WebRTCDataChannelGDNative() { - interface = nullptr; -} - -WebRTCDataChannelGDNative::~WebRTCDataChannelGDNative() { -} - -Error WebRTCDataChannelGDNative::poll() { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->poll(interface->data); -} - -void WebRTCDataChannelGDNative::close() { - ERR_FAIL_COND(interface == nullptr); - interface->close(interface->data); -} - -void WebRTCDataChannelGDNative::set_write_mode(WriteMode p_mode) { - ERR_FAIL_COND(interface == nullptr); - interface->set_write_mode(interface->data, p_mode); -} - -WebRTCDataChannel::WriteMode WebRTCDataChannelGDNative::get_write_mode() const { - ERR_FAIL_COND_V(interface == nullptr, WRITE_MODE_BINARY); - return (WriteMode)interface->get_write_mode(interface->data); -} - -bool WebRTCDataChannelGDNative::was_string_packet() const { - ERR_FAIL_COND_V(interface == nullptr, false); - return interface->was_string_packet(interface->data); -} - -WebRTCDataChannel::ChannelState WebRTCDataChannelGDNative::get_ready_state() const { - ERR_FAIL_COND_V(interface == nullptr, STATE_CLOSED); - return (ChannelState)interface->get_ready_state(interface->data); -} - -String WebRTCDataChannelGDNative::get_label() const { - ERR_FAIL_COND_V(interface == nullptr, ""); - return String(interface->get_label(interface->data)); -} - -bool WebRTCDataChannelGDNative::is_ordered() const { - ERR_FAIL_COND_V(interface == nullptr, false); - return interface->is_ordered(interface->data); -} - -int WebRTCDataChannelGDNative::get_id() const { - ERR_FAIL_COND_V(interface == nullptr, -1); - return interface->get_id(interface->data); -} - -int WebRTCDataChannelGDNative::get_max_packet_life_time() const { - ERR_FAIL_COND_V(interface == nullptr, -1); - return interface->get_max_packet_life_time(interface->data); -} - -int WebRTCDataChannelGDNative::get_max_retransmits() const { - ERR_FAIL_COND_V(interface == nullptr, -1); - return interface->get_max_retransmits(interface->data); -} - -String WebRTCDataChannelGDNative::get_protocol() const { - ERR_FAIL_COND_V(interface == nullptr, ""); - return String(interface->get_protocol(interface->data)); -} - -bool WebRTCDataChannelGDNative::is_negotiated() const { - ERR_FAIL_COND_V(interface == nullptr, false); - return interface->is_negotiated(interface->data); -} - -int WebRTCDataChannelGDNative::get_buffered_amount() const { - ERR_FAIL_COND_V(interface == NULL, 0); - return interface->get_buffered_amount(interface->data); -} - -Error WebRTCDataChannelGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size); -} - -Error WebRTCDataChannelGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size); -} - -int WebRTCDataChannelGDNative::get_max_packet_size() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_max_packet_size(interface->data); -} - -int WebRTCDataChannelGDNative::get_available_packet_count() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_available_packet_count(interface->data); -} - -void WebRTCDataChannelGDNative::set_native_webrtc_data_channel(const godot_net_webrtc_data_channel *p_impl) { - interface = p_impl; -} - -#endif // WEBRTC_GDNATIVE_ENABLED diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp index d60d694df1..48117f05f2 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.cpp +++ b/modules/webrtc/webrtc_multiplayer_peer.cpp @@ -43,22 +43,6 @@ void WebRTCMultiplayerPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("close"), &WebRTCMultiplayerPeer::close); } -void WebRTCMultiplayerPeer::set_transfer_channel(int p_channel) { - transfer_channel = p_channel; -} - -int WebRTCMultiplayerPeer::get_transfer_channel() const { - return transfer_channel; -} - -void WebRTCMultiplayerPeer::set_transfer_mode(Multiplayer::TransferMode p_mode) { - transfer_mode = p_mode; -} - -Multiplayer::TransferMode WebRTCMultiplayerPeer::get_transfer_mode() const { - return transfer_mode; -} - void WebRTCMultiplayerPeer::set_target_peer(int p_peer_id) { target_peer = p_peer_id; } @@ -188,14 +172,6 @@ void WebRTCMultiplayerPeer::_find_next_peer() { next_packet_peer = 0; } -void WebRTCMultiplayerPeer::set_refuse_new_connections(bool p_enable) { - refuse_connections = p_enable; -} - -bool WebRTCMultiplayerPeer::is_refusing_new_connections() const { - return refuse_connections; -} - MultiplayerPeer::ConnectionStatus WebRTCMultiplayerPeer::get_connection_status() const { return connection_status; } @@ -279,7 +255,7 @@ Dictionary WebRTCMultiplayerPeer::get_peers() { Error WebRTCMultiplayerPeer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime) { ERR_FAIL_COND_V(p_peer_id < 0 || p_peer_id > ~(1 << 31), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_unreliable_lifetime < 0, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(refuse_connections, ERR_UNAUTHORIZED); + ERR_FAIL_COND_V(is_refusing_new_connections(), ERR_UNAUTHORIZED); // Peer must be valid, and in new state (to create data channels) ERR_FAIL_COND_V(!p_peer.is_valid(), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_peer->get_connection_state() != WebRTCPeerConnection::STATE_NEW, ERR_INVALID_PARAMETER); @@ -352,9 +328,9 @@ Error WebRTCMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, ERR_UNCONFIGURED); - int ch = transfer_channel; + int ch = get_transfer_channel(); if (ch == 0) { - switch (transfer_mode) { + switch (get_transfer_mode()) { case Multiplayer::TRANSFER_MODE_RELIABLE: ch = CH_RELIABLE; break; diff --git a/modules/webrtc/webrtc_multiplayer_peer.h b/modules/webrtc/webrtc_multiplayer_peer.h index 80a6491492..4a7e9ad7c8 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.h +++ b/modules/webrtc/webrtc_multiplayer_peer.h @@ -65,10 +65,7 @@ private: uint32_t unique_id = 0; int target_peer = 0; int client_count = 0; - bool refuse_connections = false; ConnectionStatus connection_status = CONNECTION_DISCONNECTED; - int transfer_channel = 0; - Multiplayer::TransferMode transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; int next_packet_peer = 0; bool server_compat = false; @@ -97,10 +94,6 @@ public: int get_max_packet_size() const override; // MultiplayerPeer - void set_transfer_channel(int p_channel) override; - int get_transfer_channel() const override; - void set_transfer_mode(Multiplayer::TransferMode p_mode) override; - Multiplayer::TransferMode get_transfer_mode() const override; void set_target_peer(int p_peer_id) override; int get_unique_id() const override; @@ -110,9 +103,6 @@ public: void poll() override; - void set_refuse_new_connections(bool p_enable) override; - bool is_refusing_new_connections() const override; - ConnectionStatus get_connection_status() const override; }; diff --git a/modules/webrtc/webrtc_peer_connection.cpp b/modules/webrtc/webrtc_peer_connection.cpp index 3e2938bf7d..ad28aa76c7 100644 --- a/modules/webrtc/webrtc_peer_connection.cpp +++ b/modules/webrtc/webrtc_peer_connection.cpp @@ -30,17 +30,29 @@ #include "webrtc_peer_connection.h" -WebRTCPeerConnection *(*WebRTCPeerConnection::_create)() = nullptr; +#ifdef JAVASCRIPT_ENABLED +#include "webrtc_peer_connection_js.h" +#else +#include "webrtc_peer_connection_extension.h" +#endif -Ref<WebRTCPeerConnection> WebRTCPeerConnection::create_ref() { - return create(); +StringName WebRTCPeerConnection::default_extension; + +void WebRTCPeerConnection::set_default_extension(const StringName &p_extension) { + default_extension = p_extension; } WebRTCPeerConnection *WebRTCPeerConnection::create() { - if (!_create) { - return nullptr; +#ifdef JAVASCRIPT_ENABLED + return memnew(WebRTCPeerConnectionJS); +#else + if (default_extension == String()) { + WARN_PRINT_ONCE("No default WebRTC extension configured."); + return memnew(WebRTCPeerConnectionExtension); } - return _create(); + Object *obj = ClassDB::instantiate(default_extension); + return Object::cast_to<WebRTCPeerConnectionExtension>(obj); +#endif } void WebRTCPeerConnection::_bind_methods() { diff --git a/modules/webrtc/webrtc_peer_connection.h b/modules/webrtc/webrtc_peer_connection.h index fcfb9ae9ae..e2ef3e55ad 100644 --- a/modules/webrtc/webrtc_peer_connection.h +++ b/modules/webrtc/webrtc_peer_connection.h @@ -47,11 +47,15 @@ public: STATE_CLOSED }; +private: + static StringName default_extension; + protected: static void _bind_methods(); - static WebRTCPeerConnection *(*_create)(); public: + static void set_default_extension(const StringName &p_name); + virtual ConnectionState get_connection_state() const = 0; virtual Error initialize(Dictionary p_config = Dictionary()) = 0; @@ -63,7 +67,6 @@ public: virtual Error poll() = 0; virtual void close() = 0; - static Ref<WebRTCPeerConnection> create_ref(); static WebRTCPeerConnection *create(); WebRTCPeerConnection(); diff --git a/modules/webrtc/webrtc_peer_connection_extension.cpp b/modules/webrtc/webrtc_peer_connection_extension.cpp new file mode 100644 index 0000000000..33288e66d6 --- /dev/null +++ b/modules/webrtc/webrtc_peer_connection_extension.cpp @@ -0,0 +1,131 @@ +/*************************************************************************/ +/* webrtc_peer_connection_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "webrtc_peer_connection_extension.h" + +void WebRTCPeerConnectionExtension::_bind_methods() { + ClassDB::bind_method(D_METHOD("make_default"), &WebRTCPeerConnectionExtension::make_default); + + GDVIRTUAL_BIND(_get_connection_state); + GDVIRTUAL_BIND(_initialize, "p_config"); + GDVIRTUAL_BIND(_create_data_channel, "p_label", "p_config"); + GDVIRTUAL_BIND(_create_offer); + GDVIRTUAL_BIND(_set_remote_description, "p_type", "p_sdp"); + GDVIRTUAL_BIND(_set_local_description, "p_type", "p_sdp"); + GDVIRTUAL_BIND(_add_ice_candidate, "p_sdp_mid_name", "p_sdp_mline_index", "p_sdp_name"); + GDVIRTUAL_BIND(_poll); + GDVIRTUAL_BIND(_close); +} + +void WebRTCPeerConnectionExtension::make_default() { + ERR_FAIL_COND_MSG(!_get_extension(), vformat("Can't make %s the default without extending it.", get_class())); + WebRTCPeerConnection::set_default_extension(get_class()); +} + +WebRTCPeerConnection::ConnectionState WebRTCPeerConnectionExtension::get_connection_state() const { + int state; + if (GDVIRTUAL_CALL(_get_connection_state, state)) { + return (ConnectionState)state; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_get_connection_state is unimplemented!"); + return STATE_DISCONNECTED; +} + +Error WebRTCPeerConnectionExtension::initialize(Dictionary p_config) { + int err; + if (GDVIRTUAL_CALL(_initialize, p_config, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_initialize is unimplemented!"); + return ERR_UNCONFIGURED; +} + +Ref<WebRTCDataChannel> WebRTCPeerConnectionExtension::create_data_channel(String p_label, Dictionary p_options) { + Object *ret = nullptr; + if (GDVIRTUAL_CALL(_create_data_channel, p_label, p_options, ret)) { + WebRTCDataChannel *ch = Object::cast_to<WebRTCDataChannel>(ret); + ERR_FAIL_COND_V_MSG(ret && !ch, nullptr, "Returned object must be an instance of WebRTCDataChannel."); + return ch; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_create_data_channel is unimplemented!"); + return nullptr; +} + +Error WebRTCPeerConnectionExtension::create_offer() { + int err; + if (GDVIRTUAL_CALL(_create_offer, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_create_offer is unimplemented!"); + return ERR_UNCONFIGURED; +} + +Error WebRTCPeerConnectionExtension::set_local_description(String p_type, String p_sdp) { + int err; + if (GDVIRTUAL_CALL(_set_local_description, p_type, p_sdp, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_set_local_description is unimplemented!"); + return ERR_UNCONFIGURED; +} + +Error WebRTCPeerConnectionExtension::set_remote_description(String p_type, String p_sdp) { + int err; + if (GDVIRTUAL_CALL(_set_remote_description, p_type, p_sdp, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_set_remote_description is unimplemented!"); + return ERR_UNCONFIGURED; +} + +Error WebRTCPeerConnectionExtension::add_ice_candidate(String p_sdp_mid_name, int p_sdp_mline_index, String p_sdp_name) { + int err; + if (GDVIRTUAL_CALL(_add_ice_candidate, p_sdp_mid_name, p_sdp_mline_index, p_sdp_name, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_add_ice_candidate is unimplemented!"); + return ERR_UNCONFIGURED; +} + +Error WebRTCPeerConnectionExtension::poll() { + int err; + if (GDVIRTUAL_CALL(_poll, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_poll is unimplemented!"); + return ERR_UNCONFIGURED; +} + +void WebRTCPeerConnectionExtension::close() { + if (GDVIRTUAL_CALL(_close)) { + return; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_close is unimplemented!"); +} diff --git a/modules/webrtc/webrtc_peer_connection_gdnative.h b/modules/webrtc/webrtc_peer_connection_extension.h index 578af0202f..b3c2039fc1 100644 --- a/modules/webrtc/webrtc_peer_connection_gdnative.h +++ b/modules/webrtc/webrtc_peer_connection_extension.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* webrtc_peer_connection_gdnative.h */ +/* webrtc_peer_connection_extension.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,30 +28,23 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef WEBRTC_PEER_CONNECTION_GDNATIVE_H -#define WEBRTC_PEER_CONNECTION_GDNATIVE_H +#ifndef WEBRTC_PEER_CONNECTION_EXTENSION_H +#define WEBRTC_PEER_CONNECTION_EXTENSION_H -#ifdef WEBRTC_GDNATIVE_ENABLED - -#include "modules/gdnative/include/net/godot_net.h" #include "webrtc_peer_connection.h" -class WebRTCPeerConnectionGDNative : public WebRTCPeerConnection { - GDCLASS(WebRTCPeerConnectionGDNative, WebRTCPeerConnection); +#include "core/object/gdvirtual.gen.inc" +#include "core/object/script_language.h" +#include "core/variant/native_ptr.h" + +class WebRTCPeerConnectionExtension : public WebRTCPeerConnection { + GDCLASS(WebRTCPeerConnectionExtension, WebRTCPeerConnection); protected: static void _bind_methods(); - static WebRTCPeerConnection *_create(); - -private: - static const godot_net_webrtc_library *default_library; - const godot_net_webrtc_peer_connection *interface; public: - static Error set_default_library(const godot_net_webrtc_library *p_library); - static void make_default() { WebRTCPeerConnection::_create = WebRTCPeerConnectionGDNative::_create; } - - void set_native_webrtc_peer_connection(const godot_net_webrtc_peer_connection *p_impl); + void make_default(); virtual ConnectionState get_connection_state() const override; @@ -60,14 +53,22 @@ public: virtual Error create_offer() override; virtual Error set_remote_description(String type, String sdp) override; virtual Error set_local_description(String type, String sdp) override; - virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) override; + virtual Error add_ice_candidate(String p_sdp_mid_name, int p_sdp_mline_index, String p_sdp_name) override; virtual Error poll() override; virtual void close() override; - WebRTCPeerConnectionGDNative(); - ~WebRTCPeerConnectionGDNative(); -}; + /** GDExtension **/ + GDVIRTUAL0RC(int, _get_connection_state); + GDVIRTUAL1R(int, _initialize, Dictionary); + GDVIRTUAL2R(Object *, _create_data_channel, String, Dictionary); + GDVIRTUAL0R(int, _create_offer); + GDVIRTUAL2R(int, _set_remote_description, String, String); + GDVIRTUAL2R(int, _set_local_description, String, String); + GDVIRTUAL3R(int, _add_ice_candidate, String, int, String); + GDVIRTUAL0R(int, _poll); + GDVIRTUAL0(_close); -#endif // WEBRTC_GDNATIVE_ENABLED + WebRTCPeerConnectionExtension() {} +}; -#endif // WEBRTC_PEER_CONNECTION_GDNATIVE_H +#endif // WEBRTC_PEER_CONNECTION_EXTENSION_H diff --git a/modules/webrtc/webrtc_peer_connection_gdnative.cpp b/modules/webrtc/webrtc_peer_connection_gdnative.cpp deleted file mode 100644 index dcf78dfb73..0000000000 --- a/modules/webrtc/webrtc_peer_connection_gdnative.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/*************************************************************************/ -/* webrtc_peer_connection_gdnative.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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. */ -/*************************************************************************/ - -#ifdef WEBRTC_GDNATIVE_ENABLED - -#include "webrtc_peer_connection_gdnative.h" - -#include "core/io/resource_loader.h" -#include "modules/gdnative/nativescript/nativescript.h" -#include "webrtc_data_channel_gdnative.h" - -const godot_net_webrtc_library *WebRTCPeerConnectionGDNative::default_library = nullptr; - -Error WebRTCPeerConnectionGDNative::set_default_library(const godot_net_webrtc_library *p_lib) { - if (default_library) { - const godot_net_webrtc_library *old = default_library; - default_library = nullptr; - old->unregistered(); - } - default_library = p_lib; - return OK; // Maybe add version check and fail accordingly -} - -WebRTCPeerConnection *WebRTCPeerConnectionGDNative::_create() { - WebRTCPeerConnectionGDNative *obj = memnew(WebRTCPeerConnectionGDNative); - ERR_FAIL_COND_V_MSG(!default_library, obj, "Default GDNative WebRTC implementation not defined."); - - // Call GDNative constructor - Error err = (Error)default_library->create_peer_connection(obj); - ERR_FAIL_COND_V_MSG(err != OK, obj, "GDNative default library constructor returned an error."); - - return obj; -} - -void WebRTCPeerConnectionGDNative::_bind_methods() { -} - -WebRTCPeerConnectionGDNative::WebRTCPeerConnectionGDNative() { - interface = nullptr; -} - -WebRTCPeerConnectionGDNative::~WebRTCPeerConnectionGDNative() { -} - -Error WebRTCPeerConnectionGDNative::initialize(Dictionary p_config) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->initialize(interface->data, (const godot_dictionary *)&p_config); -} - -Ref<WebRTCDataChannel> WebRTCPeerConnectionGDNative::create_data_channel(String p_label, Dictionary p_options) { - ERR_FAIL_COND_V(interface == nullptr, nullptr); - return (WebRTCDataChannel *)interface->create_data_channel(interface->data, p_label.utf8().get_data(), (const godot_dictionary *)&p_options); -} - -Error WebRTCPeerConnectionGDNative::create_offer() { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->create_offer(interface->data); -} - -Error WebRTCPeerConnectionGDNative::set_local_description(String p_type, String p_sdp) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->set_local_description(interface->data, p_type.utf8().get_data(), p_sdp.utf8().get_data()); -} - -Error WebRTCPeerConnectionGDNative::set_remote_description(String p_type, String p_sdp) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->set_remote_description(interface->data, p_type.utf8().get_data(), p_sdp.utf8().get_data()); -} - -Error WebRTCPeerConnectionGDNative::add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->add_ice_candidate(interface->data, sdpMidName.utf8().get_data(), sdpMlineIndexName, sdpName.utf8().get_data()); -} - -Error WebRTCPeerConnectionGDNative::poll() { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->poll(interface->data); -} - -void WebRTCPeerConnectionGDNative::close() { - ERR_FAIL_COND(interface == nullptr); - interface->close(interface->data); -} - -WebRTCPeerConnection::ConnectionState WebRTCPeerConnectionGDNative::get_connection_state() const { - ERR_FAIL_COND_V(interface == nullptr, STATE_DISCONNECTED); - return (ConnectionState)interface->get_connection_state(interface->data); -} - -void WebRTCPeerConnectionGDNative::set_native_webrtc_peer_connection(const godot_net_webrtc_peer_connection *p_impl) { - interface = p_impl; -} - -#endif // WEBRTC_GDNATIVE_ENABLED diff --git a/modules/webrtc/webrtc_peer_connection_js.h b/modules/webrtc/webrtc_peer_connection_js.h index 0272e67f6f..d2beccaf03 100644 --- a/modules/webrtc/webrtc_peer_connection_js.h +++ b/modules/webrtc/webrtc_peer_connection_js.h @@ -63,9 +63,6 @@ private: static void _on_error(void *p_obj); public: - static WebRTCPeerConnection *_create() { return memnew(WebRTCPeerConnectionJS); } - static void make_default() { WebRTCPeerConnection::_create = WebRTCPeerConnectionJS::_create; } - virtual ConnectionState get_connection_state() const; virtual Error initialize(Dictionary configuration = Dictionary()); diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml index f75a42357a..8d8ab220e2 100644 --- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml +++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml @@ -31,10 +31,6 @@ </description> </method> </methods> - <members> - <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" /> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="TransferMode" default="2" /> - </members> <signals> <signal name="peer_packet"> <argument index="0" name="peer_source" type="int" /> diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp index 7464cf2bf5..3a27855a5e 100644 --- a/modules/websocket/websocket_multiplayer_peer.cpp +++ b/modules/websocket/websocket_multiplayer_peer.cpp @@ -105,23 +105,6 @@ Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer // // MultiplayerPeer // -void WebSocketMultiplayerPeer::set_transfer_channel(int p_channel) { - // Websocket does not have channels. -} - -int WebSocketMultiplayerPeer::get_transfer_channel() const { - return 0; -} - -void WebSocketMultiplayerPeer::set_transfer_mode(Multiplayer::TransferMode p_mode) { - // Websocket uses TCP, reliable -} - -Multiplayer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const { - // Websocket uses TCP, reliable - return Multiplayer::TRANSFER_MODE_RELIABLE; -} - void WebSocketMultiplayerPeer::set_target_peer(int p_target_peer) { _target_peer = p_target_peer; } @@ -137,14 +120,6 @@ int WebSocketMultiplayerPeer::get_unique_id() const { return _peer_id; } -void WebSocketMultiplayerPeer::set_refuse_new_connections(bool p_enable) { - _refusing = p_enable; -} - -bool WebSocketMultiplayerPeer::is_refusing_new_connections() const { - return _refusing; -} - void WebSocketMultiplayerPeer::_send_sys(Ref<WebSocketPeer> p_peer, uint8_t p_type, int32_t p_peer_id) { ERR_FAIL_COND(!p_peer.is_valid()); ERR_FAIL_COND(!p_peer->is_connected_to_host()); diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h index d97a599fe9..380edf67ed 100644 --- a/modules/websocket/websocket_multiplayer_peer.h +++ b/modules/websocket/websocket_multiplayer_peer.h @@ -68,7 +68,6 @@ protected: bool _is_multiplayer = false; int _target_peer = 0; int _peer_id = 0; - int _refusing = false; static void _bind_methods(); @@ -78,15 +77,9 @@ protected: public: /* MultiplayerPeer */ - void set_transfer_channel(int p_channel) override; - int get_transfer_channel() const override; - void set_transfer_mode(Multiplayer::TransferMode p_mode) override; - Multiplayer::TransferMode get_transfer_mode() const override; void set_target_peer(int p_target_peer) override; int get_packet_peer() const override; int get_unique_id() const override; - void set_refuse_new_connections(bool p_enable) override; - bool is_refusing_new_connections() const override; /* PacketPeer */ virtual int get_available_packet_count() const override; diff --git a/modules/webxr/register_types.cpp b/modules/webxr/register_types.cpp index 078a6547cf..16b483c39e 100644 --- a/modules/webxr/register_types.cpp +++ b/modules/webxr/register_types.cpp @@ -33,15 +33,34 @@ #include "webxr_interface.h" #include "webxr_interface_js.h" +#ifdef JAVASCRIPT_ENABLED +Ref<WebXRInterfaceJS> webxr; +#endif + void register_webxr_types() { GDREGISTER_VIRTUAL_CLASS(WebXRInterface); #ifdef JAVASCRIPT_ENABLED - Ref<WebXRInterfaceJS> webxr; webxr.instantiate(); XRServer::get_singleton()->add_interface(webxr); #endif } void unregister_webxr_types() { +#ifdef JAVASCRIPT_ENABLED + if (webxr.is_valid()) { + // uninitialise our interface if it is initialised + if (webxr->is_initialized()) { + webxr->uninitialize(); + } + + // unregister our interface from the XR server + if (XRServer::get_singleton()) { + XRServer::get_singleton()->remove_interface(webxr); + } + + // and release + webxr.unref(); + } +#endif } diff --git a/platform/javascript/.eslintrc.js b/platform/javascript/.eslintrc.js index 0ff9d67d26..2c81f1f02d 100644 --- a/platform/javascript/.eslintrc.js +++ b/platform/javascript/.eslintrc.js @@ -39,5 +39,13 @@ module.exports = { // Closure compiler (exported properties) "quote-props": ["error", "consistent"], "dot-notation": "off", + // No comma dangle for functions (it's madness, and ES2017) + "comma-dangle": ["error", { + "arrays": "always-multiline", + "objects": "always-multiline", + "imports": "always-multiline", + "exports": "always-multiline", + "functions": "never" + }], } }; diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp index be4d2cba20..124b4ee1c8 100644 --- a/platform/javascript/display_server_javascript.cpp +++ b/platform/javascript/display_server_javascript.cpp @@ -595,6 +595,12 @@ void DisplayServerJavaScript::virtual_keyboard_hide() { godot_js_display_vk_hide(); } +// Window blur callback +EM_BOOL DisplayServerJavaScript::blur_callback(int p_event_type, const EmscriptenFocusEvent *p_event, void *p_user_data) { + Input::get_singleton()->release_pressed_events(); + return false; +} + // Gamepad void DisplayServerJavaScript::gamepad_callback(int p_index, int p_connected, const char *p_id, const char *p_guid) { Input *input = Input::get_singleton(); @@ -797,6 +803,7 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive SET_EM_CALLBACK(canvas_id, mousedown, mouse_button_callback) SET_EM_WINDOW_CALLBACK(mousemove, mousemove_callback) SET_EM_WINDOW_CALLBACK(mouseup, mouse_button_callback) + SET_EM_WINDOW_CALLBACK(blur, blur_callback) SET_EM_CALLBACK(canvas_id, wheel, wheel_callback) SET_EM_CALLBACK(canvas_id, touchstart, touch_press_callback) SET_EM_CALLBACK(canvas_id, touchmove, touchmove_callback) diff --git a/platform/javascript/display_server_javascript.h b/platform/javascript/display_server_javascript.h index bf5e229c9a..1863ddefeb 100644 --- a/platform/javascript/display_server_javascript.h +++ b/platform/javascript/display_server_javascript.h @@ -85,6 +85,8 @@ private: static EM_BOOL touch_press_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data); static EM_BOOL touchmove_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data); + static EM_BOOL blur_callback(int p_event_type, const EmscriptenFocusEvent *p_event, void *p_user_data); + static void gamepad_callback(int p_index, int p_connected, const char *p_id, const char *p_guid); void process_joypads(); diff --git a/platform/javascript/js/libs/library_godot_audio.js b/platform/javascript/js/libs/library_godot_audio.js index f6010fd12a..6cbb0567f4 100644 --- a/platform/javascript/js/libs/library_godot_audio.js +++ b/platform/javascript/js/libs/library_godot_audio.js @@ -229,7 +229,7 @@ const GodotAudioWorklet = { 'godot-processor', { 'outputChannelCount': [channels], - }, + } ); return Promise.resolve(); }); diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp index 54a3104482..2404c20153 100644 --- a/platform/osx/export/export_plugin.cpp +++ b/platform/osx/export/export_plugin.cpp @@ -95,6 +95,7 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_pictures", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_music", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0)); + r_options->push_back(ExportOption(PropertyInfo(Variant::ARRAY, "codesign/entitlements/app_sandbox/helper_executables", PROPERTY_HINT_ARRAY_TYPE, itos(Variant::STRING) + "/" + itos(PROPERTY_HINT_GLOBAL_FILE) + ":"), Array())); r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray())); @@ -535,6 +536,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = ERR_CANT_CREATE; } + Array helpers = p_preset->get("codesign/entitlements/app_sandbox/helper_executables"); + // Create our folder structure. if (err == OK) { print_line("Creating " + tmp_app_path_name + "/Contents/MacOS"); @@ -546,6 +549,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks"); } + if ((err == OK) && helpers.size() > 0) { + print_line("Creating " + tmp_app_path_name + "/Contents/Helpers"); + err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Helpers"); + } + if (err == OK) { print_line("Creating " + tmp_app_path_name + "/Contents/Resources"); err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Resources"); @@ -688,6 +696,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p bool sign_enabled = p_preset->get("codesign/enable"); String ent_path = p_preset->get("codesign/entitlements/custom_file"); + String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + "_helper.entitlements"); if (sign_enabled && (ent_path == "")) { ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements"); @@ -819,10 +828,43 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } else { err = ERR_CANT_CREATE; } + + if ((err == OK) && helpers.size() > 0) { + ent_f = FileAccess::open(hlp_ent_path, FileAccess::WRITE); + if (ent_f) { + ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); + ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"); + ent_f->store_line("<plist version=\"1.0\">"); + ent_f->store_line("<dict>"); + ent_f->store_line("<key>com.apple.security.app-sandbox</key>"); + ent_f->store_line("<true/>"); + ent_f->store_line("<key>com.apple.security.inherit</key>"); + ent_f->store_line("<true/>"); + ent_f->store_line("</dict>"); + ent_f->store_line("</plist>"); + + ent_f->close(); + memdelete(ent_f); + } else { + err = ERR_CANT_CREATE; + } + } + } + + if ((err == OK) && helpers.size() > 0) { + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + for (int i = 0; i < helpers.size(); i++) { + String hlp_path = helpers[i]; + err = da->copy(hlp_path, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file()); + if (err == OK && sign_enabled) { + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path); + } + FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755); + } } if (err == OK) { - DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < shared_objects.size(); i++) { String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path); if (da->dir_exists(src_path)) { @@ -842,7 +884,6 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), ent_path); } } - memdelete(da); } if (sign_enabled) { @@ -903,6 +944,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = _notarize(p_preset, p_path); } + // Clean up temporary entitlements files. + DirAccess::remove_file_or_error(hlp_ent_path); + // Clean up temporary .app dir. tmp_app_dir->change_dir(tmp_app_path_name); tmp_app_dir->erase_contents_recursive(); @@ -916,7 +960,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) { String dir = p_root_path.plus_file(p_folder); - DirAccess *da = DirAccess::open(dir); + DirAccessRef da = DirAccess::open(dir); da->list_dir_begin(); String f; while ((f = da->get_next()) != "") { @@ -967,7 +1011,7 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String } else if (da->current_is_dir()) { _zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name); } else { - bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)); + bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)) || p_folder.ends_with("Helpers"); OS::Time time = OS::get_singleton()->get_time(); OS::Date date = OS::get_singleton()->get_date(); @@ -1012,7 +1056,6 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String } } da->list_dir_end(); - memdelete(da); } bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp index c4b2608812..48817679bc 100644 --- a/scene/2d/physical_bone_2d.cpp +++ b/scene/2d/physical_bone_2d.cpp @@ -150,27 +150,15 @@ void PhysicalBone2D::_start_physics_simulation() { return; } - // Reset to Bone2D position + // Reset to Bone2D position. _position_at_bone2d(); - // Apply the layers and masks + // Apply the layers and masks. PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); - // Apply the correct mode - RigidDynamicBody2D::Mode rigid_mode = get_mode(); - if (rigid_mode == RigidDynamicBody2D::MODE_STATIC) { - set_body_mode(PhysicsServer2D::BODY_MODE_STATIC); - } else if (rigid_mode == RigidDynamicBody2D::MODE_DYNAMIC) { - set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC); - } else if (rigid_mode == RigidDynamicBody2D::MODE_KINEMATIC) { - set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC); - } else if (rigid_mode == RigidDynamicBody2D::MODE_DYNAMIC_LOCKED) { - set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED); - } else { - // Default to Dynamic. - set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC); - } + // Apply the correct mode. + _apply_body_mode(); _internal_simulate_physics = true; set_physics_process_internal(true); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index c3dc9ab92b..c07a999588 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -34,8 +34,8 @@ #include "scene/scene_string_names.h" void PhysicsBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08)); - ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08)); + ClassDB::bind_method(D_METHOD("move_and_collide", "linear_velocity", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08)); + ClassDB::bind_method(D_METHOD("test_move", "from", "linear_velocity", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08)); ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with); @@ -57,7 +57,10 @@ PhysicsBody2D::~PhysicsBody2D() { Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin) { PhysicsServer2D::MotionResult result; - if (move_and_collide(p_motion, result, p_margin, p_test_only)) { + // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky. + double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); + + if (move_and_collide(p_motion * delta, result, p_margin, p_test_only)) { // Create a new instance when the cached reference is invalid or still in use in script. if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) { motion_cache.instantiate(); @@ -133,7 +136,10 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion r = const_cast<PhysicsServer2D::MotionResult *>(&r_collision->result); } - return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_margin, r); + // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky. + double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); + + return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion * delta, p_margin, r); } TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() { @@ -430,7 +436,7 @@ void RigidDynamicBody2D::_body_state_changed_callback(void *p_instance, PhysicsD void RigidDynamicBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) { set_block_transform_notify(true); // don't want notify (would feedback loop) - if (mode != MODE_KINEMATIC) { + if (!freeze || freeze_mode != FREEZE_MODE_KINEMATIC) { set_global_transform(p_state->get_transform()); } @@ -524,29 +530,60 @@ void RigidDynamicBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) } } -void RigidDynamicBody2D::set_mode(Mode p_mode) { - mode = p_mode; - switch (p_mode) { - case MODE_DYNAMIC: { - set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC); - } break; - case MODE_STATIC: { - set_body_mode(PhysicsServer2D::BODY_MODE_STATIC); +void RigidDynamicBody2D::_apply_body_mode() { + if (freeze) { + switch (freeze_mode) { + case FREEZE_MODE_STATIC: { + set_body_mode(PhysicsServer2D::BODY_MODE_STATIC); + } break; + case FREEZE_MODE_KINEMATIC: { + set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC); + } break; + } + } else if (lock_rotation) { + set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC_LINEAR); + } else { + set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC); + } +} - } break; - case MODE_KINEMATIC: { - set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC); +void RigidDynamicBody2D::set_lock_rotation_enabled(bool p_lock_rotation) { + if (p_lock_rotation == lock_rotation) { + return; + } - } break; - case MODE_DYNAMIC_LOCKED: { - set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED); + lock_rotation = p_lock_rotation; + _apply_body_mode(); +} - } break; +bool RigidDynamicBody2D::is_lock_rotation_enabled() const { + return lock_rotation; +} + +void RigidDynamicBody2D::set_freeze_enabled(bool p_freeze) { + if (p_freeze == freeze) { + return; + } + + freeze = p_freeze; + _apply_body_mode(); +} + +bool RigidDynamicBody2D::is_freeze_enabled() const { + return freeze; +} + +void RigidDynamicBody2D::set_freeze_mode(FreezeMode p_freeze_mode) { + if (p_freeze_mode == freeze_mode) { + return; } + + freeze_mode = p_freeze_mode; + _apply_body_mode(); } -RigidDynamicBody2D::Mode RigidDynamicBody2D::get_mode() const { - return mode; +RigidDynamicBody2D::FreezeMode RigidDynamicBody2D::get_freeze_mode() const { + return freeze_mode; } void RigidDynamicBody2D::set_mass(real_t p_mass) { @@ -844,17 +881,14 @@ TypedArray<String> RigidDynamicBody2D::get_configuration_warnings() const { TypedArray<String> warnings = CollisionObject2D::get_configuration_warnings(); - if ((get_mode() == MODE_DYNAMIC || get_mode() == MODE_DYNAMIC_LOCKED) && (ABS(t.elements[0].length() - 1.0) > 0.05 || ABS(t.elements[1].length() - 1.0) > 0.05)) { - warnings.push_back(TTR("Size changes to RigidDynamicBody2D (in dynamic modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); + if (ABS(t.elements[0].length() - 1.0) > 0.05 || ABS(t.elements[1].length() - 1.0) > 0.05) { + warnings.push_back(TTR("Size changes to RigidDynamicBody2D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); } return warnings; } void RigidDynamicBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_mode", "mode"), &RigidDynamicBody2D::set_mode); - ClassDB::bind_method(D_METHOD("get_mode"), &RigidDynamicBody2D::get_mode); - ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidDynamicBody2D::set_mass); ClassDB::bind_method(D_METHOD("get_mass"), &RigidDynamicBody2D::get_mass); @@ -918,11 +952,19 @@ void RigidDynamicBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidDynamicBody2D::set_can_sleep); ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidDynamicBody2D::is_able_to_sleep); + ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidDynamicBody2D::set_lock_rotation_enabled); + ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidDynamicBody2D::is_lock_rotation_enabled); + + ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidDynamicBody2D::set_freeze_enabled); + ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidDynamicBody2D::is_freeze_enabled); + + ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidDynamicBody2D::set_freeze_mode); + ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidDynamicBody2D::get_freeze_mode); + ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidDynamicBody2D::get_colliding_bodies); GDVIRTUAL_BIND(_integrate_forces, "state"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,exp"), "set_inertia", "get_inertia"); ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode"); @@ -936,6 +978,9 @@ void RigidDynamicBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "lock_rotation"), "set_lock_rotation_enabled", "is_lock_rotation_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "freeze"), "set_freeze_enabled", "is_freeze_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "freeze_mode", PROPERTY_HINT_ENUM, "Static,Kinematic"), "set_freeze_mode", "get_freeze_mode"); ADD_GROUP("Linear", "linear_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); @@ -952,10 +997,8 @@ void RigidDynamicBody2D::_bind_methods() { ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("sleeping_state_changed")); - BIND_ENUM_CONSTANT(MODE_DYNAMIC); - BIND_ENUM_CONSTANT(MODE_STATIC); - BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED); - BIND_ENUM_CONSTANT(MODE_KINEMATIC); + BIND_ENUM_CONSTANT(FREEZE_MODE_STATIC); + BIND_ENUM_CONSTANT(FREEZE_MODE_KINEMATIC); BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO); BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM); @@ -1090,9 +1133,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo if (on_floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) { Transform2D gt = get_global_transform(); - if (result.travel.length() > margin) { - gt.elements[2] -= result.travel.slide(up_direction); - } else { + if (result.travel.length() <= margin + CMP_EPSILON) { gt.elements[2] -= result.travel; } set_global_transform(gt); @@ -1111,7 +1152,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Avoid to move forward on a wall if floor_block_on_wall is true. if (p_was_on_floor && !on_floor && !vel_dir_facing_up) { // If the movement is large the body can be prevented from reaching the walls. - if (result.travel.length() <= margin) { + if (result.travel.length() <= margin + CMP_EPSILON) { // Cancels the motion. Transform2D gt = get_global_transform(); gt.elements[2] -= result.travel; @@ -1240,13 +1281,16 @@ void CharacterBody2D::_move_and_slide_free(double p_delta) { } void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) { - if (Math::is_equal_approx(floor_snap_length, 0) || on_floor || !was_on_floor || vel_dir_facing_up) { + if (on_floor || !was_on_floor || vel_dir_facing_up) { return; } + // Snap by at least collision margin to keep floor state consistent. + real_t length = MAX(floor_snap_length, margin); + Transform2D gt = get_global_transform(); PhysicsServer2D::MotionResult result; - if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false, true)) { + if (move_and_collide(-up_direction * length, result, margin, true, false, true)) { bool apply = true; if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { on_floor = true; @@ -1274,12 +1318,15 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) } bool CharacterBody2D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up) { - if (Math::is_equal_approx(floor_snap_length, 0) || up_direction == Vector2() || on_floor || !was_on_floor || vel_dir_facing_up) { + if (up_direction == Vector2() || on_floor || !was_on_floor || vel_dir_facing_up) { return false; } + // Snap by at least collision margin to keep floor state consistent. + real_t length = MAX(floor_snap_length, margin); + PhysicsServer2D::MotionResult result; - if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false, true)) { + if (move_and_collide(-up_direction * length, result, margin, true, false, true)) { if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { return true; } @@ -1568,7 +1615,7 @@ void CharacterBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,1000,0.1"), "set_floor_snap_length", "get_floor_snap_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater"), "set_floor_snap_length", "get_floor_snap_length"); ADD_GROUP("Moving platform", "moving_platform"); ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_floor_layers", "get_moving_platform_floor_layers"); ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_wall_layers", "get_moving_platform_wall_layers"); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 5d0d98a2df..e789ac4cb7 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -92,7 +92,7 @@ class AnimatableBody2D : public StaticBody2D { GDCLASS(AnimatableBody2D, StaticBody2D); private: - bool sync_to_physics = false; + bool sync_to_physics = true; Transform2D last_valid_transform; @@ -117,11 +117,9 @@ class RigidDynamicBody2D : public PhysicsBody2D { GDCLASS(RigidDynamicBody2D, PhysicsBody2D); public: - enum Mode { - MODE_DYNAMIC, - MODE_STATIC, - MODE_DYNAMIC_LOCKED, - MODE_KINEMATIC, + enum FreezeMode { + FREEZE_MODE_STATIC, + FREEZE_MODE_KINEMATIC, }; enum CenterOfMassMode { @@ -137,7 +135,9 @@ public: private: bool can_sleep = true; - Mode mode = MODE_DYNAMIC; + bool lock_rotation = false; + bool freeze = false; + FreezeMode freeze_mode = FREEZE_MODE_STATIC; real_t mass = 1.0; real_t inertia = 0.0; @@ -211,9 +211,17 @@ protected: GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState2D *) + void _apply_body_mode(); + public: - void set_mode(Mode p_mode); - Mode get_mode() const; + void set_lock_rotation_enabled(bool p_lock_rotation); + bool is_lock_rotation_enabled() const; + + void set_freeze_enabled(bool p_freeze); + bool is_freeze_enabled() const; + + void set_freeze_mode(FreezeMode p_freeze_mode); + FreezeMode get_freeze_mode() const; void set_mass(real_t p_mass); real_t get_mass() const; @@ -290,7 +298,7 @@ private: void _reload_physics_characteristics(); }; -VARIANT_ENUM_CAST(RigidDynamicBody2D::Mode); +VARIANT_ENUM_CAST(RigidDynamicBody2D::FreezeMode); VARIANT_ENUM_CAST(RigidDynamicBody2D::CenterOfMassMode); VARIANT_ENUM_CAST(RigidDynamicBody2D::CCDMode); @@ -327,14 +335,14 @@ private: real_t margin = 0.08; MotionMode motion_mode = MOTION_MODE_GROUNDED; - bool floor_stop_on_slope = false; bool floor_constant_speed = false; + bool floor_stop_on_slope = true; bool floor_block_on_wall = true; bool slide_on_ceiling = true; int max_slides = 4; int platform_layer; real_t floor_max_angle = Math::deg2rad((real_t)45.0); - real_t floor_snap_length = 0; + real_t floor_snap_length = 1; real_t free_mode_min_slide_angle = Math::deg2rad((real_t)15.0); Vector2 up_direction = Vector2(0.0, -1.0); uint32_t moving_platform_floor_layers = UINT32_MAX; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 03db9c0d32..929233e4e0 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -2034,10 +2034,22 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { return false; } else if (components.size() == 2 && components[0].begins_with("layer_") && components[0].trim_prefix("layer_").is_valid_int()) { int index = components[0].trim_prefix("layer_").to_int(); - if (index < 0 || index >= (int)layers.size()) { + if (index < 0) { return false; } + if (index >= (int)layers.size()) { + _clear_internals(); + while (index >= (int)layers.size()) { + layers.push_back(TileMapLayer()); + } + _recreate_internals(); + + notify_property_list_changed(); + emit_signal(SNAME("changed")); + update_configuration_warnings(); + } + if (components[1] == "name") { set_layer_name(index, p_value); return true; diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp index c34c150145..afd11482e3 100644 --- a/scene/3d/bone_attachment_3d.cpp +++ b/scene/3d/bone_attachment_3d.cpp @@ -110,7 +110,7 @@ TypedArray<String> BoneAttachment3D::get_configuration_warnings() const { } else { Skeleton3D *parent = Object::cast_to<Skeleton3D>(get_parent()); if (!parent) { - warnings.append(TTR("Parent node is not a Skeleton3D node! Please use an extenral Skeleton3D if you intend to use the BoneAttachment3D without it being a child of a Skeleton3D node.")); + warnings.append(TTR("Parent node is not a Skeleton3D node! Please use an external Skeleton3D if you intend to use the BoneAttachment3D without it being a child of a Skeleton3D node.")); } } diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index c79f956642..4e496fba47 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -124,8 +124,7 @@ TypedArray<String> CollisionShape3D::get_configuration_warnings() const { if (shape.is_valid() && Object::cast_to<RigidDynamicBody3D>(get_parent()) && - Object::cast_to<ConcavePolygonShape3D>(*shape) && - Object::cast_to<RigidDynamicBody3D>(get_parent())->get_mode() != RigidDynamicBody3D::MODE_STATIC) { + Object::cast_to<ConcavePolygonShape3D>(*shape)) { warnings.push_back(TTR("ConcavePolygonShape3D doesn't support RigidDynamicBody3D in another mode than static.")); } diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 48da186860..bbf2c81a92 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -38,8 +38,8 @@ #endif void PhysicsBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "test_only", "safe_margin", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(1)); - ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "collision", "safe_margin", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("move_and_collide", "linear_velocity", "test_only", "safe_margin", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("test_move", "from", "linear_velocity", "collision", "safe_margin", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(1)); ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock); ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock); @@ -97,7 +97,10 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) { Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_test_only, real_t p_margin, int p_max_collisions) { PhysicsServer3D::MotionResult result; - if (move_and_collide(p_motion, result, p_margin, p_test_only, p_max_collisions)) { + // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky + double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); + + if (move_and_collide(p_motion * delta, result, p_margin, p_test_only, p_max_collisions)) { // Create a new instance when the cached reference is invalid or still in use in script. if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) { motion_cache.instantiate(); @@ -177,7 +180,10 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion r = const_cast<PhysicsServer3D::MotionResult *>(&r_collision->result); } - return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_margin, r, p_max_collisions); + // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky + double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); + + return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion * delta, p_margin, r, p_max_collisions); } void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { @@ -599,27 +605,60 @@ void RigidDynamicBody3D::_notification(int p_what) { #endif } -void RigidDynamicBody3D::set_mode(Mode p_mode) { - mode = p_mode; - switch (p_mode) { - case MODE_DYNAMIC: { - set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC); - } break; - case MODE_STATIC: { - set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); - } break; - case MODE_DYNAMIC_LOCKED: { - set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED); - } break; - case MODE_KINEMATIC: { - set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); - } break; +void RigidDynamicBody3D::_apply_body_mode() { + if (freeze) { + switch (freeze_mode) { + case FREEZE_MODE_STATIC: { + set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); + } break; + case FREEZE_MODE_KINEMATIC: { + set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); + } break; + } + } else if (lock_rotation) { + set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR); + } else { + set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC); + } +} + +void RigidDynamicBody3D::set_lock_rotation_enabled(bool p_lock_rotation) { + if (p_lock_rotation == lock_rotation) { + return; } - update_configuration_warnings(); + + lock_rotation = p_lock_rotation; + _apply_body_mode(); } -RigidDynamicBody3D::Mode RigidDynamicBody3D::get_mode() const { - return mode; +bool RigidDynamicBody3D::is_lock_rotation_enabled() const { + return lock_rotation; +} + +void RigidDynamicBody3D::set_freeze_enabled(bool p_freeze) { + if (p_freeze == freeze) { + return; + } + + freeze = p_freeze; + _apply_body_mode(); +} + +bool RigidDynamicBody3D::is_freeze_enabled() const { + return freeze; +} + +void RigidDynamicBody3D::set_freeze_mode(FreezeMode p_freeze_mode) { + if (p_freeze_mode == freeze_mode) { + return; + } + + freeze_mode = p_freeze_mode; + _apply_body_mode(); +} + +RigidDynamicBody3D::FreezeMode RigidDynamicBody3D::get_freeze_mode() const { + return freeze_mode; } void RigidDynamicBody3D::set_mass(real_t p_mass) { @@ -892,17 +931,14 @@ TypedArray<String> RigidDynamicBody3D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); - if ((get_mode() == MODE_DYNAMIC || get_mode() == MODE_DYNAMIC_LOCKED) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) { - warnings.push_back(TTR("Size changes to RigidDynamicBody (in dynamic modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); + if (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05) { + warnings.push_back(TTR("Size changes to RigidDynamicBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); } return warnings; } void RigidDynamicBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_mode", "mode"), &RigidDynamicBody3D::set_mode); - ClassDB::bind_method(D_METHOD("get_mode"), &RigidDynamicBody3D::get_mode); - ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidDynamicBody3D::set_mass); ClassDB::bind_method(D_METHOD("get_mass"), &RigidDynamicBody3D::get_mass); @@ -963,11 +999,19 @@ void RigidDynamicBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidDynamicBody3D::set_can_sleep); ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidDynamicBody3D::is_able_to_sleep); + ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidDynamicBody3D::set_lock_rotation_enabled); + ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidDynamicBody3D::is_lock_rotation_enabled); + + ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidDynamicBody3D::set_freeze_enabled); + ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidDynamicBody3D::is_freeze_enabled); + + ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidDynamicBody3D::set_freeze_mode); + ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidDynamicBody3D::get_freeze_mode); + ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidDynamicBody3D::get_colliding_bodies); GDVIRTUAL_BIND(_integrate_forces, "state"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inertia", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,exp"), "set_inertia", "get_inertia"); ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode"); @@ -981,6 +1025,9 @@ void RigidDynamicBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "lock_rotation"), "set_lock_rotation_enabled", "is_lock_rotation_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "freeze"), "set_freeze_enabled", "is_freeze_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "freeze_mode", PROPERTY_HINT_ENUM, "Static,Kinematic"), "set_freeze_mode", "get_freeze_mode"); ADD_GROUP("Linear", "linear_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); @@ -994,10 +1041,8 @@ void RigidDynamicBody3D::_bind_methods() { ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("sleeping_state_changed")); - BIND_ENUM_CONSTANT(MODE_DYNAMIC); - BIND_ENUM_CONSTANT(MODE_STATIC); - BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED); - BIND_ENUM_CONSTANT(MODE_KINEMATIC); + BIND_ENUM_CONSTANT(FREEZE_MODE_STATIC); + BIND_ENUM_CONSTANT(FREEZE_MODE_KINEMATIC); BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO); BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM); @@ -1146,8 +1191,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo if (collision_state.floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) { Transform3D gt = get_global_transform(); - real_t travel_total = result.travel.length(); - if (travel_total <= margin + CMP_EPSILON) { + if (result.travel.length() <= margin + CMP_EPSILON) { gt.origin -= result.travel; } set_global_transform(gt); @@ -1186,7 +1230,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo Transform3D gt = get_global_transform(); real_t travel_total = result.travel.length(); real_t cancel_dist_max = MIN(0.1, margin * 20); - if (travel_total < margin + CMP_EPSILON) { + if (travel_total <= margin + CMP_EPSILON) { gt.origin -= result.travel; } else if (travel_total < cancel_dist_max) { // If the movement is large the body can be prevented from reaching the walls. gt.origin -= result.travel.slide(up_direction); @@ -1377,7 +1421,9 @@ void CharacterBody3D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) return; } + // Snap by at least collision margin to keep floor state consistent. real_t length = MAX(floor_snap_length, margin); + Transform3D gt = get_global_transform(); PhysicsServer3D::MotionResult result; if (move_and_collide(-up_direction * length, result, margin, true, 4, false, true)) { @@ -1403,12 +1449,15 @@ void CharacterBody3D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) } bool CharacterBody3D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up) { - if (Math::is_zero_approx(floor_snap_length) || up_direction == Vector3() || collision_state.floor || !was_on_floor || vel_dir_facing_up) { + if (up_direction == Vector3() || collision_state.floor || !was_on_floor || vel_dir_facing_up) { return false; } + // Snap by at least collision margin to keep floor state consistent. + real_t length = MAX(floor_snap_length, margin); + PhysicsServer3D::MotionResult result; - if (move_and_collide(-up_direction * floor_snap_length, result, margin, true, 4, false, true)) { + if (move_and_collide(-up_direction * length, result, margin, true, 4, false, true)) { CollisionState result_state; // Don't apply direction for any type. _set_collision_direction(result, result_state, CollisionState()); diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 96f3d7d747..a53147cb8f 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -105,7 +105,7 @@ private: Vector3 linear_velocity; Vector3 angular_velocity; - bool sync_to_physics = false; + bool sync_to_physics = true; Transform3D last_valid_transform; @@ -133,11 +133,9 @@ class RigidDynamicBody3D : public PhysicsBody3D { GDCLASS(RigidDynamicBody3D, PhysicsBody3D); public: - enum Mode { - MODE_DYNAMIC, - MODE_STATIC, - MODE_DYNAMIC_LOCKED, - MODE_KINEMATIC, + enum FreezeMode { + FREEZE_MODE_STATIC, + FREEZE_MODE_KINEMATIC, }; enum CenterOfMassMode { @@ -145,11 +143,11 @@ public: CENTER_OF_MASS_MODE_CUSTOM, }; - GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *) - -protected: +private: bool can_sleep = true; - Mode mode = MODE_DYNAMIC; + bool lock_rotation = false; + bool freeze = false; + FreezeMode freeze_mode = FREEZE_MODE_STATIC; real_t mass = 1.0; Vector3 inertia; @@ -214,16 +212,28 @@ protected: void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape); static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state); - virtual void _body_state_changed(PhysicsDirectBodyState3D *p_state); +protected: void _notification(int p_what); static void _bind_methods(); virtual void _validate_property(PropertyInfo &property) const override; + GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *) + + virtual void _body_state_changed(PhysicsDirectBodyState3D *p_state); + + void _apply_body_mode(); + public: - void set_mode(Mode p_mode); - Mode get_mode() const; + void set_lock_rotation_enabled(bool p_lock_rotation); + bool is_lock_rotation_enabled() const; + + void set_freeze_enabled(bool p_freeze); + bool is_freeze_enabled() const; + + void set_freeze_mode(FreezeMode p_freeze_mode); + FreezeMode get_freeze_mode() const; void set_mass(real_t p_mass); real_t get_mass() const; @@ -298,7 +308,7 @@ private: void _reload_physics_characteristics(); }; -VARIANT_ENUM_CAST(RigidDynamicBody3D::Mode); +VARIANT_ENUM_CAST(RigidDynamicBody3D::FreezeMode); VARIANT_ENUM_CAST(RigidDynamicBody3D::CenterOfMassMode); class KinematicCollision3D; @@ -364,8 +374,8 @@ private: }; CollisionState collision_state; - bool floor_stop_on_slope = false; bool floor_constant_speed = false; + bool floor_stop_on_slope = true; bool floor_block_on_wall = true; bool slide_on_ceiling = true; int max_slides = 6; diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp index 466f67afb8..8d90aabfac 100644 --- a/scene/3d/skeleton_ik_3d.cpp +++ b/scene/3d/skeleton_ik_3d.cpp @@ -99,7 +99,7 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain child_ci->current_pos = child_ci->initial_transform.origin; if (child_ci->parent_item) { - child_ci->length = (child_ci->current_pos - child_ci->parent_item->current_pos).length(); + child_ci->length = child_ci->parent_item->current_pos.distance_to(child_ci->current_pos); } } @@ -140,7 +140,7 @@ void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet, Vec solve_simple_backwards(p_task->chain, p_solve_magnet); solve_simple_forwards(p_task->chain, p_solve_magnet, p_origin_pos); - distance_to_goal = (p_task->chain.tips[0].chain_item->current_pos - p_task->chain.tips[0].end_effector->goal_transform.origin).length(); + distance_to_goal = p_task->chain.tips[0].end_effector->goal_transform.origin.distance_to(p_task->chain.tips[0].chain_item->current_pos); } } diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp index bc3bb81ed4..9a2aaa8be2 100644 --- a/scene/3d/vehicle_body_3d.cpp +++ b/scene/3d/vehicle_body_3d.cpp @@ -470,7 +470,7 @@ real_t VehicleBody3D::_ray_cast(int p_idx, PhysicsDirectBodyState3D *s) { } void VehicleBody3D::_update_suspension(PhysicsDirectBodyState3D *s) { - real_t chassisMass = mass; + real_t chassisMass = get_mass(); for (int w_it = 0; w_it < wheels.size(); w_it++) { VehicleWheel3D &wheel_info = *wheels[w_it]; @@ -558,7 +558,7 @@ void VehicleBody3D::_resolve_single_bilateral(PhysicsDirectBodyState3D *s, const rel_pos2, normal, s->get_inverse_inertia_tensor().get_main_diagonal(), - 1.0 / mass, + 1.0 / get_mass(), b2invinertia, b2invmass); @@ -584,7 +584,7 @@ void VehicleBody3D::_resolve_single_bilateral(PhysicsDirectBodyState3D *s, const #define ONLY_USE_LINEAR_MASS #ifdef ONLY_USE_LINEAR_MASS - real_t massTerm = real_t(1.) / ((1.0 / mass) + b2invmass); + real_t massTerm = real_t(1.) / ((1.0 / get_mass()) + b2invmass); impulse = -contactDamping * rel_vel * massTerm; #else real_t velocityImpulse = -contactDamping * rel_vel * jacDiagABInv; diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index bca3b2059d..d9c08ec272 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -1071,10 +1071,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { if (mm.is_valid() && box_selecting) { box_selecting_to = mm->get_position(); - box_selecting_rect = Rect2(MIN(box_selecting_from.x, box_selecting_to.x), - MIN(box_selecting_from.y, box_selecting_to.y), - ABS(box_selecting_from.x - box_selecting_to.x), - ABS(box_selecting_from.y - box_selecting_to.y)); + box_selecting_rect = Rect2(box_selecting_from.min(box_selecting_to), (box_selecting_from - box_selecting_to).abs()); for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index d9acbeb828..89fd9bfc88 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -260,24 +260,29 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { } else { if (selecting_enabled) { - if (!b->is_double_click() && (OS::get_singleton()->get_ticks_msec() - selection.last_dblclk) < 600) { + const int triple_click_timeout = 600; + const int triple_click_tolerance = 5; + const bool is_triple_click = !b->is_double_click() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < triple_click_timeout && b->get_position().distance_to(last_dblclk_pos) < triple_click_tolerance; + + if (is_triple_click && text.length()) { // Triple-click select all. selection.enabled = true; selection.begin = 0; selection.end = text.length(); selection.double_click = true; - selection.last_dblclk = 0; + last_dblclk = 0; caret_column = selection.begin; } else if (b->is_double_click()) { // Double-click select word. + last_dblclk = OS::get_singleton()->get_ticks_msec(); + last_dblclk_pos = b->get_position(); Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid); for (int i = 0; i < words.size(); i++) { - if (words[i].x < caret_column && words[i].y > caret_column) { + if ((words[i].x < caret_column && words[i].y > caret_column) || (i == words.size() - 1 && caret_column == words[i].y)) { selection.enabled = true; selection.begin = words[i].x; selection.end = words[i].y; selection.double_click = true; - selection.last_dblclk = OS::get_singleton()->get_ticks_msec(); caret_column = selection.end; break; } @@ -1555,6 +1560,20 @@ void LineEdit::deselect() { update(); } +bool LineEdit::has_selection() const { + return selection.enabled; +} + +int LineEdit::get_selection_from_column() const { + ERR_FAIL_COND_V(!selection.enabled, -1); + return selection.begin; +} + +int LineEdit::get_selection_to_column() const { + ERR_FAIL_COND_V(!selection.enabled, -1); + return selection.end; +} + void LineEdit::selection_delete() { if (selection.enabled) { delete_text(selection.begin, selection.end); @@ -2089,6 +2108,9 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("select", "from", "to"), &LineEdit::select, DEFVAL(0), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("select_all"), &LineEdit::select_all); ClassDB::bind_method(D_METHOD("deselect"), &LineEdit::deselect); + ClassDB::bind_method(D_METHOD("has_selection"), &LineEdit::has_selection); + ClassDB::bind_method(D_METHOD("get_selection_from_column"), &LineEdit::get_selection_from_column); + ClassDB::bind_method(D_METHOD("get_selection_to_column"), &LineEdit::get_selection_to_column); ClassDB::bind_method(D_METHOD("set_text", "text"), &LineEdit::set_text); ClassDB::bind_method(D_METHOD("get_text"), &LineEdit::get_text); ClassDB::bind_method(D_METHOD("get_draw_control_chars"), &LineEdit::get_draw_control_chars); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index e364a79c83..923024dd56 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -136,7 +136,6 @@ private: bool creating = false; bool double_click = false; bool drag_attempt = false; - uint64_t last_dblclk = 0; } selection; struct TextOperation { @@ -153,6 +152,9 @@ private: bool pressing_inside = false; } clear_button_status; + uint64_t last_dblclk = 0; + Vector2 last_dblclk_pos; + bool caret_blink_enabled = false; bool caret_force_displayed = false; bool draw_caret = true; @@ -229,6 +231,9 @@ public: void select_all(); void selection_delete(); void deselect(); + bool has_selection() const; + int get_selection_from_column() const; + int get_selection_to_column() const; void delete_char(); void delete_text(int p_from_column, int p_to_column); diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 7faa9aca2c..ef34bec347 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -98,29 +98,45 @@ void Tabs::gui_input(const Ref<InputEvent> &p_event) { if (mm.is_valid()) { Point2 pos = mm->get_position(); - highlight_arrow = -1; if (buttons_visible) { Ref<Texture2D> incr = get_theme_icon(SNAME("increment")); Ref<Texture2D> decr = get_theme_icon(SNAME("decrement")); if (is_layout_rtl()) { if (pos.x < decr->get_width()) { - highlight_arrow = 1; + if (highlight_arrow != 1) { + highlight_arrow = 1; + update(); + } } else if (pos.x < incr->get_width() + decr->get_width()) { - highlight_arrow = 0; + if (highlight_arrow != 0) { + highlight_arrow = 0; + update(); + } + } else if (highlight_arrow != -1) { + highlight_arrow = -1; + update(); } } else { int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width(); if (pos.x > limit_minus_buttons + decr->get_width()) { - highlight_arrow = 1; + if (highlight_arrow != 1) { + highlight_arrow = 1; + update(); + } } else if (pos.x > limit_minus_buttons) { - highlight_arrow = 0; + if (highlight_arrow != 0) { + highlight_arrow = 0; + update(); + } + } else if (highlight_arrow != -1) { + highlight_arrow = -1; + update(); } } } _update_hover(); - update(); return; } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 09899413f2..5b13e1da0b 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -3689,7 +3689,7 @@ void TextEdit::select_word_under_caret() { int end = 0; const Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid()); for (int i = 0; i < words.size(); i++) { - if (words[i].x <= caret.column && words[i].y >= caret.column) { + if ((words[i].x < caret.column && words[i].y > caret.column) || (i == words.size() - 1 && caret.column == words[i].y)) { begin = words[i].x; end = words[i].y; break; @@ -5411,7 +5411,7 @@ void TextEdit::_update_selection_mode_word() { int end = beg; Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid()); for (int i = 0; i < words.size(); i++) { - if (words[i].x < caret_pos && words[i].y > caret_pos) { + if ((words[i].x < caret_pos && words[i].y > caret_pos) || (i == words.size() - 1 && caret_pos == words[i].y)) { beg = words[i].x; end = words[i].y; break; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 2be59ca04d..7d7596635c 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -144,6 +144,7 @@ void TreeItem::_change_tree(Tree *p_tree) { /* cell mode */ void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) { ERR_FAIL_INDEX(p_column, cells.size()); + Cell &c = cells.write[p_column]; c.mode = p_mode; c.min = 0; @@ -155,8 +156,9 @@ void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) { c.text = ""; c.dirty = true; c.icon_max_w = 0; + c.cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } TreeItem::TreeCellMode TreeItem::get_cell_mode(int p_column) const { @@ -167,22 +169,27 @@ TreeItem::TreeCellMode TreeItem::get_cell_mode(int p_column) const { /* check mode */ void TreeItem::set_checked(int p_column, bool p_checked) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].checked = p_checked; cells.write[p_column].indeterminate = false; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } void TreeItem::set_indeterminate(int p_column, bool p_indeterminate) { ERR_FAIL_INDEX(p_column, cells.size()); + // Prevent uncheck if indeterminate set to false twice if (p_indeterminate == cells[p_column].indeterminate) { return; } + cells.write[p_column].indeterminate = p_indeterminate; cells.write[p_column].checked = false; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } bool TreeItem::is_checked(int p_column) const { @@ -214,8 +221,10 @@ void TreeItem::set_text(int p_column, String p_text) { } cells.write[p_column].step = 0; } + + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } String TreeItem::get_text(int p_column) const { @@ -231,7 +240,7 @@ void TreeItem::set_text_direction(int p_column, Control::TextDirection p_text_di cells.write[p_column].dirty = true; _changed_notify(p_column); } - cached_minimum_size_dirty = true; + cells.write[p_column].cached_minimum_size_dirty = true; } Control::TextDirection TreeItem::get_text_direction(int p_column) const { @@ -241,10 +250,12 @@ Control::TextDirection TreeItem::get_text_direction(int p_column) const { void TreeItem::clear_opentype_features(int p_column) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].opentype_features.clear(); cells.write[p_column].dirty = true; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } void TreeItem::set_opentype_feature(int p_column, const String &p_name, int p_value) { @@ -253,8 +264,9 @@ void TreeItem::set_opentype_feature(int p_column, const String &p_name, int p_va if (!cells[p_column].opentype_features.has(tag) || (int)cells[p_column].opentype_features[tag] != p_value) { cells.write[p_column].opentype_features[tag] = p_value; cells.write[p_column].dirty = true; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } } @@ -269,11 +281,13 @@ int TreeItem::get_opentype_feature(int p_column, const String &p_name) const { void TreeItem::set_structured_text_bidi_override(int p_column, Control::StructuredTextParser p_parser) { ERR_FAIL_INDEX(p_column, cells.size()); + if (cells[p_column].st_parser != p_parser) { cells.write[p_column].st_parser = p_parser; cells.write[p_column].dirty = true; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } } @@ -284,10 +298,12 @@ Control::StructuredTextParser TreeItem::get_structured_text_bidi_override(int p_ void TreeItem::set_structured_text_bidi_override_options(int p_column, Array p_args) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].st_args = p_args; cells.write[p_column].dirty = true; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } Array TreeItem::get_structured_text_bidi_override_options(int p_column) const { @@ -297,11 +313,13 @@ Array TreeItem::get_structured_text_bidi_override_options(int p_column) const { void TreeItem::set_language(int p_column, const String &p_language) { ERR_FAIL_INDEX(p_column, cells.size()); + if (cells[p_column].language != p_language) { cells.write[p_column].language = p_language; cells.write[p_column].dirty = true; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } } @@ -312,10 +330,11 @@ String TreeItem::get_language(int p_column) const { void TreeItem::set_suffix(int p_column, String p_suffix) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].suffix = p_suffix; + cells.write[p_column].cached_minimum_size_dirty = true; _changed_notify(p_column); - cached_minimum_size_dirty = true; } String TreeItem::get_suffix(int p_column) const { @@ -325,9 +344,11 @@ String TreeItem::get_suffix(int p_column) const { void TreeItem::set_icon(int p_column, const Ref<Texture2D> &p_icon) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].icon = p_icon; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } Ref<Texture2D> TreeItem::get_icon(int p_column) const { @@ -337,9 +358,11 @@ Ref<Texture2D> TreeItem::get_icon(int p_column) const { void TreeItem::set_icon_region(int p_column, const Rect2 &p_icon_region) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].icon_region = p_icon_region; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } Rect2 TreeItem::get_icon_region(int p_column) const { @@ -360,9 +383,11 @@ Color TreeItem::get_icon_modulate(int p_column) const { void TreeItem::set_icon_max_width(int p_column, int p_max) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].icon_max_w = p_max; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } int TreeItem::get_icon_max_width(int p_column) const { @@ -474,8 +499,11 @@ void TreeItem::uncollapse_tree() { void TreeItem::set_custom_minimum_height(int p_height) { custom_min_height = p_height; + + for (Cell &c : cells) + c.cached_minimum_size_dirty = true; + _changed_notify(); - cached_minimum_size_dirty = true; } int TreeItem::get_custom_minimum_height() const { @@ -799,8 +827,9 @@ void TreeItem::add_button(int p_column, const Ref<Texture2D> &p_button, int p_id button.disabled = p_disabled; button.tooltip = p_tooltip; cells.write[p_column].buttons.push_back(button); + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } int TreeItem::get_button_count(int p_column) const { @@ -843,8 +872,9 @@ void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture2D> &p_butto ERR_FAIL_INDEX(p_column, cells.size()); ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); cells.write[p_column].buttons.write[p_idx].texture = p_button; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } void TreeItem::set_button_color(int p_column, int p_idx, const Color &p_color) { @@ -859,8 +889,9 @@ void TreeItem::set_button_disabled(int p_column, int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); cells.write[p_column].buttons.write[p_idx].disabled = p_disabled; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } bool TreeItem::is_button_disabled(int p_column, int p_idx) const { @@ -872,9 +903,11 @@ bool TreeItem::is_button_disabled(int p_column, int p_idx) const { void TreeItem::set_editable(int p_column, bool p_editable) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].editable = p_editable; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } bool TreeItem::is_editable(int p_column) { @@ -906,8 +939,9 @@ void TreeItem::clear_custom_color(int p_column) { void TreeItem::set_custom_font(int p_column, const Ref<Font> &p_font) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].custom_font = p_font; - cached_minimum_size_dirty = true; + cells.write[p_column].cached_minimum_size_dirty = true; } Ref<Font> TreeItem::get_custom_font(int p_column) const { @@ -917,8 +951,9 @@ Ref<Font> TreeItem::get_custom_font(int p_column) const { void TreeItem::set_custom_font_size(int p_column, int p_font_size) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].custom_font_size = p_font_size; - cached_minimum_size_dirty = true; + cells.write[p_column].cached_minimum_size_dirty = true; } int TreeItem::get_custom_font_size(int p_column) const { @@ -961,8 +996,9 @@ Color TreeItem::get_custom_bg_color(int p_column) const { void TreeItem::set_custom_as_button(int p_column, bool p_button) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].custom_button = p_button; - cached_minimum_size_dirty = true; + cells.write[p_column].cached_minimum_size_dirty = true; } bool TreeItem::is_custom_set_as_button(int p_column) const { @@ -972,9 +1008,11 @@ bool TreeItem::is_custom_set_as_button(int p_column) const { void TreeItem::set_text_align(int p_column, TextAlign p_align) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].text_align = p_align; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } TreeItem::TextAlign TreeItem::get_text_align(int p_column) const { @@ -984,9 +1022,11 @@ TreeItem::TextAlign TreeItem::get_text_align(int p_column) const { void TreeItem::set_expand_right(int p_column, bool p_enable) { ERR_FAIL_INDEX(p_column, cells.size()); + cells.write[p_column].expand_right = p_enable; + cells.write[p_column].cached_minimum_size_dirty = true; + _changed_notify(p_column); - cached_minimum_size_dirty = true; } bool TreeItem::get_expand_right(int p_column) const { @@ -996,8 +1036,11 @@ bool TreeItem::get_expand_right(int p_column) const { void TreeItem::set_disable_folding(bool p_disable) { disable_folding = p_disable; + + for (Cell &c : cells) + c.cached_minimum_size_dirty = true; + _changed_notify(0); - cached_minimum_size_dirty = true; } bool TreeItem::is_folding_disabled() const { @@ -1009,14 +1052,12 @@ Size2 TreeItem::get_minimum_size(int p_column) { Tree *tree = get_tree(); ERR_FAIL_COND_V(!tree, Size2()); - if (cached_minimum_size_dirty) { - Size2 size; + const TreeItem::Cell &cell = cells[p_column]; - // Default offset? - //size.width += (disable_folding || tree->hide_folding) ? tree->cache.hseparation : tree->cache.item_margin; + if (cell.cached_minimum_size_dirty) { + Size2 size; // Text. - const TreeItem::Cell &cell = cells[p_column]; if (!cell.text.is_empty()) { if (cell.dirty) { tree->update_item_cell(this, p_column); @@ -1052,11 +1093,11 @@ Size2 TreeItem::get_minimum_size(int p_column) { size.width += (cell.buttons.size() - 1) * tree->cache.button_margin; } - cached_minimum_size = size; - cached_minimum_size_dirty = false; + cells.write[p_column].cached_minimum_size = size; + cells.write[p_column].cached_minimum_size_dirty = false; } - return cached_minimum_size; + return cell.cached_minimum_size; } Variant TreeItem::_call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { @@ -1337,10 +1378,6 @@ void Tree::update_cache() { cache.title_button_color = get_theme_color(SNAME("title_button_color")); v_scroll->set_custom_step(cache.font->get_height(cache.font_size)); - - for (TreeItem *item = get_root(); item; item = item->get_next()) { - item->cached_minimum_size_dirty = true; - } } int Tree::compute_item_height(TreeItem *p_item) const { @@ -4001,10 +4038,12 @@ TreeItem *Tree::get_next_selected(TreeItem *p_item) { int Tree::get_column_minimum_width(int p_column) const { ERR_FAIL_INDEX_V(p_column, columns.size(), -1); + // Use the custom minimum width. int min_width = columns[p_column].custom_min_width; + // Check if the visible title of the column is wider. if (show_column_titles) { - min_width = MAX(cache.font->get_string_size(columns[p_column].title).width, min_width); + min_width = MAX(cache.font->get_string_size(columns[p_column].title).width + cache.bg->get_margin(SIDE_LEFT) + cache.bg->get_margin(SIDE_RIGHT), min_width); } if (!columns[p_column].clip_content) { @@ -4029,7 +4068,11 @@ int Tree::get_column_minimum_width(int p_column) const { Size2 item_size = item->get_minimum_size(p_column); if (p_column == 0) { item_size.width += cache.item_margin * depth; + } else { + item_size.width += cache.hseparation; } + + // Check if the item is wider. min_width = MAX(min_width, item_size.width); } } @@ -4069,9 +4112,6 @@ int Tree::get_column_width(int p_column) const { } } - if (p_column < columns.size() - 1) { - column_width += cache.hseparation; - } return column_width; } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 85fed941dc..c4a6b6b058 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -95,6 +95,9 @@ private: bool expand_right = false; Color icon_color = Color(1, 1, 1); + Size2i cached_minimum_size; + bool cached_minimum_size_dirty = true; + TextAlign text_align = ALIGN_LEFT; Variant meta; @@ -130,9 +133,6 @@ private: bool disable_folding = false; int custom_min_height = 0; - Size2i cached_minimum_size; - bool cached_minimum_size_dirty = true; - TreeItem *parent = nullptr; // parent item TreeItem *prev = nullptr; // previous in list TreeItem *next = nullptr; // next in list diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index e7da41db9d..f8be00f5fb 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -1390,6 +1390,12 @@ void QuadMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset"); } +uint32_t QuadMesh::surface_get_format(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, 1, 0); + + return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV; +} + QuadMesh::QuadMesh() { primitive_type = PRIMITIVE_TRIANGLES; } @@ -1460,7 +1466,7 @@ void SphereMesh::_create_mesh_array(Array &p_arr) const { } else { Vector3 p = Vector3(x * radius * w, y, z * radius * w); points.push_back(p); - Vector3 normal = Vector3(x * radius * w * scale, y / scale, z * radius * w * scale); + Vector3 normal = Vector3(x * w * scale, radius * (y / scale), z * w * scale); normals.push_back(normal.normalized()); }; ADD_TANGENT(z, 0.0, -x, 1.0) diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 7915cb0028..d447dad97a 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -285,6 +285,8 @@ protected: virtual void _create_mesh_array(Array &p_arr) const override; public: + virtual uint32_t surface_get_format(int p_idx) const override; + QuadMesh(); void set_size(const Size2 &p_size); diff --git a/scene/resources/skeleton_modification_2d.cpp b/scene/resources/skeleton_modification_2d.cpp index e533fb054a..7ac40b497d 100644 --- a/scene/resources/skeleton_modification_2d.cpp +++ b/scene/resources/skeleton_modification_2d.cpp @@ -96,37 +96,25 @@ float SkeletonModification2D::clamp_angle(float p_angle, float p_min_bound, floa p_max_bound = Math_TAU + p_max_bound; } if (p_min_bound > p_max_bound) { - float tmp = p_min_bound; - p_min_bound = p_max_bound; - p_max_bound = tmp; + SWAP(p_min_bound, p_max_bound); } + bool is_beyond_bounds = (p_angle < p_min_bound || p_angle > p_max_bound); + bool is_within_bounds = (p_angle > p_min_bound && p_angle < p_max_bound); + // Note: May not be the most optimal way to clamp, but it always constraints to the nearest angle. - if (p_invert == false) { - if (p_angle < p_min_bound || p_angle > p_max_bound) { - Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound)); - Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound)); - Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle)); - - if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) { - p_angle = p_min_bound; - } else { - p_angle = p_max_bound; - } - } - } else { - if (p_angle > p_min_bound && p_angle < p_max_bound) { - Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound)); - Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound)); - Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle)); + if ((!p_invert && is_beyond_bounds) || (p_invert && is_within_bounds)) { + Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound)); + Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound)); + Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle)); - if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) { - p_angle = p_min_bound; - } else { - p_angle = p_max_bound; - } + if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) { + p_angle = p_min_bound; + } else { + p_angle = p_max_bound; } } + return p_angle; } @@ -152,9 +140,7 @@ void SkeletonModification2D::editor_draw_angle_constraints(Bone2D *p_operation_b arc_angle_max = (Math_PI * 2) + arc_angle_max; } if (arc_angle_min > arc_angle_max) { - float tmp = arc_angle_min; - arc_angle_min = arc_angle_max; - arc_angle_max = tmp; + SWAP(arc_angle_min, arc_angle_max); } arc_angle_min += p_operation_bone->get_bone_angle(); arc_angle_max += p_operation_bone->get_bone_angle(); diff --git a/scene/resources/skeleton_modification_2d_fabrik.cpp b/scene/resources/skeleton_modification_2d_fabrik.cpp index 6e9429034f..3b5c555f89 100644 --- a/scene/resources/skeleton_modification_2d_fabrik.cpp +++ b/scene/resources/skeleton_modification_2d_fabrik.cpp @@ -247,7 +247,7 @@ void SkeletonModification2DFABRIK::chain_backwards() { } float current_bone2d_node_length = current_bone2d_node->get_length() * MIN(current_bone2d_node->get_global_scale().x, current_bone2d_node->get_global_scale().y); - float length = current_bone2d_node_length / (previous_pose.get_origin() - current_pose.get_origin()).length(); + float length = current_bone2d_node_length / (current_pose.get_origin().distance_to(previous_pose.get_origin())); Vector2 finish_position = previous_pose.get_origin().lerp(current_pose.get_origin(), length); current_pose.set_origin(finish_position); @@ -268,7 +268,7 @@ void SkeletonModification2DFABRIK::chain_forwards() { Transform2D next_pose = fabrik_transform_chain[i + 1]; float current_bone2d_node_length = current_bone2d_node->get_length() * MIN(current_bone2d_node->get_global_scale().x, current_bone2d_node->get_global_scale().y); - float length = current_bone2d_node_length / (current_pose.get_origin() - next_pose.get_origin()).length(); + float length = current_bone2d_node_length / (next_pose.get_origin().distance_to(current_pose.get_origin())); Vector2 finish_position = current_pose.get_origin().lerp(next_pose.get_origin(), length); current_pose.set_origin(finish_position); diff --git a/scene/resources/skeleton_modification_3d.cpp b/scene/resources/skeleton_modification_3d.cpp index ee02ede2d5..b476952d86 100644 --- a/scene/resources/skeleton_modification_3d.cpp +++ b/scene/resources/skeleton_modification_3d.cpp @@ -72,37 +72,25 @@ real_t SkeletonModification3D::clamp_angle(real_t p_angle, real_t p_min_bound, r p_max_bound = Math_TAU + p_max_bound; } if (p_min_bound > p_max_bound) { - real_t tmp = p_min_bound; - p_min_bound = p_max_bound; - p_max_bound = tmp; + SWAP(p_min_bound, p_max_bound); } + bool is_beyond_bounds = (p_angle < p_min_bound || p_angle > p_max_bound); + bool is_within_bounds = (p_angle > p_min_bound && p_angle < p_max_bound); + // Note: May not be the most optimal way to clamp, but it always constraints to the nearest angle. - if (p_invert == false) { - if (p_angle < p_min_bound || p_angle > p_max_bound) { - Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound)); - Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound)); - Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle)); - - if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) { - p_angle = p_min_bound; - } else { - p_angle = p_max_bound; - } - } - } else { - if (p_angle > p_min_bound && p_angle < p_max_bound) { - Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound)); - Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound)); - Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle)); - - if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) { - p_angle = p_min_bound; - } else { - p_angle = p_max_bound; - } + if ((!p_invert && is_beyond_bounds) || (p_invert && is_within_bounds)) { + Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound)); + Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound)); + Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle)); + + if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) { + p_angle = p_min_bound; + } else { + p_angle = p_max_bound; } } + return p_angle; } diff --git a/scene/resources/skeleton_modification_3d_fabrik.cpp b/scene/resources/skeleton_modification_3d_fabrik.cpp index 69f75eb7b5..e615615924 100644 --- a/scene/resources/skeleton_modification_3d_fabrik.cpp +++ b/scene/resources/skeleton_modification_3d_fabrik.cpp @@ -232,7 +232,7 @@ void SkeletonModification3DFABRIK::chain_backwards() { int current_bone_idx = fabrik_data_chain[i].bone_idx; Transform3D current_trans = stack->skeleton->local_pose_to_global_pose(current_bone_idx, stack->skeleton->get_bone_local_pose_override(current_bone_idx)); - real_t length = fabrik_data_chain[i].length / (next_bone_trans.origin - current_trans.origin).length(); + real_t length = fabrik_data_chain[i].length / (current_trans.origin.distance_to(next_bone_trans.origin)); current_trans.origin = next_bone_trans.origin.lerp(current_trans.origin, length); // Apply it back to the skeleton @@ -253,7 +253,7 @@ void SkeletonModification3DFABRIK::chain_forwards() { int next_bone_idx = fabrik_data_chain[i + 1].bone_idx; Transform3D next_bone_trans = stack->skeleton->local_pose_to_global_pose(next_bone_idx, stack->skeleton->get_bone_local_pose_override(next_bone_idx)); - real_t length = fabrik_data_chain[i].length / (current_trans.origin - next_bone_trans.origin).length(); + real_t length = fabrik_data_chain[i].length / (next_bone_trans.origin.distance_to(current_trans.origin)); next_bone_trans.origin = current_trans.origin.lerp(next_bone_trans.origin, length); // Apply it back to the skeleton diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index d5e370568d..a8cd872408 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -1176,6 +1176,7 @@ Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_coun ERR_FAIL_COND_V(simplify_func == nullptr, lod); ERR_FAIL_COND_V(vertex_array.size() == 0, lod); ERR_FAIL_COND_V(index_array.size() == 0, lod); + ERR_FAIL_COND_V(index_array.size() % 3 != 0, lod); lod.resize(index_array.size()); LocalVector<float> vertices; //uses floats diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 3dc32632cc..80cab99373 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -1248,6 +1248,14 @@ bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const { return atlas->is_pixel_opaque(x, y); } +Ref<Image> AtlasTexture::get_image() const { + if (!atlas.is_valid()) { + return Ref<Image>(); + } + + return atlas->get_image()->get_rect(region); +} + AtlasTexture::AtlasTexture() {} ///////////////////////////////////////// diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 93f4e2de5a..862b9a47a6 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -250,6 +250,8 @@ public: bool is_pixel_opaque(int p_x, int p_y) const override; + virtual Ref<Image> get_image() const override; + AtlasTexture(); }; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 67cbd0e094..5a8c5b3782 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -1019,20 +1019,25 @@ Vector<Vector2> TileSet::get_tile_shape_polygon() { void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled, Ref<Texture2D> p_texture) { if (tile_meshes_dirty) { - Vector<Vector2> uvs = get_tile_shape_polygon(); + Vector<Vector2> shape = get_tile_shape_polygon(); + Vector<Vector2> uvs; + uvs.resize(shape.size()); + for (int i = 0; i < shape.size(); i++) { + uvs.write[i] = shape[i] + Vector2(0.5, 0.5); + } Vector<Color> colors; - colors.resize(uvs.size()); + colors.resize(shape.size()); colors.fill(Color(1.0, 1.0, 1.0, 1.0)); // Filled mesh. tile_filled_mesh->clear_surfaces(); Array a; a.resize(Mesh::ARRAY_MAX); - a[Mesh::ARRAY_VERTEX] = uvs; + a[Mesh::ARRAY_VERTEX] = shape; a[Mesh::ARRAY_TEX_UV] = uvs; a[Mesh::ARRAY_COLOR] = colors; - a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(uvs); + a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(shape); tile_filled_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES); // Lines mesh. @@ -1040,9 +1045,9 @@ void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform a.clear(); a.resize(Mesh::ARRAY_MAX); // Add the first point again when drawing lines. - uvs.push_back(uvs[0]); + shape.push_back(shape[0]); colors.push_back(colors[0]); - a[Mesh::ARRAY_VERTEX] = uvs; + a[Mesh::ARRAY_VERTEX] = shape; a[Mesh::ARRAY_COLOR] = colors; tile_lines_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINE_STRIP, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES); @@ -3520,6 +3525,13 @@ Vector2i TileSetAtlasSource::get_tile_id(int p_index) const { } bool TileSetAtlasSource::has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_size, int p_animation_columns, Vector2i p_animation_separation, int p_frames_count, Vector2i p_ignored_tile) const { + if (p_atlas_coords.x < 0 || p_atlas_coords.y < 0) { + return false; + } + if (p_size.x <= 0 || p_size.y <= 0) { + return false; + } + Size2i atlas_grid_size = get_atlas_grid_size(); for (int frame = 0; frame < p_frames_count; frame++) { Vector2i frame_coords = p_atlas_coords + (p_size + p_animation_separation) * ((p_animation_columns > 0) ? Vector2i(frame % p_animation_columns, frame / p_animation_columns) : Vector2i(frame, 0)); for (int x = 0; x < p_size.x; x++) { @@ -3528,6 +3540,11 @@ bool TileSetAtlasSource::has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_s if (_coords_mapping_cache.has(coords) && _coords_mapping_cache[coords] != p_ignored_tile) { return false; } + if (coords.x >= atlas_grid_size.x || coords.y >= atlas_grid_size.y) { + if (!(_coords_mapping_cache.has(coords) && _coords_mapping_cache[coords] == p_ignored_tile)) { + return false; // Only accept tiles outside the atlas if they are part of the ignored tile. + } + } } } } @@ -3558,8 +3575,7 @@ Vector2i TileSetAtlasSource::get_tile_effective_texture_offset(Vector2i p_atlas_ margin = Vector2i(MAX(0, margin.x), MAX(0, margin.y)); Vector2i effective_texture_offset = Object::cast_to<TileData>(get_tile_data(p_atlas_coords, p_alternative_tile))->get_texture_offset(); if (ABS(effective_texture_offset.x) > margin.x || ABS(effective_texture_offset.y) > margin.y) { - effective_texture_offset.x = CLAMP(effective_texture_offset.x, -margin.x, margin.x); - effective_texture_offset.y = CLAMP(effective_texture_offset.y, -margin.y, margin.y); + effective_texture_offset = effective_texture_offset.clamp(-margin, margin); } return effective_texture_offset; diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index edd769aa9a..38b98b7bca 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -113,7 +113,7 @@ void Body2DSW::update_mass_properties() { _inv_inertia = 0; _inv_mass = 0; } break; - case PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED: { + case PhysicsServer2D::BODY_MODE_DYNAMIC_LINEAR: { _inv_inertia = 0; _inv_mass = 1.0 / mass; @@ -257,7 +257,7 @@ void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) { set_active(true); } break; - case PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED: { + case PhysicsServer2D::BODY_MODE_DYNAMIC_LINEAR: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; _inv_inertia = 0; angular_velocity = 0; diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index b9b26eb21d..1058f75407 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -34,6 +34,9 @@ #include "core/os/os.h" #include "core/templates/pair.h" #include "physics_server_2d_sw.h" + +#define TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR 0.05 + _FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (!(p_object->get_collision_layer() & p_collision_mask)) { return false; @@ -435,6 +438,8 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape); ERR_FAIL_COND_V(!shape, 0); + real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; + Rect2 aabb = p_shape_xform.xform(shape->get_aabb()); aabb = aabb.merge(Rect2(aabb.position + p_motion, aabb.size)); //motion aabb = aabb.grow(p_margin); @@ -445,7 +450,7 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh rcd.best_len = 0; rcd.best_object = nullptr; rcd.best_shape = 0; - rcd.min_allowed_depth = space->test_motion_min_contact_depth; + rcd.min_allowed_depth = min_contact_depth; for (int i = 0; i < amount; i++) { if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { @@ -569,6 +574,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co ExcludedShapeSW excluded_shape_pairs[max_excluded_shape_pairs]; int excluded_shape_pair_count = 0; + real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; + real_t motion_length = p_motion.length(); Vector2 motion_normal = p_motion / motion_length; @@ -671,6 +678,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co break; } + recovered = true; + Vector2 recover_motion; for (int i = 0; i < cbk.amount; i++) { Vector2 a = sr[i * 2 + 0]; @@ -682,9 +691,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co // Compute depth on recovered motion. real_t depth = n.dot(a + recover_motion) - d; - if (depth > 0.0) { + if (depth > min_contact_depth + CMP_EPSILON) { // Only recover if there is penetration. - recover_motion -= n * depth * 0.4; + recover_motion -= n * (depth - min_contact_depth) * 0.4; } } @@ -693,8 +702,6 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co break; } - recovered = true; - body_transform.elements[2] += recover_motion; body_aabb.position += recover_motion; @@ -870,7 +877,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co rcd.best_shape = 0; // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. - rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth); + rcd.min_allowed_depth = MIN(motion_length, min_contact_depth); int from_shape = best_shape != -1 ? best_shape : 0; int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); @@ -1141,9 +1148,6 @@ void Space2DSW::set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_valu case PhysicsServer2D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break; - case PhysicsServer2D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: - test_motion_min_contact_depth = p_value; - break; } } @@ -1163,8 +1167,6 @@ real_t Space2DSW::get_param(PhysicsServer2D::SpaceParameter p_param) const { return body_time_to_sleep; case PhysicsServer2D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias; - case PhysicsServer2D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: - return test_motion_min_contact_depth; } return 0; } diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index 30c6b4cf55..a1a8a77ee4 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -102,7 +102,6 @@ private: real_t contact_max_separation = 1.5; real_t contact_max_allowed_penetration = 0.3; real_t constraint_bias = 0.2; - real_t test_motion_min_contact_depth = 0.005; enum { INTERSECTION_QUERY_MAX = 2048 diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp index 5924e249a5..91fe80a3dc 100644 --- a/servers/physics_3d/body_3d_sw.cpp +++ b/servers/physics_3d/body_3d_sw.cpp @@ -154,7 +154,7 @@ void Body3DSW::update_mass_properties() { _inv_inertia = Vector3(); _inv_mass = 0; } break; - case PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED: { + case PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR: { _inv_inertia_tensor.set_zero(); _inv_mass = 1.0 / mass; @@ -310,7 +310,7 @@ void Body3DSW::set_mode(PhysicsServer3D::BodyMode p_mode) { set_active(true); } break; - case PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED: { + case PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; _inv_inertia = Vector3(); angular_velocity = Vector3(); diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp index cc4eab1f0b..78c4e30c83 100644 --- a/servers/physics_3d/space_3d_sw.cpp +++ b/servers/physics_3d/space_3d_sw.cpp @@ -34,6 +34,8 @@ #include "core/config/project_settings.h" #include "physics_server_3d_sw.h" +#define TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR 0.05 + _FORCE_INLINE_ static bool _can_collide_with(CollisionObject3DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (!(p_object->get_collision_layer() & p_collision_mask)) { return false; @@ -488,13 +490,15 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform3D &p_sh Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape); ERR_FAIL_COND_V(!shape, 0); + real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; + AABB aabb = p_shape_xform.xform(shape->get_aabb()); aabb = aabb.grow(p_margin); int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); _RestCallbackData rcd; - rcd.min_allowed_depth = space->test_motion_min_contact_depth; + rcd.min_allowed_depth = min_contact_depth; for (int i = 0; i < amount; i++) { if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { @@ -658,6 +662,8 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb)); body_aabb = body_aabb.grow(p_margin); + real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; + real_t motion_length = p_motion.length(); Vector3 motion_normal = p_motion / motion_length; @@ -711,8 +717,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co break; } - Vector3 recover_motion; + recovered = true; + Vector3 recover_motion; for (int i = 0; i < cbk.amount; i++) { Vector3 a = sr[i * 2 + 0]; Vector3 b = sr[i * 2 + 1]; @@ -723,9 +730,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co // Compute depth on recovered motion. real_t depth = n.dot(a + recover_motion) - d; - if (depth > 0.0) { + if (depth > min_contact_depth + CMP_EPSILON) { // Only recover if there is penetration. - recover_motion -= n * depth * 0.4; + recover_motion -= n * (depth - min_contact_depth) * 0.4; } } @@ -734,8 +741,6 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co break; } - recovered = true; - body_transform.origin += recover_motion; body_aabb.position += recover_motion; @@ -889,7 +894,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co } // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. - rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth); + rcd.min_allowed_depth = MIN(motion_length, min_contact_depth); int from_shape = best_shape != -1 ? best_shape : 0; int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); @@ -1158,9 +1163,6 @@ void Space3DSW::set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_valu case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break; - case PhysicsServer3D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: - test_motion_min_contact_depth = p_value; - break; } } @@ -1182,8 +1184,6 @@ real_t Space3DSW::get_param(PhysicsServer3D::SpaceParameter p_param) const { return body_angular_velocity_damp_ratio; case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias; - case PhysicsServer3D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: - return test_motion_min_contact_depth; } return 0; } diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h index fc2a7d304d..daa1244bf8 100644 --- a/servers/physics_3d/space_3d_sw.h +++ b/servers/physics_3d/space_3d_sw.h @@ -96,7 +96,6 @@ private: real_t contact_max_separation = 0.05; real_t contact_max_allowed_penetration = 0.01; real_t constraint_bias = 0.01; - real_t test_motion_min_contact_depth = 0.00001; enum { INTERSECTION_QUERY_MAX = 2048 diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 8d5367e735..3fc94cd727 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -670,7 +670,6 @@ void PhysicsServer2D::_bind_methods() { BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD); BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP); BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS); - BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH); BIND_ENUM_CONSTANT(SHAPE_WORLD_BOUNDARY); BIND_ENUM_CONSTANT(SHAPE_SEPARATION_RAY); @@ -700,7 +699,7 @@ void PhysicsServer2D::_bind_methods() { BIND_ENUM_CONSTANT(BODY_MODE_STATIC); BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC); BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC); - BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LOCKED); + BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LINEAR); BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE); BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 30d3c47051..4b85382fe5 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -262,7 +262,6 @@ public: SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD, SPACE_PARAM_BODY_TIME_TO_SLEEP, SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS, - SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH, }; virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0; @@ -350,7 +349,7 @@ public: BODY_MODE_STATIC, BODY_MODE_KINEMATIC, BODY_MODE_DYNAMIC, - BODY_MODE_DYNAMIC_LOCKED, + BODY_MODE_DYNAMIC_LINEAR, }; virtual RID body_create() = 0; diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index e868246636..9384cdc7b8 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -834,7 +834,7 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(BODY_MODE_STATIC); BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC); BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC); - BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LOCKED); + BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LINEAR); BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE); BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION); @@ -867,7 +867,6 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP); BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO); BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS); - BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH); BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_X); BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_Y); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 3e34da9561..14d395e714 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -271,7 +271,6 @@ public: SPACE_PARAM_BODY_TIME_TO_SLEEP, SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO, SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS, - SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH }; virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0; @@ -361,7 +360,7 @@ public: BODY_MODE_STATIC, BODY_MODE_KINEMATIC, BODY_MODE_DYNAMIC, - BODY_MODE_DYNAMIC_LOCKED, + BODY_MODE_DYNAMIC_LINEAR, }; virtual RID body_create() = 0; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index f507a83072..c2227587ec 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1394,6 +1394,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p update_skeletons = true; } } + c = c->next; } } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index b0fdd0b0a9..0f98417215 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -2415,6 +2415,13 @@ RID RendererSceneRenderRD::render_buffers_get_back_depth_texture(RID p_render_bu return rb->depth_back_texture; } +RID RendererSceneRenderRD::render_buffers_get_depth_texture(RID p_render_buffers) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + ERR_FAIL_COND_V(!rb, RID()); + + return rb->depth_texture; +} + RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index eb61af517a..db423b7d25 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -1197,6 +1197,7 @@ public: virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override; virtual void gi_set_use_half_resolution(bool p_enable) override; + RID render_buffers_get_depth_texture(RID p_render_buffers); RID render_buffers_get_ao_texture(RID p_render_buffers); RID render_buffers_get_back_buffer_texture(RID p_render_buffers); RID render_buffers_get_back_depth_texture(RID p_render_buffers); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index ec0d25376f..ed87932762 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -4138,6 +4138,7 @@ void RendererStorageRD::particles_set_use_local_coordinates(RID p_particles, boo ERR_FAIL_COND(!particles); particles->use_local_coords = p_enable; + particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES); } void RendererStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) { @@ -4352,10 +4353,8 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { total_amount *= particles->trail_bind_poses.size(); } - Vector<ParticleData> data; - data.resize(total_amount); - Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(particles->particle_buffer); + ERR_FAIL_COND_V(buffer.size() != (int)(total_amount * sizeof(ParticleData)), AABB()); Transform3D inv = particles->emission_transform.affine_inverse(); @@ -4363,7 +4362,7 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { if (buffer.size()) { bool first = true; - const ParticleData *particle_data = (const ParticleData *)data.ptr(); + const ParticleData *particle_data = reinterpret_cast<const ParticleData *>(buffer.ptr()); for (int i = 0; i < total_amount; i++) { if (particle_data[i].active) { Vector3 pos = Vector3(particle_data[i].xform[12], particle_data[i].xform[13], particle_data[i].xform[14]); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 02395a884f..4950b7d5e5 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -621,7 +621,6 @@ private: float color[4]; float custom[3]; float lifetime; - uint32_t pad[3]; }; struct ParticlesFrameParams { diff --git a/servers/xr/xr_interface_extension.cpp b/servers/xr/xr_interface_extension.cpp index 315442fc57..7fdf90770d 100644 --- a/servers/xr/xr_interface_extension.cpp +++ b/servers/xr/xr_interface_extension.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "xr_interface_extension.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" #include "servers/rendering/renderer_storage.h" #include "servers/rendering/rendering_server_globals.h" @@ -246,17 +247,21 @@ void XRInterfaceExtension::notification(int p_what) { } RID XRInterfaceExtension::get_render_target_texture(RID p_render_target) { - RendererStorage *storage = RSG::storage; - ERR_FAIL_NULL_V_MSG(storage, RID(), "Renderer storage not setup"); + // In due time this will need to be enhance to return the correct INTERNAL RID for the chosen rendering engine. + // So once a GLES driver is implemented we'll return that and the implemented plugin needs to handle this correctly too. + RendererStorageRD *rd_storage = RendererStorageRD::base_singleton; + ERR_FAIL_NULL_V_MSG(rd_storage, RID(), "Renderer storage not setup"); - return storage->render_target_get_texture(p_render_target); + return rd_storage->render_target_get_rd_texture(p_render_target); } /* RID XRInterfaceExtension::get_render_target_depth(RID p_render_target) { - RendererStorage *storage = RSG::storage; - ERR_FAIL_NULL_V_MSG(storage, RID(), "Renderer storage not setup"); + // TODO implement this, the problem is that our depth texture isn't part of our render target as it is used for 3D rendering only + // but we don't have access to our render buffers from here.... + RendererSceneRenderRD * rd_scene = ?????; + ERR_FAIL_NULL_V_MSG(rd_scene, RID(), "Renderer scene render not setup"); - return storage->render_target_get_depth(p_render_target); + return rd_scene->render_buffers_get_depth_texture(????????????); } */ diff --git a/tests/test_physics_3d.cpp b/tests/test_physics_3d.cpp index 3d1dad6545..d839ae26b7 100644 --- a/tests/test_physics_3d.cpp +++ b/tests/test_physics_3d.cpp @@ -361,7 +361,7 @@ public: RID mesh_instance = vs->instance_create2(capsule_mesh, scenario); character = ps->body_create(); - ps->body_set_mode(character, PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED); + ps->body_set_mode(character, PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR); ps->body_set_space(character, space); //todo add space ps->body_add_shape(character, capsule_shape); diff --git a/tests/test_translation.h b/tests/test_translation.h index 52ff49bf9b..93c53bbbc9 100644 --- a/tests/test_translation.h +++ b/tests/test_translation.h @@ -35,6 +35,10 @@ #include "core/string/translation.h" #include "core/string/translation_po.h" +#ifdef TOOLS_ENABLED +#include "editor/import/resource_importer_csv_translation.h" +#endif + #include "thirdparty/doctest/doctest.h" namespace TestTranslation { @@ -145,6 +149,33 @@ TEST_CASE("[OptimizedTranslation] Generate from Translation and read messages") CHECK(messages.size() == 0); } +#ifdef TOOLS_ENABLED +TEST_CASE("[Translation] CSV import") { + Ref<ResourceImporterCSVTranslation> import_csv_translation = memnew(ResourceImporterCSVTranslation); + + Map<StringName, Variant> options; + options["compress"] = false; + options["delimiter"] = 0; + + List<String> gen_files; + + Error result = import_csv_translation->import(TestUtils::get_data_path("translations.csv"), + "", options, nullptr, &gen_files); + CHECK(result == OK); + CHECK(gen_files.size() == 2); + + for (const String &file : gen_files) { + Ref<Translation> translation = ResourceLoader::load(file); + CHECK(translation.is_valid()); + TranslationServer::get_singleton()->add_translation(translation); + } + + TranslationServer::get_singleton()->set_locale("de"); + + CHECK(Object().tr("GOOD_MORNING", "") == "Guten Morgen"); +} +#endif // TOOLS_ENABLED + } // namespace TestTranslation #endif // TEST_TRANSLATION_H |