Add object encoding param to serialization methods

Network peers get_var/put_var
File get_var/store_var
GDScript/Mono/VisualScript bytes2var/var2bytes
Add MultiplayerAPI.allow_object_decoding member which deprecates PacketPeer.allow_object_decoding.

Break ABI compatibaility (API compatibility for GDNative).

(cherry picked from commit 393e62b98a)
This commit is contained in:
Fabio Alessandrelli 2019-03-26 16:52:42 +01:00 committed by Hein-Pieter van Braam-Stewart
parent a1ad05df86
commit e0fe795433
23 changed files with 220 additions and 104 deletions

View File

@ -1908,18 +1908,18 @@ bool _File::file_exists(const String &p_name) const {
return FileAccess::exists(p_name); return FileAccess::exists(p_name);
} }
void _File::store_var(const Variant &p_var) { void _File::store_var(const Variant &p_var, bool p_full_objects) {
ERR_FAIL_COND(!f); ERR_FAIL_COND(!f);
int len; int len;
Error err = encode_variant(p_var, NULL, len); Error err = encode_variant(p_var, NULL, len, p_full_objects);
ERR_FAIL_COND(err != OK); ERR_FAIL_COND(err != OK);
PoolVector<uint8_t> buff; PoolVector<uint8_t> buff;
buff.resize(len); buff.resize(len);
PoolVector<uint8_t>::Write w = buff.write(); PoolVector<uint8_t>::Write w = buff.write();
err = encode_variant(p_var, &w[0], len); err = encode_variant(p_var, &w[0], len, p_full_objects);
ERR_FAIL_COND(err != OK); ERR_FAIL_COND(err != OK);
w = PoolVector<uint8_t>::Write(); w = PoolVector<uint8_t>::Write();
@ -1927,7 +1927,7 @@ void _File::store_var(const Variant &p_var) {
store_buffer(buff); store_buffer(buff);
} }
Variant _File::get_var() const { Variant _File::get_var(bool p_allow_objects) const {
ERR_FAIL_COND_V(!f, Variant()); ERR_FAIL_COND_V(!f, Variant());
uint32_t len = get_32(); uint32_t len = get_32();
@ -1937,7 +1937,7 @@ Variant _File::get_var() const {
PoolVector<uint8_t>::Read r = buff.read(); PoolVector<uint8_t>::Read r = buff.read();
Variant v; Variant v;
Error err = decode_variant(v, &r[0], len); Error err = decode_variant(v, &r[0], len, NULL, p_allow_objects);
ERR_FAIL_COND_V(err != OK, Variant()); ERR_FAIL_COND_V(err != OK, Variant());
return v; return v;
@ -1980,7 +1980,7 @@ void _File::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_endian_swap"), &_File::get_endian_swap); ClassDB::bind_method(D_METHOD("get_endian_swap"), &_File::get_endian_swap);
ClassDB::bind_method(D_METHOD("set_endian_swap", "enable"), &_File::set_endian_swap); ClassDB::bind_method(D_METHOD("set_endian_swap", "enable"), &_File::set_endian_swap);
ClassDB::bind_method(D_METHOD("get_error"), &_File::get_error); ClassDB::bind_method(D_METHOD("get_error"), &_File::get_error);
ClassDB::bind_method(D_METHOD("get_var"), &_File::get_var); ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &_File::get_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("store_8", "value"), &_File::store_8); ClassDB::bind_method(D_METHOD("store_8", "value"), &_File::store_8);
ClassDB::bind_method(D_METHOD("store_16", "value"), &_File::store_16); ClassDB::bind_method(D_METHOD("store_16", "value"), &_File::store_16);
@ -1993,7 +1993,7 @@ void _File::_bind_methods() {
ClassDB::bind_method(D_METHOD("store_line", "line"), &_File::store_line); ClassDB::bind_method(D_METHOD("store_line", "line"), &_File::store_line);
ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &_File::store_csv_line, DEFVAL(",")); ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &_File::store_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("store_string", "string"), &_File::store_string); ClassDB::bind_method(D_METHOD("store_string", "string"), &_File::store_string);
ClassDB::bind_method(D_METHOD("store_var", "value"), &_File::store_var); ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &_File::store_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &_File::store_pascal_string); ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &_File::store_pascal_string);
ClassDB::bind_method(D_METHOD("get_pascal_string"), &_File::get_pascal_string); ClassDB::bind_method(D_METHOD("get_pascal_string"), &_File::get_pascal_string);
@ -2223,17 +2223,17 @@ _Marshalls *_Marshalls::get_singleton() {
return singleton; return singleton;
} }
String _Marshalls::variant_to_base64(const Variant &p_var) { String _Marshalls::variant_to_base64(const Variant &p_var, bool p_full_objects) {
int len; int len;
Error err = encode_variant(p_var, NULL, len); Error err = encode_variant(p_var, NULL, len, p_full_objects);
ERR_FAIL_COND_V(err != OK, ""); ERR_FAIL_COND_V(err != OK, "");
PoolVector<uint8_t> buff; PoolVector<uint8_t> buff;
buff.resize(len); buff.resize(len);
PoolVector<uint8_t>::Write w = buff.write(); PoolVector<uint8_t>::Write w = buff.write();
err = encode_variant(p_var, &w[0], len); err = encode_variant(p_var, &w[0], len, p_full_objects);
ERR_FAIL_COND_V(err != OK, ""); ERR_FAIL_COND_V(err != OK, "");
int b64len = len / 3 * 4 + 4 + 1; int b64len = len / 3 * 4 + 4 + 1;
@ -2249,7 +2249,7 @@ String _Marshalls::variant_to_base64(const Variant &p_var) {
return ret; return ret;
}; };
Variant _Marshalls::base64_to_variant(const String &p_str) { Variant _Marshalls::base64_to_variant(const String &p_str, bool p_allow_objects) {
int strlen = p_str.length(); int strlen = p_str.length();
CharString cstr = p_str.ascii(); CharString cstr = p_str.ascii();
@ -2261,7 +2261,7 @@ Variant _Marshalls::base64_to_variant(const String &p_str) {
int len = base64_decode((char *)(&w[0]), (char *)cstr.get_data(), strlen); int len = base64_decode((char *)(&w[0]), (char *)cstr.get_data(), strlen);
Variant v; Variant v;
Error err = decode_variant(v, &w[0], len); Error err = decode_variant(v, &w[0], len, NULL, p_allow_objects);
ERR_FAIL_COND_V(err != OK, Variant()); ERR_FAIL_COND_V(err != OK, Variant());
return v; return v;
@ -2340,8 +2340,8 @@ String _Marshalls::base64_to_utf8(const String &p_str) {
void _Marshalls::_bind_methods() { void _Marshalls::_bind_methods() {
ClassDB::bind_method(D_METHOD("variant_to_base64", "variant"), &_Marshalls::variant_to_base64); ClassDB::bind_method(D_METHOD("variant_to_base64", "variant", "full_objects"), &_Marshalls::variant_to_base64, DEFVAL(false));
ClassDB::bind_method(D_METHOD("base64_to_variant", "base64_str"), &_Marshalls::base64_to_variant); ClassDB::bind_method(D_METHOD("base64_to_variant", "base64_str", "allow_objects"), &_Marshalls::base64_to_variant, DEFVAL(false));
ClassDB::bind_method(D_METHOD("raw_to_base64", "array"), &_Marshalls::raw_to_base64); ClassDB::bind_method(D_METHOD("raw_to_base64", "array"), &_Marshalls::raw_to_base64);
ClassDB::bind_method(D_METHOD("base64_to_raw", "base64_str"), &_Marshalls::base64_to_raw); ClassDB::bind_method(D_METHOD("base64_to_raw", "base64_str"), &_Marshalls::base64_to_raw);

View File

@ -463,7 +463,7 @@ public:
double get_double() const; double get_double() const;
real_t get_real() const; real_t get_real() const;
Variant get_var() const; Variant get_var(bool p_allow_objects = false) const;
PoolVector<uint8_t> get_buffer(int p_length) const; ///< get an array of bytes PoolVector<uint8_t> get_buffer(int p_length) const; ///< get an array of bytes
String get_line() const; String get_line() const;
@ -500,7 +500,7 @@ public:
void store_buffer(const PoolVector<uint8_t> &p_buffer); ///< store an array of bytes void store_buffer(const PoolVector<uint8_t> &p_buffer); ///< store an array of bytes
void store_var(const Variant &p_var); void store_var(const Variant &p_var, bool p_full_objects = false);
bool file_exists(const String &p_name) const; ///< return true if a file exists bool file_exists(const String &p_name) const; ///< return true if a file exists
@ -569,8 +569,8 @@ protected:
public: public:
static _Marshalls *get_singleton(); static _Marshalls *get_singleton();
String variant_to_base64(const Variant &p_var); String variant_to_base64(const Variant &p_var, bool p_full_objects = false);
Variant base64_to_variant(const String &p_str); Variant base64_to_variant(const String &p_str, bool p_allow_objects = false);
String raw_to_base64(const PoolVector<uint8_t> &p_arr); String raw_to_base64(const PoolVector<uint8_t> &p_arr);
PoolVector<uint8_t> base64_to_raw(const String &p_str); PoolVector<uint8_t> base64_to_raw(const String &p_str);

View File

@ -299,7 +299,7 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
ERR_FAIL_COND(p_offset >= p_packet_len); ERR_FAIL_COND(p_offset >= p_packet_len);
int vlen; int vlen;
Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen, network_peer->is_object_decoding_allowed()); 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());
ERR_EXPLAIN("Invalid packet received. Unable to decode RPC argument."); ERR_EXPLAIN("Invalid packet received. Unable to decode RPC argument.");
ERR_FAIL_COND(err != OK); ERR_FAIL_COND(err != OK);
@ -335,7 +335,7 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p
ERR_FAIL_COND(!_can_call_mode(p_node, rset_mode, p_from)); ERR_FAIL_COND(!_can_call_mode(p_node, rset_mode, p_from));
Variant value; Variant value;
Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, network_peer->is_object_decoding_allowed()); Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed());
ERR_EXPLAIN("Invalid packet received. Unable to decode RSET value."); ERR_EXPLAIN("Invalid packet received. Unable to decode RSET value.");
ERR_FAIL_COND(err != OK); ERR_FAIL_COND(err != OK);
@ -526,11 +526,11 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
if (p_set) { if (p_set) {
// Set argument. // Set argument.
Error err = encode_variant(*p_arg[0], NULL, len, network_peer->is_object_decoding_allowed()); Error err = encode_variant(*p_arg[0], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed());
ERR_EXPLAIN("Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_EXPLAIN("Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!");
ERR_FAIL_COND(err != OK); ERR_FAIL_COND(err != OK);
MAKE_ROOM(ofs + len); MAKE_ROOM(ofs + len);
encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len, network_peer->is_object_decoding_allowed()); encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed());
ofs += len; ofs += len;
} else { } else {
@ -539,11 +539,11 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
packet_cache.write[ofs] = p_argcount; packet_cache.write[ofs] = p_argcount;
ofs += 1; ofs += 1;
for (int i = 0; i < p_argcount; i++) { for (int i = 0; i < p_argcount; i++) {
Error err = encode_variant(*p_arg[i], NULL, len, network_peer->is_object_decoding_allowed()); Error err = encode_variant(*p_arg[i], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed());
ERR_EXPLAIN("Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_EXPLAIN("Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!");
ERR_FAIL_COND(err != OK); ERR_FAIL_COND(err != OK);
MAKE_ROOM(ofs + len); MAKE_ROOM(ofs + len);
encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len, network_peer->is_object_decoding_allowed()); encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed());
ofs += len; ofs += len;
} }
} }
@ -818,6 +818,16 @@ Vector<int> MultiplayerAPI::get_network_connected_peers() const {
return ret; return ret;
} }
void MultiplayerAPI::set_allow_object_decoding(bool p_enable) {
allow_object_decoding = p_enable;
}
bool MultiplayerAPI::is_object_decoding_allowed() const {
return allow_object_decoding;
}
void MultiplayerAPI::_bind_methods() { void MultiplayerAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node); ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node);
ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE)); ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE));
@ -838,6 +848,10 @@ void MultiplayerAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_network_connected_peers"), &MultiplayerAPI::get_network_connected_peers); ClassDB::bind_method(D_METHOD("get_network_connected_peers"), &MultiplayerAPI::get_network_connected_peers);
ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &MultiplayerAPI::set_refuse_new_network_connections); ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &MultiplayerAPI::set_refuse_new_network_connections);
ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &MultiplayerAPI::is_refusing_new_network_connections); ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &MultiplayerAPI::is_refusing_new_network_connections);
ClassDB::bind_method(D_METHOD("set_allow_object_decoding", "enable"), &MultiplayerAPI::set_allow_object_decoding);
ClassDB::bind_method(D_METHOD("is_object_decoding_allowed"), &MultiplayerAPI::is_object_decoding_allowed);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer");
@ -859,7 +873,8 @@ void MultiplayerAPI::_bind_methods() {
BIND_ENUM_CONSTANT(RPC_MODE_PUPPETSYNC); BIND_ENUM_CONSTANT(RPC_MODE_PUPPETSYNC);
} }
MultiplayerAPI::MultiplayerAPI() { MultiplayerAPI::MultiplayerAPI() :
allow_object_decoding(false) {
rpc_sender_id = 0; rpc_sender_id = 0;
root_node = NULL; root_node = NULL;
clear(); clear();

View File

@ -63,6 +63,7 @@ private:
int last_send_cache_id; int last_send_cache_id;
Vector<uint8_t> packet_cache; Vector<uint8_t> packet_cache;
Node *root_node; Node *root_node;
bool allow_object_decoding;
protected: protected:
static void _bind_methods(); static void _bind_methods();
@ -126,6 +127,9 @@ public:
void set_refuse_new_network_connections(bool p_refuse); void set_refuse_new_network_connections(bool p_refuse);
bool is_refusing_new_network_connections() const; bool is_refusing_new_network_connections() const;
void set_allow_object_decoding(bool p_enable);
bool is_object_decoding_allowed() const;
MultiplayerAPI(); MultiplayerAPI();
~MultiplayerAPI(); ~MultiplayerAPI();
}; };

