Merge pull request #40413 from akien-mga/3.2-cherrypicks

Cherry-picks for the 3.2 branch (future 3.2.3) - 3rd batch
This commit is contained in:
Rémi Verschelde 2020-07-15 15:18:29 +02:00 committed by GitHub
commit 4abebfa476
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 367 additions and 188 deletions

View File

@ -31,6 +31,7 @@
#include "packet_peer_udp.h"
#include "core/io/ip.h"
#include "core/io/udp_server.h"
void PacketPeerUDP::set_blocking_mode(bool p_enable) {
@ -38,13 +39,14 @@ void PacketPeerUDP::set_blocking_mode(bool 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);
}
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);
@ -59,7 +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);
@ -133,7 +135,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);
@ -188,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);
@ -245,9 +246,13 @@ 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);
queue_count = 0;
connected = false;
@ -266,6 +271,9 @@ Error PacketPeerUDP::_poll() {
if (!_sock->is_open()) {
return FAILED;
}
if (udp_server) {
return OK; // Handled by UDPServer.
}
Error err;
int read;
@ -287,23 +295,29 @@ Error PacketPeerUDP::_poll() {
return FAILED;
}
if (rb.space_left() < read + 24) {
err = store_packet(ip, port, recv_buffer, read);
#ifdef TOOLS_ENABLED
WARN_PRINTS("Buffer full, dropping packets!");
#endif
continue;
if (err != OK) {
WARN_PRINT("Buffer full, dropping packets!");
}
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();
@ -349,6 +363,7 @@ PacketPeerUDP::PacketPeerUDP() :
connected(false),
blocking(true),
broadcast(false),
udp_server(nullptr),
_sock(Ref<NetSocket>(NetSocket::create())) {
rb.resize(16);
}

View File

@ -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;
bool blocking;
bool broadcast;
UDPServer *udp_server;
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;

View File

@ -33,10 +33,8 @@
#include "core/os/file_access.h"
#include "core/translation.h"
RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const String &p_path) {
RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
enum Status {
STATUS_NONE,
STATUS_READING_ID,
STATUS_READING_STRING,
@ -56,6 +54,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
bool skip_this = false;
bool skip_next = false;
bool is_eof = false;
const String path = f->get_path();
while (!is_eof) {
@ -67,7 +66,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
if (status == STATUS_READING_ID) {
memdelete(f);
ERR_FAIL_V_MSG(RES(), p_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;
}
@ -76,9 +75,8 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
if (l.begins_with("msgid")) {
if (status == STATUS_READING_ID) {
memdelete(f);
ERR_FAIL_V_MSG(RES(), p_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 != "") {
@ -98,9 +96,8 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
if (l.begins_with("msgstr")) {
if (status != STATUS_READING_ID) {
memdelete(f);
ERR_FAIL_V_MSG(RES(), p_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();
@ -115,7 +112,10 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
continue; //nothing to read or comment
}
ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, RES(), p_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
@ -128,7 +128,10 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
}
}
ERR_FAIL_COND_V_MSG(end_pos == -1, RES(), p_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();
@ -141,7 +144,6 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
line++;
}
f->close();
memdelete(f);
if (status == STATUS_READING_STRING) {
@ -153,7 +155,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
config = msg_str;
}
ERR_FAIL_COND_V_MSG(config == "", RES(), "No config found in file: " + p_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++) {
@ -190,7 +192,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 {

View File

@ -37,7 +37,7 @@
class TranslationLoaderPO : public ResourceFormatLoader {
public:
static RES load_translation(FileAccess *f, Error *r_error, const String &p_path = String());
static RES load_translation(FileAccess *f, Error *r_error);
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;

View File

@ -33,10 +33,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 {
if (!_sock->is_open())
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() {
@ -93,11 +157,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() {
@ -107,6 +180,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() :

View File

@ -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();

View File

@ -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>

View File

@ -97,6 +97,7 @@
[codeblock]
call("set", "position", Vector2(42.0, 0.0))
[/codeblock]
[b]Note:[/b] In C#, the method name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined methods where you should use the same convention as in the C# source (typically PascalCase).
</description>
</method>
<method name="call_deferred" qualifiers="vararg">
@ -109,6 +110,7 @@
[codeblock]
call_deferred("set", "position", Vector2(42.0, 0.0))
[/codeblock]
[b]Note:[/b] In C#, the method name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined methods where you should use the same convention as in the C# source (typically PascalCase).
</description>
</method>
<method name="callv">
@ -205,6 +207,7 @@
</argument>
<description>
Returns the [Variant] value of the given [code]property[/code]. If the [code]property[/code] doesn't exist, this will return [code]null[/code].
[b]Note:[/b] In C#, the property name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined properties where you should use the same convention as in the C# source (typically PascalCase).
</description>
</method>
<method name="get_class" qualifiers="const">
@ -405,6 +408,7 @@
</argument>
<description>
Assigns a new value to the given property. If the [code]property[/code] does not exist, nothing will happen.
[b]Note:[/b] In C#, the property name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined properties where you should use the same convention as in the C# source (typically PascalCase).
</description>
</method>
<method name="set_block_signals">
@ -425,6 +429,7 @@
</argument>
<description>
Assigns a new value to the given property, after the current frame's physics step. This is equivalent to calling [method set] via [method call_deferred], i.e. [code]call_deferred("set", property, value)[/code].
[b]Note:[/b] In C#, the property name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined properties where you should use the same convention as in the C# source (typically PascalCase).
</description>
</method>
<method name="set_indexed">

View File

@ -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>

View File

@ -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 [CollisionShape] for the main body of your vehicle and add [VehicleWheel] nodes for the wheels. You should also add a [MeshInstance] 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 VehicleBody will determine the center of gravity of your vehicle so it is better to keep this low and move the [CollisionShape] and [MeshInstance] 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 [PhysicsBody] class.
</description>
<tutorials>
</tutorials>

View File

@ -5,6 +5,7 @@
</brief_description>
<description>
This node needs to be used as a child node of [VehicleBody] 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 [PhysicsBody] class.
</description>
<tutorials>
</tutorials>

View File

@ -89,7 +89,7 @@ void EditorAudioBus::_notification(int p_what) {
bypass->set_icon(get_icon("AudioBusBypass", "EditorIcons"));
bypass->add_color_override("icon_color_pressed", bypass_color);
bus_options->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
bus_options->set_icon(get_icon("GuiTabMenuHl", "EditorIcons"));
update_bus();
set_process(true);
@ -181,7 +181,7 @@ void EditorAudioBus::_notification(int p_what) {
mute->set_icon(get_icon("AudioBusMute", "EditorIcons"));
bypass->set_icon(get_icon("AudioBusBypass", "EditorIcons"));
bus_options->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
bus_options->set_icon(get_icon("GuiTabMenuHl", "EditorIcons"));
} break;
case NOTIFICATION_MOUSE_EXIT:
case NOTIFICATION_DRAG_END: {

View File

@ -997,7 +997,7 @@ void EditorSettings::setup_language() {
FileAccessMemory *fa = memnew(FileAccessMemory);
fa->open_custom(data.ptr(), data.size());
Ref<Translation> tr = TranslationLoaderPO::load_translation(fa, NULL, "translation_" + String(etl->lang));
Ref<Translation> tr = TranslationLoaderPO::load_translation(fa, NULL);
if (tr.is_valid()) {
tr->set_locale(etl->lang);

View File

@ -1 +1 @@
<svg height="16" viewBox="0 0 6 16" width="6" xmlns="http://www.w3.org/2000/svg"><path d="m3 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm0 6a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm0 6a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#fff" fill-opacity=".39216"/></svg>
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm0 6a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm0 6a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#fff" fill-opacity=".39216"/></svg>

Before

Width:  |  Height:  |  Size: 322 B

After

Width:  |  Height:  |  Size: 324 B

View File

@ -1 +1 @@
<svg height="16" viewBox="0 0 6 16" width="6" xmlns="http://www.w3.org/2000/svg"><path d="m3 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm0 6a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm0 6a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#e0e0e0"/></svg>
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm0 6a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm0 6a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#e0e0e0"/></svg>

Before

Width:  |  Height:  |  Size: 303 B

After

Width:  |  Height:  |  Size: 305 B

View File

@ -126,7 +126,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
stop->set_icon(get_icon("Stop", "EditorIcons"));
onion_toggle->set_icon(get_icon("Onion", "EditorIcons"));
onion_skinning->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
onion_skinning->set_icon(get_icon("GuiTabMenuHl", "EditorIcons"));
pin->set_icon(get_icon("Pin", "EditorIcons"));

View File

@ -3861,7 +3861,7 @@ void CanvasItemEditor::_notification(int p_what) {
rotate_button->set_icon(get_icon("ToolRotate", "EditorIcons"));
smart_snap_button->set_icon(get_icon("Snap", "EditorIcons"));
grid_snap_button->set_icon(get_icon("SnapGrid", "EditorIcons"));
snap_config_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
snap_config_menu->set_icon(get_icon("GuiTabMenuHl", "EditorIcons"));
skeleton_menu->set_icon(get_icon("Bone", "EditorIcons"));
override_camera_button->set_icon(get_icon("Camera2D", "EditorIcons"));
pan_button->set_icon(get_icon("ToolPan", "EditorIcons"));
@ -3878,7 +3878,7 @@ void CanvasItemEditor::_notification(int p_what) {
key_scale_button->set_icon(get_icon("KeyScale", "EditorIcons"));
key_insert_button->set_icon(get_icon("Key", "EditorIcons"));
key_auto_insert_button->set_icon(get_icon("AutoKey", "EditorIcons"));
animation_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
animation_menu->set_icon(get_icon("GuiTabMenuHl", "EditorIcons"));
zoom_minus->set_icon(get_icon("ZoomLess", "EditorIcons"));
zoom_plus->set_icon(get_icon("ZoomMore", "EditorIcons"));
@ -6262,7 +6262,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
selector->add_child(vbc);
vbc->set_h_size_flags(SIZE_EXPAND_FILL);
vbc->set_v_size_flags(SIZE_EXPAND_FILL);
vbc->set_custom_minimum_size(Size2(200, 260) * EDSCALE);
vbc->set_custom_minimum_size(Size2(240, 260) * EDSCALE);
btn_group = memnew(VBoxContainer);
vbc->add_child(btn_group);

View File

@ -2542,7 +2542,7 @@ void SpatialEditorViewport::_notification(int p_what) {
if (p_what == NOTIFICATION_THEME_CHANGED) {
view_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
view_menu->set_icon(get_icon("GuiTabMenuHl", "EditorIcons"));
preview_camera->set_icon(get_icon("Camera", "EditorIcons"));
view_menu->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));

View File

@ -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) {

View File

@ -181,7 +181,7 @@ void AreaBullet::reload_body() {
void AreaBullet::set_space(SpaceBullet *p_space) {
// Clear the old space if there is one
if (space) {
overlappingObjects.clear();
clear_overlaps(false);
isScratched = false;
// Remove this object form the physics world

View File

@ -668,6 +668,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 {

View File

@ -219,7 +219,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;
}
@ -458,6 +458,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");
}

View File

@ -2020,116 +2020,114 @@ 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
}

View File

@ -63,7 +63,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;

View File

@ -1432,13 +1432,14 @@ void KinematicBody::_bind_methods() {
KinematicBody::KinematicBody() :
PhysicsBody(PhysicsServer::BODY_MODE_KINEMATIC) {
margin = 0.001;
locked_axis = 0;
on_floor = false;
on_ceiling = false;
on_wall = false;
set_safe_margin(0.001);
}
KinematicBody::~KinematicBody() {
if (motion_cache.is_valid()) {

View File

@ -228,7 +228,7 @@ struct SpatialIndexer2D {
List<VisibilityNotifier2D *> added;
List<VisibilityNotifier2D *> removed;
int visible_cells = (end.x - begin.x) * (end.y - begin.y);
uint64_t visible_cells = (uint64_t)(end.x - begin.x) * (uint64_t)(end.y - begin.y);
if (visible_cells > 10000) {

View File

@ -773,7 +773,7 @@ BodySW::BodySW() :
active = true;
mass = 1;
kinematic_safe_margin = 0.01;
kinematic_safe_margin = 0.001;
//_inv_inertia=Transform();
_inv_mass = 1;
bounce = 0;

View File

@ -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

View File

@ -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__ */

18
thirdparty/enet/enet/godot_ext.h vendored Normal file
View File

@ -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__

View File

@ -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;

View File

@ -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);

View File

@ -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)
{