|
@@ -34,6 +34,10 @@
|
|
#include "scene/main/node.h"
|
|
#include "scene/main/node.h"
|
|
#include <stdint.h>
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
+#define NODE_ID_COMPRESSION_SHIFT 3
|
|
|
|
+#define NAME_ID_COMPRESSION_SHIFT 5
|
|
|
|
+#define BYTE_ONLY_OR_NO_ARGS_SHIFT 6
|
|
|
|
+
|
|
#ifdef DEBUG_ENABLED
|
|
#ifdef DEBUG_ENABLED
|
|
#include "core/os/os.h"
|
|
#include "core/os/os.h"
|
|
#endif
|
|
#endif
|
|
@@ -168,6 +172,16 @@ Ref<NetworkedMultiplayerPeer> MultiplayerAPI::get_network_peer() const {
|
|
return network_peer;
|
|
return network_peer;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Returns the packet size stripping the node path added when the node is not yet cached.
|
|
|
|
+int get_packet_len(uint32_t p_node_target, int p_packet_len) {
|
|
|
|
+ if (p_node_target & 0x80000000) {
|
|
|
|
+ int ofs = p_node_target & 0x7FFFFFFF;
|
|
|
|
+ return p_packet_len - (p_packet_len - ofs);
|
|
|
|
+ } else {
|
|
|
|
+ return p_packet_len;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) {
|
|
void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) {
|
|
|
|
|
|
ERR_FAIL_COND_MSG(root_node == NULL, "Multiplayer root node was not initialized. If you are using custom multiplayer, remember to set the root node via MultiplayerAPI.set_root_node before using it.");
|
|
ERR_FAIL_COND_MSG(root_node == NULL, "Multiplayer root node was not initialized. If you are using custom multiplayer, remember to set the root node via MultiplayerAPI.set_root_node before using it.");
|
|
@@ -204,8 +218,8 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
|
|
int name_id_offset = 1;
|
|
int name_id_offset = 1;
|
|
ERR_FAIL_COND_MSG(p_packet_len < packet_min_size, "Invalid packet received. Size too small.");
|
|
ERR_FAIL_COND_MSG(p_packet_len < packet_min_size, "Invalid packet received. Size too small.");
|
|
// Compute the meta size, which depends on the compression level.
|
|
// Compute the meta size, which depends on the compression level.
|
|
- int node_id_compression = (p_packet[0] & 24) >> 3;
|
|
|
|
- int name_id_compression = (p_packet[0] & 32) >> 5;
|
|
|
|
|
|
+ int node_id_compression = (p_packet[0] & 24) >> NODE_ID_COMPRESSION_SHIFT;
|
|
|
|
+ int name_id_compression = (p_packet[0] & 32) >> NAME_ID_COMPRESSION_SHIFT;
|
|
|
|
|
|
switch (node_id_compression) {
|
|
switch (node_id_compression) {
|
|
case NETWORK_NODE_ID_COMPRESSION_8:
|
|
case NETWORK_NODE_ID_COMPRESSION_8:
|
|
@@ -250,6 +264,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
|
|
// Unreachable, checked before.
|
|
// Unreachable, checked before.
|
|
CRASH_NOW();
|
|
CRASH_NOW();
|
|
}
|
|
}
|
|
|
|
+
|
|
Node *node = _process_get_node(p_from, p_packet, node_target, p_packet_len);
|
|
Node *node = _process_get_node(p_from, p_packet, node_target, p_packet_len);
|
|
ERR_FAIL_COND_MSG(node == NULL, "Invalid packet received. Requested node was not found.");
|
|
ERR_FAIL_COND_MSG(node == NULL, "Invalid packet received. Requested node was not found.");
|
|
|
|
|
|
@@ -266,13 +281,14 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
|
|
CRASH_NOW();
|
|
CRASH_NOW();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ const int packet_len = get_packet_len(node_target, p_packet_len);
|
|
if (packet_type == NETWORK_COMMAND_REMOTE_CALL) {
|
|
if (packet_type == NETWORK_COMMAND_REMOTE_CALL) {
|
|
|
|
|
|
- _process_rpc(node, name_id, p_from, p_packet, p_packet_len, packet_min_size);
|
|
|
|
|
|
+ _process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size);
|
|
|
|
|
|
} else {
|
|
} else {
|
|
|
|
|
|
- _process_rset(node, name_id, p_from, p_packet, p_packet_len, packet_min_size);
|
|
|
|
|
|
+ _process_rset(node, name_id, p_from, p_packet, packet_len, packet_min_size);
|
|
}
|
|
}
|
|
|
|
|
|
} break;
|
|
} break;
|
|
@@ -326,7 +342,7 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, uin
|
|
|
|
|
|
void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) {
|
|
void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) {
|
|
|
|
|
|
- ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
|
|
|
|
|
|
+ ERR_FAIL_COND_MSG(p_offset > p_packet_len, "Invalid packet received. Size too small.");
|
|
|
|
|
|
// Check that remote can call the RPC on this node.
|
|
// Check that remote can call the RPC on this node.
|
|
StringName name = p_node->get_node_rpc_method(p_rpc_method_id);
|
|
StringName name = p_node->get_node_rpc_method(p_rpc_method_id);
|
|
@@ -340,14 +356,30 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id,
|
|
bool can_call = _can_call_mode(p_node, rpc_mode, p_from);
|
|
bool can_call = _can_call_mode(p_node, rpc_mode, p_from);
|
|
ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
|
|
ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
|
|
|
|
|
|
- int argc = p_packet[p_offset];
|
|
|
|
|
|
+ int argc = 0;
|
|
|
|
+ bool byte_only = false;
|
|
|
|
+
|
|
|
|
+ const bool byte_only_or_no_args = ((p_packet[0] & 64) >> BYTE_ONLY_OR_NO_ARGS_SHIFT) == 1;
|
|
|
|
+ if (byte_only_or_no_args) {
|
|
|
|
+ if (p_offset < p_packet_len) {
|
|
|
|
+ // This packet contains only bytes.
|
|
|
|
+ argc = 1;
|
|
|
|
+ byte_only = true;
|
|
|
|
+ } else {
|
|
|
|
+ // This rpc calls a method without parameters.
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // Normal variant, takes the argument count from the packet.
|
|
|
|
+ ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
|
|
|
|
+ argc = p_packet[p_offset];
|
|
|
|
+ p_offset += 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
Vector<Variant> args;
|
|
Vector<Variant> args;
|
|
Vector<const Variant *> argp;
|
|
Vector<const Variant *> argp;
|
|
args.resize(argc);
|
|
args.resize(argc);
|
|
argp.resize(argc);
|
|
argp.resize(argc);
|
|
|
|
|
|
- p_offset++;
|
|
|
|
-
|
|
|
|
#ifdef DEBUG_ENABLED
|
|
#ifdef DEBUG_ENABLED
|
|
if (profiling) {
|
|
if (profiling) {
|
|
ObjectID id = p_node->get_instance_id();
|
|
ObjectID id = p_node->get_instance_id();
|
|
@@ -356,16 +388,26 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id,
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- for (int i = 0; i < argc; i++) {
|
|
|
|
|
|
+ if (byte_only) {
|
|
|
|
+ Vector<uint8_t> pure_data;
|
|
|
|
+ const int len = p_packet_len - p_offset;
|
|
|
|
+ pure_data.resize(len);
|
|
|
|
+ memcpy(pure_data.ptrw(), &p_packet[p_offset], len);
|
|
|
|
+ args.write[0] = pure_data;
|
|
|
|
+ argp.write[0] = &args[0];
|
|
|
|
+ p_offset += len;
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = 0; i < argc; i++) {
|
|
|
|
|
|
- ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
|
|
|
|
|
|
+ ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
|
|
|
|
|
|
- int vlen;
|
|
|
|
- Error err = _decode_and_decompress_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen);
|
|
|
|
- ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RPC argument.");
|
|
|
|
|
|
+ int vlen;
|
|
|
|
+ Error err = _decode_and_decompress_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen);
|
|
|
|
+ ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RPC argument.");
|
|
|
|
|
|
- argp.write[i] = &args[i];
|
|
|
|
- p_offset += vlen;
|
|
|
|
|
|
+ argp.write[i] = &args[i];
|
|
|
|
+ p_offset += vlen;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
Callable::CallError ce;
|
|
Callable::CallError ce;
|
|
@@ -742,10 +784,12 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
|
|
// - `NetworkCommands` in the first three bits.
|
|
// - `NetworkCommands` in the first three bits.
|
|
// - `NetworkNodeIdCompression` in the next 2 bits.
|
|
// - `NetworkNodeIdCompression` in the next 2 bits.
|
|
// - `NetworkNameIdCompression` in the next 1 bit.
|
|
// - `NetworkNameIdCompression` in the next 1 bit.
|
|
- // - So we still have the last two bits free!
|
|
|
|
|
|
+ // - `byte_only_or_no_args` in the next 1 bit.
|
|
|
|
+ // - So we still have the last bit free!
|
|
uint8_t command_type = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL;
|
|
uint8_t command_type = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL;
|
|
uint8_t node_id_compression = UINT8_MAX;
|
|
uint8_t node_id_compression = UINT8_MAX;
|
|
uint8_t name_id_compression = UINT8_MAX;
|
|
uint8_t name_id_compression = UINT8_MAX;
|
|
|
|
+ bool byte_only_or_no_args = false;
|
|
|
|
|
|
MAKE_ROOM(1);
|
|
MAKE_ROOM(1);
|
|
// The meta is composed along the way, so just set 0 for now.
|
|
// The meta is composed along the way, so just set 0 for now.
|
|
@@ -835,17 +879,28 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
|
|
ofs += 2;
|
|
ofs += 2;
|
|
}
|
|
}
|
|
|
|
|
|
- // Call arguments.
|
|
|
|
- MAKE_ROOM(ofs + 1);
|
|
|
|
- packet_cache.write[ofs] = p_argcount;
|
|
|
|
- ofs += 1;
|
|
|
|
- for (int i = 0; i < p_argcount; i++) {
|
|
|
|
- int len(0);
|
|
|
|
- Error err = _encode_and_compress_variant(*p_arg[i], NULL, len);
|
|
|
|
- ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!");
|
|
|
|
- MAKE_ROOM(ofs + len);
|
|
|
|
- _encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len);
|
|
|
|
- ofs += len;
|
|
|
|
|
|
+ if (p_argcount == 0) {
|
|
|
|
+ byte_only_or_no_args = true;
|
|
|
|
+ } else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) {
|
|
|
|
+ byte_only_or_no_args = true;
|
|
|
|
+ // Special optimization when only the byte vector is sent.
|
|
|
|
+ const Vector<uint8_t> data = *p_arg[0];
|
|
|
|
+ MAKE_ROOM(ofs + data.size());
|
|
|
|
+ copymem(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size());
|
|
|
|
+ ofs += data.size();
|
|
|
|
+ } else {
|
|
|
|
+ // Arguments
|
|
|
|
+ MAKE_ROOM(ofs + 1);
|
|
|
|
+ packet_cache.write[ofs] = p_argcount;
|
|
|
|
+ ofs += 1;
|
|
|
|
+ for (int i = 0; i < p_argcount; i++) {
|
|
|
|
+ int len(0);
|
|
|
|
+ Error err = _encode_and_compress_variant(*p_arg[i], NULL, len);
|
|
|
|
+ ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!");
|
|
|
|
+ MAKE_ROOM(ofs + len);
|
|
|
|
+ _encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len);
|
|
|
|
+ ofs += len;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -854,7 +909,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
|
|
ERR_FAIL_COND(name_id_compression > 1);
|
|
ERR_FAIL_COND(name_id_compression > 1);
|
|
|
|
|
|
// We can now set the meta
|
|
// We can now set the meta
|
|
- packet_cache.write[0] = command_type + (node_id_compression << 3) + (name_id_compression << 5);
|
|
|
|
|
|
+ packet_cache.write[0] = command_type + (node_id_compression << NODE_ID_COMPRESSION_SHIFT) + (name_id_compression << NAME_ID_COMPRESSION_SHIFT) + ((byte_only_or_no_args ? 1 : 0) << BYTE_ONLY_OR_NO_ARGS_SHIFT);
|
|
|
|
|
|
#ifdef DEBUG_ENABLED
|
|
#ifdef DEBUG_ENABLED
|
|
if (profiling) {
|
|
if (profiling) {
|