View File

@ -79,7 +79,7 @@ Error PacketPeer::put_packet_buffer(const PoolVector<uint8_t> &p_buffer) {
return put_packet(&r[0], len); return put_packet(&r[0], len);
} }
Error PacketPeer::get_var(Variant &r_variant) { Error PacketPeer::get_var(Variant &r_variant, bool p_allow_objects) {
const uint8_t *buffer; const uint8_t *buffer;
int buffer_size; int buffer_size;
@ -87,13 +87,13 @@ Error PacketPeer::get_var(Variant &r_variant) {
if (err) if (err)
return err; return err;
return decode_variant(r_variant, buffer, buffer_size, NULL, allow_object_decoding); return decode_variant(r_variant, buffer, buffer_size, NULL, p_allow_objects || allow_object_decoding);
} }
Error PacketPeer::put_var(const Variant &p_packet) { Error PacketPeer::put_var(const Variant &p_packet, bool p_full_objects) {
int len; int len;
Error err = encode_variant(p_packet, NULL, len, allow_object_decoding); // compute len first Error err = encode_variant(p_packet, NULL, len, p_full_objects || allow_object_decoding); // compute len first
if (err) if (err)
return err; return err;
@ -102,15 +102,15 @@ Error PacketPeer::put_var(const Variant &p_packet) {
uint8_t *buf = (uint8_t *)alloca(len); uint8_t *buf = (uint8_t *)alloca(len);
ERR_FAIL_COND_V(!buf, ERR_OUT_OF_MEMORY); ERR_FAIL_COND_V(!buf, ERR_OUT_OF_MEMORY);
err = encode_variant(p_packet, buf, len, allow_object_decoding); err = encode_variant(p_packet, buf, len, p_full_objects || allow_object_decoding);
ERR_FAIL_COND_V(err, err); ERR_FAIL_COND_V(err, err);
return put_packet(buf, len); return put_packet(buf, len);
} }
Variant PacketPeer::_bnd_get_var() { Variant PacketPeer::_bnd_get_var(bool p_allow_objects) {
Variant var; Variant var;
get_var(var); get_var(var, p_allow_objects);
return var; return var;
}; };
@ -132,8 +132,8 @@ Error PacketPeer::_get_packet_error() const {
void PacketPeer::_bind_methods() { void PacketPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_var"), &PacketPeer::_bnd_get_var); ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &PacketPeer::_bnd_get_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("put_var", "var"), &PacketPeer::put_var); ClassDB::bind_method(D_METHOD("put_var", "var", "full_objects"), &PacketPeer::put_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_packet"), &PacketPeer::_get_packet); ClassDB::bind_method(D_METHOD("get_packet"), &PacketPeer::_get_packet);
ClassDB::bind_method(D_METHOD("put_packet", "buffer"), &PacketPeer::_put_packet); ClassDB::bind_method(D_METHOD("put_packet", "buffer"), &PacketPeer::_put_packet);
ClassDB::bind_method(D_METHOD("get_packet_error"), &PacketPeer::_get_packet_error); ClassDB::bind_method(D_METHOD("get_packet_error"), &PacketPeer::_get_packet_error);

View File

@ -39,8 +39,7 @@ class PacketPeer : public Reference {
GDCLASS(PacketPeer, Reference); GDCLASS(PacketPeer, Reference);
Variant _bnd_get_var(); Variant _bnd_get_var(bool p_allow_objects = false);
void _bnd_put_var(const Variant &p_var);
static void _bind_methods(); static void _bind_methods();
@ -64,8 +63,8 @@ public:
virtual Error get_packet_buffer(PoolVector<uint8_t> &r_buffer); virtual Error get_packet_buffer(PoolVector<uint8_t> &r_buffer);
virtual Error put_packet_buffer(const PoolVector<uint8_t> &p_buffer); virtual Error put_packet_buffer(const PoolVector<uint8_t> &p_buffer);
virtual Error get_var(Variant &r_variant); virtual Error get_var(Variant &r_variant, bool p_allow_objects = false);
virtual Error put_var(const Variant &p_packet); virtual Error put_var(const Variant &p_packet, bool p_full_objects = false);
void set_allow_object_decoding(bool p_enable); void set_allow_object_decoding(bool p_enable);
bool is_object_decoding_allowed() const; bool is_object_decoding_allowed() const;

View File

@ -221,14 +221,14 @@ void StreamPeer::put_utf8_string(const String &p_string) {
put_u32(cs.length()); put_u32(cs.length());
put_data((const uint8_t *)cs.get_data(), cs.length()); put_data((const uint8_t *)cs.get_data(), cs.length());
} }
void StreamPeer::put_var(const Variant &p_variant) { void StreamPeer::put_var(const Variant &p_variant, bool p_full_objects) {
int len = 0; int len = 0;
Vector<uint8_t> buf; Vector<uint8_t> buf;
encode_variant(p_variant, NULL, len); encode_variant(p_variant, NULL, len, p_full_objects);
buf.resize(len); buf.resize(len);
put_32(len); put_32(len);
encode_variant(p_variant, buf.ptrw(), len); encode_variant(p_variant, buf.ptrw(), len, p_full_objects);
put_data(buf.ptr(), buf.size()); put_data(buf.ptr(), buf.size());
} }
@ -359,7 +359,7 @@ String StreamPeer::get_utf8_string(int p_bytes) {
ret.parse_utf8((const char *)buf.ptr(), buf.size()); ret.parse_utf8((const char *)buf.ptr(), buf.size());
return ret; return ret;
} }
Variant StreamPeer::get_var() { Variant StreamPeer::get_var(bool p_allow_objects) {
int len = get_32(); int len = get_32();
Vector<uint8_t> var; Vector<uint8_t> var;
@ -369,7 +369,7 @@ Variant StreamPeer::get_var() {
ERR_FAIL_COND_V(err != OK, Variant()); ERR_FAIL_COND_V(err != OK, Variant());
Variant ret; Variant ret;
decode_variant(ret, var.ptr(), len); decode_variant(ret, var.ptr(), len, NULL, p_allow_objects);
return ret; return ret;
} }
@ -398,7 +398,7 @@ void StreamPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("put_double", "value"), &StreamPeer::put_double); ClassDB::bind_method(D_METHOD("put_double", "value"), &StreamPeer::put_double);
ClassDB::bind_method(D_METHOD("put_string", "value"), &StreamPeer::put_string); ClassDB::bind_method(D_METHOD("put_string", "value"), &StreamPeer::put_string);
ClassDB::bind_method(D_METHOD("put_utf8_string", "value"), &StreamPeer::put_utf8_string); ClassDB::bind_method(D_METHOD("put_utf8_string", "value"), &StreamPeer::put_utf8_string);
ClassDB::bind_method(D_METHOD("put_var", "value"), &StreamPeer::put_var); ClassDB::bind_method(D_METHOD("put_var", "value", "full_objects"), &StreamPeer::put_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_8"), &StreamPeer::get_8); ClassDB::bind_method(D_METHOD("get_8"), &StreamPeer::get_8);
ClassDB::bind_method(D_METHOD("get_u8"), &StreamPeer::get_u8); ClassDB::bind_method(D_METHOD("get_u8"), &StreamPeer::get_u8);
@ -412,7 +412,7 @@ void StreamPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_double"), &StreamPeer::get_double); ClassDB::bind_method(D_METHOD("get_double"), &StreamPeer::get_double);
ClassDB::bind_method(D_METHOD("get_string", "bytes"), &StreamPeer::get_string, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_string", "bytes"), &StreamPeer::get_string, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_utf8_string", "bytes"), &StreamPeer::get_utf8_string, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_utf8_string", "bytes"), &StreamPeer::get_utf8_string, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_var"), &StreamPeer::get_var); ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &StreamPeer::get_var, DEFVAL(false));
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian_enabled");
} }

