summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct3
-rw-r--r--core/io/packet_peer_udp.cpp65
-rw-r--r--core/io/packet_peer_udp.h7
-rw-r--r--core/io/translation_loader_po.cpp22
-rw-r--r--core/io/udp_server.cpp100
-rw-r--r--core/io/udp_server.h29
-rw-r--r--doc/classes/CodeHighlighter.xml145
-rw-r--r--doc/classes/CollisionObject2D.xml2
-rw-r--r--doc/classes/DisplayServer.xml2
-rw-r--r--doc/classes/EditorSyntaxHighlighter.xml31
-rw-r--r--doc/classes/ProjectSettings.xml4
-rw-r--r--doc/classes/ScriptEditor.xml28
-rw-r--r--doc/classes/ScriptEditorBase.xml67
-rw-r--r--doc/classes/SyntaxHighlighter.xml53
-rw-r--r--doc/classes/TextEdit.xml68
-rw-r--r--doc/classes/UDPServer.xml20
-rw-r--r--doc/classes/VehicleBody3D.xml1
-rw-r--r--doc/classes/VehicleWheel3D.xml1
-rw-r--r--editor/editor_dir_dialog.cpp2
-rw-r--r--editor/editor_node.cpp4
-rw-r--r--editor/plugins/script_editor_plugin.cpp4
-rw-r--r--editor/plugins/shader_editor_plugin.cpp2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp1
-rw-r--r--editor/project_export.cpp4
-rw-r--r--editor/quick_open.cpp271
-rw-r--r--editor/quick_open.h31
-rw-r--r--main/main.cpp32
-rw-r--r--misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@2x.pngbin21443 -> 14779 bytes
-rw-r--r--misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@3x.pngbin21443 -> 14779 bytes
-rw-r--r--modules/enet/networked_multiplayer_enet.cpp3
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp3
-rw-r--r--modules/gdscript/gdscript.cpp62
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp2
-rw-r--r--platform/android/display_server_android.cpp2
-rw-r--r--platform/osx/display_server_osx.h2
-rw-r--r--platform/osx/display_server_osx.mm24
-rw-r--r--platform/uwp/os_uwp.h2
-rw-r--r--platform/windows/display_server_windows.cpp2
-rw-r--r--platform/windows/display_server_windows.h2
-rw-r--r--scene/3d/physics_body_3d.cpp2
-rw-r--r--scene/gui/dialogs.cpp8
-rw-r--r--scene/gui/dialogs.h4
-rw-r--r--scene/gui/rich_text_label.cpp2
-rw-r--r--scene/register_scene_types.cpp2
-rw-r--r--servers/display_server.cpp4
-rw-r--r--servers/display_server.h2
-rw-r--r--servers/physics_3d/body_3d_sw.cpp2
-rw-r--r--servers/rendering/shader_language.cpp12
-rw-r--r--thirdparty/enet/enet/enet.h34
-rw-r--r--thirdparty/enet/enet/godot.h8
-rw-r--r--thirdparty/enet/enet/godot_ext.h18
-rw-r--r--thirdparty/enet/godot.cpp11
-rw-r--r--thirdparty/enet/patches/dtls_support.patch13
-rw-r--r--thirdparty/enet/patches/godot.patch (renamed from thirdparty/enet/patches/ipv6_support.patch)71
54 files changed, 880 insertions, 416 deletions
diff --git a/SConstruct b/SConstruct
index ef74ce7736..e7ca8b3030 100644
--- a/SConstruct
+++ b/SConstruct
@@ -72,7 +72,6 @@ env_base.disabled_modules = []
env_base.use_ptrcall = False
env_base.module_version_string = ""
env_base.msvc = False
-env_base.stable_release = version.status == "stable"
env_base.__class__.disable_module = methods.disable_module
@@ -129,7 +128,7 @@ opts.Add("custom_modules", "A list of comma-separated directory paths containing
opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False))
opts.Add(BoolVariable("progress", "Show a progress indicator during compilation", True))
opts.Add(EnumVariable("warnings", "Level of compilation warnings", "all", ("extra", "all", "moderate", "no")))
-opts.Add(BoolVariable("werror", "Treat compiler warnings as errors", not env_base.stable_release))
+opts.Add(BoolVariable("werror", "Treat compiler warnings as errors", False))
opts.Add(BoolVariable("dev", "If yes, alias for verbose=yes warnings=extra werror=yes", False))
opts.Add("extra_suffix", "Custom extra suffix added to the base filename of all generated binary files", "")
opts.Add(BoolVariable("vsproj", "Generate a Visual Studio solution", False))
diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp
index 862fca96fc..e633a56d54 100644
--- a/core/io/packet_peer_udp.cpp
+++ b/core/io/packet_peer_udp.cpp
@@ -31,12 +31,14 @@
#include "packet_peer_udp.h"
#include "core/io/ip.h"
+#include "core/io/udp_server.h"
void PacketPeerUDP::set_blocking_mode(bool p_enable) {
blocking = p_enable;
}
void PacketPeerUDP::set_broadcast_enabled(bool p_enabled) {
+ ERR_FAIL_COND(udp_server);
broadcast = p_enabled;
if (_sock.is_valid() && _sock->is_open()) {
_sock->set_broadcasting_enabled(p_enabled);
@@ -44,6 +46,7 @@ void PacketPeerUDP::set_broadcast_enabled(bool p_enabled) {
}
Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_if_name) {
+ ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!p_multi_address.is_valid(), ERR_INVALID_PARAMETER);
@@ -58,6 +61,7 @@ Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_i
}
Error PacketPeerUDP::leave_multicast_group(IP_Address p_multi_address, String p_if_name) {
+ ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!_sock->is_open(), ERR_UNCONFIGURED);
return _sock->leave_multicast_group(p_multi_address, p_if_name);
@@ -130,7 +134,7 @@ Error PacketPeerUDP::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
}
do {
- if (connected) {
+ if (connected && !udp_server) {
err = _sock->send(p_buffer, p_buffer_size, sent);
} else {
err = _sock->sendto(p_buffer, p_buffer_size, sent, peer_addr, peer_port);
@@ -186,26 +190,25 @@ Error PacketPeerUDP::listen(int p_port, const IP_Address &p_bind_address, int p_
return OK;
}
-Error PacketPeerUDP::connect_socket(Ref<NetSocket> p_sock) {
- Error err;
- int read = 0;
- uint16_t r_port;
- IP_Address r_ip;
-
- err = p_sock->recvfrom(recv_buffer, sizeof(recv_buffer), read, r_ip, r_port, true);
- ERR_FAIL_COND_V(err != OK, err);
- err = p_sock->connect_to_host(r_ip, r_port);
- ERR_FAIL_COND_V(err != OK, err);
+Error PacketPeerUDP::connect_shared_socket(Ref<NetSocket> p_sock, IP_Address p_ip, uint16_t p_port, UDPServer *p_server) {
+ udp_server = p_server;
+ connected = true;
_sock = p_sock;
- peer_addr = r_ip;
- peer_port = r_port;
+ peer_addr = p_ip;
+ peer_port = p_port;
packet_ip = peer_addr;
packet_port = peer_port;
- connected = true;
return OK;
}
+void PacketPeerUDP::disconnect_shared_socket() {
+ udp_server = nullptr;
+ _sock = Ref<NetSocket>(NetSocket::create());
+ close();
+}
+
Error PacketPeerUDP::connect_to_host(const IP_Address &p_host, int p_port) {
+ ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
@@ -243,7 +246,11 @@ bool PacketPeerUDP::is_connected_to_host() const {
}
void PacketPeerUDP::close() {
- if (_sock.is_valid()) {
+ if (udp_server) {
+ udp_server->remove_peer(peer_addr, peer_port);
+ udp_server = nullptr;
+ _sock = Ref<NetSocket>(NetSocket::create());
+ } else if (_sock.is_valid()) {
_sock->close();
}
rb.resize(16);
@@ -262,6 +269,9 @@ Error PacketPeerUDP::_poll() {
if (!_sock->is_open()) {
return FAILED;
}
+ if (udp_server) {
+ return OK; // Handled by UDPServer.
+ }
Error err;
int read;
@@ -284,24 +294,29 @@ Error PacketPeerUDP::_poll() {
return FAILED;
}
- if (rb.space_left() < read + 24) {
+ err = store_packet(ip, port, recv_buffer, read);
#ifdef TOOLS_ENABLED
+ if (err != OK) {
WARN_PRINT("Buffer full, dropping packets!");
-#endif
- continue;
}
-
- uint32_t port32 = port;
- rb.write(ip.get_ipv6(), 16);
- rb.write((uint8_t *)&port32, 4);
- rb.write((uint8_t *)&read, 4);
- rb.write(recv_buffer, read);
- ++queue_count;
+#endif
}
return OK;
}
+Error PacketPeerUDP::store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size) {
+ if (rb.space_left() < p_buf_size + 24) {
+ return ERR_OUT_OF_MEMORY;
+ }
+ rb.write(p_ip.get_ipv6(), 16);
+ rb.write((uint8_t *)&p_port, 4);
+ rb.write((uint8_t *)&p_buf_size, 4);
+ rb.write(p_buf, p_buf_size);
+ ++queue_count;
+ return OK;
+}
+
bool PacketPeerUDP::is_listening() const {
return _sock.is_valid() && _sock->is_open();
}
diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h
index ad0a60f60d..9a44a1ebea 100644
--- a/core/io/packet_peer_udp.h
+++ b/core/io/packet_peer_udp.h
@@ -35,6 +35,8 @@
#include "core/io/net_socket.h"
#include "core/io/packet_peer.h"
+class UDPServer;
+
class PacketPeerUDP : public PacketPeer {
GDCLASS(PacketPeerUDP, PacketPeer);
@@ -55,6 +57,7 @@ protected:
bool connected = false;
bool blocking = true;
bool broadcast = false;
+ UDPServer *udp_server = nullptr;
Ref<NetSocket> _sock;
static void _bind_methods();
@@ -72,7 +75,9 @@ public:
Error wait();
bool is_listening() const;
- Error connect_socket(Ref<NetSocket> p_sock); // Used by UDPServer
+ Error connect_shared_socket(Ref<NetSocket> p_sock, IP_Address p_ip, uint16_t p_port, UDPServer *ref); // Used by UDPServer
+ void disconnect_shared_socket(); // Used by UDPServer
+ Error store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size); // Used internally and by UDPServer
Error connect_to_host(const IP_Address &p_host, int p_port);
bool is_connected_to_host() const;
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index 0e0a948953..11aeddee09 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -35,7 +35,6 @@
RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
enum Status {
-
STATUS_NONE,
STATUS_READING_ID,
STATUS_READING_STRING,
@@ -56,6 +55,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
bool skip_this = false;
bool skip_next = false;
bool is_eof = false;
+ const String path = f->get_path();
while (!is_eof) {
String l = f->get_line().strip_edges();
@@ -65,7 +65,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
if (is_eof && l.empty()) {
if (status == STATUS_READING_ID) {
memdelete(f);
- ERR_FAIL_V_MSG(RES(), f->get_path() + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: ");
+ ERR_FAIL_V_MSG(RES(), "Unexpected EOF while reading 'msgid' at: " + path + ":" + itos(line));
} else {
break;
}
@@ -74,7 +74,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
if (l.begins_with("msgid")) {
if (status == STATUS_READING_ID) {
memdelete(f);
- ERR_FAIL_V_MSG(RES(), f->get_path() + ":" + itos(line) + " Unexpected 'msgid', was expecting 'msgstr' while parsing: ");
+ ERR_FAIL_V_MSG(RES(), "Unexpected 'msgid', was expecting 'msgstr' while parsing: " + path + ":" + itos(line));
}
if (msg_id != "") {
@@ -96,7 +96,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
if (l.begins_with("msgstr")) {
if (status != STATUS_READING_ID) {
memdelete(f);
- ERR_FAIL_V_MSG(RES(), f->get_path() + ":" + itos(line) + " Unexpected 'msgstr', was expecting 'msgid' while parsing: ");
+ ERR_FAIL_V_MSG(RES(), "Unexpected 'msgstr', was expecting 'msgid' while parsing: " + path + ":" + itos(line));
}
l = l.substr(6, l.length()).strip_edges();
@@ -111,7 +111,10 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
continue; //nothing to read or comment
}
- ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, RES(), f->get_path() + ":" + itos(line) + " Invalid line '" + l + "' while parsing: ");
+ if (!l.begins_with("\"") || status == STATUS_NONE) {
+ memdelete(f);
+ ERR_FAIL_V_MSG(RES(), "Invalid line '" + l + "' while parsing: " + path + ":" + itos(line));
+ }
l = l.substr(1, l.length());
// Find final quote, ignoring escaped ones (\").
@@ -133,7 +136,10 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
escape_next = false;
}
- ERR_FAIL_COND_V_MSG(end_pos == -1, RES(), f->get_path() + ":" + itos(line) + ": Expected '\"' at end of message while parsing file.");
+ if (end_pos == -1) {
+ memdelete(f);
+ ERR_FAIL_V_MSG(RES(), "Expected '\"' at end of message while parsing: " + path + ":" + itos(line));
+ }
l = l.substr(0, end_pos);
l = l.c_unescape();
@@ -147,7 +153,6 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
line++;
}
- f->close();
memdelete(f);
if (status == STATUS_READING_STRING) {
@@ -160,7 +165,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
}
}
- ERR_FAIL_COND_V_MSG(config == "", RES(), "No config found in file: " + f->get_path() + ".");
+ ERR_FAIL_COND_V_MSG(config == "", RES(), "No config found in file: " + path + ".");
Vector<String> configs = config.split("\n");
for (int i = 0; i < configs.size(); i++) {
@@ -197,7 +202,6 @@ RES TranslationLoaderPO::load(const String &p_path, const String &p_original_pat
void TranslationLoaderPO::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("po");
- //p_extensions->push_back("mo"); //mo in the future...
}
bool TranslationLoaderPO::handles_type(const String &p_type) const {
diff --git a/core/io/udp_server.cpp b/core/io/udp_server.cpp
index 1d329daf8b..acd15aadc6 100644
--- a/core/io/udp_server.cpp
+++ b/core/io/udp_server.cpp
@@ -32,10 +32,58 @@
void UDPServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &UDPServer::listen, DEFVAL("*"));
+ ClassDB::bind_method(D_METHOD("poll"), &UDPServer::poll);
ClassDB::bind_method(D_METHOD("is_connection_available"), &UDPServer::is_connection_available);
ClassDB::bind_method(D_METHOD("is_listening"), &UDPServer::is_listening);
ClassDB::bind_method(D_METHOD("take_connection"), &UDPServer::take_connection);
ClassDB::bind_method(D_METHOD("stop"), &UDPServer::stop);
+ ClassDB::bind_method(D_METHOD("set_max_pending_connections", "max_pending_connections"), &UDPServer::set_max_pending_connections);
+ ClassDB::bind_method(D_METHOD("get_max_pending_connections"), &UDPServer::get_max_pending_connections);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_pending_connections", PROPERTY_HINT_RANGE, "0,256,1"), "set_max_pending_connections", "get_max_pending_connections");
+}
+
+Error UDPServer::poll() {
+ ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
+ if (!_sock->is_open()) {
+ return ERR_UNCONFIGURED;
+ }
+ Error err;
+ int read;
+ IP_Address ip;
+ uint16_t port;
+ while (true) {
+ err = _sock->recvfrom(recv_buffer, sizeof(recv_buffer), read, ip, port);
+ if (err != OK) {
+ if (err == ERR_BUSY) {
+ break;
+ }
+ return FAILED;
+ }
+ Peer p;
+ p.ip = ip;
+ p.port = port;
+ List<Peer>::Element *E = peers.find(p);
+ if (!E) {
+ E = pending.find(p);
+ }
+ if (E) {
+ E->get().peer->store_packet(ip, port, recv_buffer, read);
+ } else {
+ if (pending.size() >= max_pending_connections) {
+ // Drop connection.
+ continue;
+ }
+ // It's a new peer, add it to the pending list.
+ Peer peer;
+ peer.ip = ip;
+ peer.port = port;
+ peer.peer = memnew(PacketPeerUDP);
+ peer.peer->connect_shared_socket(_sock, ip, port, this);
+ peer.peer->store_packet(ip, port, recv_buffer, read);
+ pending.push_back(peer);
+ }
+ }
+ return OK;
}
Error UDPServer::listen(uint16_t p_port, const IP_Address &p_bind_address) {
@@ -82,8 +130,24 @@ bool UDPServer::is_connection_available() const {
return false;
}
- Error err = _sock->poll(NetSocket::POLL_TYPE_IN, 0);
- return (err == OK);
+ return pending.size() > 0;
+}
+
+void UDPServer::set_max_pending_connections(int p_max) {
+ ERR_FAIL_COND_MSG(p_max < 0, "Max pending connections value must be a positive number (0 means refuse new connections).");
+ max_pending_connections = p_max;
+ while (p_max > pending.size()) {
+ List<Peer>::Element *E = pending.back();
+ if (!E) {
+ break;
+ }
+ memdelete(E->get().peer);
+ pending.erase(E);
+ }
+}
+
+int UDPServer::get_max_pending_connections() const {
+ return max_pending_connections;
}
Ref<PacketPeerUDP> UDPServer::take_connection() {
@@ -92,11 +156,20 @@ Ref<PacketPeerUDP> UDPServer::take_connection() {
return conn;
}
- conn = Ref<PacketPeerUDP>(memnew(PacketPeerUDP));
- conn->connect_socket(_sock);
- _sock = Ref<NetSocket>(NetSocket::create());
- listen(bind_port, bind_address);
- return conn;
+ Peer peer = pending[0];
+ pending.pop_front();
+ peers.push_back(peer);
+ return peer.peer;
+}
+
+void UDPServer::remove_peer(IP_Address p_ip, int p_port) {
+ Peer peer;
+ peer.ip = p_ip;
+ peer.port = p_port;
+ List<Peer>::Element *E = peers.find(peer);
+ if (E) {
+ peers.erase(E);
+ }
}
void UDPServer::stop() {
@@ -105,6 +178,19 @@ void UDPServer::stop() {
}
bind_port = 0;
bind_address = IP_Address();
+ List<Peer>::Element *E = peers.front();
+ while (E) {
+ E->get().peer->disconnect_shared_socket();
+ E = E->next();
+ }
+ E = pending.front();
+ while (E) {
+ E->get().peer->disconnect_shared_socket();
+ memdelete(E->get().peer);
+ E = E->next();
+ }
+ peers.clear();
+ pending.clear();
}
UDPServer::UDPServer() :
diff --git a/core/io/udp_server.h b/core/io/udp_server.h
index 90bb82b62b..3175b09b19 100644
--- a/core/io/udp_server.h
+++ b/core/io/udp_server.h
@@ -38,15 +38,40 @@ class UDPServer : public Reference {
GDCLASS(UDPServer, Reference);
protected:
- static void _bind_methods();
- int bind_port;
+ enum {
+ PACKET_BUFFER_SIZE = 65536
+ };
+
+ struct Peer {
+ PacketPeerUDP *peer;
+ IP_Address ip;
+ uint16_t port = 0;
+
+ bool operator==(const Peer &p_other) const {
+ return (ip == p_other.ip && port == p_other.port);
+ }
+ };
+ uint8_t recv_buffer[PACKET_BUFFER_SIZE];
+
+ int bind_port = 0;
IP_Address bind_address;
+
+ List<Peer> peers;
+ List<Peer> pending;
+ int max_pending_connections = 16;
+
Ref<NetSocket> _sock;
+ static void _bind_methods();
+
public:
+ void remove_peer(IP_Address p_ip, int p_port);
Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*"));
+ Error poll();
bool is_listening() const;
bool is_connection_available() const;
+ void set_max_pending_connections(int p_max);
+ int get_max_pending_connections() const;
Ref<PacketPeerUDP> take_connection();
void stop();
diff --git a/doc/classes/CodeHighlighter.xml b/doc/classes/CodeHighlighter.xml
new file mode 100644
index 0000000000..7a1dad547b
--- /dev/null
+++ b/doc/classes/CodeHighlighter.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CodeHighlighter" inherits="SyntaxHighlighter" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_color_region">
+ <return type="void">
+ </return>
+ <argument index="0" name="p_start_key" type="String">
+ </argument>
+ <argument index="1" name="p_end_key" type="String">
+ </argument>
+ <argument index="2" name="p_color" type="Color">
+ </argument>
+ <argument index="3" name="p_line_only" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_keyword_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="keyword" type="String">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_member_keyword_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="member_keyword" type="String">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="clear_color_regions">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="clear_keyword_colors">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="clear_member_keyword_colors">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_keyword_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="keyword" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_member_keyword_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="member_keyword" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_color_region" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="p_start_key" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_keyword_color" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="keyword" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_member_keyword_color" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="member_keyword" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_color_region">
+ <return type="void">
+ </return>
+ <argument index="0" name="p_start_key" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_keyword_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="keyword" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_member_keyword_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="member_keyword" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="color_regions" type="Dictionary" setter="set_color_regions" getter="get_color_regions" default="{}">
+ </member>
+ <member name="function_color" type="Color" setter="set_function_color" getter="get_function_color" default="Color( 0, 0, 0, 1 )">
+ </member>
+ <member name="keyword_colors" type="Dictionary" setter="set_keyword_colors" getter="get_keyword_colors" default="{}">
+ </member>
+ <member name="member_keyword_colors" type="Dictionary" setter="set_member_keyword_colors" getter="get_member_keyword_colors" default="{}">
+ </member>
+ <member name="member_variable_color" type="Color" setter="set_member_variable_color" getter="get_member_variable_color" default="Color( 0, 0, 0, 1 )">
+ </member>
+ <member name="number_color" type="Color" setter="set_number_color" getter="get_number_color" default="Color( 0, 0, 0, 1 )">
+ </member>
+ <member name="symbol_color" type="Color" setter="set_symbol_color" getter="get_symbol_color" default="Color( 0, 0, 0, 1 )">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml
index c2dd48108f..bf82e921fb 100644
--- a/doc/classes/CollisionObject2D.xml
+++ b/doc/classes/CollisionObject2D.xml
@@ -216,7 +216,7 @@
</method>
</methods>
<members>
- <member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable">
+ <member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" default="true">
If [code]true[/code], this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events.
</member>
</members>
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index d118cf8205..49af8d7de2 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -139,7 +139,7 @@
<description>
</description>
</method>
- <method name="get_swap_ok_cancel">
+ <method name="get_swap_cancel_ok">
<return type="bool">
</return>
<description>
diff --git a/doc/classes/EditorSyntaxHighlighter.xml b/doc/classes/EditorSyntaxHighlighter.xml
new file mode 100644
index 0000000000..103d95e1d6
--- /dev/null
+++ b/doc/classes/EditorSyntaxHighlighter.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorSyntaxHighlighter" inherits="SyntaxHighlighter" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_get_name" qualifiers="virtual">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="_get_supported_extentions" qualifiers="virtual">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="_get_supported_languages" qualifiers="virtual">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index c8427ac61f..e255ce2e1a 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -472,8 +472,8 @@
<member name="gui/common/default_scroll_deadzone" type="int" setter="" getter="" default="0">
Default value for [member ScrollContainer.scroll_deadzone], which will be used for all [ScrollContainer]s unless overridden.
</member>
- <member name="gui/common/swap_ok_cancel" type="bool" setter="" getter="" default="false">
- If [code]true[/code], swaps OK and Cancel buttons in dialogs on Windows and UWP to follow interface conventions.
+ <member name="gui/common/swap_cancel_ok" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], swaps Cancel and OK buttons in dialogs on Windows and UWP to follow interface conventions.
</member>
<member name="gui/common/text_edit_undo_stack_max_size" type="int" setter="" getter="" default="1024">
</member>
diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml
index f0ad781f77..20b0750431 100644
--- a/doc/classes/ScriptEditor.xml
+++ b/doc/classes/ScriptEditor.xml
@@ -33,6 +33,12 @@
<description>
</description>
</method>
+ <method name="get_current_editor" qualifiers="const">
+ <return type="ScriptEditorBase">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_current_script">
<return type="Script">
</return>
@@ -50,6 +56,12 @@
<description>
</description>
</method>
+ <method name="get_open_script_editors" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_open_scripts" qualifiers="const">
<return type="Array">
</return>
@@ -76,6 +88,22 @@
<description>
</description>
</method>
+ <method name="register_syntax_highlighter">
+ <return type="void">
+ </return>
+ <argument index="0" name="syntax_highlighter" type="EditorSyntaxHighlighter">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="unregister_syntax_highlighter">
+ <return type="void">
+ </return>
+ <argument index="0" name="syntax_highlighter" type="EditorSyntaxHighlighter">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="editor_script_changed">
diff --git a/doc/classes/ScriptEditorBase.xml b/doc/classes/ScriptEditorBase.xml
new file mode 100644
index 0000000000..9968ae06c3
--- /dev/null
+++ b/doc/classes/ScriptEditorBase.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ScriptEditorBase" inherits="VBoxContainer" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_syntax_highlighter" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="highlighter" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <signals>
+ <signal name="edited_script_changed">
+ <description>
+ </description>
+ </signal>
+ <signal name="go_to_help">
+ <argument index="0" name="what" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="name_changed">
+ <description>
+ </description>
+ </signal>
+ <signal name="replace_in_files_requested">
+ <argument index="0" name="text" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="request_help">
+ <argument index="0" name="topic" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="request_open_script_at_line">
+ <argument index="0" name="script" type="Object">
+ </argument>
+ <argument index="1" name="line" type="int">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="request_save_history">
+ <description>
+ </description>
+ </signal>
+ <signal name="search_in_files_requested">
+ <argument index="0" name="text" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/SyntaxHighlighter.xml b/doc/classes/SyntaxHighlighter.xml
new file mode 100644
index 0000000000..2d6e3de02a
--- /dev/null
+++ b/doc/classes/SyntaxHighlighter.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SyntaxHighlighter" inherits="Resource" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_get_line_syntax_highlighting" qualifiers="virtual">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="p_line" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="_update_cache" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="clear_highlighting_cache">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_line_syntax_highlighting">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="p_line" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_text_edit">
+ <return type="TextEdit">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="update_cache">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index b7b4278da0..b7240655af 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -9,32 +9,6 @@
<tutorials>
</tutorials>
<methods>
- <method name="add_color_region">
- <return type="void">
- </return>
- <argument index="0" name="begin_key" type="String">
- </argument>
- <argument index="1" name="end_key" type="String">
- </argument>
- <argument index="2" name="color" type="Color">
- </argument>
- <argument index="3" name="line_only" type="bool" default="false">
- </argument>
- <description>
- Adds color region (given the delimiters) and its colors.
- </description>
- </method>
- <method name="add_keyword_color">
- <return type="void">
- </return>
- <argument index="0" name="keyword" type="String">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- Adds a [code]keyword[/code] and its [Color].
- </description>
- </method>
<method name="can_fold" qualifiers="const">
<return type="bool">
</return>
@@ -51,13 +25,6 @@
Centers the viewport on the line the editing cursor is at. This also resets the [member scroll_horizontal] value to [code]0[/code].
</description>
</method>
- <method name="clear_colors">
- <return type="void">
- </return>
- <description>
- Clears all custom syntax coloring information previously added with [method add_color_region] or [method add_keyword_color].
- </description>
- </method>
<method name="clear_undo_history">
<return type="void">
</return>
@@ -152,15 +119,6 @@
Returns an array containing the line number of each breakpoint.
</description>
</method>
- <method name="get_keyword_color" qualifiers="const">
- <return type="Color">
- </return>
- <argument index="0" name="keyword" type="String">
- </argument>
- <description>
- Returns the [Color] of the specified [code]keyword[/code].
- </description>
- </method>
<method name="get_line" qualifiers="const">
<return type="String">
</return>
@@ -226,15 +184,6 @@
Returns a [String] text with the word under the mouse cursor location.
</description>
</method>
- <method name="has_keyword_color" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="keyword" type="String">
- </argument>
- <description>
- Returns whether the specified [code]keyword[/code] has a color set to it or not.
- </description>
- </method>
<method name="insert_text_at_cursor">
<return type="void">
</return>
@@ -473,8 +422,7 @@
<member name="smooth_scrolling" type="bool" setter="set_smooth_scroll_enable" getter="is_smooth_scroll_enabled" default="false">
If [code]true[/code], sets the [code]step[/code] of the scrollbars to [code]0.25[/code] which results in smoother scrolling.
</member>
- <member name="syntax_highlighting" type="bool" setter="set_syntax_coloring" getter="is_syntax_coloring_enabled" default="false">
- If [code]true[/code], any custom color properties that have been set for this [TextEdit] will be visible.
+ <member name="syntax_highlighter" type="SyntaxHighlighter" setter="set_syntax_highlighter" getter="get_syntax_highlighter">
</member>
<member name="text" type="String" setter="set_text" getter="get_text" default="&quot;&quot;">
String value of the [TextEdit].
@@ -508,6 +456,12 @@
Emitted when the info icon is clicked.
</description>
</signal>
+ <signal name="line_edited_from">
+ <argument index="0" name="line" type="int">
+ </argument>
+ <description>
+ </description>
+ </signal>
<signal name="request_completion">
<description>
</description>
@@ -627,8 +581,6 @@
<theme_item name="font_color_selected" type="Color" default="Color( 0, 0, 0, 1 )">
Sets the [Color] of the selected text. [member override_selected_font_color] has to be enabled.
</theme_item>
- <theme_item name="function_color" type="Color" default="Color( 0.4, 0.64, 0.81, 1 )">
- </theme_item>
<theme_item name="line_number_color" type="Color" default="Color( 0.67, 0.67, 0.67, 0.4 )">
Sets the [Color] of the line numbers. [member show_line_numbers] has to be enabled.
</theme_item>
@@ -638,13 +590,9 @@
<theme_item name="mark_color" type="Color" default="Color( 1, 0.4, 0.4, 0.4 )">
Sets the [Color] of marked text.
</theme_item>
- <theme_item name="member_variable_color" type="Color" default="Color( 0.9, 0.31, 0.35, 1 )">
- </theme_item>
<theme_item name="normal" type="StyleBox">
Sets the [StyleBox] of this [TextEdit].
</theme_item>
- <theme_item name="number_color" type="Color" default="Color( 0.92, 0.58, 0.2, 1 )">
- </theme_item>
<theme_item name="read_only" type="StyleBox">
Sets the [StyleBox] of this [TextEdit] when [member readonly] is enabled.
</theme_item>
@@ -655,8 +603,6 @@
</theme_item>
<theme_item name="space" type="Texture2D">
</theme_item>
- <theme_item name="symbol_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
- </theme_item>
<theme_item name="tab" type="Texture2D">
Sets a custom [Texture2D] for tab text characters.
</theme_item>
diff --git a/doc/classes/UDPServer.xml b/doc/classes/UDPServer.xml
index f3c865c392..aabfed85f0 100644
--- a/doc/classes/UDPServer.xml
+++ b/doc/classes/UDPServer.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
A simple server that opens a UDP socket and returns connected [PacketPeerUDP] upon receiving new packets. See also [method PacketPeerUDP.connect_to_host].
+ After starting the server ([method listen]), you will need to [method poll] it at regular intervals (e.g. inside [method Node._process]) for it to process new packets, delivering them to the appropriate [PacketPeerUDP], and taking new connections.
Below a small example of how it can be used:
[codeblock]
# server.gd
@@ -17,6 +18,7 @@
server.listen(4242)
func _process(delta):
+ server.poll() # Important!
if server.is_connection_available():
var peer : PacketPeerUDP = server.take_connection()
var pkt = peer.get_packet()
@@ -57,7 +59,7 @@
<return type="bool">
</return>
<description>
- Returns [code]true[/code] if a packet with a new address/port combination is received on the socket.
+ Returns [code]true[/code] if a packet with a new address/port combination was received on the socket.
</description>
</method>
<method name="is_listening" qualifiers="const">
@@ -78,21 +80,33 @@
Starts the server by opening a UDP socket listening on the given port. You can optionally specify a [code]bind_address[/code] to only listen for packets sent to that address. See also [method PacketPeerUDP.listen].
</description>
</method>
+ <method name="poll">
+ <return type="int" enum="Error">
+ </return>
+ <description>
+ Call this method at regular intervals (e.g. inside [method Node._process]) to process new packets. And packet from known address/port pair will be delivered to the appropriate [PacketPeerUDP], any packet received from an unknown address/port pair will be added as a pending connection (see [method is_connection_available], [method take_connection]). The maximum number of pending connection is defined via [member max_pending_connections].
+ </description>
+ </method>
<method name="stop">
<return type="void">
</return>
<description>
- Stops the server, closing the UDP socket if open. Will not disconnect any connected [PacketPeerUDP].
+ Stops the server, closing the UDP socket if open. Will close all connected [PacketPeerUDP] accepted via [method take_connection] (remote peers will not be notified).
</description>
</method>
<method name="take_connection">
<return type="PacketPeerUDP">
</return>
<description>
- Returns a [PacketPeerUDP] connected to the address/port combination of the first packet in queue. Will return [code]null[/code] if no packet is in queue. See also [method PacketPeerUDP.connect_to_host].
+ Returns the first pending connection (connected to the appropriate address/port). Will return [code]null[/code] if no new connection is available. See also [method is_connection_available], [method PacketPeerUDP.connect_to_host].
</description>
</method>
</methods>
+ <members>
+ <member name="max_pending_connections" type="int" setter="set_max_pending_connections" getter="get_max_pending_connections" default="16">
+ Define the maximum number of pending connections, during [method poll], any new pending connection exceeding that value will be automatically dropped. Setting this value to [code]0[/code] effectively prevents any new pending connection to be accepted (e.g. when all your players have connected).
+ </member>
+ </members>
<constants>
</constants>
</class>
diff --git a/doc/classes/VehicleBody3D.xml b/doc/classes/VehicleBody3D.xml
index b8b85ff605..5a2cce376e 100644
--- a/doc/classes/VehicleBody3D.xml
+++ b/doc/classes/VehicleBody3D.xml
@@ -6,6 +6,7 @@
<description>
This node implements all the physics logic needed to simulate a car. It is based on the raycast vehicle system commonly found in physics engines. You will need to add a [CollisionShape3D] for the main body of your vehicle and add [VehicleWheel3D] nodes for the wheels. You should also add a [MeshInstance3D] to this node for the 3D model of your car but this model should not include meshes for the wheels. You should control the vehicle by using the [member brake], [member engine_force], and [member steering] properties and not change the position or orientation of this node directly.
[b]Note:[/b] The origin point of your VehicleBody3D will determine the center of gravity of your vehicle so it is better to keep this low and move the [CollisionShape3D] and [MeshInstance3D] upwards.
+ [b]Note:[/b] This class has known issues and isn't designed to provide realistic 3D vehicle physics. If you want advanced vehicle physics, you will probably have to write your own physics integration using another [PhysicsBody3D] class.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VehicleWheel3D.xml b/doc/classes/VehicleWheel3D.xml
index c71d797eff..97b2abfa92 100644
--- a/doc/classes/VehicleWheel3D.xml
+++ b/doc/classes/VehicleWheel3D.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
This node needs to be used as a child node of [VehicleBody3D] and simulates the behavior of one of its wheels. This node also acts as a collider to detect if the wheel is touching a surface.
+ [b]Note:[/b] This class has known issues and isn't designed to provide realistic 3D vehicle physics. If you want advanced vehicle physics, you will probably have to write your own physics integration using another [PhysicsBody3D] class.
</description>
<tutorials>
</tutorials>
diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp
index 3c1c3c8a86..206fdef7c9 100644
--- a/editor/editor_dir_dialog.cpp
+++ b/editor/editor_dir_dialog.cpp
@@ -182,7 +182,7 @@ EditorDirDialog::EditorDirDialog() {
tree->connect("item_activated", callable_mp(this, &EditorDirDialog::_item_activated));
- makedir = add_button(TTR("Create Folder"), DisplayServer::get_singleton()->get_swap_ok_cancel(), "makedir");
+ makedir = add_button(TTR("Create Folder"), DisplayServer::get_singleton()->get_swap_cancel_ok(), "makedir");
makedir->connect("pressed", callable_mp(this, &EditorDirDialog::_make_dir));
makedialog = memnew(ConfirmationDialog);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 0541ee0fba..9c0efd0881 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -6482,7 +6482,7 @@ EditorNode::EditorNode() {
confirmation->connect("confirmed", callable_mp(this, &EditorNode::_menu_confirm_current));
save_confirmation = memnew(ConfirmationDialog);
- save_confirmation->add_button(TTR("Don't Save"), DisplayServer::get_singleton()->get_swap_ok_cancel(), "discard");
+ save_confirmation->add_button(TTR("Don't Save"), DisplayServer::get_singleton()->get_swap_cancel_ok(), "discard");
gui_base->add_child(save_confirmation);
save_confirmation->connect("confirmed", callable_mp(this, &EditorNode::_menu_confirm_current));
save_confirmation->connect("custom_action", callable_mp(this, &EditorNode::_discard_changes));
@@ -6701,7 +6701,7 @@ EditorNode::EditorNode() {
open_imported = memnew(ConfirmationDialog);
open_imported->get_ok()->set_text(TTR("Open Anyway"));
- new_inherited_button = open_imported->add_button(TTR("New Inherited"), !DisplayServer::get_singleton()->get_swap_ok_cancel(), "inherit");
+ new_inherited_button = open_imported->add_button(TTR("New Inherited"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "inherit");
open_imported->connect("confirmed", callable_mp(this, &EditorNode::_open_imported));
open_imported->connect("custom_action", callable_mp(this, &EditorNode::_inherit_imported));
gui_base->add_child(open_imported);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index d66bdb46fe..4f783f4e27 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -3354,7 +3354,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
erase_tab_confirm = memnew(ConfirmationDialog);
erase_tab_confirm->get_ok()->set_text(TTR("Save"));
- erase_tab_confirm->add_button(TTR("Discard"), DisplayServer::get_singleton()->get_swap_ok_cancel(), "discard");
+ erase_tab_confirm->add_button(TTR("Discard"), DisplayServer::get_singleton()->get_swap_cancel_ok(), "discard");
erase_tab_confirm->connect("confirmed", callable_mp(this, &ScriptEditor::_close_current_tab));
erase_tab_confirm->connect("custom_action", callable_mp(this, &ScriptEditor::_close_discard_current_tab));
add_child(erase_tab_confirm);
@@ -3388,7 +3388,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::_reload_scripts));
disk_changed->get_ok()->set_text(TTR("Reload"));
- disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_ok_cancel(), "resave");
+ disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
disk_changed->connect("custom_action", callable_mp(this, &ScriptEditor::_resave_scripts));
}
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 3867c8538a..60ba3802fb 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -667,7 +667,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
disk_changed->connect("confirmed", callable_mp(this, &ShaderEditor::_reload_shader_from_disk));
disk_changed->get_ok()->set_text(TTR("Reload"));
- disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_ok_cancel(), "resave");
+ disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
disk_changed->connect("custom_action", callable_mp(this, &ShaderEditor::save_external_data));
add_child(disk_changed);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index ea6c5edcef..d987f6f7c0 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -1711,6 +1711,7 @@ void VisualShaderEditor::_notification(int p_what) {
preview_text->add_theme_font_override("font", get_theme_font("expression", "EditorFonts"));
preview_text->add_theme_color_override("font_color", text_color);
syntax_highlighter->set_symbol_color(symbol_color);
+ syntax_highlighter->clear_color_regions();
syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
syntax_highlighter->add_color_region("//", "", comment_color, false);
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index eee8799a87..f45161d87b 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -1248,7 +1248,7 @@ ProjectExportDialog::ProjectExportDialog() {
get_cancel()->set_text(TTR("Close"));
get_ok()->set_text(TTR("Export PCK/Zip"));
- export_button = add_button(TTR("Export Project"), !DisplayServer::get_singleton()->get_swap_ok_cancel(), "export");
+ export_button = add_button(TTR("Export Project"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "export");
export_button->connect("pressed", callable_mp(this, &ProjectExportDialog::_export_project));
// Disable initially before we select a valid preset
export_button->set_disabled(true);
@@ -1263,7 +1263,7 @@ ProjectExportDialog::ProjectExportDialog() {
export_all_dialog->add_button(TTR("Release"), true, "release");
export_all_dialog->connect("custom_action", callable_mp(this, &ProjectExportDialog::_export_all_dialog_action));
- export_all_button = add_button(TTR("Export All"), !DisplayServer::get_singleton()->get_swap_ok_cancel(), "export");
+ export_all_button = add_button(TTR("Export All"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "export");
export_all_button->connect("pressed", callable_mp(this, &ProjectExportDialog::_export_all_dialog));
export_all_button->set_disabled(true);
diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp
index 4af6fb2053..e1308b4895 100644
--- a/editor/quick_open.cpp
+++ b/editor/quick_open.cpp
@@ -34,183 +34,184 @@
void EditorQuickOpen::popup_dialog(const StringName &p_base, bool p_enable_multi, bool p_dontclear) {
base_type = p_base;
- search_options->set_select_mode(p_enable_multi ? Tree::SELECT_MULTI : Tree::SELECT_SINGLE);
- popup_centered_ratio(0.4);
+ allow_multi_select = p_enable_multi;
+ search_options->set_select_mode(allow_multi_select ? Tree::SELECT_MULTI : Tree::SELECT_SINGLE);
+ popup_centered_clamped(Size2i(600, 440), 0.8f);
+
+ EditorFileSystemDirectory *efsd = EditorFileSystem::get_singleton()->get_filesystem();
+ _build_search_cache(efsd);
if (p_dontclear) {
search_box->select_all();
+ _update_search();
} else {
- search_box->clear();
+ search_box->clear(); // This will emit text_changed.
}
-
search_box->grab_focus();
- _update_search();
}
-String EditorQuickOpen::get_selected() const {
- TreeItem *ti = search_options->get_selected();
- if (!ti) {
- return String();
+void EditorQuickOpen::_build_search_cache(EditorFileSystemDirectory *p_efsd) {
+ for (int i = 0; i < p_efsd->get_subdir_count(); i++) {
+ _build_search_cache(p_efsd->get_subdir(i));
}
- return "res://" + ti->get_text(0);
-}
+ for (int i = 0; i < p_efsd->get_file_count(); i++) {
+ String file_type = p_efsd->get_file_type(i);
+ if (ClassDB::is_parent_class(file_type, base_type)) {
+ String file = p_efsd->get_file_path(i);
+ files.push_back(file.substr(6, file.length()));
-Vector<String> EditorQuickOpen::get_selected_files() const {
- Vector<String> files;
+ // Store refs to used icons.
+ String ext = file.get_extension();
+ if (!icons.has(ext)) {
+ icons.insert(ext, get_theme_icon((has_theme_icon(file_type, "EditorIcons") ? file_type : "Object"), "EditorIcons"));
+ }
+ }
+ }
+}
- TreeItem *item = search_options->get_next_selected(search_options->get_root());
- while (item) {
- files.push_back("res://" + item->get_text(0));
- item = search_options->get_next_selected(item);
+void EditorQuickOpen::_update_search() {
+ const String search_text = search_box->get_text();
+ const bool empty_search = search_text == "";
+
+ // Filter possible candidates.
+ Vector<Entry> entries;
+ for (int i = 0; i < files.size(); i++) {
+ if (empty_search || search_text.is_subsequence_ofi(files[i])) {
+ Entry r;
+ r.path = files[i];
+ r.score = empty_search ? 0 : _score_path(search_text, files[i].to_lower());
+ entries.push_back(r);
+ }
}
- return files;
-}
+ // Display results
+ TreeItem *root = search_options->get_root();
+ root->clear_children();
-void EditorQuickOpen::_text_changed(const String &p_newtext) {
- _update_search();
-}
+ if (entries.size() > 0) {
+ if (!empty_search) {
+ SortArray<Entry, EntryComparator> sorter;
+ sorter.sort(entries.ptrw(), entries.size());
+ }
-void EditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> k = p_ie;
- if (k.is_valid()) {
- switch (k->get_keycode()) {
- case KEY_UP:
- case KEY_DOWN:
- case KEY_PAGEUP:
- case KEY_PAGEDOWN: {
- search_options->call("_gui_input", k);
- search_box->accept_event();
+ const int entry_limit = MIN(entries.size(), 300);
+ for (int i = 0; i < entry_limit; i++) {
+ TreeItem *ti = search_options->create_item(root);
+ ti->set_text(0, entries[i].path);
+ ti->set_icon(0, *icons.lookup_ptr(entries[i].path.get_extension()));
+ }
- TreeItem *root = search_options->get_root();
- if (!root->get_children()) {
- break;
- }
+ TreeItem *to_select = root->get_children();
+ to_select->select(0);
+ to_select->set_as_cursor(0);
+ search_options->scroll_to_item(to_select);
- TreeItem *current = search_options->get_selected();
- TreeItem *item = search_options->get_next_selected(root);
- while (item) {
- item->deselect(0);
- item = search_options->get_next_selected(item);
- }
+ get_ok()->set_disabled(false);
+ } else {
+ search_options->deselect_all();
- current->select(0);
- current->set_as_cursor(0);
- } break;
- }
+ get_ok()->set_disabled(true);
}
}
-float EditorQuickOpen::_score_path(String search, String path) const {
- // Positive bias for matches close to the _beginning of the file name_.
- String file = path.get_file();
- int pos = file.findn(search);
+float EditorQuickOpen::_score_path(const String &p_search, const String &p_path) {
+ float score = 0.9f + .1f * (p_search.length() / (float)p_path.length());
+
+ // Positive bias for matches close to the beginning of the file name.
+ String file = p_path.get_file();
+ int pos = file.findn(p_search);
if (pos != -1) {
- return 1.0f - 0.1f * (float(pos) / file.length());
+ return score * (1.0f - 0.1f * (float(pos) / file.length()));
}
- // Positive bias for matches close to the _end of the path_.
- String base = path.get_base_dir();
- pos = base.rfindn(search);
+ // Positive bias for matches close to the end of the path.
+ pos = p_path.rfindn(p_search);
if (pos != -1) {
- return 0.9f - 0.1f * (float(base.length() - pos) / base.length());
+ return score * (0.8f - 0.1f * (float(p_path.length() - pos) / p_path.length()));
}
- // Results that contain all characters but not the string.
- return path.similarity(search) * 0.8f;
+ // Remaining results belong to the same class of results.
+ return score * 0.69f;
}
-void EditorQuickOpen::_parse_fs(EditorFileSystemDirectory *efsd, Vector<Pair<String, Ref<Texture2D>>> &list) {
- for (int i = 0; i < efsd->get_subdir_count(); i++) {
- _parse_fs(efsd->get_subdir(i), list);
- }
-
- for (int i = 0; i < efsd->get_file_count(); i++) {
- StringName file_type = efsd->get_file_type(i);
-
- if (ClassDB::is_parent_class(file_type, base_type)) {
- String file = efsd->get_file_path(i);
- file = file.substr(6, file.length());
-
- if (search_box->get_text().is_subsequence_ofi(file)) {
- Pair<String, Ref<Texture2D>> pair;
- pair.first = file;
- pair.second = search_options->get_theme_icon(search_options->has_theme_icon(file_type, ei) ? file_type : ot, ei);
- list.push_back(pair);
- }
- }
+void EditorQuickOpen::_confirmed() {
+ if (!search_options->get_selected()) {
+ return;
}
+ _cleanup();
+ emit_signal("quick_open");
+ hide();
}
-Vector<Pair<String, Ref<Texture2D>>> EditorQuickOpen::_sort_fs(Vector<Pair<String, Ref<Texture2D>>> &list) {
- String search_text = search_box->get_text().to_lower();
- Vector<Pair<String, Ref<Texture2D>>> sorted_list;
+void EditorQuickOpen::cancel_pressed() {
+ _cleanup();
+}
- if (search_text == String() || list.size() == 0) {
- return list;
- }
+void EditorQuickOpen::_cleanup() {
+ files.clear();
+ icons.clear();
+}
- Vector<float> scores;
- scores.resize(list.size());
- for (int i = 0; i < list.size(); i++) {
- scores.write[i] = _score_path(search_text, list[i].first.to_lower());
- }
+void EditorQuickOpen::_text_changed(const String &p_newtext) {
+ _update_search();
+}
- while (list.size() > 0) {
- float best_score = 0.0f;
- int best_idx = 0;
+void EditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_ie) {
+ Ref<InputEventKey> k = p_ie;
+ if (k.is_valid()) {
+ switch (k->get_keycode()) {
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PAGEUP:
+ case KEY_PAGEDOWN: {
+ search_options->call("_gui_input", k);
+ search_box->accept_event();
- for (int i = 0; i < list.size(); i++) {
- float current_score = scores[i];
- if (current_score > best_score) {
- best_score = current_score;
- best_idx = i;
- }
+ if (allow_multi_select) {
+ TreeItem *root = search_options->get_root();
+ if (!root->get_children()) {
+ break;
+ }
+
+ TreeItem *current = search_options->get_selected();
+ TreeItem *item = search_options->get_next_selected(root);
+ while (item) {
+ item->deselect(0);
+ item = search_options->get_next_selected(item);
+ }
+
+ current->select(0);
+ current->set_as_cursor(0);
+ }
+ } break;
}
-
- sorted_list.push_back(list[best_idx]);
- list.remove(best_idx);
- scores.remove(best_idx);
}
-
- return sorted_list;
}
-void EditorQuickOpen::_update_search() {
- search_options->clear();
- TreeItem *root = search_options->create_item();
- EditorFileSystemDirectory *efsd = EditorFileSystem::get_singleton()->get_filesystem();
- Vector<Pair<String, Ref<Texture2D>>> list;
-
- _parse_fs(efsd, list);
- list = _sort_fs(list);
-
- for (int i = 0; i < list.size(); i++) {
- TreeItem *ti = search_options->create_item(root);
- ti->set_text(0, list[i].first);
- ti->set_icon(0, list[i].second);
- }
-
- TreeItem *result = root->get_children();
- if (result) {
- result->select(0);
- result->set_as_cursor(0);
+String EditorQuickOpen::get_selected() const {
+ TreeItem *ti = search_options->get_selected();
+ if (!ti) {
+ return String();
}
- get_ok()->set_disabled(!result);
+ return "res://" + ti->get_text(0);
}
-void EditorQuickOpen::_confirmed() {
- if (!search_options->get_selected()) {
- return;
+Vector<String> EditorQuickOpen::get_selected_files() const {
+ Vector<String> selected_files;
+
+ TreeItem *item = search_options->get_next_selected(search_options->get_root());
+ while (item) {
+ selected_files.push_back("res://" + item->get_text(0));
+ item = search_options->get_next_selected(item);
}
- emit_signal("quick_open");
- hide();
+
+ return selected_files;
}
-void EditorQuickOpen::_theme_changed() {
- search_box->set_right_icon(search_options->get_theme_icon("Search", ei));
+StringName EditorQuickOpen::get_base_type() const {
+ return base_type;
}
void EditorQuickOpen::_notification(int p_what) {
@@ -226,8 +227,8 @@ void EditorQuickOpen::_notification(int p_what) {
}
}
-StringName EditorQuickOpen::get_base_type() const {
- return base_type;
+void EditorQuickOpen::_theme_changed() {
+ search_box->set_right_icon(search_options->get_theme_icon("Search", "EditorIcons"));
}
void EditorQuickOpen::_bind_methods() {
@@ -235,6 +236,8 @@ void EditorQuickOpen::_bind_methods() {
}
EditorQuickOpen::EditorQuickOpen() {
+ allow_multi_select = false;
+
VBoxContainer *vbc = memnew(VBoxContainer);
vbc->connect("theme_changed", callable_mp(this, &EditorQuickOpen::_theme_changed));
add_child(vbc);
@@ -243,18 +246,16 @@ EditorQuickOpen::EditorQuickOpen() {
search_box->connect("text_changed", callable_mp(this, &EditorQuickOpen::_text_changed));
search_box->connect("gui_input", callable_mp(this, &EditorQuickOpen::_sbox_input));
vbc->add_margin_child(TTR("Search:"), search_box);
+ register_text_enter(search_box);
search_options = memnew(Tree);
search_options->connect("item_activated", callable_mp(this, &EditorQuickOpen::_confirmed));
+ search_options->create_item();
search_options->set_hide_root(true);
search_options->set_hide_folding(true);
search_options->add_theme_constant_override("draw_guides", 1);
vbc->add_margin_child(TTR("Matches:"), search_options, true);
get_ok()->set_text(TTR("Open"));
- register_text_enter(search_box);
set_hide_on_ok(false);
-
- ei = "EditorIcons";
- ot = "Object";
}
diff --git a/editor/quick_open.h b/editor/quick_open.h
index 5bcdfc7bf2..6486ee0221 100644
--- a/editor/quick_open.h
+++ b/editor/quick_open.h
@@ -31,7 +31,7 @@
#ifndef EDITOR_QUICK_OPEN_H
#define EDITOR_QUICK_OPEN_H
-#include "core/pair.h"
+#include "core/oa_hash_map.h"
#include "editor_file_system.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/tree.h"
@@ -41,19 +41,32 @@ class EditorQuickOpen : public ConfirmationDialog {
LineEdit *search_box;
Tree *search_options;
-
StringName base_type;
- StringName ei;
- StringName ot;
+ bool allow_multi_select;
- void _update_search();
+ Vector<String> files;
+ OAHashMap<String, Ref<Texture2D>> icons;
- void _sbox_input(const Ref<InputEvent> &p_ie);
- void _parse_fs(EditorFileSystemDirectory *efsd, Vector<Pair<String, Ref<Texture2D>>> &list);
- Vector<Pair<String, Ref<Texture2D>>> _sort_fs(Vector<Pair<String, Ref<Texture2D>>> &list);
- float _score_path(String search, String path) const;
+ struct Entry {
+ String path;
+ float score;
+ };
+
+ struct EntryComparator {
+ _FORCE_INLINE_ bool operator()(const Entry &A, const Entry &B) const {
+ return A.score > B.score;
+ }
+ };
+
+ void _update_search();
+ void _build_search_cache(EditorFileSystemDirectory *p_efsd);
+ float _score_path(const String &p_search, const String &p_path);
void _confirmed();
+ virtual void cancel_pressed() override;
+ void _cleanup();
+
+ void _sbox_input(const Ref<InputEvent> &p_ie);
void _text_changed(const String &p_newtext);
void _theme_changed();
diff --git a/main/main.cpp b/main/main.cpp
index bb4751c61d..a500e173a2 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -954,21 +954,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
#endif
- GLOBAL_DEF("logging/file_logging/enable_file_logging", false);
- // Only file logging by default on desktop platforms as logs can't be
- // accessed easily on mobile/Web platforms (if at all).
- // This also prevents logs from being created for the editor instance, as feature tags
- // are disabled while in the editor (even if they should logically apply).
- GLOBAL_DEF("logging/file_logging/enable_file_logging.pc", true);
- GLOBAL_DEF("logging/file_logging/log_path", "user://logs/godot.log");
- GLOBAL_DEF("logging/file_logging/max_log_files", 5);
- ProjectSettings::get_singleton()->set_custom_property_info("logging/file_logging/max_log_files", PropertyInfo(Variant::INT, "logging/file_logging/max_log_files", PROPERTY_HINT_RANGE, "0,20,1,or_greater")); //no negative numbers
- if (FileAccess::get_create_func(FileAccess::ACCESS_USERDATA) && GLOBAL_GET("logging/file_logging/enable_file_logging")) {
- String base_path = GLOBAL_GET("logging/file_logging/log_path");
- int max_files = GLOBAL_GET("logging/file_logging/max_log_files");
- OS::get_singleton()->add_logger(memnew(RotatedFileLogger(base_path, max_files)));
- }
-
#ifdef TOOLS_ENABLED
if (editor) {
Engine::get_singleton()->set_editor_hint(true);
@@ -985,6 +970,23 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
#endif
+ GLOBAL_DEF("logging/file_logging/enable_file_logging", false);
+ // Only file logging by default on desktop platforms as logs can't be
+ // accessed easily on mobile/Web platforms (if at all).
+ // This also prevents logs from being created for the editor instance, as feature tags
+ // are disabled while in the editor (even if they should logically apply).
+ GLOBAL_DEF("logging/file_logging/enable_file_logging.pc", true);
+ GLOBAL_DEF("logging/file_logging/log_path", "user://logs/godot.log");
+ GLOBAL_DEF("logging/file_logging/max_log_files", 5);
+ ProjectSettings::get_singleton()->set_custom_property_info("logging/file_logging/max_log_files", PropertyInfo(Variant::INT, "logging/file_logging/max_log_files", PROPERTY_HINT_RANGE, "0,20,1,or_greater")); //no negative numbers
+ if (!project_manager && !editor && FileAccess::get_create_func(FileAccess::ACCESS_USERDATA) && GLOBAL_GET("logging/file_logging/enable_file_logging")) {
+ // Don't create logs for the project manager as they would be written to
+ // the current working directory, which is inconvenient.
+ String base_path = GLOBAL_GET("logging/file_logging/log_path");
+ int max_files = GLOBAL_GET("logging/file_logging/max_log_files");
+ OS::get_singleton()->add_logger(memnew(RotatedFileLogger(base_path, max_files)));
+ }
+
if (main_args.size() == 0 && String(GLOBAL_DEF("application/run/main_scene", "")) == "") {
#ifdef TOOLS_ENABLED
if (!editor && !project_manager) {
diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@2x.png
index 766b0b66ef..3a0469319b 100644
--- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@2x.png
+++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@2x.png
Binary files differ
diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@3x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@3x.png
index 766b0b66ef..3a0469319b 100644
--- a/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@3x.png
+++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@3x.png
Binary files differ
diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp
index 4e7698b67c..ed3924f2d2 100644
--- a/modules/enet/networked_multiplayer_enet.cpp
+++ b/modules/enet/networked_multiplayer_enet.cpp
@@ -640,6 +640,9 @@ int NetworkedMultiplayerENet::get_unique_id() const {
void NetworkedMultiplayerENet::set_refuse_new_connections(bool p_enable) {
refuse_connections = p_enable;
+#ifdef GODOT_ENET
+ enet_host_refuse_new_connections(host, p_enable);
+#endif
}
bool NetworkedMultiplayerENet::is_refusing_new_connections() const {
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index ae0b5222f0..019fa0d1f8 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -214,7 +214,7 @@ List<ClassAPI> generate_c_api_classes() {
{
List<StringName> inheriters;
ClassDB::get_inheriters_from_class("Reference", &inheriters);
- bool is_reference = !!inheriters.find(class_name);
+ bool is_reference = !!inheriters.find(class_name) || class_name == "Reference";
// @Unclear
class_api.is_reference = !class_api.is_singleton && is_reference;
}
@@ -452,6 +452,7 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
source.push_back("\t\t\t\t\t{\n");
source.push_back("\t\t\t\t\t\t\"name\": \"" + e->get().argument_names[i] + "\",\n");
source.push_back("\t\t\t\t\t\t\"type\": \"" + e->get().argument_types[i] + "\",\n");
+ source.push_back(String("\t\t\t\t\t\t\"has_default_value\": ") + (e->get().default_arguments.has(i) ? "true" : "false") + ",\n");
source.push_back("\t\t\t\t\t\t\"default_value\": \"" + (e->get().default_arguments.has(i) ? (String)e->get().default_arguments[i] : "") + "\"\n");
source.push_back(String("\t\t\t\t\t}") + ((i < e->get().argument_names.size() - 1) ? "," : "") + "\n");
}
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 01af562327..632407c61f 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -2001,116 +2001,114 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
String GDScriptWarning::get_message() const {
#define CHECK_SYMBOLS(m_amount) ERR_FAIL_COND_V(symbols.size() < m_amount, String());
- String msg;
-
switch (code) {
case UNASSIGNED_VARIABLE_OP_ASSIGN: {
CHECK_SYMBOLS(1);
- msg = "Using assignment with operation but the variable '" + symbols[0] + "' was not previously assigned a value.";
+ return "Using assignment with operation but the variable '" + symbols[0] + "' was not previously assigned a value.";
} break;
case UNASSIGNED_VARIABLE: {
CHECK_SYMBOLS(1);
- msg = "The variable '" + symbols[0] + "' was used but never assigned a value.";
+ return "The variable '" + symbols[0] + "' was used but never assigned a value.";
} break;
case UNUSED_VARIABLE: {
CHECK_SYMBOLS(1);
- msg = "The local variable '" + symbols[0] + "' is declared but never used in the block. If this is intended, prefix it with an underscore: '_" + symbols[0] + "'";
+ return "The local variable '" + symbols[0] + "' is declared but never used in the block. If this is intended, prefix it with an underscore: '_" + symbols[0] + "'";
} break;
case SHADOWED_VARIABLE: {
CHECK_SYMBOLS(2);
- msg = "The local variable '" + symbols[0] + "' is shadowing an already-defined variable at line " + symbols[1] + ".";
+ return "The local variable '" + symbols[0] + "' is shadowing an already-defined variable at line " + symbols[1] + ".";
} break;
case UNUSED_CLASS_VARIABLE: {
CHECK_SYMBOLS(1);
- msg = "The class variable '" + symbols[0] + "' is declared but never used in the script.";
+ return "The class variable '" + symbols[0] + "' is declared but never used in the script.";
} break;
case UNUSED_ARGUMENT: {
CHECK_SYMBOLS(2);
- msg = "The argument '" + symbols[1] + "' is never used in the function '" + symbols[0] + "'. If this is intended, prefix it with an underscore: '_" + symbols[1] + "'";
+ return "The argument '" + symbols[1] + "' is never used in the function '" + symbols[0] + "'. If this is intended, prefix it with an underscore: '_" + symbols[1] + "'";
} break;
case UNREACHABLE_CODE: {
CHECK_SYMBOLS(1);
- msg = "Unreachable code (statement after return) in function '" + symbols[0] + "()'.";
+ return "Unreachable code (statement after return) in function '" + symbols[0] + "()'.";
} break;
case STANDALONE_EXPRESSION: {
- msg = "Standalone expression (the line has no effect).";
+ return "Standalone expression (the line has no effect).";
} break;
case VOID_ASSIGNMENT: {
CHECK_SYMBOLS(1);
- msg = "Assignment operation, but the function '" + symbols[0] + "()' returns void.";
+ return "Assignment operation, but the function '" + symbols[0] + "()' returns void.";
} break;
case NARROWING_CONVERSION: {
- msg = "Narrowing conversion (float is converted to int and loses precision).";
+ return "Narrowing conversion (float is converted to int and loses precision).";
} break;
case FUNCTION_MAY_YIELD: {
CHECK_SYMBOLS(1);
- msg = "Assigned variable is typed but the function '" + symbols[0] + "()' may yield and return a GDScriptFunctionState instead.";
+ return "Assigned variable is typed but the function '" + symbols[0] + "()' may yield and return a GDScriptFunctionState instead.";
} break;
case VARIABLE_CONFLICTS_FUNCTION: {
CHECK_SYMBOLS(1);
- msg = "Variable declaration of '" + symbols[0] + "' conflicts with a function of the same name.";
+ return "Variable declaration of '" + symbols[0] + "' conflicts with a function of the same name.";
} break;
case FUNCTION_CONFLICTS_VARIABLE: {
CHECK_SYMBOLS(1);
- msg = "Function declaration of '" + symbols[0] + "()' conflicts with a variable of the same name.";
+ return "Function declaration of '" + symbols[0] + "()' conflicts with a variable of the same name.";
} break;
case FUNCTION_CONFLICTS_CONSTANT: {
CHECK_SYMBOLS(1);
- msg = "Function declaration of '" + symbols[0] + "()' conflicts with a constant of the same name.";
+ return "Function declaration of '" + symbols[0] + "()' conflicts with a constant of the same name.";
} break;
case INCOMPATIBLE_TERNARY: {
- msg = "Values of the ternary conditional are not mutually compatible.";
+ return "Values of the ternary conditional are not mutually compatible.";
} break;
case UNUSED_SIGNAL: {
CHECK_SYMBOLS(1);
- msg = "The signal '" + symbols[0] + "' is declared but never emitted.";
+ return "The signal '" + symbols[0] + "' is declared but never emitted.";
} break;
case RETURN_VALUE_DISCARDED: {
CHECK_SYMBOLS(1);
- msg = "The function '" + symbols[0] + "()' returns a value, but this value is never used.";
+ return "The function '" + symbols[0] + "()' returns a value, but this value is never used.";
} break;
case PROPERTY_USED_AS_FUNCTION: {
CHECK_SYMBOLS(2);
- msg = "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a property with the same name. Did you mean to access it?";
+ return "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a property with the same name. Did you mean to access it?";
} break;
case CONSTANT_USED_AS_FUNCTION: {
CHECK_SYMBOLS(2);
- msg = "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a constant with the same name. Did you mean to access it?";
+ return "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a constant with the same name. Did you mean to access it?";
} break;
case FUNCTION_USED_AS_PROPERTY: {
CHECK_SYMBOLS(2);
- msg = "The property '" + symbols[0] + "' was not found in base '" + symbols[1] + "' but there's a method with the same name. Did you mean to call it?";
+ return "The property '" + symbols[0] + "' was not found in base '" + symbols[1] + "' but there's a method with the same name. Did you mean to call it?";
} break;
case INTEGER_DIVISION: {
- msg = "Integer division, decimal part will be discarded.";
+ return "Integer division, decimal part will be discarded.";
} break;
case UNSAFE_PROPERTY_ACCESS: {
CHECK_SYMBOLS(2);
- msg = "The property '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype).";
+ return "The property '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype).";
} break;
case UNSAFE_METHOD_ACCESS: {
CHECK_SYMBOLS(2);
- msg = "The method '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype).";
+ return "The method '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype).";
} break;
case UNSAFE_CAST: {
CHECK_SYMBOLS(1);
- msg = "The value is cast to '" + symbols[0] + "' but has an unknown type.";
+ return "The value is cast to '" + symbols[0] + "' but has an unknown type.";
} break;
case UNSAFE_CALL_ARGUMENT: {
CHECK_SYMBOLS(4);
- msg = "The argument '" + symbols[0] + "' of the function '" + symbols[1] + "' requires a the subtype '" + symbols[2] + "' but the supertype '" + symbols[3] + "' was provided";
+ return "The argument '" + symbols[0] + "' of the function '" + symbols[1] + "' requires a the subtype '" + symbols[2] + "' but the supertype '" + symbols[3] + "' was provided";
} break;
case DEPRECATED_KEYWORD: {
CHECK_SYMBOLS(2);
- msg = "The '" + symbols[0] + "' keyword is deprecated and will be removed in a future release, please replace its uses by '" + symbols[1] + "'.";
+ return "The '" + symbols[0] + "' keyword is deprecated and will be removed in a future release, please replace its uses by '" + symbols[1] + "'.";
} break;
case STANDALONE_TERNARY: {
- msg = "Standalone ternary conditional operator: the return value is being discarded.";
- } break;
+ return "Standalone ternary conditional operator: the return value is being discarded.";
+ }
case WARNING_MAX:
- ERR_FAIL_V_MSG(String(), "Invalid GDScript warning code: " + get_name_from_code(code) + ".");
+ break; // Can't happen, but silences warning
}
- return msg + " [" + get_name() + "]";
+ ERR_FAIL_V_MSG(String(), "Invalid GDScript warning code: " + get_name_from_code(code) + ".");
#undef CHECK_SYMBOLS
}
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 330530be80..385d5dd7cb 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -62,7 +62,7 @@ void ExtendGDScriptParser::update_diagnostics() {
const GDScriptWarning &warning = E->get();
lsp::Diagnostic diagnostic;
diagnostic.severity = lsp::DiagnosticSeverity::Warning;
- diagnostic.message = warning.get_message();
+ diagnostic.message = "(" + warning.get_name() + "): " + warning.get_message();
diagnostic.source = "gdscript";
diagnostic.code = warning.code;
lsp::Range range;
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 1fb0d7ef60..3bc9e6d876 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -448,6 +448,8 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
#endif
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
+
+ r_error = OK;
}
DisplayServerAndroid::~DisplayServerAndroid() {
diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h
index c636463e68..68e8454fd0 100644
--- a/platform/osx/display_server_osx.h
+++ b/platform/osx/display_server_osx.h
@@ -288,7 +288,7 @@ public:
virtual CursorShape cursor_get_shape() const override;
virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override;
- virtual bool get_swap_ok_cancel() override;
+ virtual bool get_swap_cancel_ok() override;
virtual int keyboard_get_layout_count() const override;
virtual int keyboard_get_current_layout() const override;
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 4793591b54..5cc2b25910 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -2583,16 +2583,18 @@ void DisplayServerOSX::window_set_size(const Size2i p_size, WindowID p_window) {
Size2i size = p_size / screen_get_max_scale();
- if (!wd.borderless) {
- // NSRect used by setFrame includes the title bar, so add it to our size.y
- CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
- if (menuBarHeight != 0.f) {
- size.y += menuBarHeight;
- }
- }
+ NSPoint top_left;
+ NSRect old_frame = [wd.window_object frame];
+ top_left.x = old_frame.origin.x;
+ top_left.y = NSMaxY(old_frame);
- NSRect frame = [wd.window_object frame];
- [wd.window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, size.x, size.y) display:YES];
+ NSRect new_frame = NSMakeRect(0, 0, size.x, size.y);
+ new_frame = [wd.window_object frameRectForContentRect:new_frame];
+
+ new_frame.origin.x = top_left.x;
+ new_frame.origin.y = top_left.y - new_frame.size.height;
+
+ [wd.window_object setFrame:new_frame display:YES];
_update_window(wd);
}
@@ -2913,8 +2915,8 @@ void DisplayServerOSX::window_set_ime_position(const Point2i &p_pos, WindowID p_
wd.im_position = p_pos;
}
-bool DisplayServerOSX::get_swap_ok_cancel() {
- return true;
+bool DisplayServerOSX::get_swap_cancel_ok() {
+ return false;
}
void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) {
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index 95359c68b0..c35b634353 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -245,7 +245,7 @@ public:
void run();
- virtual bool get_swap_ok_cancel() { return true; }
+ virtual bool get_swap_cancel_ok() { return true; }
void input_event(const Ref<InputEvent> &p_event);
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 3eba0934b1..0251ffe664 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1367,7 +1367,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
}
}
-bool DisplayServerWindows::get_swap_ok_cancel() {
+bool DisplayServerWindows::get_swap_cancel_ok() {
return true;
}
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 8433bb449b..725f9697c5 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -520,7 +520,7 @@ public:
virtual CursorShape cursor_get_shape() const;
virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
- virtual bool get_swap_ok_cancel();
+ virtual bool get_swap_cancel_ok();
virtual void enable_for_stealing_focus(OS::ProcessID pid);
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index fda072e233..72ae75b236 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -1241,12 +1241,12 @@ void KinematicBody3D::_direct_state_changed(Object *p_state) {
KinematicBody3D::KinematicBody3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) {
- margin = 0.001;
locked_axis = 0;
on_floor = false;
on_ceiling = false;
on_wall = false;
+ set_safe_margin(0.001);
PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
}
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index faef979090..9077bfa4ba 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -258,7 +258,7 @@ Button *AcceptDialog::add_cancel(const String &p_cancel) {
if (p_cancel == "") {
c = RTR("Cancel");
}
- Button *b = swap_ok_cancel ? add_button(c, true) : add_button(c);
+ Button *b = swap_cancel_ok ? add_button(c, true) : add_button(c);
b->connect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed));
return b;
}
@@ -286,9 +286,9 @@ void AcceptDialog::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_autowrap"), "set_autowrap", "has_autowrap");
}
-bool AcceptDialog::swap_ok_cancel = false;
-void AcceptDialog::set_swap_ok_cancel(bool p_swap) {
- swap_ok_cancel = p_swap;
+bool AcceptDialog::swap_cancel_ok = false;
+void AcceptDialog::set_swap_cancel_ok(bool p_swap) {
+ swap_cancel_ok = p_swap;
}
AcceptDialog::AcceptDialog() {
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index 063090c832..de08685ce2 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -54,7 +54,7 @@ class AcceptDialog : public Window {
void _custom_action(const String &p_action);
void _update_child_rects();
- static bool swap_ok_cancel;
+ static bool swap_cancel_ok;
void _input_from_window(const Ref<InputEvent> &p_event);
void _parent_focused();
@@ -75,7 +75,7 @@ protected:
public:
Label *get_label() { return label; }
- static void set_swap_ok_cancel(bool p_swap);
+ static void set_swap_cancel_ok(bool p_swap);
void register_text_enter(Node *p_line_edit);
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 22e5bd55f3..8d7bccf814 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -2769,7 +2769,7 @@ void RichTextLabel::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selection_enabled"), "set_selection_enabled", "is_selection_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_RESOURCE_TYPE, "17/17:RichTextEffect", (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE), "RichTextEffect"), "set_effects", "get_effects");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, "RichTextEffect", (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects");
ADD_SIGNAL(MethodInfo("meta_clicked", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
ADD_SIGNAL(MethodInfo("meta_hover_started", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 0ad1d39755..3cbc64c075 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -372,7 +372,7 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
- AcceptDialog::set_swap_ok_cancel(GLOBAL_DEF("gui/common/swap_ok_cancel", bool(DisplayServer::get_singleton()->get_swap_ok_cancel())));
+ AcceptDialog::set_swap_cancel_ok(GLOBAL_DEF("gui/common/swap_cancel_ok", bool(DisplayServer::get_singleton()->get_swap_cancel_ok())));
#endif
/* REGISTER 3D */
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 72cfd87880..65db0de001 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -238,7 +238,7 @@ void DisplayServer::cursor_set_custom_image(const RES &p_cursor, CursorShape p_s
WARN_PRINT("Custom cursor shape not supported by this display server.");
}
-bool DisplayServer::get_swap_ok_cancel() {
+bool DisplayServer::get_swap_cancel_ok() {
return false;
}
@@ -464,7 +464,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("cursor_get_shape"), &DisplayServer::cursor_get_shape);
ClassDB::bind_method(D_METHOD("cursor_set_custom_image", "cursor", "shape", "hotspot"), &DisplayServer::cursor_set_custom_image, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
- ClassDB::bind_method(D_METHOD("get_swap_ok_cancel"), &DisplayServer::get_swap_ok_cancel);
+ ClassDB::bind_method(D_METHOD("get_swap_cancel_ok"), &DisplayServer::get_swap_cancel_ok);
ClassDB::bind_method(D_METHOD("enable_for_stealing_focus", "process_id"), &DisplayServer::enable_for_stealing_focus);
diff --git a/servers/display_server.h b/servers/display_server.h
index 79f6f5d0fc..2cf0a83dbd 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -318,7 +318,7 @@ public:
virtual CursorShape cursor_get_shape() const;
virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
- virtual bool get_swap_ok_cancel();
+ virtual bool get_swap_cancel_ok();
virtual void enable_for_stealing_focus(OS::ProcessID pid);
diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp
index a3bdc96c9f..d1f16cb4ae 100644
--- a/servers/physics_3d/body_3d_sw.cpp
+++ b/servers/physics_3d/body_3d_sw.cpp
@@ -750,7 +750,7 @@ Body3DSW::Body3DSW() :
active = true;
mass = 1;
- kinematic_safe_margin = 0.01;
+ kinematic_safe_margin = 0.001;
//_inv_inertia=Transform();
_inv_mass = 1;
bounce = 0;
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index b903951400..535011710d 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -1137,13 +1137,13 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
} else if (na == TYPE_FLOAT && nb == TYPE_VEC4) {
valid = true;
ret_type = TYPE_VEC4;
- } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT2) {
+ } else if (na == TYPE_FLOAT && nb == TYPE_MAT2) {
valid = true;
ret_type = TYPE_MAT2;
- } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT3) {
+ } else if (na == TYPE_FLOAT && nb == TYPE_MAT3) {
valid = true;
ret_type = TYPE_MAT3;
- } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT4) {
+ } else if (na == TYPE_FLOAT && nb == TYPE_MAT4) {
valid = true;
ret_type = TYPE_MAT4;
} else if (p_op->op == OP_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) {
@@ -1313,13 +1313,13 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
} else if (na == TYPE_VEC4 && nb == TYPE_FLOAT) {
valid = true;
ret_type = TYPE_VEC4;
- } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT2 && nb == TYPE_VEC2) {
+ } else if (na == TYPE_MAT2 && nb == TYPE_FLOAT) {
valid = true;
ret_type = TYPE_MAT2;
- } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT3 && nb == TYPE_VEC3) {
+ } else if (na == TYPE_MAT3 && nb == TYPE_FLOAT) {
valid = true;
ret_type = TYPE_MAT3;
- } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT4 && nb == TYPE_VEC4) {
+ } else if (na == TYPE_MAT4 && nb == TYPE_FLOAT) {
valid = true;
ret_type = TYPE_MAT4;
} else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) {
diff --git a/thirdparty/enet/enet/enet.h b/thirdparty/enet/enet/enet.h
index 3900353c34..24d36647d9 100644
--- a/thirdparty/enet/enet/enet.h
+++ b/thirdparty/enet/enet/enet.h
@@ -13,7 +13,16 @@ extern "C"
#include <stdint.h>
#include <stdlib.h>
+// -- Godot start --
+#if 0
+#ifdef _WIN32
+#include "enet/win32.h"
+#else
+#include "enet/unix.h"
+#endif
+#endif
#include "enet/godot.h"
+// -- Godot end --
#include "enet/types.h"
#include "enet/protocol.h"
@@ -69,6 +78,7 @@ typedef enum _ENetSocketShutdown
ENET_SOCKET_SHUTDOWN_READ_WRITE = 2
} ENetSocketShutdown;
+#define ENET_HOST_ANY 0
#define ENET_HOST_BROADCAST 0xFFFFFFFFU
#define ENET_PORT_ANY 0
@@ -82,13 +92,15 @@ typedef enum _ENetSocketShutdown
* but not for enet_host_create. Once a server responds to a broadcast, the
* address is updated from ENET_HOST_BROADCAST to the server's actual IP address.
*/
+// -- Godot start --
+#if 0
typedef struct _ENetAddress
{
- uint8_t host[16];
+ enet_uint32 host;
enet_uint16 port;
- uint8_t wildcard;
} ENetAddress;
-#define enet_host_equal(host_a, host_b) (memcmp(&host_a, &host_b,16) == 0)
+#endif
+// -- Godot end --
/**
* Packet flag bit constants.
@@ -535,16 +547,6 @@ ENET_API int enet_address_set_host_ip (ENetAddress * address, const char * hostN
*/
ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName);
-/** Sets the host field in the address parameter from ip struct.
- @param address destination to store resolved address
- @param ip the ip struct to read from
- @param size the size of the ip struct.
- @retval 0 on success
- @retval != 0 on failure
- @returns the address of the given ip in address on success.
-*/
-ENET_API void enet_address_set_ip(ENetAddress * address, const uint8_t * ip, size_t size);
-
/** Gives the printable form of the IP address specified in the address parameter.
@param address address printed
@param hostName destination for name, must not be NULL
@@ -585,8 +587,6 @@ ENET_API void enet_host_channel_limit (ENetHost *, size_t);
ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32);
extern void enet_host_bandwidth_throttle (ENetHost *);
extern enet_uint32 enet_host_random_seed (void);
-ENET_API void enet_host_dtls_server_setup (ENetHost *, void *, void *);
-ENET_API void enet_host_dtls_client_setup (ENetHost *, void *, uint8_t, const char *);
ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *);
ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID);
@@ -616,6 +616,10 @@ ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t,
extern size_t enet_protocol_command_size (enet_uint8);
+// -- Godot start --
+#include "enet/godot_ext.h"
+// -- Godot end --
+
#ifdef __cplusplus
}
#endif
diff --git a/thirdparty/enet/enet/godot.h b/thirdparty/enet/enet/godot.h
index 4f25ea9c7b..296b92763d 100644
--- a/thirdparty/enet/enet/godot.h
+++ b/thirdparty/enet/enet/godot.h
@@ -69,4 +69,12 @@ typedef struct
typedef void ENetSocketSet;
+typedef struct _ENetAddress
+{
+ uint8_t host[16];
+ uint16_t port;
+ uint8_t wildcard;
+} ENetAddress;
+#define enet_host_equal(host_a, host_b) (memcmp(&host_a, &host_b,16) == 0)
+
#endif /* __ENET_GODOT_H__ */
diff --git a/thirdparty/enet/enet/godot_ext.h b/thirdparty/enet/enet/godot_ext.h
new file mode 100644
index 0000000000..84a23b1c85
--- /dev/null
+++ b/thirdparty/enet/enet/godot_ext.h
@@ -0,0 +1,18 @@
+#ifndef __ENET_GODOT_EXT_H__
+#define __ENET_GODOT_EXT_H__
+
+/** Sets the host field in the address parameter from ip struct.
+ @param address destination to store resolved address
+ @param ip the ip struct to read from
+ @param size the size of the ip struct.
+ @retval 0 on success
+ @retval != 0 on failure
+ @returns the address of the given ip in address on success.
+*/
+ENET_API void enet_address_set_ip(ENetAddress * address, const uint8_t * ip, size_t size);
+
+ENET_API void enet_host_dtls_server_setup (ENetHost *, void *, void *);
+ENET_API void enet_host_dtls_client_setup (ENetHost *, void *, uint8_t, const char *);
+ENET_API void enet_host_refuse_new_connections (ENetHost *, int);
+
+#endif // __ENET_GODOT_EXT_H__
diff --git a/thirdparty/enet/godot.cpp b/thirdparty/enet/godot.cpp
index 9fefa53e77..36b5131f80 100644
--- a/thirdparty/enet/godot.cpp
+++ b/thirdparty/enet/godot.cpp
@@ -51,6 +51,7 @@ public:
virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) = 0;
virtual int set_option(ENetSocketOption p_option, int p_value) = 0;
virtual void close() = 0;
+ virtual void set_refuse_new_connections(bool p_refuse) { /* Only used by dtls server */ }
virtual ~ENetGodotSocket(){};
};
@@ -250,6 +251,10 @@ public:
close();
}
+ void set_refuse_new_connections(bool p_refuse) {
+ udp_server->set_max_pending_connections(p_refuse ? 0 : 16);
+ }
+
Error bind(IP_Address p_ip, uint16_t p_port) {
return udp_server->listen(p_port, p_ip);
}
@@ -269,6 +274,7 @@ public:
}
Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) {
+ udp_server->poll();
// TODO limits? Maybe we can better enforce allowed connections!
if (udp_server->is_connection_available()) {
Ref<PacketPeerUDP> udp = udp_server->take_connection();
@@ -409,6 +415,11 @@ void enet_host_dtls_client_setup(ENetHost *host, void *p_cert, uint8_t p_verify,
memdelete(sock);
}
+void enet_host_refuse_new_connections(ENetHost *host, int p_refuse) {
+ ERR_FAIL_COND(!host->socket);
+ ((ENetGodotSocket *)host->socket)->set_refuse_new_connections(p_refuse);
+}
+
int enet_socket_bind(ENetSocket socket, const ENetAddress *address) {
IP_Address ip;
diff --git a/thirdparty/enet/patches/dtls_support.patch b/thirdparty/enet/patches/dtls_support.patch
deleted file mode 100644
index ce3480a858..0000000000
--- a/thirdparty/enet/patches/dtls_support.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/thirdparty/enet/enet/enet.h b/thirdparty/enet/enet/enet.h
-index 966e3a465d..ac7552adb2 100644
---- a/thirdparty/enet/enet/enet.h
-+++ b/thirdparty/enet/enet/enet.h
-@@ -578,6 +578,8 @@ ENET_API void enet_host_channel_limit (ENetHost *, size_t);
- ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32);
- extern void enet_host_bandwidth_throttle (ENetHost *);
- extern enet_uint32 enet_host_random_seed (void);
-+ENET_API void enet_host_dtls_server_setup (ENetHost *, void *, void *);
-+ENET_API void enet_host_dtls_client_setup (ENetHost *, void *, uint8_t, const char *);
-
- ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *);
- ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID);
diff --git a/thirdparty/enet/patches/ipv6_support.patch b/thirdparty/enet/patches/godot.patch
index 1f79863645..c8b4a5225d 100644
--- a/thirdparty/enet/patches/ipv6_support.patch
+++ b/thirdparty/enet/patches/godot.patch
@@ -1,61 +1,54 @@
diff --git a/thirdparty/enet/enet/enet.h b/thirdparty/enet/enet/enet.h
-index 650b199ee5..246cbb0a62 100644
+index 54d91b5603..24d36647d9 100644
--- a/thirdparty/enet/enet/enet.h
+++ b/thirdparty/enet/enet/enet.h
-@@ -10,13 +10,10 @@ extern "C"
+@@ -10,13 +10,19 @@ extern "C"
{
#endif
+#include <stdint.h>
#include <stdlib.h>
--#ifdef _WIN32
--#include "enet/win32.h"
--#else
--#include "enet/unix.h"
--#endif
++// -- Godot start --
++#if 0
+ #ifdef _WIN32
+ #include "enet/win32.h"
+ #else
+ #include "enet/unix.h"
+ #endif
++#endif
+#include "enet/godot.h"
++// -- Godot end --
#include "enet/types.h"
#include "enet/protocol.h"
-@@ -72,7 +69,6 @@ typedef enum _ENetSocketShutdown
- ENET_SOCKET_SHUTDOWN_READ_WRITE = 2
- } ENetSocketShutdown;
-
--#define ENET_HOST_ANY 0
- #define ENET_HOST_BROADCAST 0xFFFFFFFFU
- #define ENET_PORT_ANY 0
-
-@@ -88,9 +84,11 @@ typedef enum _ENetSocketShutdown
+@@ -86,11 +92,15 @@ typedef enum _ENetSocketShutdown
+ * but not for enet_host_create. Once a server responds to a broadcast, the
+ * address is updated from ENET_HOST_BROADCAST to the server's actual IP address.
*/
++// -- Godot start --
++#if 0
typedef struct _ENetAddress
{
-- enet_uint32 host;
-+ uint8_t host[16];
+ enet_uint32 host;
enet_uint16 port;
-+ uint8_t wildcard;
} ENetAddress;
-+#define enet_host_equal(host_a, host_b) (memcmp(&host_a, &host_b,16) == 0)
++#endif
++// -- Godot end --
/**
* Packet flag bit constants.
-@@ -519,6 +517,16 @@ ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSock
- */
- ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName);
+@@ -606,6 +616,10 @@ ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t,
+
+ extern size_t enet_protocol_command_size (enet_uint8);
-+/** Sets the host field in the address parameter from ip struct.
-+ @param address destination to store resolved address
-+ @param ip the ip struct to read from
-+ @param size the size of the ip struct.
-+ @retval 0 on success
-+ @retval != 0 on failure
-+ @returns the address of the given ip in address on success.
-+*/
-+ENET_API void enet_address_set_ip(ENetAddress * address, const uint8_t * ip, size_t size);
++// -- Godot start --
++#include "enet/godot_ext.h"
++// -- Godot end --
+
- /** Gives the printable form of the IP address specified in the address parameter.
- @param address address printed
- @param hostName destination for name, must not be NULL
+ #ifdef __cplusplus
+ }
+ #endif
diff --git a/thirdparty/enet/host.c b/thirdparty/enet/host.c
index 3be6c0922c..fc4da4ca67 100644
--- a/thirdparty/enet/host.c
@@ -70,10 +63,10 @@ index 3be6c0922c..fc4da4ca67 100644
host -> receivedData = NULL;
host -> receivedDataLength = 0;
diff --git a/thirdparty/enet/protocol.c b/thirdparty/enet/protocol.c
-index 29d648732d..ab26886de4 100644
+index 0a60253173..fefc0e6f0a 100644
--- a/thirdparty/enet/protocol.c
+++ b/thirdparty/enet/protocol.c
-@@ -298,7 +298,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
+@@ -307,7 +307,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
}
else
if (currentPeer -> state != ENET_PEER_STATE_CONNECTING &&
@@ -82,7 +75,7 @@ index 29d648732d..ab26886de4 100644
{
if (currentPeer -> address.port == host -> receivedAddress.port &&
currentPeer -> connectID == command -> connect.connectID)
-@@ -1010,9 +1010,8 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
+@@ -1027,9 +1027,8 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
if (peer -> state == ENET_PEER_STATE_DISCONNECTED ||
peer -> state == ENET_PEER_STATE_ZOMBIE ||
@@ -94,7 +87,7 @@ index 29d648732d..ab26886de4 100644
(peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID &&
sessionID != peer -> incomingSessionID))
return 0;
-@@ -1054,7 +1053,7 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
+@@ -1071,7 +1070,7 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
if (peer != NULL)
{