You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-09 12:50:35 +00:00
Optmized data sent during RPC and RSet calls.
- Now is sent the method ID rather the full function name. - The passed IDs (Node and Method) are compressed so to use less possible space. - The variant (INT and BOOL) is now encoded and compressed so to use much less data. - Optimized RPCMode retrieval for GDScript functions. - Added checksum to assert the methods are the same across peers. This work has been kindly sponsored by IMVU.
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "core/io/marshalls.h"
|
#include "core/io/marshalls.h"
|
||||||
#include "scene/main/node.h"
|
#include "scene/main/node.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
#include "core/os/os.h"
|
#include "core/os/os.h"
|
||||||
@@ -180,7 +181,8 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
|
|||||||
}
|
}
|
||||||
#endif
|
#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) {
|
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_CALL:
|
||||||
case NETWORK_COMMAND_REMOTE_SET: {
|
case NETWORK_COMMAND_REMOTE_SET: {
|
||||||
|
|
||||||
ERR_FAIL_COND_MSG(p_packet_len < 6, "Invalid packet received. Size too small.");
|
// 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;
|
||||||
|
|
||||||
Node *node = _process_get_node(p_from, p_packet, p_packet_len);
|
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.");
|
ERR_FAIL_COND_MSG(node == NULL, "Invalid packet received. Requested node was not found.");
|
||||||
|
|
||||||
// Detect cstring end.
|
uint16_t name_id = 0;
|
||||||
int len_end = 5;
|
switch (name_id_compression) {
|
||||||
for (; len_end < p_packet_len; len_end++) {
|
case NETWORK_NAME_ID_COMPRESSION_8:
|
||||||
if (p_packet[len_end] == 0) {
|
name_id = p_packet[name_id_offset];
|
||||||
break;
|
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) {
|
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 {
|
} 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;
|
} 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;
|
Node *node = NULL;
|
||||||
|
|
||||||
if (target & 0x80000000) {
|
if (p_node_target & 0x80000000) {
|
||||||
// Use full path (not cached yet).
|
// 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.");
|
ERR_FAIL_COND_V_MSG(ofs >= p_packet_len, NULL, "Invalid packet received. Size smaller than declared.");
|
||||||
|
|
||||||
@@ -256,7 +306,7 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int
|
|||||||
ERR_PRINT("Failed to get path from RPC: " + String(np) + ".");
|
ERR_PRINT("Failed to get path from RPC: " + String(np) + ".");
|
||||||
} else {
|
} else {
|
||||||
// Use cached path.
|
// Use cached path.
|
||||||
int id = target;
|
int id = p_node_target;
|
||||||
|
|
||||||
Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from);
|
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.");
|
ERR_FAIL_COND_V_MSG(!E, NULL, "Invalid packet received. Requests invalid peer cache.");
|
||||||
@@ -274,21 +324,21 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int
|
|||||||
return node;
|
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.");
|
ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
|
||||||
|
|
||||||
// Check that remote can call the RPC on this node.
|
// Check that remote can call the RPC on this node.
|
||||||
RPCMode rpc_mode = RPC_MODE_DISABLED;
|
StringName name = p_node->get_node_rpc_method(p_rpc_method_id);
|
||||||
const Map<StringName, RPCMode>::Element *E = p_node->get_node_rpc_mode(p_name);
|
RPCMode rpc_mode = p_node->get_node_rpc_mode_by_id(p_rpc_method_id);
|
||||||
if (E) {
|
if (name == StringName() && p_node->get_script_instance()) {
|
||||||
rpc_mode = E->get();
|
name = p_node->get_script_instance()->get_rpc_method(p_rpc_method_id);
|
||||||
} else if (p_node->get_script_instance()) {
|
rpc_mode = p_node->get_script_instance()->get_rpc_mode_by_id(p_rpc_method_id);
|
||||||
rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_name);
|
|
||||||
}
|
}
|
||||||
|
ERR_FAIL_COND(name == StringName());
|
||||||
|
|
||||||
bool can_call = _can_call_mode(p_node, rpc_mode, p_from);
|
bool can_call = _can_call_mode(p_node, rpc_mode, p_from);
|
||||||
ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(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];
|
int argc = p_packet[p_offset];
|
||||||
Vector<Variant> args;
|
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.");
|
ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
|
||||||
|
|
||||||
int vlen;
|
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.");
|
ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RPC argument.");
|
||||||
|
|
||||||
argp.write[i] = &args[i];
|
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;
|
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) {
|
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;
|
error = "RPC - " + error;
|
||||||
ERR_PRINT(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.");
|
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.
|
// Check that remote can call the RSET on this node.
|
||||||
RPCMode rset_mode = RPC_MODE_DISABLED;
|
StringName name = p_node->get_node_rset_property(p_rpc_property_id);
|
||||||
const Map<StringName, RPCMode>::Element *E = p_node->get_node_rset_mode(p_name);
|
RPCMode rset_mode = p_node->get_node_rset_mode_by_id(p_rpc_property_id);
|
||||||
if (E) {
|
if (name == StringName() && p_node->get_script_instance()) {
|
||||||
rset_mode = E->get();
|
name = p_node->get_script_instance()->get_rset_property(p_rpc_property_id);
|
||||||
} else if (p_node->get_script_instance()) {
|
rset_mode = p_node->get_script_instance()->get_rset_mode_by_id(p_rpc_property_id);
|
||||||
rset_mode = p_node->get_script_instance()->get_rset_mode(p_name);
|
|
||||||
}
|
}
|
||||||
|
ERR_FAIL_COND(name == StringName());
|
||||||
|
|
||||||
bool can_call = _can_call_mode(p_node, rset_mode, p_from);
|
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
|
#ifdef DEBUG_ENABLED
|
||||||
if (profiling) {
|
if (profiling) {
|
||||||
@@ -353,26 +403,33 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
Variant value;
|
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.");
|
ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RSET value.");
|
||||||
|
|
||||||
bool valid;
|
bool valid;
|
||||||
|
|
||||||
p_node->set(p_name, value, &valid);
|
p_node->set(name, value, &valid);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
String error = "Error setting remote property '" + String(p_name) + "', not found in object of type " + p_node->get_class() + ".";
|
String error = "Error setting remote property '" + String(name) + "', not found in object of type " + p_node->get_class() + ".";
|
||||||
ERR_PRINT(error);
|
ERR_PRINT(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) {
|
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.");
|
ERR_FAIL_COND_MSG(p_packet_len < 38, "Invalid packet received. Size too small.");
|
||||||
int id = decode_uint32(&p_packet[1]);
|
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;
|
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;
|
NodePath path = paths;
|
||||||
|
|
||||||
@@ -380,6 +437,13 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
|
|||||||
path_get_cache[p_from] = PathGetCache();
|
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;
|
PathGetCache::NodeInfo ni;
|
||||||
ni.path = path;
|
ni.path = path;
|
||||||
ni.instance = 0;
|
ni.instance = 0;
|
||||||
@@ -392,9 +456,10 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
|
|||||||
|
|
||||||
Vector<uint8_t> packet;
|
Vector<uint8_t> packet;
|
||||||
|
|
||||||
packet.resize(1 + len);
|
packet.resize(1 + 1 + len);
|
||||||
packet.write[0] = NETWORK_COMMAND_CONFIRM_PATH;
|
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_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
|
||||||
network_peer->set_target_peer(p_from);
|
network_peer->set_target_peer(p_from);
|
||||||
@@ -403,13 +468,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) {
|
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;
|
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;
|
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);
|
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.");
|
ERR_FAIL_COND_MSG(!psc, "Invalid packet received. Tries to confirm a path which was not found in cache.");
|
||||||
|
|
||||||
@@ -418,7 +489,7 @@ void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet,
|
|||||||
E->get() = true;
|
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;
|
bool has_all_peers = true;
|
||||||
List<int> peers_to_add; // If one is missing, take note to add it.
|
List<int> peers_to_add; // If one is missing, take note to add it.
|
||||||
|
|
||||||
@@ -443,20 +514,32 @@ bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (peers_to_add.size() > 0) {
|
||||||
|
|
||||||
// Those that need to be added, send a message for this.
|
// Those that need to be added, send a message for this.
|
||||||
|
|
||||||
for (List<int>::Element *E = peers_to_add.front(); E; E = E->next()) {
|
|
||||||
|
|
||||||
// Encode function name.
|
// Encode function name.
|
||||||
CharString pname = String(p_path).utf8();
|
const CharString path = String(p_path).utf8();
|
||||||
int len = encode_cstring(pname.get_data(), NULL);
|
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;
|
Vector<uint8_t> packet;
|
||||||
|
packet.resize(1 + 4 + path_len + methods_md5_len);
|
||||||
|
int ofs = 0;
|
||||||
|
|
||||||
packet.resize(1 + 4 + len);
|
packet.write[ofs] = NETWORK_COMMAND_SIMPLIFY_PATH;
|
||||||
packet.write[0] = NETWORK_COMMAND_SIMPLIFY_PATH;
|
ofs += 1;
|
||||||
encode_uint32(psc->id, &packet.write[1]);
|
|
||||||
encode_cstring(pname.get_data(), &packet.write[5]);
|
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]);
|
||||||
|
|
||||||
|
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_target_peer(E->get()); // To all of you.
|
||||||
network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
|
network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
|
||||||
@@ -464,10 +547,159 @@ bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int
|
|||||||
|
|
||||||
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;
|
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 || network_peer->is_object_decoding_allowed());
|
||||||
|
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 || network_peer->is_object_decoding_allowed());
|
||||||
|
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) {
|
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.");
|
ERR_FAIL_COND_MSG(network_peer.is_null(), "Attempt to remote call/set when networking is not active in SceneTree.");
|
||||||
@@ -496,6 +728,9 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
|
|||||||
psc->id = last_send_cache_id++;
|
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.
|
// Create base packet, lots of hardcode because it must be tight.
|
||||||
|
|
||||||
int ofs = 0;
|
int ofs = 0;
|
||||||
@@ -503,45 +738,125 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
|
|||||||
#define MAKE_ROOM(m_amount) \
|
#define MAKE_ROOM(m_amount) \
|
||||||
if (packet_cache.size() < m_amount) packet_cache.resize(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);
|
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;
|
ofs += 1;
|
||||||
|
|
||||||
// Encode ID.
|
// 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);
|
MAKE_ROOM(ofs + 4);
|
||||||
encode_uint32(psc->id, &(packet_cache.write[ofs]));
|
encode_uint32(psc->id, &(packet_cache.write[ofs]));
|
||||||
ofs += 4;
|
ofs += 4;
|
||||||
|
}
|
||||||
// Encode function name.
|
} else {
|
||||||
CharString name = String(p_name).utf8();
|
// The targets doesn't know the node yet, so we need to use 32 bits int.
|
||||||
int len = encode_cstring(name.get_data(), NULL);
|
node_id_compression = NETWORK_NODE_ID_COMPRESSION_32;
|
||||||
MAKE_ROOM(ofs + len);
|
MAKE_ROOM(ofs + 4);
|
||||||
encode_cstring(name.get_data(), &(packet_cache.write[ofs]));
|
encode_uint32(psc->id, &(packet_cache.write[ofs]));
|
||||||
ofs += len;
|
ofs += 4;
|
||||||
|
}
|
||||||
|
|
||||||
if (p_set) {
|
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.
|
// 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!");
|
ERR_FAIL_COND_MSG(err != OK, "Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!");
|
||||||
MAKE_ROOM(ofs + len);
|
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;
|
ofs += len;
|
||||||
|
|
||||||
} else {
|
} 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.
|
// Call arguments.
|
||||||
MAKE_ROOM(ofs + 1);
|
MAKE_ROOM(ofs + 1);
|
||||||
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, 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!");
|
ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!");
|
||||||
MAKE_ROOM(ofs + len);
|
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;
|
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
|
#ifdef DEBUG_ENABLED
|
||||||
if (profiling) {
|
if (profiling) {
|
||||||
bandwidth_outgoing_data.write[bandwidth_outgoing_pointer].timestamp = OS::get_singleton()->get_ticks_msec();
|
bandwidth_outgoing_data.write[bandwidth_outgoing_pointer].timestamp = OS::get_singleton()->get_ticks_msec();
|
||||||
@@ -550,9 +865,6 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
|
|||||||
}
|
}
|
||||||
#endif
|
#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.
|
// 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);
|
network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
|
||||||
|
|
||||||
@@ -562,6 +874,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->set_target_peer(p_to); // To all of you.
|
||||||
network_peer->put_packet(packet_cache.ptr(), ofs); // A message with love.
|
network_peer->put_packet(packet_cache.ptr(), ofs); // A message with love.
|
||||||
} else {
|
} 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.
|
// Not all verified path, so send one by one.
|
||||||
|
|
||||||
// Append path at the end, since we will need it for some packets.
|
// Append path at the end, since we will need it for some packets.
|
||||||
@@ -647,16 +962,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)) {
|
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.
|
// Check that send mode can use local call.
|
||||||
|
|
||||||
const Map<StringName, RPCMode>::Element *E = p_node->get_node_rpc_mode(p_method);
|
RPCMode rpc_mode = p_node->get_node_rpc_mode(p_method);
|
||||||
if (E) {
|
call_local_native = _should_call_local(rpc_mode, is_master, skip_rpc);
|
||||||
call_local_native = _should_call_local(E->get(), is_master, skip_rpc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (call_local_native) {
|
if (call_local_native) {
|
||||||
// Done below.
|
// Done below.
|
||||||
} else if (p_node->get_script_instance()) {
|
} else if (p_node->get_script_instance()) {
|
||||||
// Attempt with script.
|
// 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);
|
call_local_script = _should_call_local(rpc_mode, is_master, skip_rpc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -719,11 +1032,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)) {
|
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.
|
// Check that send mode can use local call.
|
||||||
const Map<StringName, RPCMode>::Element *E = p_node->get_node_rset_mode(p_property);
|
RPCMode rpc_mode = p_node->get_node_rset_mode(p_property);
|
||||||
if (E) {
|
set_local = _should_call_local(rpc_mode, is_master, skip_rset);
|
||||||
|
|
||||||
set_local = _should_call_local(E->get(), is_master, skip_rset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (set_local) {
|
if (set_local) {
|
||||||
bool valid;
|
bool valid;
|
||||||
@@ -740,7 +1050,7 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
|
|||||||
}
|
}
|
||||||
} else if (p_node->get_script_instance()) {
|
} else if (p_node->get_script_instance()) {
|
||||||
// Attempt with script.
|
// 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);
|
set_local = _should_call_local(rpc_mode, is_master, skip_rset);
|
||||||
|
|
||||||
|
|||||||
@@ -98,23 +98,37 @@ protected:
|
|||||||
void _process_packet(int p_from, const uint8_t *p_packet, int p_packet_len);
|
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_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);
|
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);
|
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 StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
|
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 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 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 _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);
|
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:
|
public:
|
||||||
enum NetworkCommands {
|
enum NetworkCommands {
|
||||||
NETWORK_COMMAND_REMOTE_CALL,
|
NETWORK_COMMAND_REMOTE_CALL = 0,
|
||||||
NETWORK_COMMAND_REMOTE_SET,
|
NETWORK_COMMAND_REMOTE_SET,
|
||||||
NETWORK_COMMAND_SIMPLIFY_PATH,
|
NETWORK_COMMAND_SIMPLIFY_PATH,
|
||||||
NETWORK_COMMAND_CONFIRM_PATH,
|
NETWORK_COMMAND_CONFIRM_PATH,
|
||||||
NETWORK_COMMAND_RAW,
|
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 {
|
enum RPCMode {
|
||||||
|
|
||||||
RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default)
|
RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default)
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "core/core_string_names.h"
|
#include "core/core_string_names.h"
|
||||||
#include "core/project_settings.h"
|
#include "core/project_settings.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
|
ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
|
||||||
int ScriptServer::_language_count = 0;
|
int ScriptServer::_language_count = 0;
|
||||||
@@ -644,6 +645,14 @@ Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_nam
|
|||||||
return Variant();
|
return Variant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t PlaceHolderScriptInstance::get_rpc_method_id(const StringName &p_method) const {
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t PlaceHolderScriptInstance::get_rset_property_id(const StringName &p_method) const {
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) :
|
PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) :
|
||||||
owner(p_owner),
|
owner(p_owner),
|
||||||
language(p_language),
|
language(p_language),
|
||||||
|
|||||||
@@ -40,6 +40,21 @@ class ScriptLanguage;
|
|||||||
|
|
||||||
typedef void (*ScriptEditRequestFunction)(const String &p_path);
|
typedef void (*ScriptEditRequestFunction)(const String &p_path);
|
||||||
|
|
||||||
|
struct ScriptNetData {
|
||||||
|
StringName name;
|
||||||
|
MultiplayerAPI::RPCMode mode;
|
||||||
|
bool operator==(ScriptNetData const &p_other) const {
|
||||||
|
return name == p_other.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SortNetData {
|
||||||
|
StringName::AlphCompare compare;
|
||||||
|
bool operator()(const ScriptNetData &p_a, const ScriptNetData &p_b) const {
|
||||||
|
return compare(p_a.name, p_b.name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class ScriptServer {
|
class ScriptServer {
|
||||||
enum {
|
enum {
|
||||||
|
|
||||||
@@ -154,6 +169,18 @@ public:
|
|||||||
|
|
||||||
virtual bool is_placeholder_fallback_enabled() const { return false; }
|
virtual bool is_placeholder_fallback_enabled() const { return false; }
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rpc_methods() const = 0;
|
||||||
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const = 0;
|
||||||
|
virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const = 0;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const = 0;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const = 0;
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_property) const = 0;
|
||||||
|
virtual StringName get_rset_property(const uint16_t p_rset_property_id) const = 0;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const = 0;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0;
|
||||||
|
|
||||||
Script() {}
|
Script() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -195,7 +222,16 @@ public:
|
|||||||
virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid);
|
virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid);
|
||||||
virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid);
|
virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid);
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rpc_methods() const = 0;
|
||||||
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const = 0;
|
||||||
|
virtual StringName get_rpc_method(uint16_t p_id) const = 0;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const = 0;
|
||||||
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0;
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const = 0;
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_variable) const = 0;
|
||||||
|
virtual StringName get_rset_property(uint16_t p_id) const = 0;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const = 0;
|
||||||
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0;
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0;
|
||||||
|
|
||||||
virtual ScriptLanguage *get_language() = 0;
|
virtual ScriptLanguage *get_language() = 0;
|
||||||
@@ -409,7 +445,16 @@ public:
|
|||||||
virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = NULL);
|
virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = NULL);
|
||||||
virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = NULL);
|
virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = NULL);
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rpc_methods() const { return Vector<ScriptNetData>(); }
|
||||||
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
|
||||||
|
virtual StringName get_rpc_method(uint16_t p_id) const { return StringName(); }
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
|
||||||
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const { return Vector<ScriptNetData>(); }
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
|
||||||
|
virtual StringName get_rset_property(uint16_t p_id) const { return StringName(); }
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
|
||||||
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
|
||||||
|
|
||||||
PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner);
|
PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#include "core/project_settings.h"
|
#include "core/project_settings.h"
|
||||||
#include "core/variant.h"
|
#include "core/variant.h"
|
||||||
#include "gdnative/gdnative.h"
|
#include "gdnative/gdnative.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "nativescript.h"
|
#include "nativescript.h"
|
||||||
|
|
||||||
@@ -67,6 +68,14 @@ void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char
|
|||||||
if (classes->has(p_base)) {
|
if (classes->has(p_base)) {
|
||||||
desc.base_data = &(*classes)[p_base];
|
desc.base_data = &(*classes)[p_base];
|
||||||
desc.base_native_type = desc.base_data->base_native_type;
|
desc.base_native_type = desc.base_data->base_native_type;
|
||||||
|
|
||||||
|
const NativeScriptDesc *b = desc.base_data;
|
||||||
|
while (b) {
|
||||||
|
desc.rpc_count += b->rpc_count;
|
||||||
|
desc.rset_count += b->rset_count;
|
||||||
|
b = b->base_data;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
desc.base_data = NULL;
|
desc.base_data = NULL;
|
||||||
desc.base_native_type = p_base;
|
desc.base_native_type = p_base;
|
||||||
@@ -87,10 +96,20 @@ void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const
|
|||||||
desc.destroy_func = p_destroy_func;
|
desc.destroy_func = p_destroy_func;
|
||||||
desc.is_tool = true;
|
desc.is_tool = true;
|
||||||
desc.base = p_base;
|
desc.base = p_base;
|
||||||
|
desc.rpc_count = 0;
|
||||||
|
desc.rset_count = 0;
|
||||||
|
|
||||||
if (classes->has(p_base)) {
|
if (classes->has(p_base)) {
|
||||||
desc.base_data = &(*classes)[p_base];
|
desc.base_data = &(*classes)[p_base];
|
||||||
desc.base_native_type = desc.base_data->base_native_type;
|
desc.base_native_type = desc.base_data->base_native_type;
|
||||||
|
|
||||||
|
const NativeScriptDesc *b = desc.base_data;
|
||||||
|
while (b) {
|
||||||
|
desc.rpc_count += b->rpc_count;
|
||||||
|
desc.rset_count += b->rset_count;
|
||||||
|
b = b->base_data;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
desc.base_data = NULL;
|
desc.base_data = NULL;
|
||||||
desc.base_native_type = p_base;
|
desc.base_native_type = p_base;
|
||||||
@@ -109,6 +128,11 @@ void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const cha
|
|||||||
NativeScriptDesc::Method method;
|
NativeScriptDesc::Method method;
|
||||||
method.method = p_method;
|
method.method = p_method;
|
||||||
method.rpc_mode = p_attr.rpc_type;
|
method.rpc_mode = p_attr.rpc_type;
|
||||||
|
method.rpc_method_id = UINT16_MAX;
|
||||||
|
if (p_attr.rpc_type != GODOT_METHOD_RPC_MODE_DISABLED) {
|
||||||
|
method.rpc_method_id = E->get().rpc_count;
|
||||||
|
E->get().rpc_count += 1;
|
||||||
|
}
|
||||||
method.info = MethodInfo(p_function_name);
|
method.info = MethodInfo(p_function_name);
|
||||||
|
|
||||||
E->get().methods.insert(p_function_name, method);
|
E->get().methods.insert(p_function_name, method);
|
||||||
@@ -125,6 +149,10 @@ void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const c
|
|||||||
property.default_value = *(Variant *)&p_attr->default_value;
|
property.default_value = *(Variant *)&p_attr->default_value;
|
||||||
property.getter = p_get_func;
|
property.getter = p_get_func;
|
||||||
property.rset_mode = p_attr->rset_type;
|
property.rset_mode = p_attr->rset_type;
|
||||||
|
if (p_attr->rset_type != GODOT_METHOD_RPC_MODE_DISABLED) {
|
||||||
|
property.rset_property_id = E->get().rset_count;
|
||||||
|
E->get().rset_count += 1;
|
||||||
|
}
|
||||||
property.setter = p_set_func;
|
property.setter = p_set_func;
|
||||||
property.info = PropertyInfo((Variant::Type)p_attr->type,
|
property.info = PropertyInfo((Variant::Type)p_attr->type,
|
||||||
p_path,
|
p_path,
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include "nativescript.h"
|
#include "nativescript.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "gdnative/gdnative.h"
|
#include "gdnative/gdnative.h"
|
||||||
|
|
||||||
#include "core/core_string_names.h"
|
#include "core/core_string_names.h"
|
||||||
@@ -402,6 +404,262 @@ void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> NativeScript::get_rpc_methods() const {
|
||||||
|
|
||||||
|
Vector<ScriptNetData> v;
|
||||||
|
|
||||||
|
NativeScriptDesc *script_data = get_script_desc();
|
||||||
|
|
||||||
|
while (script_data) {
|
||||||
|
|
||||||
|
for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) {
|
||||||
|
if (E->get().rpc_mode != GODOT_METHOD_RPC_MODE_DISABLED) {
|
||||||
|
ScriptNetData nd;
|
||||||
|
nd.name = E->key();
|
||||||
|
nd.mode = MultiplayerAPI::RPCMode(E->get().rpc_mode);
|
||||||
|
v.push_back(nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
script_data = script_data->base_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t NativeScript::get_rpc_method_id(const StringName &p_method) const {
|
||||||
|
NativeScriptDesc *script_data = get_script_desc();
|
||||||
|
|
||||||
|
while (script_data) {
|
||||||
|
|
||||||
|
Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
|
||||||
|
if (E) {
|
||||||
|
return E->get().rpc_method_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_data = script_data->base_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName NativeScript::get_rpc_method(uint16_t p_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_id == UINT16_MAX, StringName());
|
||||||
|
|
||||||
|
NativeScriptDesc *script_data = get_script_desc();
|
||||||
|
|
||||||
|
while (script_data) {
|
||||||
|
|
||||||
|
for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) {
|
||||||
|
if (E->get().rpc_method_id == p_id) {
|
||||||
|
return E->key();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
script_data = script_data->base_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return StringName();
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode NativeScript::get_rpc_mode_by_id(uint16_t p_id) const {
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V(p_id == UINT16_MAX, MultiplayerAPI::RPC_MODE_DISABLED);
|
||||||
|
|
||||||
|
NativeScriptDesc *script_data = get_script_desc();
|
||||||
|
|
||||||
|
while (script_data) {
|
||||||
|
|
||||||
|
for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) {
|
||||||
|
if (E->get().rpc_method_id == p_id) {
|
||||||
|
switch (E->get().rpc_mode) {
|
||||||
|
case GODOT_METHOD_RPC_MODE_DISABLED:
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
case GODOT_METHOD_RPC_MODE_REMOTE:
|
||||||
|
return MultiplayerAPI::RPC_MODE_REMOTE;
|
||||||
|
case GODOT_METHOD_RPC_MODE_MASTER:
|
||||||
|
return MultiplayerAPI::RPC_MODE_MASTER;
|
||||||
|
case GODOT_METHOD_RPC_MODE_PUPPET:
|
||||||
|
return MultiplayerAPI::RPC_MODE_PUPPET;
|
||||||
|
case GODOT_METHOD_RPC_MODE_REMOTESYNC:
|
||||||
|
return MultiplayerAPI::RPC_MODE_REMOTESYNC;
|
||||||
|
case GODOT_METHOD_RPC_MODE_MASTERSYNC:
|
||||||
|
return MultiplayerAPI::RPC_MODE_MASTERSYNC;
|
||||||
|
case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
|
||||||
|
return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
|
||||||
|
default:
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
script_data = script_data->base_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode NativeScript::get_rpc_mode(const StringName &p_method) const {
|
||||||
|
|
||||||
|
NativeScriptDesc *script_data = get_script_desc();
|
||||||
|
|
||||||
|
while (script_data) {
|
||||||
|
|
||||||
|
Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
|
||||||
|
if (E) {
|
||||||
|
switch (E->get().rpc_mode) {
|
||||||
|
case GODOT_METHOD_RPC_MODE_DISABLED:
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
case GODOT_METHOD_RPC_MODE_REMOTE:
|
||||||
|
return MultiplayerAPI::RPC_MODE_REMOTE;
|
||||||
|
case GODOT_METHOD_RPC_MODE_MASTER:
|
||||||
|
return MultiplayerAPI::RPC_MODE_MASTER;
|
||||||
|
case GODOT_METHOD_RPC_MODE_PUPPET:
|
||||||
|
return MultiplayerAPI::RPC_MODE_PUPPET;
|
||||||
|
case GODOT_METHOD_RPC_MODE_REMOTESYNC:
|
||||||
|
return MultiplayerAPI::RPC_MODE_REMOTESYNC;
|
||||||
|
case GODOT_METHOD_RPC_MODE_MASTERSYNC:
|
||||||
|
return MultiplayerAPI::RPC_MODE_MASTERSYNC;
|
||||||
|
case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
|
||||||
|
return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
|
||||||
|
default:
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
script_data = script_data->base_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> NativeScript::get_rset_properties() const {
|
||||||
|
Vector<ScriptNetData> v;
|
||||||
|
|
||||||
|
NativeScriptDesc *script_data = get_script_desc();
|
||||||
|
|
||||||
|
while (script_data) {
|
||||||
|
|
||||||
|
for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) {
|
||||||
|
if (E.get().rset_mode != GODOT_METHOD_RPC_MODE_DISABLED) {
|
||||||
|
ScriptNetData nd;
|
||||||
|
nd.name = E.key();
|
||||||
|
nd.mode = MultiplayerAPI::RPCMode(E.get().rset_mode);
|
||||||
|
v.push_back(nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
script_data = script_data->base_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t NativeScript::get_rset_property_id(const StringName &p_variable) const {
|
||||||
|
NativeScriptDesc *script_data = get_script_desc();
|
||||||
|
|
||||||
|
while (script_data) {
|
||||||
|
|
||||||
|
OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.find(p_variable);
|
||||||
|
if (E) {
|
||||||
|
return E.get().rset_property_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_data = script_data->base_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName NativeScript::get_rset_property(uint16_t p_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_id == UINT16_MAX, StringName());
|
||||||
|
|
||||||
|
NativeScriptDesc *script_data = get_script_desc();
|
||||||
|
|
||||||
|
while (script_data) {
|
||||||
|
|
||||||
|
for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) {
|
||||||
|
if (E.get().rset_property_id == p_id) {
|
||||||
|
return E.key();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
script_data = script_data->base_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return StringName();
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode NativeScript::get_rset_mode_by_id(uint16_t p_id) const {
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V(p_id == UINT16_MAX, MultiplayerAPI::RPC_MODE_DISABLED);
|
||||||
|
|
||||||
|
NativeScriptDesc *script_data = get_script_desc();
|
||||||
|
|
||||||
|
while (script_data) {
|
||||||
|
|
||||||
|
for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) {
|
||||||
|
if (E.get().rset_property_id == p_id) {
|
||||||
|
switch (E.get().rset_mode) {
|
||||||
|
case GODOT_METHOD_RPC_MODE_DISABLED:
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
case GODOT_METHOD_RPC_MODE_REMOTE:
|
||||||
|
return MultiplayerAPI::RPC_MODE_REMOTE;
|
||||||
|
case GODOT_METHOD_RPC_MODE_MASTER:
|
||||||
|
return MultiplayerAPI::RPC_MODE_MASTER;
|
||||||
|
case GODOT_METHOD_RPC_MODE_PUPPET:
|
||||||
|
return MultiplayerAPI::RPC_MODE_PUPPET;
|
||||||
|
case GODOT_METHOD_RPC_MODE_REMOTESYNC:
|
||||||
|
return MultiplayerAPI::RPC_MODE_REMOTESYNC;
|
||||||
|
case GODOT_METHOD_RPC_MODE_MASTERSYNC:
|
||||||
|
return MultiplayerAPI::RPC_MODE_MASTERSYNC;
|
||||||
|
case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
|
||||||
|
return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
|
||||||
|
default:
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
script_data = script_data->base_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode NativeScript::get_rset_mode(const StringName &p_variable) const {
|
||||||
|
|
||||||
|
NativeScriptDesc *script_data = get_script_desc();
|
||||||
|
|
||||||
|
while (script_data) {
|
||||||
|
|
||||||
|
OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.find(p_variable);
|
||||||
|
if (E) {
|
||||||
|
switch (E.get().rset_mode) {
|
||||||
|
case GODOT_METHOD_RPC_MODE_DISABLED:
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
case GODOT_METHOD_RPC_MODE_REMOTE:
|
||||||
|
return MultiplayerAPI::RPC_MODE_REMOTE;
|
||||||
|
case GODOT_METHOD_RPC_MODE_MASTER:
|
||||||
|
return MultiplayerAPI::RPC_MODE_MASTER;
|
||||||
|
case GODOT_METHOD_RPC_MODE_PUPPET:
|
||||||
|
return MultiplayerAPI::RPC_MODE_PUPPET;
|
||||||
|
case GODOT_METHOD_RPC_MODE_REMOTESYNC:
|
||||||
|
return MultiplayerAPI::RPC_MODE_REMOTESYNC;
|
||||||
|
case GODOT_METHOD_RPC_MODE_MASTERSYNC:
|
||||||
|
return MultiplayerAPI::RPC_MODE_MASTERSYNC;
|
||||||
|
case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
|
||||||
|
return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
|
||||||
|
default:
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
script_data = script_data->base_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
String NativeScript::get_class_documentation() const {
|
String NativeScript::get_class_documentation() const {
|
||||||
NativeScriptDesc *script_data = get_script_desc();
|
NativeScriptDesc *script_data = get_script_desc();
|
||||||
|
|
||||||
@@ -803,72 +1061,44 @@ Ref<Script> NativeScriptInstance::get_script() const {
|
|||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> NativeScriptInstance::get_rpc_methods() const {
|
||||||
|
return script->get_rpc_methods();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t NativeScriptInstance::get_rpc_method_id(const StringName &p_method) const {
|
||||||
|
return script->get_rpc_method_id(p_method);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName NativeScriptInstance::get_rpc_method(uint16_t p_id) const {
|
||||||
|
return script->get_rpc_method(p_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode NativeScriptInstance::get_rpc_mode_by_id(uint16_t p_id) const {
|
||||||
|
return script->get_rpc_mode_by_id(p_id);
|
||||||
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode NativeScriptInstance::get_rpc_mode(const StringName &p_method) const {
|
MultiplayerAPI::RPCMode NativeScriptInstance::get_rpc_mode(const StringName &p_method) const {
|
||||||
|
return script->get_rpc_mode(p_method);
|
||||||
NativeScriptDesc *script_data = GET_SCRIPT_DESC();
|
|
||||||
|
|
||||||
while (script_data) {
|
|
||||||
|
|
||||||
Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
|
|
||||||
if (E) {
|
|
||||||
switch (E->get().rpc_mode) {
|
|
||||||
case GODOT_METHOD_RPC_MODE_DISABLED:
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
|
||||||
case GODOT_METHOD_RPC_MODE_REMOTE:
|
|
||||||
return MultiplayerAPI::RPC_MODE_REMOTE;
|
|
||||||
case GODOT_METHOD_RPC_MODE_MASTER:
|
|
||||||
return MultiplayerAPI::RPC_MODE_MASTER;
|
|
||||||
case GODOT_METHOD_RPC_MODE_PUPPET:
|
|
||||||
return MultiplayerAPI::RPC_MODE_PUPPET;
|
|
||||||
case GODOT_METHOD_RPC_MODE_REMOTESYNC:
|
|
||||||
return MultiplayerAPI::RPC_MODE_REMOTESYNC;
|
|
||||||
case GODOT_METHOD_RPC_MODE_MASTERSYNC:
|
|
||||||
return MultiplayerAPI::RPC_MODE_MASTERSYNC;
|
|
||||||
case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
|
|
||||||
return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
|
|
||||||
default:
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
script_data = script_data->base_data;
|
Vector<ScriptNetData> NativeScriptInstance::get_rset_properties() const {
|
||||||
|
return script->get_rset_properties();
|
||||||
}
|
}
|
||||||
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
uint16_t NativeScriptInstance::get_rset_property_id(const StringName &p_variable) const {
|
||||||
|
return script->get_rset_property_id(p_variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName NativeScriptInstance::get_rset_property(uint16_t p_id) const {
|
||||||
|
return script->get_rset_property(p_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode NativeScriptInstance::get_rset_mode_by_id(uint16_t p_id) const {
|
||||||
|
return script->get_rset_mode_by_id(p_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode NativeScriptInstance::get_rset_mode(const StringName &p_variable) const {
|
MultiplayerAPI::RPCMode NativeScriptInstance::get_rset_mode(const StringName &p_variable) const {
|
||||||
|
return script->get_rset_mode(p_variable);
|
||||||
NativeScriptDesc *script_data = GET_SCRIPT_DESC();
|
|
||||||
|
|
||||||
while (script_data) {
|
|
||||||
|
|
||||||
OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.find(p_variable);
|
|
||||||
if (E) {
|
|
||||||
switch (E.get().rset_mode) {
|
|
||||||
case GODOT_METHOD_RPC_MODE_DISABLED:
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
|
||||||
case GODOT_METHOD_RPC_MODE_REMOTE:
|
|
||||||
return MultiplayerAPI::RPC_MODE_REMOTE;
|
|
||||||
case GODOT_METHOD_RPC_MODE_MASTER:
|
|
||||||
return MultiplayerAPI::RPC_MODE_MASTER;
|
|
||||||
case GODOT_METHOD_RPC_MODE_PUPPET:
|
|
||||||
return MultiplayerAPI::RPC_MODE_PUPPET;
|
|
||||||
case GODOT_METHOD_RPC_MODE_REMOTESYNC:
|
|
||||||
return MultiplayerAPI::RPC_MODE_REMOTESYNC;
|
|
||||||
case GODOT_METHOD_RPC_MODE_MASTERSYNC:
|
|
||||||
return MultiplayerAPI::RPC_MODE_MASTERSYNC;
|
|
||||||
case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
|
|
||||||
return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
|
|
||||||
default:
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
script_data = script_data->base_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptLanguage *NativeScriptInstance::get_language() {
|
ScriptLanguage *NativeScriptInstance::get_language() {
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ struct NativeScriptDesc {
|
|||||||
godot_instance_method method;
|
godot_instance_method method;
|
||||||
MethodInfo info;
|
MethodInfo info;
|
||||||
int rpc_mode;
|
int rpc_mode;
|
||||||
|
uint16_t rpc_method_id;
|
||||||
String documentation;
|
String documentation;
|
||||||
};
|
};
|
||||||
struct Property {
|
struct Property {
|
||||||
@@ -62,6 +63,7 @@ struct NativeScriptDesc {
|
|||||||
PropertyInfo info;
|
PropertyInfo info;
|
||||||
Variant default_value;
|
Variant default_value;
|
||||||
int rset_mode;
|
int rset_mode;
|
||||||
|
uint16_t rset_property_id;
|
||||||
String documentation;
|
String documentation;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,7 +72,9 @@ struct NativeScriptDesc {
|
|||||||
String documentation;
|
String documentation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint16_t rpc_count;
|
||||||
Map<StringName, Method> methods;
|
Map<StringName, Method> methods;
|
||||||
|
uint16_t rset_count;
|
||||||
OrderedHashMap<StringName, Property> properties;
|
OrderedHashMap<StringName, Property> properties;
|
||||||
Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals
|
Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals
|
||||||
StringName base;
|
StringName base;
|
||||||
@@ -86,7 +90,9 @@ struct NativeScriptDesc {
|
|||||||
bool is_tool;
|
bool is_tool;
|
||||||
|
|
||||||
inline NativeScriptDesc() :
|
inline NativeScriptDesc() :
|
||||||
|
rpc_count(0),
|
||||||
methods(),
|
methods(),
|
||||||
|
rset_count(0),
|
||||||
properties(),
|
properties(),
|
||||||
signals_(),
|
signals_(),
|
||||||
base(),
|
base(),
|
||||||
@@ -174,6 +180,18 @@ public:
|
|||||||
virtual void get_script_method_list(List<MethodInfo> *p_list) const;
|
virtual void get_script_method_list(List<MethodInfo> *p_list) const;
|
||||||
virtual void get_script_property_list(List<PropertyInfo> *p_list) const;
|
virtual void get_script_property_list(List<PropertyInfo> *p_list) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rpc_methods() const;
|
||||||
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
|
||||||
|
virtual StringName get_rpc_method(uint16_t p_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const;
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
|
||||||
|
virtual StringName get_rset_property(uint16_t p_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
||||||
|
|
||||||
String get_class_documentation() const;
|
String get_class_documentation() const;
|
||||||
String get_method_documentation(const StringName &p_method) const;
|
String get_method_documentation(const StringName &p_method) const;
|
||||||
String get_signal_documentation(const StringName &p_signal_name) const;
|
String get_signal_documentation(const StringName &p_signal_name) const;
|
||||||
@@ -210,8 +228,19 @@ public:
|
|||||||
virtual void notification(int p_notification);
|
virtual void notification(int p_notification);
|
||||||
String to_string(bool *r_valid);
|
String to_string(bool *r_valid);
|
||||||
virtual Ref<Script> get_script() const;
|
virtual Ref<Script> get_script() const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rpc_methods() const;
|
||||||
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
|
||||||
|
virtual StringName get_rpc_method(uint16_t p_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const;
|
||||||
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const;
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
|
||||||
|
virtual StringName get_rset_property(uint16_t p_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const;
|
||||||
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
||||||
|
|
||||||
virtual ScriptLanguage *get_language();
|
virtual ScriptLanguage *get_language();
|
||||||
|
|
||||||
virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
|
virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
|
||||||
|
|||||||
@@ -93,10 +93,42 @@ void PluginScriptInstance::notification(int p_notification) {
|
|||||||
_desc->notification(_data, p_notification);
|
_desc->notification(_data, p_notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> PluginScriptInstance::get_rpc_methods() const {
|
||||||
|
return _script->get_rpc_methods();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t PluginScriptInstance::get_rpc_method_id(const StringName &p_variable) const {
|
||||||
|
return _script->get_rpc_method_id(p_variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName PluginScriptInstance::get_rpc_method(uint16_t p_id) const {
|
||||||
|
return _script->get_rpc_method(p_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode PluginScriptInstance::get_rpc_mode_by_id(uint16_t p_id) const {
|
||||||
|
return _script->get_rpc_mode_by_id(p_id);
|
||||||
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode PluginScriptInstance::get_rpc_mode(const StringName &p_method) const {
|
MultiplayerAPI::RPCMode PluginScriptInstance::get_rpc_mode(const StringName &p_method) const {
|
||||||
return _script->get_rpc_mode(p_method);
|
return _script->get_rpc_mode(p_method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> PluginScriptInstance::get_rset_properties() const {
|
||||||
|
return _script->get_rset_properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t PluginScriptInstance::get_rset_property_id(const StringName &p_variable) const {
|
||||||
|
return _script->get_rset_property_id(p_variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName PluginScriptInstance::get_rset_property(uint16_t p_id) const {
|
||||||
|
return _script->get_rset_property(p_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode PluginScriptInstance::get_rset_mode_by_id(uint16_t p_id) const {
|
||||||
|
return _script->get_rset_mode_by_id(p_id);
|
||||||
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode PluginScriptInstance::get_rset_mode(const StringName &p_variable) const {
|
MultiplayerAPI::RPCMode PluginScriptInstance::get_rset_mode(const StringName &p_variable) const {
|
||||||
return _script->get_rset_mode(p_variable);
|
return _script->get_rset_mode(p_variable);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,16 @@ public:
|
|||||||
|
|
||||||
void set_path(const String &p_path);
|
void set_path(const String &p_path);
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rpc_methods() const;
|
||||||
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
|
||||||
|
virtual StringName get_rpc_method(uint16_t p_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const;
|
||||||
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const;
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
|
||||||
|
virtual StringName get_rset_property(uint16_t p_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const;
|
||||||
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
||||||
|
|
||||||
virtual void refcount_incremented();
|
virtual void refcount_incremented();
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#include "pluginscript_instance.h"
|
#include "pluginscript_instance.h"
|
||||||
#include "pluginscript_script.h"
|
#include "pluginscript_script.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
#define __ASSERT_SCRIPT_REASON "Cannot retrieve PluginScript class for this script, is your code correct?"
|
#define __ASSERT_SCRIPT_REASON "Cannot retrieve PluginScript class for this script, is your code correct?"
|
||||||
#define ASSERT_SCRIPT_VALID() \
|
#define ASSERT_SCRIPT_VALID() \
|
||||||
@@ -298,18 +300,31 @@ Error PluginScript::reload(bool p_keep_state) {
|
|||||||
_member_lines[*key] = (*members)[*key];
|
_member_lines[*key] = (*members)[*key];
|
||||||
}
|
}
|
||||||
Array *methods = (Array *)&manifest.methods;
|
Array *methods = (Array *)&manifest.methods;
|
||||||
|
_rpc_methods.clear();
|
||||||
|
_rpc_variables.clear();
|
||||||
|
if (_ref_base_parent.is_valid()) {
|
||||||
|
_rpc_methods = _ref_base_parent->get_rpc_methods();
|
||||||
|
_rpc_variables = _ref_base_parent->get_rset_properties();
|
||||||
|
}
|
||||||
for (int i = 0; i < methods->size(); ++i) {
|
for (int i = 0; i < methods->size(); ++i) {
|
||||||
Dictionary v = (*methods)[i];
|
Dictionary v = (*methods)[i];
|
||||||
MethodInfo mi = MethodInfo::from_dict(v);
|
MethodInfo mi = MethodInfo::from_dict(v);
|
||||||
_methods_info[mi.name] = mi;
|
_methods_info[mi.name] = mi;
|
||||||
// rpc_mode is passed as an optional field and is not part of MethodInfo
|
// rpc_mode is passed as an optional field and is not part of MethodInfo
|
||||||
Variant var = v["rpc_mode"];
|
Variant var = v["rpc_mode"];
|
||||||
if (var == Variant()) {
|
if (var != Variant()) {
|
||||||
_methods_rpc_mode[mi.name] = MultiplayerAPI::RPC_MODE_DISABLED;
|
ScriptNetData nd;
|
||||||
} else {
|
nd.name = mi.name;
|
||||||
_methods_rpc_mode[mi.name] = MultiplayerAPI::RPCMode(int(var));
|
nd.mode = MultiplayerAPI::RPCMode(int(var));
|
||||||
|
if (_rpc_methods.find(nd) == -1) {
|
||||||
|
_rpc_methods.push_back(nd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort so we are 100% that they are always the same.
|
||||||
|
_rpc_methods.sort_custom<SortNetData>();
|
||||||
|
|
||||||
Array *signals = (Array *)&manifest.signals;
|
Array *signals = (Array *)&manifest.signals;
|
||||||
for (int i = 0; i < signals->size(); ++i) {
|
for (int i = 0; i < signals->size(); ++i) {
|
||||||
Variant v = (*signals)[i];
|
Variant v = (*signals)[i];
|
||||||
@@ -324,12 +339,18 @@ Error PluginScript::reload(bool p_keep_state) {
|
|||||||
_properties_default_values[pi.name] = v["default_value"];
|
_properties_default_values[pi.name] = v["default_value"];
|
||||||
// rset_mode is passed as an optional field and is not part of PropertyInfo
|
// rset_mode is passed as an optional field and is not part of PropertyInfo
|
||||||
Variant var = v["rset_mode"];
|
Variant var = v["rset_mode"];
|
||||||
if (var == Variant()) {
|
if (var != Variant()) {
|
||||||
_methods_rpc_mode[pi.name] = MultiplayerAPI::RPC_MODE_DISABLED;
|
ScriptNetData nd;
|
||||||
} else {
|
nd.name = pi.name;
|
||||||
_methods_rpc_mode[pi.name] = MultiplayerAPI::RPCMode(int(var));
|
nd.mode = MultiplayerAPI::RPCMode(int(var));
|
||||||
|
if (_rpc_variables.find(nd) == -1) {
|
||||||
|
_rpc_variables.push_back(nd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort so we are 100% that they are always the same.
|
||||||
|
_rpc_variables.sort_custom<SortNetData>();
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
/*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
|
/*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
|
||||||
@@ -455,24 +476,70 @@ int PluginScript::get_member_line(const StringName &p_member) const {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> PluginScript::get_rpc_methods() const {
|
||||||
|
return _rpc_methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t PluginScript::get_rpc_method_id(const StringName &p_method) const {
|
||||||
|
ASSERT_SCRIPT_VALID_V(UINT16_MAX);
|
||||||
|
for (int i = 0; i < _rpc_methods.size(); i++) {
|
||||||
|
if (_rpc_methods[i].name == p_method) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName PluginScript::get_rpc_method(const uint16_t p_rpc_method_id) const {
|
||||||
|
ASSERT_SCRIPT_VALID_V(StringName());
|
||||||
|
if (p_rpc_method_id >= _rpc_methods.size())
|
||||||
|
return StringName();
|
||||||
|
return _rpc_methods[p_rpc_method_id].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode PluginScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
|
||||||
|
ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
|
||||||
|
if (p_rpc_method_id >= _rpc_methods.size())
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
return _rpc_methods[p_rpc_method_id].mode;
|
||||||
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode PluginScript::get_rpc_mode(const StringName &p_method) const {
|
MultiplayerAPI::RPCMode PluginScript::get_rpc_mode(const StringName &p_method) const {
|
||||||
ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
|
ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
|
||||||
const Map<StringName, MultiplayerAPI::RPCMode>::Element *e = _methods_rpc_mode.find(p_method);
|
return get_rpc_mode_by_id(get_rpc_method_id(p_method));
|
||||||
if (e != NULL) {
|
|
||||||
return e->get();
|
|
||||||
} else {
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> PluginScript::get_rset_properties() const {
|
||||||
|
return _rpc_variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t PluginScript::get_rset_property_id(const StringName &p_property) const {
|
||||||
|
ASSERT_SCRIPT_VALID_V(UINT16_MAX);
|
||||||
|
for (int i = 0; i < _rpc_variables.size(); i++) {
|
||||||
|
if (_rpc_variables[i].name == p_property) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName PluginScript::get_rset_property(const uint16_t p_rset_property_id) const {
|
||||||
|
ASSERT_SCRIPT_VALID_V(StringName());
|
||||||
|
if (p_rset_property_id >= _rpc_variables.size())
|
||||||
|
return StringName();
|
||||||
|
return _rpc_variables[p_rset_property_id].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode PluginScript::get_rset_mode_by_id(const uint16_t p_rset_property_id) const {
|
||||||
|
ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
|
||||||
|
if (p_rset_property_id >= _rpc_variables.size())
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
return _rpc_variables[p_rset_property_id].mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode PluginScript::get_rset_mode(const StringName &p_variable) const {
|
MultiplayerAPI::RPCMode PluginScript::get_rset_mode(const StringName &p_variable) const {
|
||||||
ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
|
ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
|
||||||
const Map<StringName, MultiplayerAPI::RPCMode>::Element *e = _variables_rset_mode.find(p_variable);
|
return get_rset_mode_by_id(get_rset_property_id(p_variable));
|
||||||
if (e != NULL) {
|
|
||||||
return e->get();
|
|
||||||
} else {
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginScript::PluginScript() :
|
PluginScript::PluginScript() :
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ private:
|
|||||||
Map<StringName, PropertyInfo> _properties_info;
|
Map<StringName, PropertyInfo> _properties_info;
|
||||||
Map<StringName, MethodInfo> _signals_info;
|
Map<StringName, MethodInfo> _signals_info;
|
||||||
Map<StringName, MethodInfo> _methods_info;
|
Map<StringName, MethodInfo> _methods_info;
|
||||||
Map<StringName, MultiplayerAPI::RPCMode> _variables_rset_mode;
|
Vector<ScriptNetData> _rpc_methods;
|
||||||
Map<StringName, MultiplayerAPI::RPCMode> _methods_rpc_mode;
|
Vector<ScriptNetData> _rpc_variables;
|
||||||
|
|
||||||
Set<Object *> _instances;
|
Set<Object *> _instances;
|
||||||
//exported members
|
//exported members
|
||||||
@@ -118,8 +118,17 @@ public:
|
|||||||
|
|
||||||
virtual int get_member_line(const StringName &p_member) const;
|
virtual int get_member_line(const StringName &p_member) const;
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
virtual Vector<ScriptNetData> get_rpc_methods() const;
|
||||||
MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
|
||||||
|
virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const;
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_property) const;
|
||||||
|
virtual StringName get_rset_property(const uint16_t p_rset_property_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
||||||
|
|
||||||
PluginScript();
|
PluginScript();
|
||||||
void init(PluginScriptLanguage *language);
|
void init(PluginScriptLanguage *language);
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include "gdscript.h"
|
#include "gdscript.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "core/core_string_names.h"
|
#include "core/core_string_names.h"
|
||||||
#include "core/engine.h"
|
#include "core/engine.h"
|
||||||
#include "core/global_constants.h"
|
#include "core/global_constants.h"
|
||||||
@@ -610,6 +612,53 @@ Error GDScript::reload(bool p_keep_state) {
|
|||||||
_set_subclass_path(E->get(), path);
|
_set_subclass_path(E->get(), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy the base rpc methods so we don't mask their IDs.
|
||||||
|
rpc_functions.clear();
|
||||||
|
rpc_variables.clear();
|
||||||
|
if (base.is_valid()) {
|
||||||
|
rpc_functions = base->rpc_functions;
|
||||||
|
rpc_variables = base->rpc_variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
GDScript *cscript = this;
|
||||||
|
Map<StringName, Ref<GDScript> >::Element *sub_E = subclasses.front();
|
||||||
|
while (cscript) {
|
||||||
|
// RPC Methods
|
||||||
|
for (Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.front(); E; E = E->next()) {
|
||||||
|
if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) {
|
||||||
|
ScriptNetData nd;
|
||||||
|
nd.name = E->key();
|
||||||
|
nd.mode = E->get()->get_rpc_mode();
|
||||||
|
if (-1 == rpc_functions.find(nd)) {
|
||||||
|
rpc_functions.push_back(nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// RSet
|
||||||
|
for (Map<StringName, MemberInfo>::Element *E = cscript->member_indices.front(); E; E = E->next()) {
|
||||||
|
if (E->get().rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) {
|
||||||
|
ScriptNetData nd;
|
||||||
|
nd.name = E->key();
|
||||||
|
nd.mode = E->get().rpc_mode;
|
||||||
|
if (-1 == rpc_variables.find(nd)) {
|
||||||
|
rpc_variables.push_back(nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cscript != this)
|
||||||
|
sub_E = sub_E->next();
|
||||||
|
|
||||||
|
if (sub_E)
|
||||||
|
cscript = sub_E->get().ptr();
|
||||||
|
else
|
||||||
|
cscript = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort so we are 100% that they are always the same.
|
||||||
|
rpc_functions.sort_custom<SortNetData>();
|
||||||
|
rpc_variables.sort_custom<SortNetData>();
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -635,6 +684,60 @@ void GDScript::get_members(Set<StringName> *p_members) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> GDScript::get_rpc_methods() const {
|
||||||
|
return rpc_functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t GDScript::get_rpc_method_id(const StringName &p_method) const {
|
||||||
|
for (int i = 0; i < rpc_functions.size(); i++) {
|
||||||
|
if (rpc_functions[i].name == p_method) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName GDScript::get_rpc_method(const uint16_t p_rpc_method_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName());
|
||||||
|
return rpc_functions[p_rpc_method_id].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode GDScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
|
||||||
|
return rpc_functions[p_rpc_method_id].mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode GDScript::get_rpc_mode(const StringName &p_method) const {
|
||||||
|
return get_rpc_mode_by_id(get_rpc_method_id(p_method));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> GDScript::get_rset_properties() const {
|
||||||
|
return rpc_variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t GDScript::get_rset_property_id(const StringName &p_variable) const {
|
||||||
|
for (int i = 0; i < rpc_variables.size(); i++) {
|
||||||
|
if (rpc_variables[i].name == p_variable) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName GDScript::get_rset_property(const uint16_t p_rset_member_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), StringName());
|
||||||
|
return rpc_variables[p_rset_member_id].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode GDScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_rset_member_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
|
||||||
|
return rpc_functions[p_rset_member_id].mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode GDScript::get_rset_mode(const StringName &p_variable) const {
|
||||||
|
return get_rset_mode_by_id(get_rset_property_id(p_variable));
|
||||||
|
}
|
||||||
|
|
||||||
Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
|
Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
|
||||||
|
|
||||||
GDScript *top = this;
|
GDScript *top = this;
|
||||||
@@ -1291,40 +1394,44 @@ ScriptLanguage *GDScriptInstance::get_language() {
|
|||||||
return GDScriptLanguage::get_singleton();
|
return GDScriptLanguage::get_singleton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> GDScriptInstance::get_rpc_methods() const {
|
||||||
|
return script->get_rpc_methods();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t GDScriptInstance::get_rpc_method_id(const StringName &p_method) const {
|
||||||
|
return script->get_rpc_method_id(p_method);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName GDScriptInstance::get_rpc_method(const uint16_t p_rpc_method_id) const {
|
||||||
|
return script->get_rpc_method(p_rpc_method_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
|
||||||
|
return script->get_rpc_mode_by_id(p_rpc_method_id);
|
||||||
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_method) const {
|
MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_method) const {
|
||||||
|
return script->get_rpc_mode(p_method);
|
||||||
const GDScript *cscript = script.ptr();
|
|
||||||
|
|
||||||
while (cscript) {
|
|
||||||
const Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.find(p_method);
|
|
||||||
if (E) {
|
|
||||||
|
|
||||||
if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) {
|
|
||||||
return E->get()->get_rpc_mode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cscript = cscript->_base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
Vector<ScriptNetData> GDScriptInstance::get_rset_properties() const {
|
||||||
|
return script->get_rset_properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t GDScriptInstance::get_rset_property_id(const StringName &p_variable) const {
|
||||||
|
return script->get_rset_property_id(p_variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName GDScriptInstance::get_rset_property(const uint16_t p_rset_member_id) const {
|
||||||
|
return script->get_rset_property(p_rset_member_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
|
||||||
|
return script->get_rset_mode_by_id(p_rset_member_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_variable) const {
|
MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_variable) const {
|
||||||
|
return script->get_rset_mode(p_variable);
|
||||||
const GDScript *cscript = script.ptr();
|
|
||||||
|
|
||||||
while (cscript) {
|
|
||||||
const Map<StringName, GDScript::MemberInfo>::Element *E = cscript->member_indices.find(p_variable);
|
|
||||||
if (E) {
|
|
||||||
|
|
||||||
if (E->get().rpc_mode) {
|
|
||||||
return E->get().rpc_mode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cscript = cscript->_base;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDScriptInstance::reload_members() {
|
void GDScriptInstance::reload_members() {
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ class GDScript : public Script {
|
|||||||
Map<StringName, MemberInfo> member_indices; //members are just indices to the instanced script.
|
Map<StringName, MemberInfo> member_indices; //members are just indices to the instanced script.
|
||||||
Map<StringName, Ref<GDScript> > subclasses;
|
Map<StringName, Ref<GDScript> > subclasses;
|
||||||
Map<StringName, Vector<StringName> > _signals;
|
Map<StringName, Vector<StringName> > _signals;
|
||||||
|
Vector<ScriptNetData> rpc_functions;
|
||||||
|
Vector<ScriptNetData> rpc_variables;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
|
|
||||||
@@ -213,6 +215,18 @@ public:
|
|||||||
virtual void get_constants(Map<StringName, Variant> *p_constants);
|
virtual void get_constants(Map<StringName, Variant> *p_constants);
|
||||||
virtual void get_members(Set<StringName> *p_members);
|
virtual void get_members(Set<StringName> *p_members);
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rpc_methods() const;
|
||||||
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
|
||||||
|
virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const;
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
|
||||||
|
virtual StringName get_rset_property(const uint16_t p_variable_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
virtual bool is_placeholder_fallback_enabled() const { return placeholder_fallback_enabled; }
|
virtual bool is_placeholder_fallback_enabled() const { return placeholder_fallback_enabled; }
|
||||||
#endif
|
#endif
|
||||||
@@ -264,7 +278,16 @@ public:
|
|||||||
|
|
||||||
void reload_members();
|
void reload_members();
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rpc_methods() const;
|
||||||
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
|
||||||
|
virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
|
||||||
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const;
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
|
||||||
|
virtual StringName get_rset_property(const uint16_t p_variable_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const;
|
||||||
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
||||||
|
|
||||||
GDScriptInstance();
|
GDScriptInstance();
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "csharp_script.h"
|
#include "csharp_script.h"
|
||||||
|
|
||||||
#include <mono/metadata/threads.h>
|
#include <mono/metadata/threads.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "core/io/json.h"
|
#include "core/io/json.h"
|
||||||
#include "core/os/file_access.h"
|
#include "core/os/file_access.h"
|
||||||
@@ -1979,67 +1980,44 @@ bool CSharpInstance::refcount_decremented() {
|
|||||||
return ref_dying;
|
return ref_dying;
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode CSharpInstance::_member_get_rpc_mode(IMonoClassMember *p_member) const {
|
Vector<ScriptNetData> CSharpInstance::get_rpc_methods() const {
|
||||||
|
return script->get_rpc_methods();
|
||||||
|
}
|
||||||
|
|
||||||
if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute)))
|
uint16_t CSharpInstance::get_rpc_method_id(const StringName &p_method) const {
|
||||||
return MultiplayerAPI::RPC_MODE_REMOTE;
|
return script->get_rpc_method_id(p_method);
|
||||||
if (p_member->has_attribute(CACHED_CLASS(MasterAttribute)))
|
}
|
||||||
return MultiplayerAPI::RPC_MODE_MASTER;
|
|
||||||
if (p_member->has_attribute(CACHED_CLASS(PuppetAttribute)))
|
|
||||||
return MultiplayerAPI::RPC_MODE_PUPPET;
|
|
||||||
if (p_member->has_attribute(CACHED_CLASS(SlaveAttribute)))
|
|
||||||
return MultiplayerAPI::RPC_MODE_PUPPET;
|
|
||||||
if (p_member->has_attribute(CACHED_CLASS(RemoteSyncAttribute)))
|
|
||||||
return MultiplayerAPI::RPC_MODE_REMOTESYNC;
|
|
||||||
if (p_member->has_attribute(CACHED_CLASS(SyncAttribute)))
|
|
||||||
return MultiplayerAPI::RPC_MODE_REMOTESYNC;
|
|
||||||
if (p_member->has_attribute(CACHED_CLASS(MasterSyncAttribute)))
|
|
||||||
return MultiplayerAPI::RPC_MODE_MASTERSYNC;
|
|
||||||
if (p_member->has_attribute(CACHED_CLASS(PuppetSyncAttribute)))
|
|
||||||
return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
|
|
||||||
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
StringName CSharpInstance::get_rpc_method(const uint16_t p_rpc_method_id) const {
|
||||||
|
return script->get_rpc_method(p_rpc_method_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
|
||||||
|
return script->get_rpc_mode_by_id(p_rpc_method_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const {
|
MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const {
|
||||||
|
return script->get_rpc_mode(p_method);
|
||||||
GD_MONO_SCOPE_THREAD_ATTACH;
|
|
||||||
|
|
||||||
GDMonoClass *top = script->script_class;
|
|
||||||
|
|
||||||
while (top && top != script->native) {
|
|
||||||
GDMonoMethod *method = top->get_fetched_method_unknown_params(p_method);
|
|
||||||
|
|
||||||
if (method && !method->is_static())
|
|
||||||
return _member_get_rpc_mode(method);
|
|
||||||
|
|
||||||
top = top->get_parent_class();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
Vector<ScriptNetData> CSharpInstance::get_rset_properties() const {
|
||||||
|
return script->get_rset_properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CSharpInstance::get_rset_property_id(const StringName &p_variable) const {
|
||||||
|
return script->get_rset_property_id(p_variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName CSharpInstance::get_rset_property(const uint16_t p_rset_member_id) const {
|
||||||
|
return script->get_rset_property(p_rset_member_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
|
||||||
|
return script->get_rset_mode_by_id(p_rset_member_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const {
|
MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const {
|
||||||
|
return script->get_rset_mode(p_variable);
|
||||||
GD_MONO_SCOPE_THREAD_ATTACH;
|
|
||||||
|
|
||||||
GDMonoClass *top = script->script_class;
|
|
||||||
|
|
||||||
while (top && top != script->native) {
|
|
||||||
GDMonoField *field = top->get_field(p_variable);
|
|
||||||
|
|
||||||
if (field && !field->is_static())
|
|
||||||
return _member_get_rpc_mode(field);
|
|
||||||
|
|
||||||
GDMonoProperty *property = top->get_property(p_variable);
|
|
||||||
|
|
||||||
if (property && !property->is_static())
|
|
||||||
return _member_get_rpc_mode(property);
|
|
||||||
|
|
||||||
top = top->get_parent_class();
|
|
||||||
}
|
|
||||||
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSharpInstance::notification(int p_notification) {
|
void CSharpInstance::notification(int p_notification) {
|
||||||
@@ -3251,6 +3229,69 @@ Error CSharpScript::reload(bool p_keep_state) {
|
|||||||
_update_exports();
|
_update_exports();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpc_functions.clear();
|
||||||
|
rpc_variables.clear();
|
||||||
|
|
||||||
|
GDMonoClass *top = script_class;
|
||||||
|
while (top && top != native) {
|
||||||
|
{
|
||||||
|
Vector<GDMonoMethod *> methods = top->get_all_methods();
|
||||||
|
for (int i = 0; i < methods.size(); i++) {
|
||||||
|
if (!methods[i]->is_static()) {
|
||||||
|
MultiplayerAPI::RPCMode mode = _member_get_rpc_mode(methods[i]);
|
||||||
|
if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
|
||||||
|
ScriptNetData nd;
|
||||||
|
nd.name = methods[i]->get_name();
|
||||||
|
nd.mode = mode;
|
||||||
|
if (-1 == rpc_functions.find(nd)) {
|
||||||
|
rpc_functions.push_back(nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Vector<GDMonoField *> fields = top->get_all_fields();
|
||||||
|
for (int i = 0; i < fields.size(); i++) {
|
||||||
|
if (!fields[i]->is_static()) {
|
||||||
|
MultiplayerAPI::RPCMode mode = _member_get_rpc_mode(fields[i]);
|
||||||
|
if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
|
||||||
|
ScriptNetData nd;
|
||||||
|
nd.name = fields[i]->get_name();
|
||||||
|
nd.mode = mode;
|
||||||
|
if (-1 == rpc_variables.find(nd)) {
|
||||||
|
rpc_variables.push_back(nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Vector<GDMonoProperty *> properties = top->get_all_properties();
|
||||||
|
for (int i = 0; i < properties.size(); i++) {
|
||||||
|
if (!properties[i]->is_static()) {
|
||||||
|
MultiplayerAPI::RPCMode mode = _member_get_rpc_mode(properties[i]);
|
||||||
|
if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
|
||||||
|
ScriptNetData nd;
|
||||||
|
nd.name = properties[i]->get_name();
|
||||||
|
nd.mode = mode;
|
||||||
|
if (-1 == rpc_variables.find(nd)) {
|
||||||
|
rpc_variables.push_back(nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
top = top->get_parent_class();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort so we are 100% that they are always the same.
|
||||||
|
rpc_functions.sort_custom<SortNetData>();
|
||||||
|
rpc_variables.sort_custom<SortNetData>();
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3324,6 +3365,82 @@ int CSharpScript::get_member_line(const StringName &p_member) const {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_member) const {
|
||||||
|
|
||||||
|
if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute)))
|
||||||
|
return MultiplayerAPI::RPC_MODE_REMOTE;
|
||||||
|
if (p_member->has_attribute(CACHED_CLASS(MasterAttribute)))
|
||||||
|
return MultiplayerAPI::RPC_MODE_MASTER;
|
||||||
|
if (p_member->has_attribute(CACHED_CLASS(PuppetAttribute)))
|
||||||
|
return MultiplayerAPI::RPC_MODE_PUPPET;
|
||||||
|
if (p_member->has_attribute(CACHED_CLASS(SlaveAttribute)))
|
||||||
|
return MultiplayerAPI::RPC_MODE_PUPPET;
|
||||||
|
if (p_member->has_attribute(CACHED_CLASS(RemoteSyncAttribute)))
|
||||||
|
return MultiplayerAPI::RPC_MODE_REMOTESYNC;
|
||||||
|
if (p_member->has_attribute(CACHED_CLASS(SyncAttribute)))
|
||||||
|
return MultiplayerAPI::RPC_MODE_REMOTESYNC;
|
||||||
|
if (p_member->has_attribute(CACHED_CLASS(MasterSyncAttribute)))
|
||||||
|
return MultiplayerAPI::RPC_MODE_MASTERSYNC;
|
||||||
|
if (p_member->has_attribute(CACHED_CLASS(PuppetSyncAttribute)))
|
||||||
|
return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
|
||||||
|
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> CSharpScript::get_rpc_methods() const {
|
||||||
|
return rpc_functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CSharpScript::get_rpc_method_id(const StringName &p_method) const {
|
||||||
|
for (int i = 0; i < rpc_functions.size(); i++) {
|
||||||
|
if (rpc_functions[i].name == p_method) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName CSharpScript::get_rpc_method(const uint16_t p_rpc_method_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName());
|
||||||
|
return rpc_functions[p_rpc_method_id].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode CSharpScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
|
||||||
|
return rpc_functions[p_rpc_method_id].mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode CSharpScript::get_rpc_mode(const StringName &p_method) const {
|
||||||
|
return get_rpc_mode_by_id(get_rpc_method_id(p_method));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> CSharpScript::get_rset_properties() const {
|
||||||
|
return rpc_variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CSharpScript::get_rset_property_id(const StringName &p_variable) const {
|
||||||
|
for (int i = 0; i < rpc_variables.size(); i++) {
|
||||||
|
if (rpc_variables[i].name == p_variable) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName CSharpScript::get_rset_property(const uint16_t p_rset_member_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), StringName());
|
||||||
|
return rpc_variables[p_rset_member_id].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode CSharpScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_rset_member_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
|
||||||
|
return rpc_functions[p_rset_member_id].mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode CSharpScript::get_rset_mode(const StringName &p_variable) const {
|
||||||
|
return get_rset_mode_by_id(get_rset_property_id(p_variable));
|
||||||
|
}
|
||||||
|
|
||||||
Error CSharpScript::load_source_code(const String &p_path) {
|
Error CSharpScript::load_source_code(const String &p_path) {
|
||||||
|
|
||||||
Error ferr = read_all_file_utf8(p_path, source);
|
Error ferr = read_all_file_utf8(p_path, source);
|
||||||
|
|||||||
@@ -113,6 +113,9 @@ class CSharpScript : public Script {
|
|||||||
Map<StringName, Vector<Argument> > _signals;
|
Map<StringName, Vector<Argument> > _signals;
|
||||||
bool signals_invalidated;
|
bool signals_invalidated;
|
||||||
|
|
||||||
|
Vector<ScriptNetData> rpc_functions;
|
||||||
|
Vector<ScriptNetData> rpc_variables;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
List<PropertyInfo> exported_members_cache; // members_cache
|
List<PropertyInfo> exported_members_cache; // members_cache
|
||||||
Map<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
|
Map<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
|
||||||
@@ -146,6 +149,8 @@ class CSharpScript : public Script {
|
|||||||
static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native);
|
static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native);
|
||||||
static void initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native);
|
static void initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native);
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode _member_get_rpc_mode(IMonoClassMember *p_member) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
@@ -187,6 +192,18 @@ public:
|
|||||||
|
|
||||||
virtual int get_member_line(const StringName &p_member) const;
|
virtual int get_member_line(const StringName &p_member) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rpc_methods() const;
|
||||||
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
|
||||||
|
virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const;
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
|
||||||
|
virtual StringName get_rset_property(const uint16_t p_variable_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
virtual bool is_placeholder_fallback_enabled() const { return placeholder_fallback_enabled; }
|
virtual bool is_placeholder_fallback_enabled() const { return placeholder_fallback_enabled; }
|
||||||
#endif
|
#endif
|
||||||
@@ -232,8 +249,6 @@ class CSharpInstance : public ScriptInstance {
|
|||||||
|
|
||||||
void _call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount);
|
void _call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount);
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode _member_get_rpc_mode(IMonoClassMember *p_member) const;
|
|
||||||
|
|
||||||
void get_properties_state_for_reloading(List<Pair<StringName, Variant> > &r_state);
|
void get_properties_state_for_reloading(List<Pair<StringName, Variant> > &r_state);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -265,7 +280,16 @@ public:
|
|||||||
virtual void refcount_incremented();
|
virtual void refcount_incremented();
|
||||||
virtual bool refcount_decremented();
|
virtual bool refcount_decremented();
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rpc_methods() const;
|
||||||
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
|
||||||
|
virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
|
||||||
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const;
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
|
||||||
|
virtual StringName get_rset_property(const uint16_t p_variable_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const;
|
||||||
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
||||||
|
|
||||||
virtual void notification(int p_notification);
|
virtual void notification(int p_notification);
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include "visual_script.h"
|
#include "visual_script.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "core/core_string_names.h"
|
#include "core/core_string_names.h"
|
||||||
#include "core/os/os.h"
|
#include "core/os/os.h"
|
||||||
#include "core/project_settings.h"
|
#include "core/project_settings.h"
|
||||||
@@ -1102,6 +1104,60 @@ bool VisualScript::are_subnodes_edited() const {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Vector<ScriptNetData> VisualScript::get_rpc_methods() const {
|
||||||
|
return rpc_functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t VisualScript::get_rpc_method_id(const StringName &p_method) const {
|
||||||
|
for (int i = 0; i < rpc_functions.size(); i++) {
|
||||||
|
if (rpc_functions[i].name == p_method) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName VisualScript::get_rpc_method(const uint16_t p_rpc_method_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName());
|
||||||
|
return rpc_functions[p_rpc_method_id].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode VisualScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
|
||||||
|
return rpc_functions[p_rpc_method_id].mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode VisualScript::get_rpc_mode(const StringName &p_method) const {
|
||||||
|
return get_rpc_mode_by_id(get_rpc_method_id(p_method));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> VisualScript::get_rset_properties() const {
|
||||||
|
return rpc_variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t VisualScript::get_rset_property_id(const StringName &p_variable) const {
|
||||||
|
for (int i = 0; i < rpc_variables.size(); i++) {
|
||||||
|
if (rpc_variables[i].name == p_variable) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName VisualScript::get_rset_property(const uint16_t p_rset_property_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_rset_property_id >= rpc_variables.size(), StringName());
|
||||||
|
return rpc_variables[p_rset_property_id].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode VisualScript::get_rset_mode_by_id(const uint16_t p_rset_variable_id) const {
|
||||||
|
ERR_FAIL_COND_V(p_rset_variable_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
|
||||||
|
return rpc_functions[p_rset_variable_id].mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode VisualScript::get_rset_mode(const StringName &p_variable) const {
|
||||||
|
return get_rset_mode_by_id(get_rset_property_id(p_variable));
|
||||||
|
}
|
||||||
|
|
||||||
void VisualScript::_set_data(const Dictionary &p_data) {
|
void VisualScript::_set_data(const Dictionary &p_data) {
|
||||||
|
|
||||||
Dictionary d = p_data;
|
Dictionary d = p_data;
|
||||||
@@ -1206,6 +1262,30 @@ void VisualScript::_set_data(const Dictionary &p_data) {
|
|||||||
is_tool_script = d["is_tool_script"];
|
is_tool_script = d["is_tool_script"];
|
||||||
else
|
else
|
||||||
is_tool_script = false;
|
is_tool_script = false;
|
||||||
|
|
||||||
|
// Takes all the rpc methods
|
||||||
|
rpc_functions.clear();
|
||||||
|
rpc_variables.clear();
|
||||||
|
for (Map<StringName, Function>::Element *E = functions.front(); E; E = E->next()) {
|
||||||
|
if (E->get().function_id >= 0 && E->get().nodes.find(E->get().function_id)) {
|
||||||
|
Ref<VisualScriptFunction> vsf = E->get().nodes[E->get().function_id].node;
|
||||||
|
if (vsf.is_valid()) {
|
||||||
|
if (vsf->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) {
|
||||||
|
ScriptNetData nd;
|
||||||
|
nd.name = E->key();
|
||||||
|
nd.mode = vsf->get_rpc_mode();
|
||||||
|
if (rpc_functions.find(nd) == -1) {
|
||||||
|
rpc_functions.push_back(nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visual script doesn't have rset :(
|
||||||
|
|
||||||
|
// Sort so we are 100% that they are always the same.
|
||||||
|
rpc_functions.sort_custom<SortNetData>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary VisualScript::_get_data() const {
|
Dictionary VisualScript::_get_data() const {
|
||||||
@@ -2043,31 +2123,44 @@ Ref<Script> VisualScriptInstance::get_script() const {
|
|||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<ScriptNetData> VisualScriptInstance::get_rpc_methods() const {
|
||||||
|
return script->get_rpc_methods();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t VisualScriptInstance::get_rpc_method_id(const StringName &p_method) const {
|
||||||
|
return script->get_rpc_method_id(p_method);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName VisualScriptInstance::get_rpc_method(const uint16_t p_rpc_method_id) const {
|
||||||
|
return script->get_rpc_method(p_rpc_method_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
|
||||||
|
return script->get_rpc_mode_by_id(p_rpc_method_id);
|
||||||
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode(const StringName &p_method) const {
|
MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode(const StringName &p_method) const {
|
||||||
|
return script->get_rpc_mode(p_method);
|
||||||
if (p_method == script->get_default_func())
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
|
||||||
|
|
||||||
const Map<StringName, VisualScript::Function>::Element *E = script->functions.find(p_method);
|
|
||||||
if (!E) {
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (E->get().function_id >= 0 && E->get().nodes.has(E->get().function_id)) {
|
Vector<ScriptNetData> VisualScriptInstance::get_rset_properties() const {
|
||||||
|
return script->get_rset_properties();
|
||||||
Ref<VisualScriptFunction> vsf = E->get().nodes[E->get().function_id].node;
|
|
||||||
if (vsf.is_valid()) {
|
|
||||||
|
|
||||||
return vsf->get_rpc_mode();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
uint16_t VisualScriptInstance::get_rset_property_id(const StringName &p_variable) const {
|
||||||
|
return script->get_rset_property_id(p_variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName VisualScriptInstance::get_rset_property(const uint16_t p_rset_property_id) const {
|
||||||
|
return script->get_rset_property(p_rset_property_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode VisualScriptInstance::get_rset_mode_by_id(const uint16_t p_rset_variable_id) const {
|
||||||
|
return script->get_rset_mode_by_id(p_rset_variable_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiplayerAPI::RPCMode VisualScriptInstance::get_rset_mode(const StringName &p_variable) const {
|
MultiplayerAPI::RPCMode VisualScriptInstance::get_rset_mode(const StringName &p_variable) const {
|
||||||
|
return script->get_rset_mode(p_variable);
|
||||||
return MultiplayerAPI::RPC_MODE_DISABLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_owner) {
|
void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_owner) {
|
||||||
|
|||||||
@@ -245,6 +245,8 @@ private:
|
|||||||
Map<StringName, Function> functions;
|
Map<StringName, Function> functions;
|
||||||
Map<StringName, Variable> variables;
|
Map<StringName, Variable> variables;
|
||||||
Map<StringName, Vector<Argument> > custom_signals;
|
Map<StringName, Vector<Argument> > custom_signals;
|
||||||
|
Vector<ScriptNetData> rpc_functions;
|
||||||
|
Vector<ScriptNetData> rpc_variables;
|
||||||
|
|
||||||
Map<Object *, VisualScriptInstance *> instances;
|
Map<Object *, VisualScriptInstance *> instances;
|
||||||
|
|
||||||
@@ -362,6 +364,18 @@ public:
|
|||||||
|
|
||||||
virtual int get_member_line(const StringName &p_member) const;
|
virtual int get_member_line(const StringName &p_member) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rpc_methods() const;
|
||||||
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
|
||||||
|
virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const;
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_property) const;
|
||||||
|
virtual StringName get_rset_property(const uint16_t p_rset_property_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
virtual bool are_subnodes_edited() const;
|
virtual bool are_subnodes_edited() const;
|
||||||
#endif
|
#endif
|
||||||
@@ -441,7 +455,16 @@ public:
|
|||||||
|
|
||||||
virtual ScriptLanguage *get_language();
|
virtual ScriptLanguage *get_language();
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rpc_methods() const;
|
||||||
|
virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
|
||||||
|
virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
|
||||||
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
|
||||||
|
|
||||||
|
virtual Vector<ScriptNetData> get_rset_properties() const;
|
||||||
|
virtual uint16_t get_rset_property_id(const StringName &p_property) const;
|
||||||
|
virtual StringName get_rset_property(const uint16_t p_rset_property_id) const;
|
||||||
|
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const;
|
||||||
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
||||||
|
|
||||||
VisualScriptInstance();
|
VisualScriptInstance();
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "core/core_string_names.h"
|
#include "core/core_string_names.h"
|
||||||
#include "core/io/resource_loader.h"
|
#include "core/io/resource_loader.h"
|
||||||
#include "core/message_queue.h"
|
#include "core/message_queue.h"
|
||||||
@@ -498,22 +500,38 @@ bool Node::is_network_master() const {
|
|||||||
|
|
||||||
/***** RPC CONFIG ********/
|
/***** RPC CONFIG ********/
|
||||||
|
|
||||||
void Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode) {
|
uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode) {
|
||||||
|
|
||||||
if (p_mode == MultiplayerAPI::RPC_MODE_DISABLED) {
|
uint16_t mid = get_node_rpc_method_id(p_method);
|
||||||
data.rpc_methods.erase(p_method);
|
if (mid == UINT16_MAX) {
|
||||||
|
// It's new
|
||||||
|
NetData nd;
|
||||||
|
nd.name = p_method;
|
||||||
|
nd.mode = p_mode;
|
||||||
|
data.rpc_methods.push_back(nd);
|
||||||
|
return ((uint16_t)data.rpc_properties.size() - 1) | (1 << 15);
|
||||||
} else {
|
} else {
|
||||||
data.rpc_methods[p_method] = p_mode;
|
int c_mid = (~(1 << 15)) & mid;
|
||||||
};
|
data.rpc_methods.write[c_mid].mode = p_mode;
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode) {
|
uint16_t Node::rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode) {
|
||||||
|
|
||||||
if (p_mode == MultiplayerAPI::RPC_MODE_DISABLED) {
|
uint16_t pid = get_node_rset_property_id(p_property);
|
||||||
data.rpc_properties.erase(p_property);
|
if (pid == UINT16_MAX) {
|
||||||
|
// It's new
|
||||||
|
NetData nd;
|
||||||
|
nd.name = p_property;
|
||||||
|
nd.mode = p_mode;
|
||||||
|
data.rpc_properties.push_back(nd);
|
||||||
|
return ((uint16_t)data.rpc_properties.size() - 1) | (1 << 15);
|
||||||
} else {
|
} else {
|
||||||
data.rpc_properties[p_property] = p_mode;
|
int c_pid = (~(1 << 15)) & pid;
|
||||||
};
|
data.rpc_properties.write[c_pid].mode = p_mode;
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** RPC FUNCTIONS ********/
|
/***** RPC FUNCTIONS ********/
|
||||||
@@ -731,12 +749,94 @@ void Node::set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {
|
|||||||
multiplayer = p_multiplayer;
|
multiplayer = p_multiplayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Map<StringName, MultiplayerAPI::RPCMode>::Element *Node::get_node_rpc_mode(const StringName &p_method) {
|
uint16_t Node::get_node_rpc_method_id(const StringName &p_method) const {
|
||||||
return data.rpc_methods.find(p_method);
|
for (int i = 0; i < data.rpc_methods.size(); i++) {
|
||||||
|
if (data.rpc_methods[i].name == p_method) {
|
||||||
|
// Returns `i` with the high bit set to 1 so we know that this id comes
|
||||||
|
// from the node and not the script.
|
||||||
|
return i | (1 << 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UINT16_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Map<StringName, MultiplayerAPI::RPCMode>::Element *Node::get_node_rset_mode(const StringName &p_property) {
|
StringName Node::get_node_rpc_method(const uint16_t p_rpc_method_id) const {
|
||||||
return data.rpc_properties.find(p_property);
|
// Make sure this is a node generated ID.
|
||||||
|
if (((1 << 15) & p_rpc_method_id) > 0) {
|
||||||
|
int mid = (~(1 << 15)) & p_rpc_method_id;
|
||||||
|
if (mid < data.rpc_methods.size())
|
||||||
|
return data.rpc_methods[mid].name;
|
||||||
|
}
|
||||||
|
return StringName();
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode Node::get_node_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
|
||||||
|
// Make sure this is a node generated ID.
|
||||||
|
if (((1 << 15) & p_rpc_method_id) > 0) {
|
||||||
|
int mid = (~(1 << 15)) & p_rpc_method_id;
|
||||||
|
if (mid < data.rpc_methods.size())
|
||||||
|
return data.rpc_methods[mid].mode;
|
||||||
|
}
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode Node::get_node_rpc_mode(const StringName &p_method) const {
|
||||||
|
return get_node_rpc_mode_by_id(get_node_rpc_method_id(p_method));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Node::get_node_rset_property_id(const StringName &p_property) const {
|
||||||
|
for (int i = 0; i < data.rpc_properties.size(); i++) {
|
||||||
|
if (data.rpc_properties[i].name == p_property) {
|
||||||
|
// Returns `i` with the high bit set to 1 so we know that this id comes
|
||||||
|
// from the node and not the script.
|
||||||
|
return i | (1 << 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName Node::get_node_rset_property(const uint16_t p_rset_property_id) const {
|
||||||
|
// Make sure this is a node generated ID.
|
||||||
|
if (((1 << 15) & p_rset_property_id) > 0) {
|
||||||
|
int mid = (~(1 << 15)) & p_rset_property_id;
|
||||||
|
if (mid < data.rpc_properties.size())
|
||||||
|
return data.rpc_properties[mid].name;
|
||||||
|
}
|
||||||
|
return StringName();
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode Node::get_node_rset_mode_by_id(const uint16_t p_rset_property_id) const {
|
||||||
|
if (((1 << 15) & p_rset_property_id) > 0) {
|
||||||
|
int mid = (~(1 << 15)) & p_rset_property_id;
|
||||||
|
if (mid < data.rpc_properties.size())
|
||||||
|
return data.rpc_properties[mid].mode;
|
||||||
|
}
|
||||||
|
return MultiplayerAPI::RPC_MODE_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiplayerAPI::RPCMode Node::get_node_rset_mode(const StringName &p_property) const {
|
||||||
|
return get_node_rset_mode_by_id(get_node_rset_property_id(p_property));
|
||||||
|
}
|
||||||
|
|
||||||
|
String Node::get_rpc_md5() const {
|
||||||
|
String rpc_list;
|
||||||
|
for (int i = 0; i < data.rpc_methods.size(); i += 1) {
|
||||||
|
rpc_list += String(data.rpc_methods[i].name);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < data.rpc_properties.size(); i += 1) {
|
||||||
|
rpc_list += String(data.rpc_properties[i].name);
|
||||||
|
}
|
||||||
|
if (get_script_instance()) {
|
||||||
|
Vector<ScriptNetData> rpc = get_script_instance()->get_rpc_methods();
|
||||||
|
for (int i = 0; i < rpc.size(); i += 1) {
|
||||||
|
rpc_list += String(rpc[i].name);
|
||||||
|
}
|
||||||
|
rpc = get_script_instance()->get_rset_properties();
|
||||||
|
for (int i = 0; i < rpc.size(); i += 1) {
|
||||||
|
rpc_list += String(rpc[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rpc_list.md5_text();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Node::can_process_notification(int p_what) const {
|
bool Node::can_process_notification(int p_what) const {
|
||||||
|
|||||||
@@ -85,6 +85,11 @@ private:
|
|||||||
GroupData() { persistent = false; }
|
GroupData() { persistent = false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NetData {
|
||||||
|
StringName name;
|
||||||
|
MultiplayerAPI::RPCMode mode;
|
||||||
|
};
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
|
|
||||||
String filename;
|
String filename;
|
||||||
@@ -118,8 +123,8 @@ private:
|
|||||||
Node *pause_owner;
|
Node *pause_owner;
|
||||||
|
|
||||||
int network_master;
|
int network_master;
|
||||||
Map<StringName, MultiplayerAPI::RPCMode> rpc_methods;
|
Vector<NetData> rpc_methods;
|
||||||
Map<StringName, MultiplayerAPI::RPCMode> rpc_properties;
|
Vector<NetData> rpc_properties;
|
||||||
|
|
||||||
// variables used to properly sort the node when processing, ignored otherwise
|
// variables used to properly sort the node when processing, ignored otherwise
|
||||||
//should move all the stuff below to bits
|
//should move all the stuff below to bits
|
||||||
@@ -427,8 +432,8 @@ public:
|
|||||||
int get_network_master() const;
|
int get_network_master() const;
|
||||||
bool is_network_master() const;
|
bool is_network_master() const;
|
||||||
|
|
||||||
void rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode); // config a local method for RPC
|
uint16_t rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode); // config a local method for RPC
|
||||||
void rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode); // config a local property for RPC
|
uint16_t rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode); // config a local property for RPC
|
||||||
|
|
||||||
void rpc(const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
|
void rpc(const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
|
||||||
void rpc_unreliable(const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
|
void rpc_unreliable(const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
|
||||||
@@ -446,8 +451,22 @@ public:
|
|||||||
Ref<MultiplayerAPI> get_multiplayer() const;
|
Ref<MultiplayerAPI> get_multiplayer() const;
|
||||||
Ref<MultiplayerAPI> get_custom_multiplayer() const;
|
Ref<MultiplayerAPI> get_custom_multiplayer() const;
|
||||||
void set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
|
void set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
|
||||||
const Map<StringName, MultiplayerAPI::RPCMode>::Element *get_node_rpc_mode(const StringName &p_method);
|
|
||||||
const Map<StringName, MultiplayerAPI::RPCMode>::Element *get_node_rset_mode(const StringName &p_property);
|
/// Returns the rpc method ID, otherwise UINT32_MAX
|
||||||
|
uint16_t get_node_rpc_method_id(const StringName &p_method) const;
|
||||||
|
StringName get_node_rpc_method(const uint16_t p_rpc_method_id) const;
|
||||||
|
MultiplayerAPI::RPCMode get_node_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
|
||||||
|
MultiplayerAPI::RPCMode get_node_rpc_mode(const StringName &p_method) const;
|
||||||
|
|
||||||
|
/// Returns the rpc property ID, otherwise UINT32_MAX
|
||||||
|
uint16_t get_node_rset_property_id(const StringName &p_property) const;
|
||||||
|
StringName get_node_rset_property(const uint16_t p_rset_property_id) const;
|
||||||
|
MultiplayerAPI::RPCMode get_node_rset_mode_by_id(const uint16_t p_rpc_method_id) const;
|
||||||
|
MultiplayerAPI::RPCMode get_node_rset_mode(const StringName &p_property) const;
|
||||||
|
|
||||||
|
/// Can be used to check if the rpc methods and the rset properties are the
|
||||||
|
/// same across the peers.
|
||||||
|
String get_rpc_md5() const;
|
||||||
|
|
||||||
Node();
|
Node();
|
||||||
~Node();
|
~Node();
|
||||||
|
|||||||
Reference in New Issue
Block a user