View File

@ -73,7 +73,7 @@ public:
void put_double(double p_val); void put_double(double p_val);
void put_string(const String &p_string); void put_string(const String &p_string);
void put_utf8_string(const String &p_string); void put_utf8_string(const String &p_string);
void put_var(const Variant &p_variant); void put_var(const Variant &p_variant, bool p_full_objects = false);
uint8_t get_u8(); uint8_t get_u8();
int8_t get_8(); int8_t get_8();
@ -87,7 +87,7 @@ public:
double get_double(); double get_double();
String get_string(int p_bytes = -1); String get_string(int p_bytes = -1);
String get_utf8_string(int p_bytes = -1); String get_utf8_string(int p_bytes = -1);
Variant get_var(); Variant get_var(bool p_allow_objects = false);
StreamPeer() { big_endian = false; } StreamPeer() { big_endian = false; }
}; };

View File

@ -164,10 +164,10 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) {
case TEXT_PRINTRAW: case TEXT_PRINTRAW:
case VAR_TO_STR: case VAR_TO_STR:
case STR_TO_VAR: case STR_TO_VAR:
case VAR_TO_BYTES:
case BYTES_TO_VAR:
case TYPE_EXISTS: case TYPE_EXISTS:
return 1; return 1;
case VAR_TO_BYTES:
case BYTES_TO_VAR:
case MATH_ATAN2: case MATH_ATAN2:
case MATH_FMOD: case MATH_FMOD:
case MATH_FPOSMOD: case MATH_FPOSMOD:
@ -696,8 +696,9 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
case VAR_TO_BYTES: { case VAR_TO_BYTES: {
PoolByteArray barr; PoolByteArray barr;
bool full_objects = *p_inputs[1];
int len; int len;
Error err = encode_variant(*p_inputs[0], NULL, len); Error err = encode_variant(*p_inputs[0], NULL, len, full_objects);
if (err) { if (err) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0; r_error.argument = 0;
@ -709,7 +710,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
barr.resize(len); barr.resize(len);
{ {
PoolByteArray::Write w = barr.write(); PoolByteArray::Write w = barr.write();
encode_variant(*p_inputs[0], w.ptr(), len); encode_variant(*p_inputs[0], w.ptr(), len, full_objects);
} }
*r_return = barr; *r_return = barr;
} break; } break;
@ -724,10 +725,11 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
} }
PoolByteArray varr = *p_inputs[0]; PoolByteArray varr = *p_inputs[0];
bool allow_objects = *p_inputs[1];
Variant ret; Variant ret;
{ {
PoolByteArray::Read r = varr.read(); PoolByteArray::Read r = varr.read();
Error err = decode_variant(ret, r.ptr(), varr.size(), NULL); Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, allow_objects);
if (err != OK) { if (err != OK) {
r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format."); r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format.");
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;

View File

@ -114,7 +114,7 @@ Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, b
} else { } else {
Variant v; Variant v;
Error rerr = decode_variant(v, p_buf + p_ofs, datalen - p_ofs, NULL); Error rerr = decode_variant(v, p_buf + p_ofs, datalen - p_ofs, NULL, false);
if (rerr != OK) { if (rerr != OK) {
@ -249,9 +249,9 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd
uint32_t pos = tmpdata.size(); uint32_t pos = tmpdata.size();
int len; int len;
encode_variant(p_data, NULL, len); encode_variant(p_data, NULL, len, false);
tmpdata.resize(tmpdata.size() + len); tmpdata.resize(tmpdata.size() + len);
encode_variant(p_data, &tmpdata.write[pos], len); encode_variant(p_data, &tmpdata.write[pos], len, false);
return pos; return pos;
} break; } break;

View File

@ -501,7 +501,7 @@ Error ProjectSettings::_load_settings_binary(const String p_path) {
d.resize(vlen); d.resize(vlen);
f->get_buffer(d.ptrw(), vlen); f->get_buffer(d.ptrw(), vlen);
Variant value; Variant value;
err = decode_variant(value, d.ptr(), d.size()); err = decode_variant(value, d.ptr(), d.size(), NULL, false);
ERR_EXPLAIN("Error decoding property: " + key); ERR_EXPLAIN("Error decoding property: " + key);
ERR_CONTINUE(err != OK); ERR_CONTINUE(err != OK);
set(key, value); set(key, value);
@ -656,7 +656,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
file->store_string(key); file->store_string(key);
int len; int len;
err = encode_variant(p_custom_features, NULL, len); err = encode_variant(p_custom_features, NULL, len, false);
if (err != OK) { if (err != OK) {
memdelete(file); memdelete(file);
ERR_FAIL_V(err); ERR_FAIL_V(err);
@ -665,7 +665,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
Vector<uint8_t> buff; Vector<uint8_t> buff;
buff.resize(len); buff.resize(len);
err = encode_variant(p_custom_features, buff.ptrw(), len); err = encode_variant(p_custom_features, buff.ptrw(), len, false);
if (err != OK) { if (err != OK) {
memdelete(file); memdelete(file);
ERR_FAIL_V(err); ERR_FAIL_V(err);
@ -694,7 +694,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
file->store_string(key); file->store_string(key);
int len; int len;
err = encode_variant(value, NULL, len); err = encode_variant(value, NULL, len, false);
if (err != OK) if (err != OK)
memdelete(file); memdelete(file);
ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA); ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA);
@ -702,7 +702,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
Vector<uint8_t> buff; Vector<uint8_t> buff;
buff.resize(len); buff.resize(len);
err = encode_variant(value, buff.ptrw(), len); err = encode_variant(value, buff.ptrw(), len, false);
if (err != OK) if (err != OK)
memdelete(file); memdelete(file);
ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA); ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA);

View File

@ -134,8 +134,11 @@
</return> </return>
<argument index="0" name="bytes" type="PoolByteArray"> <argument index="0" name="bytes" type="PoolByteArray">
</argument> </argument>
<argument index="1" name="allow_objects" type="bool" default="false">
</argument>
<description> <description>
Decodes a byte array back to a value. Decodes a byte array back to a value. When [code]allow_objects[/code] is [code]true[/code] decoding objects is allowed.
[b]WARNING:[/b] Deserialized object can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats (remote code execution).
</description> </description>
</method> </method>
<method name="cartesian2polar"> <method name="cartesian2polar">
@ -1110,8 +1113,10 @@
</return> </return>
<argument index="0" name="var" type="Variant"> <argument index="0" name="var" type="Variant">
</argument> </argument>
<argument index="1" name="full_objects" type="bool" default="false">
</argument>
<description> <description>
Encodes a variable value to a byte array. Encodes a variable value to a byte array. When [code]full_objects[/code] is [code]true[/code] encoding objects is allowed (and can potentially include code).
</description> </description>
</method> </method>
<method name="var2str"> <method name="var2str">

View File

@ -206,8 +206,11 @@
<method name="get_var" qualifiers="const"> <method name="get_var" qualifiers="const">
<return type="Variant"> <return type="Variant">
</return> </return>
<argument index="0" name="allow_objects" type="bool" default="false">
</argument>
<description> <description>
Returns the next [Variant] value from the file. Returns the next [Variant] value from the file. When [code]allow_objects[/code] is [code]true[/code] decoding objects is allowed.
[b]WARNING:[/b] Deserialized object can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats (remote code execution).
</description> </description>
</method> </method>
<method name="is_open" qualifiers="const"> <method name="is_open" qualifiers="const">
@ -404,8 +407,10 @@
</return> </return>
<argument index="0" name="value" type="Variant"> <argument index="0" name="value" type="Variant">
</argument> </argument>
<argument index="1" name="full_objects" type="bool" default="false">
</argument>
<description> <description>
Stores any Variant value in the file. Stores any Variant value in the file. When [code]full_objects[/code] is [code]true[/code] encoding objects is allowed (and can potentially include code).
</description> </description>
</method> </method>
</methods> </methods>

View File

@ -32,8 +32,11 @@
</return> </return>
<argument index="0" name="base64_str" type="String"> <argument index="0" name="base64_str" type="String">
</argument> </argument>
<argument index="1" name="allow_objects" type="bool" default="false">
</argument>
<description> <description>
Return [Variant] of a given base64 encoded String. Return [Variant] of a given base64 encoded String. When [code]allow_objects[/code] is [code]true[/code] decoding objects is allowed.
[b]WARNING:[/b] Deserialized object can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats (remote code execution).
</description> </description>
</method> </method>
<method name="raw_to_base64"> <method name="raw_to_base64">
@ -59,8 +62,10 @@
</return> </return>
<argument index="0" name="variant" type="Variant"> <argument index="0" name="variant" type="Variant">
</argument> </argument>
<argument index="1" name="full_objects" type="bool" default="false">
</argument>
<description> <description>
Return base64 encoded String of a given [Variant]. Return base64 encoded String of a given [Variant]. When [code]full_objects[/code] is [code]true[/code] encoding objects is allowed (and can potentially include code).
</description> </description>
</method> </method>
</methods> </methods>

View File

@ -87,6 +87,10 @@
</method> </method>
</methods> </methods>
<members> <members>
<member name="allow_object_decoding" type="bool" setter="set_allow_object_decoding" getter="is_object_decoding_allowed">
If [code]true[/code] (or if the [member network_peer] [member PacketPeer.allow_object_decoding] the MultiplayerAPI will allow encoding and decoding of object during RPCs/RSETs.
[b]WARNING:[/b] Deserialized object can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats (remote code execution).
</member>
<member name="network_peer" type="NetworkedMultiplayerPeer" setter="set_network_peer" getter="get_network_peer"> <member name="network_peer" type="NetworkedMultiplayerPeer" setter="set_network_peer" getter="get_network_peer">
The peer object to handle the RPC system (effectively enabling networking when set). Depending on the peer itself, the MultiplayerAPI will become a network server (check with [method is_network_server]) and will set root node's network mode to master (see NETWORK_MODE_* constants in [Node]), or it will become a regular peer with root node set to puppet. All child nodes are set to inherit the network mode by default. Handling of networking-related events (connection, disconnection, new clients) is done by connecting to MultiplayerAPI's signals. The peer object to handle the RPC system (effectively enabling networking when set). Depending on the peer itself, the MultiplayerAPI will become a network server (check with [method is_network_server]) and will set root node's network mode to master (see NETWORK_MODE_* constants in [Node]), or it will become a regular peer with root node set to puppet. All child nodes are set to inherit the network mode by default. Handling of networking-related events (connection, disconnection, new clients) is done by connecting to MultiplayerAPI's signals.
</member> </member>

View File

@ -33,8 +33,11 @@
<method name="get_var"> <method name="get_var">
<return type="Variant"> <return type="Variant">
</return> </return>
<argument index="0" name="allow_objects" type="bool" default="false">
</argument>
<description> <description>
Get a Variant. Get a Variant. When [code]allow_objects[/code] (or [member allow_object_decoding]) is [code]true[/code] decoding objects is allowed.
[b]WARNING:[/b] Deserialized object can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats (remote code execution).
</description> </description>
</method> </method>
<method name="put_packet"> <method name="put_packet">
@ -51,13 +54,16 @@
</return> </return>
<argument index="0" name="var" type="Variant"> <argument index="0" name="var" type="Variant">
</argument> </argument>
<argument index="1" name="full_objects" type="bool" default="false">
</argument>
<description> <description>
Send a Variant as a packet. Send a Variant as a packet. When [code]full_objects[/code] (or [member allow_object_decoding]) is [code]true[/code] encoding objects is allowed (and can potentially include code).
</description> </description>
</method> </method>
</methods> </methods>
<members> <members>
<member name="allow_object_decoding" type="bool" setter="set_allow_object_decoding" getter="is_object_decoding_allowed"> <member name="allow_object_decoding" type="bool" setter="set_allow_object_decoding" getter="is_object_decoding_allowed">
Deprecated. Use [code]get_var[/code] and [code]put_var[/code] parameters instead.
If [code]true[/code] the PacketPeer will allow encoding and decoding of object via [method get_var] and [method put_var]. If [code]true[/code] the PacketPeer will allow encoding and decoding of object via [method get_var] and [method put_var].
[b]WARNING:[/b] Deserialized object can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats (remote code execution). [b]WARNING:[/b] Deserialized object can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats (remote code execution).
</member> </member>

View File

@ -125,8 +125,11 @@
<method name="get_var"> <method name="get_var">
<return type="Variant"> <return type="Variant">
</return> </return>
<argument index="0" name="allow_objects" type="bool" default="false">
</argument>
<description> <description>
Get a Variant from the stream. Get a Variant from the stream. When [code]allow_objects[/code] is [code]true[/code] decoding objects is allowed.
[b]WARNING:[/b] Deserialized object can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats (remote code execution).
</description> </description>
</method> </method>
<method name="put_16"> <method name="put_16">
@ -260,8 +263,10 @@
</return> </return>
<argument index="0" name="value" type="Variant"> <argument index="0" name="value" type="Variant">
</argument> </argument>
<argument index="1" name="full_objects" type="bool" default="false">
</argument>
<description> <description>
Put a Variant into the stream. Put a Variant into the stream. When [code]full_objects[/code] is [code]true[/code] encoding objects is allowed (and can potentially include code).
</description> </description>
</method> </method>
</methods> </methods>

View File

@ -768,11 +768,30 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
(void)VariantParser::parse(&ss, r_ret, errs, line); (void)VariantParser::parse(&ss, r_ret, errs, line);
} break; } break;
case VAR_TO_BYTES: { case VAR_TO_BYTES: {
VALIDATE_ARG_COUNT(1); bool full_objects = false;
if (p_arg_count < 1) {
r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 1;
r_ret = Variant();
return;
} else if (p_arg_count > 2) {
r_error.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = 2;
r_ret = Variant();
} else if (p_arg_count == 2) {
if (p_args[1]->get_type() != Variant::BOOL) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 1;
r_error.expected = Variant::BOOL;
r_ret = Variant();
return;
}
full_objects = *p_args[1];
}
PoolByteArray barr; PoolByteArray barr;
int len; int len;
Error err = encode_variant(*p_args[0], NULL, len); Error err = encode_variant(*p_args[0], NULL, len, full_objects);
if (err) { if (err) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0; r_error.argument = 0;
@ -784,15 +803,35 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
barr.resize(len); barr.resize(len);
{ {
PoolByteArray::Write w = barr.write(); PoolByteArray::Write w = barr.write();
encode_variant(*p_args[0], w.ptr(), len); encode_variant(*p_args[0], w.ptr(), len, full_objects);
} }
r_ret = barr; r_ret = barr;
} break; } break;
case BYTES_TO_VAR: { case BYTES_TO_VAR: {
VALIDATE_ARG_COUNT(1); bool allow_objects = false;
if (p_arg_count < 1) {
r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 1;
r_ret = Variant();
return;
} else if (p_arg_count > 2) {
r_error.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = 2;
r_ret = Variant();
} else if (p_arg_count == 2) {
if (p_args[1]->get_type() != Variant::BOOL) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 1;
r_error.expected = Variant::BOOL;
r_ret = Variant();
return;
}
allow_objects = *p_args[1];
}
if (p_args[0]->get_type() != Variant::POOL_BYTE_ARRAY) { if (p_args[0]->get_type() != Variant::POOL_BYTE_ARRAY) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0; r_error.argument = 1;
r_error.expected = Variant::POOL_BYTE_ARRAY; r_error.expected = Variant::POOL_BYTE_ARRAY;
r_ret = Variant(); r_ret = Variant();
return; return;
@ -802,7 +841,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
Variant ret; Variant ret;
{ {
PoolByteArray::Read r = varr.read(); PoolByteArray::Read r = varr.read();
Error err = decode_variant(ret, r.ptr(), varr.size(), NULL); Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, allow_objects);
if (err != OK) { if (err != OK) {
r_ret = RTR("Not enough bytes for decoding bytes, or invalid format."); r_ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
@ -1805,13 +1844,15 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
} break; } break;
case VAR_TO_BYTES: { case VAR_TO_BYTES: {
MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::BOOL, "full_objects"));
mi.default_arguments.push_back(false);
mi.return_val.type = Variant::POOL_BYTE_ARRAY; mi.return_val.type = Variant::POOL_BYTE_ARRAY;
return mi; return mi;
} break; } break;
case BYTES_TO_VAR: { case BYTES_TO_VAR: {
MethodInfo mi(Variant::NIL, "bytes2var", PropertyInfo(Variant::POOL_BYTE_ARRAY, "bytes")); MethodInfo mi(Variant::NIL, "bytes2var", PropertyInfo(Variant::POOL_BYTE_ARRAY, "bytes"), PropertyInfo(Variant::BOOL, "allow_objects"));
mi.default_arguments.push_back(false);
mi.return_val.type = Variant::NIL; mi.return_val.type = Variant::NIL;
mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
return mi; return mi;

View File

@ -1200,7 +1200,8 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer)
Variant v; Variant v;
int len; int len;
Error err = decode_variant(v, b, total_len, &len); // An object cannot be constant, never decode objects
Error err = decode_variant(v, b, total_len, &len, false);
if (err) if (err)
return err; return err;
b += len; b += len;
@ -1368,11 +1369,12 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code)
for (Map<int, Variant>::Element *E = rev_constant_map.front(); E; E = E->next()) { for (Map<int, Variant>::Element *E = rev_constant_map.front(); E; E = E->next()) {
int len; int len;
Error err = encode_variant(E->get(), NULL, len); // Objects cannot be constant, never encode objects
Error err = encode_variant(E->get(), NULL, len, false);
ERR_FAIL_COND_V(err != OK, Vector<uint8_t>()); ERR_FAIL_COND_V(err != OK, Vector<uint8_t>());
int pos = buf.size(); int pos = buf.size();
buf.resize(pos + len); buf.resize(pos + len);
encode_variant(E->get(), &buf.write[pos], len); encode_variant(E->get(), &buf.write[pos], len, false);
} }
for (Map<int, uint32_t>::Element *E = rev_line_map.front(); E; E = E->next()) { for (Map<int, uint32_t>::Element *E = rev_line_map.front(); E; E = E->next()) {

View File

@ -13,9 +13,9 @@ namespace Godot
{ {
public static partial class GD public static partial class GD
{ {
public static object Bytes2Var(byte[] bytes) public static object Bytes2Var(byte[] bytes, bool allow_objects = false)
{ {
return godot_icall_GD_bytes2var(bytes); return godot_icall_GD_bytes2var(bytes, allow_objects);
} }
public static object Convert(object what, Variant.Type type) public static object Convert(object what, Variant.Type type)
@ -186,9 +186,9 @@ namespace Godot
return godot_icall_GD_type_exists(type); return godot_icall_GD_type_exists(type);
} }
public static byte[] Var2Bytes(object var) public static byte[] Var2Bytes(object var, bool full_objects = false)
{ {
return godot_icall_GD_var2bytes(var); return godot_icall_GD_var2bytes(var, full_objects);
} }
public static string Var2Str(object var) public static string Var2Str(object var)
@ -197,7 +197,7 @@ namespace Godot
} }
[MethodImpl(MethodImplOptions.InternalCall)] [MethodImpl(MethodImplOptions.InternalCall)]
internal extern static object godot_icall_GD_bytes2var(byte[] bytes); internal extern static object godot_icall_GD_bytes2var(byte[] bytes, bool allow_objects);
[MethodImpl(MethodImplOptions.InternalCall)] [MethodImpl(MethodImplOptions.InternalCall)]
internal extern static object godot_icall_GD_convert(object what, Variant.Type type); internal extern static object godot_icall_GD_convert(object what, Variant.Type type);
@ -251,7 +251,7 @@ namespace Godot
internal extern static bool godot_icall_GD_type_exists(string type); internal extern static bool godot_icall_GD_type_exists(string type);
[MethodImpl(MethodImplOptions.InternalCall)] [MethodImpl(MethodImplOptions.InternalCall)]
internal extern static byte[] godot_icall_GD_var2bytes(object what); internal extern static byte[] godot_icall_GD_var2bytes(object what, bool full_objects);
[MethodImpl(MethodImplOptions.InternalCall)] [MethodImpl(MethodImplOptions.InternalCall)]
internal extern static string godot_icall_GD_var2str(object var); internal extern static string godot_icall_GD_var2str(object var);

View File

@ -41,11 +41,11 @@
#include "../mono_gd/gd_mono_utils.h" #include "../mono_gd/gd_mono_utils.h"
MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes) { MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects) {
Variant ret; Variant ret;
PoolByteArray varr = GDMonoMarshal::mono_array_to_PoolByteArray(p_bytes); PoolByteArray varr = GDMonoMarshal::mono_array_to_PoolByteArray(p_bytes);
PoolByteArray::Read r = varr.read(); PoolByteArray::Read r = varr.read();
Error err = decode_variant(ret, r.ptr(), varr.size(), NULL); Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, p_allow_objects);
if (err != OK) { if (err != OK) {
ret = RTR("Not enough bytes for decoding bytes, or invalid format."); ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
} }
@ -187,19 +187,19 @@ void godot_icall_GD_pushwarning(MonoString *p_str) {
WARN_PRINTS(GDMonoMarshal::mono_string_to_godot(p_str)); WARN_PRINTS(GDMonoMarshal::mono_string_to_godot(p_str));
} }
MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var) { MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects) {
Variant var = GDMonoMarshal::mono_object_to_variant(p_var); Variant var = GDMonoMarshal::mono_object_to_variant(p_var);
PoolByteArray barr; PoolByteArray barr;
int len; int len;
Error err = encode_variant(var, NULL, len); Error err = encode_variant(var, NULL, len, p_full_objects);
ERR_EXPLAIN("Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."); ERR_EXPLAIN("Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
ERR_FAIL_COND_V(err != OK, NULL); ERR_FAIL_COND_V(err != OK, NULL);
barr.resize(len); barr.resize(len);
{ {
PoolByteArray::Write w = barr.write(); PoolByteArray::Write w = barr.write();
encode_variant(var, w.ptr(), len); encode_variant(var, w.ptr(), len, p_full_objects);
} }
return GDMonoMarshal::PoolByteArray_to_mono_array(barr); return GDMonoMarshal::PoolByteArray_to_mono_array(barr);

View File

@ -35,7 +35,7 @@
#include "../mono_gd/gd_mono_marshal.h" #include "../mono_gd/gd_mono_marshal.h"
MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes); MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects);
MonoObject *godot_icall_GD_convert(MonoObject *p_what, int32_t p_type); MonoObject *godot_icall_GD_convert(MonoObject *p_what, int32_t p_type);
@ -71,7 +71,7 @@ MonoObject *godot_icall_GD_str2var(MonoString *p_str);
MonoBoolean godot_icall_GD_type_exists(MonoString *p_type); MonoBoolean godot_icall_GD_type_exists(MonoString *p_type);
MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var); MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects);
MonoString *godot_icall_GD_var2str(MonoObject *p_var); MonoString *godot_icall_GD_var2str(MonoObject *p_var);

