summaryrefslogtreecommitdiff
path: root/core/io
diff options
context:
space:
mode:
Diffstat (limited to 'core/io')
-rw-r--r--core/io/config_file.cpp28
-rw-r--r--core/io/config_file.h4
-rw-r--r--core/io/file_access_compressed.cpp8
-rw-r--r--core/io/file_access_network.cpp6
-rw-r--r--core/io/file_access_network.h6
-rw-r--r--core/io/image_loader.cpp4
-rw-r--r--core/io/ip.cpp6
-rw-r--r--core/io/json.cpp10
-rw-r--r--core/io/logger.cpp12
-rw-r--r--core/io/marshalls.cpp21
-rw-r--r--core/io/multiplayer_api.cpp515
-rw-r--r--core/io/multiplayer_api.h26
-rw-r--r--core/io/packet_peer.cpp20
-rw-r--r--core/io/packet_peer.h5
-rw-r--r--core/io/packet_peer_udp.cpp2
-rw-r--r--core/io/resource_format_binary.cpp119
-rw-r--r--core/io/resource_format_binary.h1
-rw-r--r--core/io/resource_importer.cpp4
-rw-r--r--core/io/resource_loader.cpp10
-rw-r--r--core/io/resource_saver.cpp2
20 files changed, 536 insertions, 273 deletions
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
index 5c25cad770..5968972143 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -86,9 +86,10 @@ void ConfigFile::set_value(const String &p_section, const String &p_key, const V
Variant ConfigFile::get_value(const String &p_section, const String &p_key, Variant p_default) const {
if (!values.has(p_section) || !values[p_section].has(p_key)) {
- ERR_FAIL_COND_V_MSG(p_default.get_type() == Variant::NIL, p_default, "Couldn't find the given section/key and no default was given.");
+ ERR_FAIL_COND_V_MSG(p_default.get_type() == Variant::NIL, Variant(), "Couldn't find the given section '" + p_section + "', key '" + p_key + "' and no default was given.");
return p_default;
}
+
return values[p_section][p_key];
}
@@ -255,6 +256,22 @@ Error ConfigFile::_internal_load(const String &p_path, FileAccess *f) {
VariantParser::StreamFile stream;
stream.f = f;
+ Error err = _parse(p_path, &stream);
+
+ memdelete(f);
+
+ return err;
+}
+
+Error ConfigFile::parse(const String &p_data) {
+
+ VariantParser::StreamString stream;
+ stream.s = p_data;
+ return _parse("<string>", &stream);
+}
+
+Error ConfigFile::_parse(const String &p_path, VariantParser::Stream *p_stream) {
+
String assign;
Variant value;
VariantParser::Tag next_tag;
@@ -270,13 +287,11 @@ Error ConfigFile::_internal_load(const String &p_path, FileAccess *f) {
next_tag.fields.clear();
next_tag.name = String();
- Error err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true);
+ Error err = VariantParser::parse_tag_assign_eof(p_stream, lines, error_text, next_tag, assign, value, NULL, true);
if (err == ERR_FILE_EOF) {
- memdelete(f);
return OK;
} else if (err != OK) {
- ERR_PRINTS("ConfgFile::load - " + p_path + ":" + itos(lines) + " error: " + error_text + ".");
- memdelete(f);
+ ERR_PRINT("ConfgFile - " + p_path + ":" + itos(lines) + " error: " + error_text + ".");
return err;
}
@@ -286,6 +301,8 @@ Error ConfigFile::_internal_load(const String &p_path, FileAccess *f) {
section = next_tag.name;
}
}
+
+ return OK;
}
void ConfigFile::_bind_methods() {
@@ -303,6 +320,7 @@ void ConfigFile::_bind_methods() {
ClassDB::bind_method(D_METHOD("erase_section_key", "section", "key"), &ConfigFile::erase_section_key);
ClassDB::bind_method(D_METHOD("load", "path"), &ConfigFile::load);
+ ClassDB::bind_method(D_METHOD("parse", "data"), &ConfigFile::parse);
ClassDB::bind_method(D_METHOD("save", "path"), &ConfigFile::save);
ClassDB::bind_method(D_METHOD("load_encrypted", "path", "key"), &ConfigFile::load_encrypted);
diff --git a/core/io/config_file.h b/core/io/config_file.h
index 95a581d156..2d61ef6afe 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -34,6 +34,7 @@
#include "core/ordered_hash_map.h"
#include "core/os/file_access.h"
#include "core/reference.h"
+#include "core/variant_parser.h"
class ConfigFile : public Reference {
@@ -46,6 +47,8 @@ class ConfigFile : public Reference {
Error _internal_load(const String &p_path, FileAccess *f);
Error _internal_save(FileAccess *file);
+ Error _parse(const String &p_path, VariantParser::Stream *p_stream);
+
protected:
static void _bind_methods();
@@ -64,6 +67,7 @@ public:
Error save(const String &p_path);
Error load(const String &p_path);
+ Error parse(const String &p_data);
Error load_encrypted(const String &p_path, const Vector<uint8_t> &p_key);
Error load_encrypted_pass(const String &p_path, const String &p_pass);
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 87ead37b91..17cc6ce58f 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -63,6 +63,10 @@ Error FileAccessCompressed::open_after_magic(FileAccess *p_base) {
f = p_base;
cmode = (Compression::Mode)f->get_32();
block_size = f->get_32();
+ if (block_size == 0) {
+ f = NULL; // Let the caller to handle the FileAccess object if failed to open as compressed file.
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Can't open compressed file '" + p_base->get_path() + "' with block size 0, it is corrupted.");
+ }
read_total = f->get_32();
int bc = (read_total / block_size) + 1;
int acc_ofs = f->get_position() + bc * 4;
@@ -125,13 +129,11 @@ Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) {
char rmagic[5];
f->get_buffer((uint8_t *)rmagic, 4);
rmagic[4] = 0;
- if (magic != rmagic) {
+ if (magic != rmagic || open_after_magic(f) != OK) {
memdelete(f);
f = NULL;
return ERR_FILE_UNRECOGNIZED;
}
-
- open_after_magic(f);
}
return OK;
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 1b09ac7208..202eb89dbd 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -231,7 +231,7 @@ FileAccessNetworkClient::FileAccessNetworkClient() {
singleton = this;
last_id = 0;
client.instance();
- sem = Semaphore::create();
+ sem = SemaphoreOld::create();
lockcount = 0;
}
@@ -522,8 +522,8 @@ FileAccessNetwork::FileAccessNetwork() {
eof_flag = false;
opened = false;
pos = 0;
- sem = Semaphore::create();
- page_sem = Semaphore::create();
+ sem = SemaphoreOld::create();
+ page_sem = SemaphoreOld::create();
buffer_mutex = Mutex::create();
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
nc->lock_mutex();
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index e2da1d0893..f329abf7c5 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -49,7 +49,7 @@ class FileAccessNetworkClient {
List<BlockRequest> block_requests;
- Semaphore *sem;
+ SemaphoreOld *sem;
Thread *thread;
bool quit;
Mutex *mutex;
@@ -85,8 +85,8 @@ public:
class FileAccessNetwork : public FileAccess {
- Semaphore *sem;
- Semaphore *page_sem;
+ SemaphoreOld *sem;
+ SemaphoreOld *page_sem;
Mutex *buffer_mutex;
bool opened;
size_t total_size;
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 05929ee8ed..720f25f91b 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -53,7 +53,7 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, FileAccess *p_c
Error err;
f = FileAccess::open(p_file, FileAccess::READ, &err);
if (!f) {
- ERR_PRINTS("Error opening file '" + p_file + "'.");
+ ERR_PRINT("Error opening file '" + p_file + "'.");
return err;
}
}
@@ -66,7 +66,7 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, FileAccess *p_c
continue;
Error err = loader[i]->load_image(p_image, f, p_force_linear, p_scale);
if (err != OK) {
- ERR_PRINTS("Error loading image: " + p_file);
+ ERR_PRINT("Error loading image: " + p_file);
}
if (err != ERR_FILE_UNRECOGNIZED) {
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index ea791fb327..7d18117711 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -71,7 +71,7 @@ struct _IP_ResolverPrivate {
}
Mutex *mutex;
- Semaphore *sem;
+ SemaphoreOld *sem;
Thread *thread;
//Semaphore* semaphore;
@@ -184,7 +184,7 @@ IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
resolver->mutex->lock();
if (resolver->queue[p_id].status != IP::RESOLVER_STATUS_DONE) {
- ERR_PRINTS("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet.");
+ ERR_PRINT("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet.");
resolver->mutex->unlock();
return IP_Address();
}
@@ -319,7 +319,7 @@ IP::IP() {
#ifndef NO_THREADS
- resolver->sem = Semaphore::create();
+ resolver->sem = SemaphoreOld::create();
if (resolver->sem) {
resolver->thread_abort = false;
diff --git a/core/io/json.cpp b/core/io/json.cpp
index dbf1676e62..144e4bdc3b 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -203,8 +203,7 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
case 'f': res = 12; break;
case 'r': res = 13; break;
case 'u': {
- //hexnumbarh - oct is deprecated
-
+ // hex number
for (int j = 0; j < 4; j++) {
CharType c = p_str[index + j + 1];
if (c == 0) {
@@ -226,7 +225,7 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
v = c - 'A';
v += 10;
} else {
- ERR_PRINT("BUG");
+ ERR_PRINT("Bug parsing hex constant.");
v = 0;
}
@@ -236,13 +235,8 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
index += 4; //will add at the end anyway
} break;
- //case '\"': res='\"'; break;
- //case '\\': res='\\'; break;
- //case '/': res='/'; break;
default: {
res = next;
- //r_err_str="Invalid escape sequence";
- //return ERR_PARSE_ERROR;
} break;
}
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index c3ea0d024e..4d732332d5 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -58,12 +58,12 @@ void Logger::log_error(const char *p_function, const char *p_file, int p_line, c
return;
}
- const char *err_type = "**ERROR**";
+ const char *err_type = "ERROR";
switch (p_type) {
- case ERR_ERROR: err_type = "**ERROR**"; break;
- case ERR_WARNING: err_type = "**WARNING**"; break;
- case ERR_SCRIPT: err_type = "**SCRIPT ERROR**"; break;
- case ERR_SHADER: err_type = "**SHADER ERROR**"; break;
+ case ERR_ERROR: err_type = "ERROR"; break;
+ case ERR_WARNING: err_type = "WARNING"; break;
+ case ERR_SCRIPT: err_type = "SCRIPT ERROR"; break;
+ case ERR_SHADER: err_type = "SHADER ERROR"; break;
default: ERR_PRINT("Unknown error type"); break;
}
@@ -74,7 +74,7 @@ void Logger::log_error(const char *p_function, const char *p_file, int p_line, c
err_details = p_code;
logf_error("%s: %s\n", err_type, err_details);
- logf_error(" At: %s:%i:%s() - %s\n", p_file, p_line, p_function, p_code);
+ logf_error(" at: %s (%s:%i) - %s\n", p_function, p_file, p_line, p_code);
}
void Logger::logf(const char *p_format, ...) {
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index e847a9cf0c..17edc4982c 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -53,8 +53,7 @@ ObjectID EncodedObjectAsID::get_object_id() const {
return id;
}
-EncodedObjectAsID::EncodedObjectAsID() :
- id(0) {
+EncodedObjectAsID::EncodedObjectAsID() {
}
#define _S(a) ((int32_t)a)
@@ -386,11 +385,11 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
if (type & ENCODE_FLAG_OBJECT_AS_ID) {
//this _is_ allowed
ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA);
- ObjectID val = decode_uint64(buf);
+ ObjectID val = ObjectID(decode_uint64(buf));
if (r_len)
(*r_len) += 8;
- if (val == 0) {
+ if (val.is_null()) {
r_variant = (Object *)NULL;
} else {
Ref<EncodedObjectAsID> obj_as_id;
@@ -803,10 +802,10 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
}
} break;
case Variant::OBJECT: {
-#ifdef DEBUG_ENABLED
+
// Test for potential wrong values sent by the debugger when it breaks.
- Object *obj = p_variant;
- if (!obj || !ObjectDB::instance_validate(obj)) {
+ Object *obj = p_variant.get_validated_object();
+ if (!obj) {
// Object is invalid, send a NULL instead.
if (buf) {
encode_uint32(Variant::NIL, buf);
@@ -814,7 +813,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
r_len += 4;
return OK;
}
-#endif // DEBUG_ENABLED
+
if (!p_full_objects) {
flags |= ENCODE_FLAG_OBJECT_AS_ID;
}
@@ -1128,9 +1127,9 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
} else {
if (buf) {
- Object *obj = p_variant;
- ObjectID id = 0;
- if (obj && ObjectDB::instance_validate(obj)) {
+ Object *obj = p_variant.get_validated_object();
+ ObjectID id;
+ if (obj) {
id = obj->get_instance_id();
}
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index 381ac4c0bb..3f66e00021 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -32,6 +32,7 @@
#include "core/io/marshalls.h"
#include "scene/main/node.h"
+#include <stdint.h>
#ifdef DEBUG_ENABLED
#include "core/os/os.h"
@@ -180,7 +181,8 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
}
#endif
- uint8_t packet_type = p_packet[0];
+ // Extract the `packet_type` from the LSB three bits:
+ uint8_t packet_type = p_packet[0] & 7;
switch (packet_type) {
@@ -197,31 +199,80 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
case NETWORK_COMMAND_REMOTE_CALL:
case NETWORK_COMMAND_REMOTE_SET: {
- ERR_FAIL_COND_MSG(p_packet_len < 6, "Invalid packet received. Size too small.");
-
- Node *node = _process_get_node(p_from, p_packet, p_packet_len);
+ // Extract packet meta
+ int packet_min_size = 1;
+ int name_id_offset = 1;
+ 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.
+ int node_id_compression = (p_packet[0] & 24) >> 3;
+ int name_id_compression = (p_packet[0] & 32) >> 5;
+
+ switch (node_id_compression) {
+ case NETWORK_NODE_ID_COMPRESSION_8:
+ packet_min_size += 1;
+ name_id_offset += 1;
+ break;
+ case NETWORK_NODE_ID_COMPRESSION_16:
+ packet_min_size += 2;
+ name_id_offset += 2;
+ break;
+ case NETWORK_NODE_ID_COMPRESSION_32:
+ packet_min_size += 4;
+ name_id_offset += 4;
+ break;
+ default:
+ ERR_FAIL_MSG("Was not possible to extract the node id compression mode.");
+ }
+ switch (name_id_compression) {
+ case NETWORK_NAME_ID_COMPRESSION_8:
+ packet_min_size += 1;
+ break;
+ case NETWORK_NAME_ID_COMPRESSION_16:
+ packet_min_size += 2;
+ break;
+ default:
+ ERR_FAIL_MSG("Was not possible to extract the name id compression mode.");
+ }
+ ERR_FAIL_COND_MSG(p_packet_len < packet_min_size, "Invalid packet received. Size too small.");
+ uint32_t node_target = 0;
+ switch (node_id_compression) {
+ case NETWORK_NODE_ID_COMPRESSION_8:
+ node_target = p_packet[1];
+ break;
+ case NETWORK_NODE_ID_COMPRESSION_16:
+ node_target = decode_uint16(p_packet + 1);
+ break;
+ case NETWORK_NODE_ID_COMPRESSION_32:
+ node_target = decode_uint32(p_packet + 1);
+ break;
+ default:
+ // Unreachable, checked before.
+ CRASH_NOW();
+ }
+ 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.");
- // Detect cstring end.
- int len_end = 5;
- for (; len_end < p_packet_len; len_end++) {
- if (p_packet[len_end] == 0) {
+ uint16_t name_id = 0;
+ switch (name_id_compression) {
+ case NETWORK_NAME_ID_COMPRESSION_8:
+ name_id = p_packet[name_id_offset];
break;
- }
+ case NETWORK_NAME_ID_COMPRESSION_16:
+ name_id = decode_uint16(p_packet + name_id_offset);
+ break;
+ default:
+ // Unreachable, checked before.
+ CRASH_NOW();
}
- ERR_FAIL_COND_MSG(len_end >= p_packet_len, "Invalid packet received. Size too small.");
-
- StringName name = String::utf8((const char *)&p_packet[5]);
-
if (packet_type == NETWORK_COMMAND_REMOTE_CALL) {
- _process_rpc(node, name, p_from, p_packet, p_packet_len, len_end + 1);
+ _process_rpc(node, name_id, p_from, p_packet, p_packet_len, packet_min_size);
} else {
- _process_rset(node, name, p_from, p_packet, p_packet_len, len_end + 1);
+ _process_rset(node, name_id, p_from, p_packet, p_packet_len, packet_min_size);
}
} break;
@@ -233,15 +284,14 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
}
}
-Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int p_packet_len) {
+Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len) {
- uint32_t target = decode_uint32(&p_packet[1]);
Node *node = NULL;
- if (target & 0x80000000) {
+ if (p_node_target & 0x80000000) {
// Use full path (not cached yet).
- int ofs = target & 0x7FFFFFFF;
+ int ofs = p_node_target & 0x7FFFFFFF;
ERR_FAIL_COND_V_MSG(ofs >= p_packet_len, NULL, "Invalid packet received. Size smaller than declared.");
@@ -253,10 +303,10 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int
node = root_node->get_node(np);
if (!node)
- ERR_PRINTS("Failed to get path from RPC: " + String(np) + ".");
+ ERR_PRINT("Failed to get path from RPC: " + String(np) + ".");
} else {
// Use cached path.
- int id = target;
+ int id = p_node_target;
Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from);
ERR_FAIL_COND_V_MSG(!E, NULL, "Invalid packet received. Requests invalid peer cache.");
@@ -269,26 +319,26 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int
node = root_node->get_node(ni->path);
if (!node)
- ERR_PRINTS("Failed to get cached path from RPC: " + String(ni->path) + ".");
+ ERR_PRINT("Failed to get cached path from RPC: " + String(ni->path) + ".");
}
return node;
}
-void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, 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.");
// Check that remote can call the RPC on this node.
- RPCMode rpc_mode = RPC_MODE_DISABLED;
- const Map<StringName, RPCMode>::Element *E = p_node->get_node_rpc_mode(p_name);
- if (E) {
- rpc_mode = E->get();
- } else if (p_node->get_script_instance()) {
- rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_name);
+ StringName name = p_node->get_node_rpc_method(p_rpc_method_id);
+ RPCMode rpc_mode = p_node->get_node_rpc_mode_by_id(p_rpc_method_id);
+ if (name == StringName() && p_node->get_script_instance()) {
+ name = p_node->get_script_instance()->get_rpc_method(p_rpc_method_id);
+ rpc_mode = p_node->get_script_instance()->get_rpc_mode_by_id(p_rpc_method_id);
}
+ ERR_FAIL_COND(name == StringName());
bool can_call = _can_call_mode(p_node, rpc_mode, p_from);
- ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(p_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];
Vector<Variant> args;
@@ -311,7 +361,7 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
int vlen;
- Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ 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];
@@ -320,29 +370,29 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
Variant::CallError ce;
- p_node->call(p_name, (const Variant **)argp.ptr(), argc, ce);
+ p_node->call(name, (const Variant **)argp.ptr(), argc, ce);
if (ce.error != Variant::CallError::CALL_OK) {
- String error = Variant::get_call_error_text(p_node, p_name, (const Variant **)argp.ptr(), argc, ce);
+ String error = Variant::get_call_error_text(p_node, name, (const Variant **)argp.ptr(), argc, ce);
error = "RPC - " + error;
- ERR_PRINTS(error);
+ ERR_PRINT(error);
}
}
-void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) {
+void MultiplayerAPI::_process_rset(Node *p_node, const uint16_t p_rpc_property_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.");
// Check that remote can call the RSET on this node.
- RPCMode rset_mode = RPC_MODE_DISABLED;
- const Map<StringName, RPCMode>::Element *E = p_node->get_node_rset_mode(p_name);
- if (E) {
- rset_mode = E->get();
- } else if (p_node->get_script_instance()) {
- rset_mode = p_node->get_script_instance()->get_rset_mode(p_name);
+ StringName name = p_node->get_node_rset_property(p_rpc_property_id);
+ RPCMode rset_mode = p_node->get_node_rset_mode_by_id(p_rpc_property_id);
+ if (name == StringName() && p_node->get_script_instance()) {
+ name = p_node->get_script_instance()->get_rset_property(p_rpc_property_id);
+ rset_mode = p_node->get_script_instance()->get_rset_mode_by_id(p_rpc_property_id);
}
+ ERR_FAIL_COND(name == StringName());
bool can_call = _can_call_mode(p_node, rset_mode, p_from);
- ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
+ ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
#ifdef DEBUG_ENABLED
if (profiling) {
@@ -353,26 +403,33 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p
#endif
Variant value;
- Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ Error err = _decode_and_decompress_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL);
ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RSET value.");
bool valid;
- p_node->set(p_name, value, &valid);
+ p_node->set(name, value, &valid);
if (!valid) {
- String error = "Error setting remote property '" + String(p_name) + "', not found in object of type " + p_node->get_class() + ".";
- ERR_PRINTS(error);
+ String error = "Error setting remote property '" + String(name) + "', not found in object of type " + p_node->get_class() + ".";
+ ERR_PRINT(error);
}
}
void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) {
- ERR_FAIL_COND_MSG(p_packet_len < 5, "Invalid packet received. Size too small.");
- int id = decode_uint32(&p_packet[1]);
+ ERR_FAIL_COND_MSG(p_packet_len < 38, "Invalid packet received. Size too small.");
+ int ofs = 1;
+
+ String methods_md5;
+ methods_md5.parse_utf8((const char *)(p_packet + ofs), 32);
+ ofs += 33;
+
+ int id = decode_uint32(&p_packet[ofs]);
+ ofs += 4;
String paths;
- paths.parse_utf8((const char *)&p_packet[5], p_packet_len - 5);
+ paths.parse_utf8((const char *)(p_packet + ofs), p_packet_len - ofs);
NodePath path = paths;
@@ -380,9 +437,15 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
path_get_cache[p_from] = PathGetCache();
}
+ Node *node = root_node->get_node(path);
+ ERR_FAIL_COND(node == NULL);
+ const bool valid_rpc_checksum = node->get_rpc_md5() == methods_md5;
+ if (valid_rpc_checksum == false) {
+ ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path);
+ }
+
PathGetCache::NodeInfo ni;
ni.path = path;
- ni.instance = 0;
path_get_cache[p_from].nodes[id] = ni;
@@ -392,9 +455,10 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
Vector<uint8_t> packet;
- packet.resize(1 + len);
+ packet.resize(1 + 1 + len);
packet.write[0] = NETWORK_COMMAND_CONFIRM_PATH;
- encode_cstring(pname.get_data(), &packet.write[1]);
+ packet.write[1] = valid_rpc_checksum;
+ encode_cstring(pname.get_data(), &packet.write[2]);
network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
network_peer->set_target_peer(p_from);
@@ -403,13 +467,19 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) {
- ERR_FAIL_COND_MSG(p_packet_len < 2, "Invalid packet received. Size too small.");
+ ERR_FAIL_COND_MSG(p_packet_len < 3, "Invalid packet received. Size too small.");
+
+ const bool valid_rpc_checksum = p_packet[1];
String paths;
- paths.parse_utf8((const char *)&p_packet[1], p_packet_len - 1);
+ paths.parse_utf8((const char *)&p_packet[2], p_packet_len - 2);
NodePath path = paths;
+ if (valid_rpc_checksum == false) {
+ ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path);
+ }
+
PathSentCache *psc = path_send_cache.getptr(path);
ERR_FAIL_COND_MSG(!psc, "Invalid packet received. Tries to confirm a path which was not found in cache.");
@@ -418,7 +488,7 @@ void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet,
E->get() = true;
}
-bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int p_target) {
+bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target) {
bool has_all_peers = true;
List<int> peers_to_add; // If one is missing, take note to add it.
@@ -443,31 +513,192 @@ bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int
}
}
- // Those that need to be added, send a message for this.
+ if (peers_to_add.size() > 0) {
- for (List<int>::Element *E = peers_to_add.front(); E; E = E->next()) {
+ // Those that need to be added, send a message for this.
// Encode function name.
- CharString pname = String(p_path).utf8();
- int len = encode_cstring(pname.get_data(), NULL);
+ const CharString path = String(p_path).utf8();
+ const int path_len = encode_cstring(path.get_data(), NULL);
+
+ // Extract MD5 from rpc methods list.
+ const String methods_md5 = p_node->get_rpc_md5();
+ const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder.
Vector<uint8_t> packet;
+ packet.resize(1 + 4 + path_len + methods_md5_len);
+ int ofs = 0;
+
+ packet.write[ofs] = NETWORK_COMMAND_SIMPLIFY_PATH;
+ ofs += 1;
+
+ ofs += encode_cstring(methods_md5.utf8().get_data(), &packet.write[ofs]);
+
+ ofs += encode_uint32(psc->id, &packet.write[ofs]);
+
+ ofs += encode_cstring(path.get_data(), &packet.write[ofs]);
- packet.resize(1 + 4 + len);
- packet.write[0] = NETWORK_COMMAND_SIMPLIFY_PATH;
- encode_uint32(psc->id, &packet.write[1]);
- encode_cstring(pname.get_data(), &packet.write[5]);
+ for (List<int>::Element *E = peers_to_add.front(); E; E = E->next()) {
- network_peer->set_target_peer(E->get()); // To all of you.
- network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
- network_peer->put_packet(packet.ptr(), packet.size());
+ network_peer->set_target_peer(E->get()); // To all of you.
+ network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
+ network_peer->put_packet(packet.ptr(), packet.size());
- psc->confirmed_peers.insert(E->get(), false); // Insert into confirmed, but as false since it was not confirmed.
+ psc->confirmed_peers.insert(E->get(), false); // Insert into confirmed, but as false since it was not confirmed.
+ }
}
return has_all_peers;
}
+// The variant is compressed and encoded; The first byte contains all the meta
+// information and the format is:
+// - The first LSB 5 bits are used for the variant type.
+// - The next two bits are used to store the encoding mode.
+// - The most significant is used to store the boolean value.
+#define VARIANT_META_TYPE_MASK 0x1F
+#define VARIANT_META_EMODE_MASK 0x60
+#define VARIANT_META_BOOL_MASK 0x80
+#define ENCODE_8 0 << 5
+#define ENCODE_16 1 << 5
+#define ENCODE_32 2 << 5
+#define ENCODE_64 3 << 5
+Error MultiplayerAPI::_encode_and_compress_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) {
+
+ // Unreachable because `VARIANT_MAX` == 27 and `ENCODE_VARIANT_MASK` == 31
+ CRASH_COND(p_variant.get_type() > VARIANT_META_TYPE_MASK);
+
+ uint8_t *buf = r_buffer;
+ r_len = 0;
+ uint8_t encode_mode = 0;
+
+ switch (p_variant.get_type()) {
+ case Variant::BOOL: {
+ if (buf) {
+ // We still have 1 free bit in the meta, so let's use it.
+ buf[0] = (p_variant.operator bool()) ? (1 << 7) : 0;
+ buf[0] |= encode_mode | p_variant.get_type();
+ }
+ r_len += 1;
+ } break;
+ case Variant::INT: {
+ if (buf) {
+ // Reserve the first byte for the meta.
+ buf += 1;
+ }
+ r_len += 1;
+ int64_t val = p_variant;
+ if (val <= (int64_t)INT8_MAX && val >= (int64_t)INT8_MIN) {
+ // Use 8 bit
+ encode_mode = ENCODE_8;
+ if (buf) {
+ buf[0] = val;
+ }
+ r_len += 1;
+ } else if (val <= (int64_t)INT16_MAX && val >= (int64_t)INT16_MIN) {
+ // Use 16 bit
+ encode_mode = ENCODE_16;
+ if (buf) {
+ encode_uint16(val, buf);
+ }
+ r_len += 2;
+ } else if (val <= (int64_t)INT32_MAX && val >= (int64_t)INT32_MIN) {
+ // Use 32 bit
+ encode_mode = ENCODE_32;
+ if (buf) {
+ encode_uint32(val, buf);
+ }
+ r_len += 4;
+ } else {
+ // Use 64 bit
+ encode_mode = ENCODE_64;
+ if (buf) {
+ encode_uint64(val, buf);
+ }
+ r_len += 8;
+ }
+ // Store the meta
+ if (buf) {
+ buf -= 1;
+ buf[0] = encode_mode | p_variant.get_type();
+ }
+ } break;
+ default:
+ // Any other case is not yet compressed.
+ Error err = encode_variant(p_variant, r_buffer, r_len, allow_object_decoding);
+ if (err != OK)
+ return err;
+ if (r_buffer) {
+ // The first byte is not used by the marshaling, so store the type
+ // so we know how to decompress and decode this variant.
+ r_buffer[0] = p_variant.get_type();
+ }
+ }
+
+ return OK;
+}
+Error MultiplayerAPI::_decode_and_decompress_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len) {
+
+ const uint8_t *buf = p_buffer;
+ int len = p_len;
+
+ ERR_FAIL_COND_V(len < 1, ERR_INVALID_DATA);
+ uint8_t type = buf[0] & VARIANT_META_TYPE_MASK;
+ uint8_t encode_mode = buf[0] & VARIANT_META_EMODE_MASK;
+
+ ERR_FAIL_COND_V(type >= Variant::VARIANT_MAX, ERR_INVALID_DATA);
+
+ switch (type) {
+ case Variant::BOOL: {
+ bool val = (buf[0] & VARIANT_META_BOOL_MASK) > 0;
+ r_variant = val;
+ if (r_len)
+ *r_len = 1;
+ } break;
+ case Variant::INT: {
+ buf += 1;
+ len -= 1;
+ if (r_len)
+ *r_len = 1;
+ if (encode_mode == ENCODE_8) {
+ // 8 bits.
+ ERR_FAIL_COND_V(len < 1, ERR_INVALID_DATA);
+ int8_t val = buf[0];
+ r_variant = val;
+ if (r_len)
+ (*r_len) += 1;
+ } else if (encode_mode == ENCODE_16) {
+ // 16 bits.
+ ERR_FAIL_COND_V(len < 2, ERR_INVALID_DATA);
+ int16_t val = decode_uint16(buf);
+ r_variant = val;
+ if (r_len)
+ (*r_len) += 2;
+ } else if (encode_mode == ENCODE_32) {
+ // 32 bits.
+ ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
+ int32_t val = decode_uint32(buf);
+ r_variant = val;
+ if (r_len)
+ (*r_len) += 4;
+ } else {
+ // 64 bits.
+ ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA);
+ int64_t val = decode_uint64(buf);
+ r_variant = val;
+ if (r_len)
+ (*r_len) += 8;
+ }
+ } break;
+ default:
+ Error err = decode_variant(r_variant, p_buffer, p_len, r_len, allow_object_decoding);
+ if (err != OK)
+ return err;
+ }
+
+ return OK;
+}
+
void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount) {
ERR_FAIL_COND_MSG(network_peer.is_null(), "Attempt to remote call/set when networking is not active in SceneTree.");
@@ -496,6 +727,9 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
psc->id = last_send_cache_id++;
}
+ // See if all peers have cached path (if so, call can be fast).
+ const bool has_all_peers = _send_confirm_path(p_from, from_path, psc, p_to);
+
// Create base packet, lots of hardcode because it must be tight.
int ofs = 0;
@@ -503,45 +737,125 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
#define MAKE_ROOM(m_amount) \
if (packet_cache.size() < m_amount) packet_cache.resize(m_amount);
- // Encode type.
+ // Encode meta.
+ // The meta is composed by a single byte that contains (starting from the least segnificant bit):
+ // - `NetworkCommands` in the first three bits.
+ // - `NetworkNodeIdCompression` in the next 2 bits.
+ // - `NetworkNameIdCompression` in the next 1 bit.
+ // - So we still have the last two bits free!
+ uint8_t command_type = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL;
+ uint8_t node_id_compression = UINT8_MAX;
+ uint8_t name_id_compression = UINT8_MAX;
+
MAKE_ROOM(1);
- packet_cache.write[0] = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL;
+ // The meta is composed along the way, so just set 0 for now.
+ packet_cache.write[0] = 0;
ofs += 1;
- // Encode ID.
- MAKE_ROOM(ofs + 4);
- encode_uint32(psc->id, &(packet_cache.write[ofs]));
- ofs += 4;
-
- // Encode function name.
- CharString name = String(p_name).utf8();
- int len = encode_cstring(name.get_data(), NULL);
- MAKE_ROOM(ofs + len);
- encode_cstring(name.get_data(), &(packet_cache.write[ofs]));
- ofs += len;
+ // Encode Node ID.
+ if (has_all_peers) {
+ // Compress the node ID only if all the target peers already know it.
+ if (psc->id >= 0 && psc->id <= 255) {
+ // We can encode the id in 1 byte
+ node_id_compression = NETWORK_NODE_ID_COMPRESSION_8;
+ MAKE_ROOM(ofs + 1);
+ packet_cache.write[ofs] = static_cast<uint8_t>(psc->id);
+ ofs += 1;
+ } else if (psc->id >= 0 && psc->id <= 65535) {
+ // We can encode the id in 2 bytes
+ node_id_compression = NETWORK_NODE_ID_COMPRESSION_16;
+ MAKE_ROOM(ofs + 2);
+ encode_uint16(static_cast<uint16_t>(psc->id), &(packet_cache.write[ofs]));
+ ofs += 2;
+ } else {
+ // Too big, let's use 4 bytes.
+ node_id_compression = NETWORK_NODE_ID_COMPRESSION_32;
+ MAKE_ROOM(ofs + 4);
+ encode_uint32(psc->id, &(packet_cache.write[ofs]));
+ ofs += 4;
+ }
+ } else {
+ // The targets doesn't know the node yet, so we need to use 32 bits int.
+ node_id_compression = NETWORK_NODE_ID_COMPRESSION_32;
+ MAKE_ROOM(ofs + 4);
+ encode_uint32(psc->id, &(packet_cache.write[ofs]));
+ ofs += 4;
+ }
if (p_set) {
+
+ // Take the rpc property ID
+ uint16_t property_id = p_from->get_node_rset_property_id(p_name);
+ if (property_id == UINT16_MAX && p_from->get_script_instance()) {
+ property_id = p_from->get_script_instance()->get_rset_property_id(p_name);
+ }
+ ERR_FAIL_COND_MSG(property_id == UINT16_MAX, "Unable to take the `property_id` for the property:" + p_name + ". this can happen only if this property is not marked as `remote`.");
+
+ if (property_id <= UINT8_MAX) {
+ // The ID fits in 1 byte
+ name_id_compression = NETWORK_NAME_ID_COMPRESSION_8;
+ MAKE_ROOM(ofs + 1);
+ packet_cache.write[ofs] = static_cast<uint8_t>(property_id);
+ ofs += 1;
+ } else {
+ // The ID is larger, let's use 2 bytes
+ name_id_compression = NETWORK_NAME_ID_COMPRESSION_16;
+ MAKE_ROOM(ofs + 2);
+ encode_uint16(property_id, &(packet_cache.write[ofs]));
+ ofs += 2;
+ }
+
// Set argument.
- Error err = encode_variant(*p_arg[0], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ int len(0);
+ Error err = _encode_and_compress_variant(*p_arg[0], NULL, len);
ERR_FAIL_COND_MSG(err != OK, "Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!");
MAKE_ROOM(ofs + len);
- encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ _encode_and_compress_variant(*p_arg[0], &(packet_cache.write[ofs]), len);
ofs += len;
} else {
+ // Take the rpc method ID
+ uint16_t method_id = p_from->get_node_rpc_method_id(p_name);
+ if (method_id == UINT16_MAX && p_from->get_script_instance()) {
+ method_id = p_from->get_script_instance()->get_rpc_method_id(p_name);
+ }
+ ERR_FAIL_COND_MSG(method_id == UINT16_MAX, "Unable to take the `method_id` for the function:" + p_name + ". this can happen only if this method is not marked as `remote`.");
+
+ if (method_id <= UINT8_MAX) {
+ // The ID fits in 1 byte
+ name_id_compression = NETWORK_NAME_ID_COMPRESSION_8;
+ MAKE_ROOM(ofs + 1);
+ packet_cache.write[ofs] = static_cast<uint8_t>(method_id);
+ ofs += 1;
+ } else {
+ // The ID is larger, let's use 2 bytes
+ name_id_compression = NETWORK_NAME_ID_COMPRESSION_16;
+ MAKE_ROOM(ofs + 2);
+ encode_uint16(method_id, &(packet_cache.write[ofs]));
+ ofs += 2;
+ }
+
// Call arguments.
MAKE_ROOM(ofs + 1);
packet_cache.write[ofs] = p_argcount;
ofs += 1;
for (int i = 0; i < p_argcount; i++) {
- Error err = encode_variant(*p_arg[i], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ 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_variant(*p_arg[i], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed());
+ _encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len);
ofs += len;
}
}
+ ERR_FAIL_COND(command_type > 7);
+ ERR_FAIL_COND(node_id_compression > 3);
+ ERR_FAIL_COND(name_id_compression > 1);
+
+ // We can now set the meta
+ packet_cache.write[0] = command_type + (node_id_compression << 3) + (name_id_compression << 5);
+
#ifdef DEBUG_ENABLED
if (profiling) {
bandwidth_outgoing_data.write[bandwidth_outgoing_pointer].timestamp = OS::get_singleton()->get_ticks_msec();
@@ -550,9 +864,6 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
}
#endif
- // See if all peers have cached path (is so, call can be fast).
- bool has_all_peers = _send_confirm_path(from_path, psc, p_to);
-
// Take chance and set transfer mode, since all send methods will use it.
network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
@@ -562,6 +873,9 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
network_peer->set_target_peer(p_to); // To all of you.
network_peer->put_packet(packet_cache.ptr(), ofs); // A message with love.
} else {
+ // Unreachable because the node ID is never compressed if the peers doesn't know it.
+ CRASH_COND(node_id_compression != NETWORK_NODE_ID_COMPRESSION_32);
+
// Not all verified path, so send one by one.
// Append path at the end, since we will need it for some packets.
@@ -647,16 +961,14 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) {
// Check that send mode can use local call.
- const Map<StringName, RPCMode>::Element *E = p_node->get_node_rpc_mode(p_method);
- if (E) {
- call_local_native = _should_call_local(E->get(), is_master, skip_rpc);
- }
+ RPCMode rpc_mode = p_node->get_node_rpc_mode(p_method);
+ call_local_native = _should_call_local(rpc_mode, is_master, skip_rpc);
if (call_local_native) {
// Done below.
} else if (p_node->get_script_instance()) {
// Attempt with script.
- RPCMode rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method);
+ rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method);
call_local_script = _should_call_local(rpc_mode, is_master, skip_rpc);
}
}
@@ -683,7 +995,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
if (ce.error != Variant::CallError::CALL_OK) {
String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce);
error = "rpc() aborted in local call: - " + error + ".";
- ERR_PRINTS(error);
+ ERR_PRINT(error);
return;
}
}
@@ -698,7 +1010,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
if (ce.error != Variant::CallError::CALL_OK) {
String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce);
error = "rpc() aborted in script local call: - " + error + ".";
- ERR_PRINTS(error);
+ ERR_PRINT(error);
return;
}
}
@@ -719,11 +1031,8 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) {
// Check that send mode can use local call.
- const Map<StringName, RPCMode>::Element *E = p_node->get_node_rset_mode(p_property);
- if (E) {
-
- set_local = _should_call_local(E->get(), is_master, skip_rset);
- }
+ RPCMode rpc_mode = p_node->get_node_rset_mode(p_property);
+ set_local = _should_call_local(rpc_mode, is_master, skip_rset);
if (set_local) {
bool valid;
@@ -735,12 +1044,12 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
if (!valid) {
String error = "rset() aborted in local set, property not found: - " + String(p_property) + ".";
- ERR_PRINTS(error);
+ ERR_PRINT(error);
return;
}
} else if (p_node->get_script_instance()) {
// Attempt with script.
- RPCMode rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property);
+ rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property);
set_local = _should_call_local(rpc_mode, is_master, skip_rset);
@@ -753,7 +1062,7 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
if (!valid) {
String error = "rset() aborted in local script set, property not found: - " + String(p_property) + ".";
- ERR_PRINTS(error);
+ ERR_PRINT(error);
return;
}
}
@@ -984,9 +1293,7 @@ void MultiplayerAPI::_bind_methods() {
BIND_ENUM_CONSTANT(RPC_MODE_REMOTE);
BIND_ENUM_CONSTANT(RPC_MODE_MASTER);
BIND_ENUM_CONSTANT(RPC_MODE_PUPPET);
- BIND_ENUM_CONSTANT(RPC_MODE_SLAVE); // Deprecated.
BIND_ENUM_CONSTANT(RPC_MODE_REMOTESYNC);
- BIND_ENUM_CONSTANT(RPC_MODE_SYNC); // Deprecated.
BIND_ENUM_CONSTANT(RPC_MODE_MASTERSYNC);
BIND_ENUM_CONSTANT(RPC_MODE_PUPPETSYNC);
}
diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h
index c9f127b6b2..8748dba03c 100644
--- a/core/io/multiplayer_api.h
+++ b/core/io/multiplayer_api.h
@@ -98,32 +98,44 @@ protected:
void _process_packet(int p_from, const uint8_t *p_packet, int p_packet_len);
void _process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len);
void _process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len);
- Node *_process_get_node(int p_from, const uint8_t *p_packet, int p_packet_len);
- void _process_rpc(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
- void _process_rset(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
+ Node *_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len);
+ void _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 _process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
void _process_raw(int p_from, const uint8_t *p_packet, int p_packet_len);
void _send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount);
- bool _send_confirm_path(NodePath p_path, PathSentCache *psc, int p_target);
+ bool _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target);
+
+ Error _encode_and_compress_variant(const Variant &p_variant, uint8_t *p_buffer, int &r_len);
+ Error _decode_and_decompress_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len);
public:
enum NetworkCommands {
- NETWORK_COMMAND_REMOTE_CALL,
+ NETWORK_COMMAND_REMOTE_CALL = 0,
NETWORK_COMMAND_REMOTE_SET,
NETWORK_COMMAND_SIMPLIFY_PATH,
NETWORK_COMMAND_CONFIRM_PATH,
NETWORK_COMMAND_RAW,
};
+ enum NetworkNodeIdCompression {
+ NETWORK_NODE_ID_COMPRESSION_8 = 0,
+ NETWORK_NODE_ID_COMPRESSION_16,
+ NETWORK_NODE_ID_COMPRESSION_32,
+ };
+
+ enum NetworkNameIdCompression {
+ NETWORK_NAME_ID_COMPRESSION_8 = 0,
+ NETWORK_NAME_ID_COMPRESSION_16,
+ };
+
enum RPCMode {
RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default)
RPC_MODE_REMOTE, // Using rpc() on it will call method / set property in all remote peers
RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote
RPC_MODE_PUPPET, // Using rpc() on it will call method for all puppets
- RPC_MODE_SLAVE = RPC_MODE_PUPPET, // Deprecated, same as puppet
RPC_MODE_REMOTESYNC, // Using rpc() on it will call method / set property in all remote peers and locally
- RPC_MODE_SYNC = RPC_MODE_REMOTESYNC, // Deprecated. Same as RPC_MODE_REMOTESYNC
RPC_MODE_MASTERSYNC, // Using rpc() on it will call method / set property in the master peer and locally
RPC_MODE_PUPPETSYNC, // Using rpc() on it will call method / set property in all puppets peers and locally
};
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
index 9e53d773ba..81d7b86161 100644
--- a/core/io/packet_peer.cpp
+++ b/core/io/packet_peer.cpp
@@ -37,20 +37,9 @@
PacketPeer::PacketPeer() :
last_get_error(OK),
- allow_object_decoding(false),
encode_buffer_max_size(8 * 1024 * 1024) {
}
-void PacketPeer::set_allow_object_decoding(bool p_enable) {
-
- allow_object_decoding = p_enable;
-}
-
-bool PacketPeer::is_object_decoding_allowed() const {
-
- return allow_object_decoding;
-}
-
void PacketPeer::set_encode_buffer_max_size(int p_max_size) {
ERR_FAIL_COND_MSG(p_max_size < 1024, "Max encode buffer must be at least 1024 bytes");
@@ -101,13 +90,13 @@ Error PacketPeer::get_var(Variant &r_variant, bool p_allow_objects) {
if (err)
return err;
- return decode_variant(r_variant, buffer, buffer_size, NULL, p_allow_objects || allow_object_decoding);
+ return decode_variant(r_variant, buffer, buffer_size, NULL, p_allow_objects);
}
Error PacketPeer::put_var(const Variant &p_packet, bool p_full_objects) {
int len;
- Error err = encode_variant(p_packet, NULL, len, p_full_objects || allow_object_decoding); // compute len first
+ Error err = encode_variant(p_packet, NULL, len, p_full_objects); // compute len first
if (err)
return err;
@@ -122,7 +111,7 @@ Error PacketPeer::put_var(const Variant &p_packet, bool p_full_objects) {
}
PoolVector<uint8_t>::Write w = encode_buffer.write();
- err = encode_variant(p_packet, w.ptr(), len, p_full_objects || allow_object_decoding);
+ err = encode_variant(p_packet, w.ptr(), len, p_full_objects);
ERR_FAIL_COND_V_MSG(err != OK, err, "Error when trying to encode Variant.");
return put_packet(w.ptr(), len);
@@ -160,13 +149,10 @@ void PacketPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_packet_error"), &PacketPeer::_get_packet_error);
ClassDB::bind_method(D_METHOD("get_available_packet_count"), &PacketPeer::get_available_packet_count);
- ClassDB::bind_method(D_METHOD("set_allow_object_decoding", "enable"), &PacketPeer::set_allow_object_decoding);
- ClassDB::bind_method(D_METHOD("is_object_decoding_allowed"), &PacketPeer::is_object_decoding_allowed);
ClassDB::bind_method(D_METHOD("get_encode_buffer_max_size"), &PacketPeer::get_encode_buffer_max_size);
ClassDB::bind_method(D_METHOD("set_encode_buffer_max_size", "max_size"), &PacketPeer::set_encode_buffer_max_size);
ADD_PROPERTY(PropertyInfo(Variant::INT, "encode_buffer_max_size"), "set_encode_buffer_max_size", "get_encode_buffer_max_size");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed");
};
/***************/
diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h
index 2b13f2e952..bee69f5ca9 100644
--- a/core/io/packet_peer.h
+++ b/core/io/packet_peer.h
@@ -49,8 +49,6 @@ class PacketPeer : public Reference {
mutable Error last_get_error;
- bool allow_object_decoding;
-
int encode_buffer_max_size;
PoolVector<uint8_t> encode_buffer;
@@ -69,9 +67,6 @@ public:
virtual Error get_var(Variant &r_variant, bool p_allow_objects = false);
virtual Error put_var(const Variant &p_packet, bool p_full_objects = false);
- void set_allow_object_decoding(bool p_enable);
- bool is_object_decoding_allowed() const;
-
void set_encode_buffer_max_size(int p_max_size);
int get_encode_buffer_max_size() const;
diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp
index 5c98c4fcab..a8cfd741bb 100644
--- a/core/io/packet_peer_udp.cpp
+++ b/core/io/packet_peer_udp.cpp
@@ -222,7 +222,7 @@ Error PacketPeerUDP::_poll() {
if (rb.space_left() < read + 24) {
#ifdef TOOLS_ENABLED
- WARN_PRINTS("Buffer full, dropping packets!");
+ WARN_PRINT("Buffer full, dropping packets!");
#endif
continue;
}
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 272d5c1116..02ae5788fc 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -73,13 +73,6 @@ enum {
VARIANT_VECTOR2_ARRAY = 37,
VARIANT_INT64 = 40,
VARIANT_DOUBLE = 41,
-#ifndef DISABLE_DEPRECATED
- VARIANT_IMAGE = 21, // - no longer variant type
- IMAGE_ENCODING_EMPTY = 0,
- IMAGE_ENCODING_RAW = 1,
- IMAGE_ENCODING_LOSSLESS = 2,
- IMAGE_ENCODING_LOSSY = 3,
-#endif
OBJECT_EMPTY = 0,
OBJECT_EXTERNAL_RESOURCE = 1,
OBJECT_INTERNAL_RESOURCE = 2,
@@ -549,69 +542,6 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) {
w.release();
r_v = array;
} break;
-#ifndef DISABLE_DEPRECATED
- case VARIANT_IMAGE: {
- uint32_t encoding = f->get_32();
- if (encoding == IMAGE_ENCODING_EMPTY) {
- r_v = Ref<Image>();
- break;
- } else if (encoding == IMAGE_ENCODING_RAW) {
- uint32_t width = f->get_32();
- uint32_t height = f->get_32();
- uint32_t mipmaps = f->get_32();
- uint32_t format = f->get_32();
- const uint32_t format_version_shift = 24;
- const uint32_t format_version_mask = format_version_shift - 1;
-
- uint32_t format_version = format >> format_version_shift;
-
- const uint32_t current_version = 0;
- if (format_version > current_version) {
-
- ERR_PRINT("Format version for encoded binary image is too new.");
- return ERR_PARSE_ERROR;
- }
-
- Image::Format fmt = Image::Format(format & format_version_mask); //if format changes, we can add a compatibility bit on top
-
- uint32_t datalen = f->get_32();
-
- PoolVector<uint8_t> imgdata;
- imgdata.resize(datalen);
- PoolVector<uint8_t>::Write w = imgdata.write();
- f->get_buffer(w.ptr(), datalen);
- _advance_padding(datalen);
- w.release();
-
- Ref<Image> image;
- image.instance();
- image->create(width, height, mipmaps, fmt, imgdata);
- r_v = image;
-
- } else {
- //compressed
- PoolVector<uint8_t> data;
- data.resize(f->get_32());
- PoolVector<uint8_t>::Write w = data.write();
- f->get_buffer(w.ptr(), data.size());
- w.release();
-
- Ref<Image> image;
-
- if (encoding == IMAGE_ENCODING_LOSSY && Image::lossy_unpacker) {
-
- image = Image::lossy_unpacker(data);
- } else if (encoding == IMAGE_ENCODING_LOSSLESS && Image::lossless_unpacker) {
-
- image = Image::lossless_unpacker(data);
- }
- _advance_padding(data.size());
-
- r_v = image;
- }
-
- } break;
-#endif
default: {
ERR_FAIL_V(ERR_FILE_CORRUPT);
} break;
@@ -836,15 +766,20 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
uint8_t header[4];
f->get_buffer(header, 4);
if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') {
- //compressed
+ // Compressed.
FileAccessCompressed *fac = memnew(FileAccessCompressed);
- fac->open_after_magic(f);
+ error = fac->open_after_magic(f);
+ if (error != OK) {
+ memdelete(fac);
+ f->close();
+ ERR_FAIL_MSG("Failed to open binary resource file: " + local_path + ".");
+ }
f = fac;
} else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') {
- //not normal
-
+ // Not normal.
error = ERR_FILE_UNRECOGNIZED;
+ f->close();
ERR_FAIL_MSG("Unrecognized binary resource file: " + local_path + ".");
}
@@ -919,6 +854,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
if (f->eof_reached()) {
error = ERR_FILE_CORRUPT;
+ f->close();
ERR_FAIL_MSG("Premature end of file (EOF): " + local_path + ".");
}
}
@@ -931,14 +867,20 @@ String ResourceInteractiveLoaderBinary::recognize(FileAccess *p_f) {
uint8_t header[4];
f->get_buffer(header, 4);
if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') {
- //compressed
+ // Compressed.
FileAccessCompressed *fac = memnew(FileAccessCompressed);
- fac->open_after_magic(f);
+ error = fac->open_after_magic(f);
+ if (error != OK) {
+ memdelete(fac);
+ f->close();
+ return "";
+ }
f = fac;
} else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') {
- //not normal
+ // Not normal.
error = ERR_FILE_UNRECOGNIZED;
+ f->close();
return "";
}
@@ -1055,14 +997,19 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
uint8_t header[4];
f->get_buffer(header, 4);
if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') {
- //compressed
+ // Compressed.
FileAccessCompressed *fac = memnew(FileAccessCompressed);
- fac->open_after_magic(f);
+ Error err = fac->open_after_magic(f);
+ if (err != OK) {
+ memdelete(fac);
+ memdelete(f);
+ ERR_FAIL_V_MSG(err, "Cannot open file '" + p_path + "'.");
+ }
f = fac;
FileAccessCompressed *facw = memnew(FileAccessCompressed);
facw->configure("RSCC");
- Error err = facw->_open(p_path + ".depren", FileAccess::WRITE);
+ err = facw->_open(p_path + ".depren", FileAccess::WRITE);
if (err) {
memdelete(fac);
memdelete(facw);
@@ -1072,9 +1019,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
fw = facw;
} else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') {
- //not normal
-
- //error=ERR_FILE_UNRECOGNIZED;
+ // Not normal.
memdelete(f);
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unrecognized binary resource file '" + local_path + "'.");
} else {
@@ -1113,7 +1058,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
memdelete(da);
//use the old approach
- WARN_PRINTS("This file is old, so it can't refactor dependencies, opening and resaving '" + p_path + "'.");
+ WARN_PRINT("This file is old, so it can't refactor dependencies, opening and resaving '" + p_path + "'.");
Error err;
f = FileAccess::open(p_path, FileAccess::READ, &err);
@@ -1255,7 +1200,7 @@ String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const
ria->res_path = ria->local_path;
//ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
String r = ria->recognize(f);
- return r;
+ return ClassDB::get_compatibility_remapped_class(r);
}
///////////////////////////////////////////////////////////
@@ -1628,14 +1573,14 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant
switch (p_variant.get_type()) {
case Variant::OBJECT: {
- RES res = p_variant.operator RefPtr();
+ RES res = p_variant;
if (res.is_null() || external_resources.has(res))
return;
if (!p_main && (!bundle_resources) && res->get_path().length() && res->get_path().find("::") == -1) {
if (res->get_path() == path) {
- ERR_PRINTS("Circular reference to resource being saved found: '" + local_path + "' will be null next time it's loaded.");
+ ERR_PRINT("Circular reference to resource being saved found: '" + local_path + "' will be null next time it's loaded.");
return;
}
int idx = external_resources.size();
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index 7737006d10..f02dbaa0c2 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -51,7 +51,6 @@ class ResourceInteractiveLoaderBinary : public ResourceInteractiveLoader {
Vector<char> str_buf;
List<RES> resource_cache;
- //Map<int,StringName> string_map;
Vector<StringName> string_map;
StringName _get_string();
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index c2d90ed204..f147170ff7 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -74,7 +74,7 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
memdelete(f);
return OK;
} else if (err != OK) {
- ERR_PRINTS("ResourceFormatImporter::load - " + p_path + ".import:" + itos(lines) + " error: " + error_text);
+ ERR_PRINT("ResourceFormatImporter::load - " + p_path + ".import:" + itos(lines) + " error: " + error_text);
memdelete(f);
return err;
}
@@ -279,7 +279,7 @@ void ResourceFormatImporter::get_internal_resource_path_list(const String &p_pat
memdelete(f);
return;
} else if (err != OK) {
- ERR_PRINTS("ResourceFormatImporter::get_internal_resource_path_list - " + p_path + ".import:" + itos(lines) + " error: " + error_text);
+ ERR_PRINT("ResourceFormatImporter::get_internal_resource_path_list - " + p_path + ".import:" + itos(lines) + " error: " + error_text);
memdelete(f);
return;
}
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 7471ab4241..6877f816e1 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -404,6 +404,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
if (!p_no_cache) {
_remove_from_loading_map(local_path);
}
+ print_verbose("Failed loading resource: " + path);
return RES();
}
if (!p_no_cache)
@@ -728,8 +729,9 @@ String ResourceLoader::get_resource_type(const String &p_path) {
for (int i = 0; i < loader_count; i++) {
String result = loader[i]->get_resource_type(local_path);
- if (result != "")
+ if (result != "") {
return result;
+ }
}
return "";
@@ -815,7 +817,7 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
if (err == ERR_FILE_EOF) {
break;
} else if (err != OK) {
- ERR_PRINTS("Parse error: " + p_path + ".remap:" + itos(lines) + " error: " + error_text + ".");
+ ERR_PRINT("Parse error: " + p_path + ".remap:" + itos(lines) + " error: " + error_text + ".");
break;
}
@@ -953,7 +955,7 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) {
ERR_FAIL_COND_V_MSG(obj == NULL, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + ".");
ResourceFormatLoader *crl = Object::cast_to<ResourceFormatLoader>(obj);
- crl->set_script(s.get_ref_ptr());
+ crl->set_script(s);
ResourceLoader::add_resource_format_loader(crl);
return true;
@@ -1013,7 +1015,7 @@ void ResourceLoader::finalize() {
#ifndef NO_THREADS
const LoadingMapKey *K = NULL;
while ((K = loading_map.next(K))) {
- ERR_PRINTS("Exited while resource is being loaded: " + K->path);
+ ERR_PRINT("Exited while resource is being loaded: " + K->path);
}
loading_map.clear();
memdelete(loading_map_mutex);
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index b468685e4d..685d21107f 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -221,7 +221,7 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) {
ERR_FAIL_COND_V_MSG(obj == NULL, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + ".");
ResourceFormatSaver *crl = Object::cast_to<ResourceFormatSaver>(obj);
- crl->set_script(s.get_ref_ptr());
+ crl->set_script(s);
ResourceSaver::add_resource_format_saver(crl);
return true;