View File

@ -183,10 +183,10 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) {
case TEXT_PRINTRAW: case TEXT_PRINTRAW:
case VAR_TO_STR: case VAR_TO_STR:
case STR_TO_VAR: case STR_TO_VAR:
case VAR_TO_BYTES:
case BYTES_TO_VAR:
case TYPE_EXISTS: case TYPE_EXISTS:
return 1; return 1;
case VAR_TO_BYTES:
case BYTES_TO_VAR:
case MATH_ATAN2: case MATH_ATAN2:
case MATH_FMOD: case MATH_FMOD:
case MATH_FPOSMOD: case MATH_FPOSMOD:
@ -491,12 +491,18 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
return PropertyInfo(Variant::STRING, "string"); return PropertyInfo(Variant::STRING, "string");
} break; } break;
case VAR_TO_BYTES: { case VAR_TO_BYTES: {
if (p_idx == 0)
return PropertyInfo(Variant::NIL, "var"); return PropertyInfo(Variant::NIL, "var");
else
return PropertyInfo(Variant::BOOL, "full_objects");
} break; } break;
case BYTES_TO_VAR: { case BYTES_TO_VAR: {
if (p_idx == 0)
return PropertyInfo(Variant::POOL_BYTE_ARRAY, "bytes"); return PropertyInfo(Variant::POOL_BYTE_ARRAY, "bytes");
else
return PropertyInfo(Variant::BOOL, "allow_objects");
} break; } break;
case COLORN: { case COLORN: {
@ -655,11 +661,15 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
} break; } break;
case VAR_TO_BYTES: { case VAR_TO_BYTES: {
if (p_idx == 0)
t = Variant::POOL_BYTE_ARRAY; t = Variant::POOL_BYTE_ARRAY;
else
t = Variant::BOOL;
} break; } break;
case BYTES_TO_VAR: { case BYTES_TO_VAR: {
if (p_idx == 1)
t = Variant::BOOL;
} break; } break;
case COLORN: { case COLORN: {
t = Variant::COLOR; t = Variant::COLOR;
@ -1192,9 +1202,16 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
} break; } break;
case VisualScriptBuiltinFunc::VAR_TO_BYTES: { case VisualScriptBuiltinFunc::VAR_TO_BYTES: {
if (p_inputs[1]->get_type() != Variant::BOOL) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 1;
r_error.expected = Variant::BOOL;
return;
}
PoolByteArray barr; PoolByteArray barr;
int len; int len;
Error err = encode_variant(*p_inputs[0], NULL, len); bool full_objects = *p_inputs[1];
Error err = encode_variant(*p_inputs[0], NULL, len, full_objects);
if (err) { if (err) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0; r_error.argument = 0;
@ -1206,7 +1223,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
barr.resize(len); barr.resize(len);
{ {
PoolByteArray::Write w = barr.write(); PoolByteArray::Write w = barr.write();
encode_variant(*p_inputs[0], w.ptr(), len); encode_variant(*p_inputs[0], w.ptr(), len, full_objects);
} }
*r_return = barr; *r_return = barr;
} break; } break;
@ -1216,15 +1233,21 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0; r_error.argument = 0;
r_error.expected = Variant::POOL_BYTE_ARRAY; r_error.expected = Variant::POOL_BYTE_ARRAY;
return;
}
if (p_inputs[1]->get_type() != Variant::BOOL) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 1;
r_error.expected = Variant::BOOL;
return; return;
} }
PoolByteArray varr = *p_inputs[0]; PoolByteArray varr = *p_inputs[0];
bool allow_objects = *p_inputs[1];
Variant ret; Variant ret;
{ {
PoolByteArray::Read r = varr.read(); PoolByteArray::Read r = varr.read();
Error err = decode_variant(ret, r.ptr(), varr.size(), NULL); Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, allow_objects);
if (err != OK) { if (err != OK) {
r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format."); r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format.");
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;