[Net] Refactor RPCs, remove RSETs

In this PR:
- Removed rset
- rpc_config can now optionally configure transfer mode
  (reliable/unreliable/ordered) and channel (channels are not actually
  implemented yet.)
- Refactor how the RPC id is computed to minimize the logic in Node and
  scripts that now only needs a single `get_rpc_methods` function.
This commit is contained in:
Fabio Alessandrelli 2021-05-26 14:07:57 +02:00
parent 0aabfb341a
commit d779b5aa3e
23 changed files with 251 additions and 1545 deletions

View file

@ -44,6 +44,56 @@
#include "core/os/os.h"
#endif
String _get_rpc_md5(const Node *p_node) {
String rpc_list;
const Vector<MultiplayerAPI::RPCConfig> node_config = p_node->get_node_rpc_methods();
for (int i = 0; i < node_config.size(); i++) {
rpc_list += String(node_config[i].name);
}
if (p_node->get_script_instance()) {
const Vector<MultiplayerAPI::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods();
for (int i = 0; i < script_config.size(); i++) {
rpc_list += String(script_config[i].name);
}
}
return rpc_list.md5_text();
}
const MultiplayerAPI::RPCConfig _get_rpc_config(const Node *p_node, const StringName &p_method, uint16_t &r_id) {
const Vector<MultiplayerAPI::RPCConfig> node_config = p_node->get_node_rpc_methods();
for (int i = 0; i < node_config.size(); i++) {
if (node_config[i].name == p_method) {
r_id = ((uint16_t)i) & (1 << 15);
return node_config[i];
}
}
if (p_node->get_script_instance()) {
const Vector<MultiplayerAPI::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods();
for (int i = 0; i < script_config.size(); i++) {
if (script_config[i].name == p_method) {
r_id = (uint16_t)i;
return script_config[i];
}
}
}
return MultiplayerAPI::RPCConfig();
}
const MultiplayerAPI::RPCConfig _get_rpc_config_by_id(Node *p_node, uint16_t p_id) {
Vector<MultiplayerAPI::RPCConfig> config;
uint16_t id = p_id;
if (id & (1 << 15)) {
id = id & ~(1 << 15);
config = p_node->get_node_rpc_methods();
} else {
config = p_node->get_script_instance()->get_rpc_methods();
}
if (id < config.size()) {
return config[p_id];
}
return MultiplayerAPI::RPCConfig();
}
_FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_master, bool &r_skip_rpc) {
switch (mode) {
case MultiplayerAPI::RPC_MODE_DISABLED: {
@ -231,8 +281,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
_process_confirm_path(p_from, p_packet, p_packet_len);
} break;
case NETWORK_COMMAND_REMOTE_CALL:
case NETWORK_COMMAND_REMOTE_SET: {
case NETWORK_COMMAND_REMOTE_CALL: {
// Extract packet meta
int packet_min_size = 1;
int name_id_offset = 1;
@ -302,13 +351,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
}
const int packet_len = get_packet_len(node_target, p_packet_len);
if (packet_type == NETWORK_COMMAND_REMOTE_CALL) {
_process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size);
} else {
_process_rset(node, name_id, p_from, p_packet, packet_len, packet_min_size);
}
_process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size);
} break;
case NETWORK_COMMAND_RAW: {
@ -362,16 +405,11 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id,
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.
StringName name = p_node->get_node_rpc_method(p_rpc_method_id);
RPCMode rpc_mode = p_node->get_node_rpc_mode_by_id(p_rpc_method_id);
if (name == StringName() && p_node->get_script_instance()) {
name = p_node->get_script_instance()->get_rpc_method(p_rpc_method_id);
rpc_mode = p_node->get_script_instance()->get_rpc_mode_by_id(p_rpc_method_id);
}
ERR_FAIL_COND(name == StringName());
const RPCConfig config = _get_rpc_config_by_id(p_node, p_rpc_method_id);
ERR_FAIL_COND(config.name == StringName());
bool can_call = _can_call_mode(p_node, rpc_mode, p_from);
ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
bool can_call = _can_call_mode(p_node, config.rpc_mode, p_from);
ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(config.name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)config.rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
int argc = 0;
bool byte_only = false;
@ -424,47 +462,14 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id,
Callable::CallError ce;
p_node->call(name, (const Variant **)argp.ptr(), argc, ce);
p_node->call(config.name, (const Variant **)argp.ptr(), argc, ce);
if (ce.error != Callable::CallError::CALL_OK) {
String error = Variant::get_call_error_text(p_node, name, (const Variant **)argp.ptr(), argc, ce);
String error = Variant::get_call_error_text(p_node, config.name, (const Variant **)argp.ptr(), argc, ce);
error = "RPC - " + error;
ERR_PRINT(error);
}
}
void MultiplayerAPI::_process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) {
ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
// Check that remote can call the RSET on this node.
StringName name = p_node->get_node_rset_property(p_rpc_property_id);
RPCMode rset_mode = p_node->get_node_rset_mode_by_id(p_rpc_property_id);
if (name == StringName() && p_node->get_script_instance()) {
name = p_node->get_script_instance()->get_rset_property(p_rpc_property_id);
rset_mode = p_node->get_script_instance()->get_rset_mode_by_id(p_rpc_property_id);
}
ERR_FAIL_COND(name == StringName());
bool can_call = _can_call_mode(p_node, rset_mode, p_from);
ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(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
_profile_node_data("in_rset", p_node->get_instance_id());
#endif
Variant value;
Error err = _decode_and_decompress_variant(value, &p_packet[p_offset], p_packet_len - p_offset, nullptr);
ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RSET value.");
bool valid;
p_node->set(name, value, &valid);
if (!valid) {
String error = "Error setting remote property '" + String(name) + "', not found in object of type " + p_node->get_class() + ".";
ERR_PRINT(error);
}
}
void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) {
ERR_FAIL_COND_MSG(p_packet_len < 38, "Invalid packet received. Size too small.");
int ofs = 1;
@ -487,7 +492,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
Node *node = root_node->get_node(path);
ERR_FAIL_COND(node == nullptr);
const bool valid_rpc_checksum = node->get_rpc_md5() == methods_md5;
const bool valid_rpc_checksum = _get_rpc_md5(node) == 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);
}
@ -569,7 +574,7 @@ bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentC
const int path_len = encode_cstring(path.get_data(), nullptr);
// Extract MD5 from rpc methods list.
const String methods_md5 = p_node->get_rpc_md5();
const String methods_md5 = _get_rpc_md5(p_node);
const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder.
Vector<uint8_t> packet;
@ -752,7 +757,7 @@ Error MultiplayerAPI::_decode_and_decompress_variant(Variant &r_variant, const u
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, uint16_t p_rpc_id, const RPCConfig &p_config, 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->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING, "Attempt to remote call/set when networking is not connected yet in SceneTree.");
@ -797,7 +802,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
// - `NetworkNameIdCompression` in the next 1 bit.
// - `byte_only_or_no_args` in the next 1 bit.
// - So we still have the last bit free!
uint8_t command_type = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL;
uint8_t command_type = NETWORK_COMMAND_REMOTE_CALL;
uint8_t node_id_compression = UINT8_MAX;
uint8_t name_id_compression = UINT8_MAX;
bool byte_only_or_no_args = false;
@ -837,81 +842,42 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
ofs += 4;
}
if (p_set) {
// Take the rpc property ID
uint16_t property_id = p_from->get_node_rset_property_id(p_name);
if (property_id == UINT16_MAX && p_from->get_script_instance()) {
property_id = p_from->get_script_instance()->get_rset_property_id(p_name);
}
ERR_FAIL_COND_MSG(property_id == UINT16_MAX, "Unable to take the `property_id` for the property:" + p_name + ". This can only happen 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.
int len(0);
Error err = _encode_and_compress_variant(*p_arg[0], nullptr, len);
ERR_FAIL_COND_MSG(err != OK, "Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!");
MAKE_ROOM(ofs + len);
_encode_and_compress_variant(*p_arg[0], &(packet_cache.write[ofs]), len);
ofs += len;
// Encode method ID
if (p_rpc_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>(p_rpc_id);
ofs += 1;
} 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,
vformat("Unable to take the `method_id` for the function \"%s\" at path: \"%s\". This happens when the method is not marked as `remote`.", p_name, p_from->get_path()));
// The ID is larger, let's use 2 bytes
name_id_compression = NETWORK_NAME_ID_COMPRESSION_16;
MAKE_ROOM(ofs + 2);
encode_uint16(p_rpc_id, &(packet_cache.write[ofs]));
ofs += 2;
}
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;
}
if (p_argcount == 0) {
byte_only_or_no_args = true;
} else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) {
byte_only_or_no_args = true;
// Special optimization when only the byte vector is sent.
const Vector<uint8_t> data = *p_arg[0];
MAKE_ROOM(ofs + data.size());
memcpy(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size());
ofs += data.size();
} else {
// Arguments
MAKE_ROOM(ofs + 1);
packet_cache.write[ofs] = p_argcount;
ofs += 1;
for (int i = 0; i < p_argcount; i++) {
int len(0);
Error err = _encode_and_compress_variant(*p_arg[i], nullptr, len);
ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!");
MAKE_ROOM(ofs + len);
_encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len);
ofs += len;
}
if (p_argcount == 0) {
byte_only_or_no_args = true;
} else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) {
byte_only_or_no_args = true;
// Special optimization when only the byte vector is sent.
const Vector<uint8_t> data = *p_arg[0];
MAKE_ROOM(ofs + data.size());
memcpy(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size());
ofs += data.size();
} else {
// Arguments
MAKE_ROOM(ofs + 1);
packet_cache.write[ofs] = p_argcount;
ofs += 1;
for (int i = 0; i < p_argcount; i++) {
int len(0);
Error err = _encode_and_compress_variant(*p_arg[i], nullptr, len);
ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!");
MAKE_ROOM(ofs + len);
_encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len);
ofs += len;
}
}
@ -927,7 +893,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
#endif
// 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_config.transfer_mode);
if (has_all_peers) {
// They all have verified paths, so send fast.
@ -1015,19 +981,15 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
bool call_local_native = false;
bool call_local_script = false;
bool is_master = p_node->is_network_master();
uint16_t rpc_id = UINT16_MAX;
const RPCConfig config = _get_rpc_config(p_node, p_method, rpc_id);
ERR_FAIL_COND_MSG(config.name == StringName(),
vformat("Unable to get the RPC configuration for the function \"%s\" at path: \"%s\". This happens when the method is not marked for RPCs.", p_method, p_node->get_path()));
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.
RPCMode rpc_mode = p_node->get_node_rpc_mode(p_method);
call_local_native = _should_call_local(rpc_mode, is_master, skip_rpc);
if (call_local_native) {
// Done below.
} else if (p_node->get_script_instance()) {
// Attempt with script.
rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method);
call_local_script = _should_call_local(rpc_mode, is_master, skip_rpc);
if (rpc_id & (1 << 15)) {
call_local_native = _should_call_local(config.rpc_mode, is_master, skip_rpc);
} else {
call_local_script = _should_call_local(config.rpc_mode, is_master, skip_rpc);
}
}
@ -1036,7 +998,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
_profile_node_data("out_rpc", p_node->get_instance_id());
#endif
_send_rpc(p_node, p_peer_id, p_unreliable, false, p_method, p_arg, p_argcount);
_send_rpc(p_node, p_peer_id, rpc_id, config, p_method, p_arg, p_argcount);
}
if (call_local_native) {
@ -1071,70 +1033,6 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
ERR_FAIL_COND_MSG(skip_rpc && !(call_local_native || call_local_script), "RPC '" + p_method + "' on yourself is not allowed by selected mode.");
}
void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) {
ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to RSET while no network peer is active.");
ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to RSET on a node which is not inside SceneTree.");
ERR_FAIL_COND_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, "Trying to send an RSET via a network peer which is not connected.");
int node_id = network_peer->get_unique_id();
bool is_master = p_node->is_network_master();
bool skip_rset = node_id == p_peer_id;
bool set_local = false;
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.
RPCMode rpc_mode = p_node->get_node_rset_mode(p_property);
set_local = _should_call_local(rpc_mode, is_master, skip_rset);
if (set_local) {
bool valid;
int temp_id = rpc_sender_id;
rpc_sender_id = get_network_unique_id();
p_node->set(p_property, p_value, &valid);
rpc_sender_id = temp_id;
if (!valid) {
String error = "rset() aborted in local set, property not found: - " + String(p_property) + ".";
ERR_PRINT(error);
return;
}
} else if (p_node->get_script_instance()) {
// Attempt with script.
rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property);
set_local = _should_call_local(rpc_mode, is_master, skip_rset);
if (set_local) {
int temp_id = rpc_sender_id;
rpc_sender_id = get_network_unique_id();
bool valid = p_node->get_script_instance()->set(p_property, p_value);
rpc_sender_id = temp_id;
if (!valid) {
String error = "rset() aborted in local script set, property not found: - " + String(p_property) + ".";
ERR_PRINT(error);
return;
}
}
}
}
if (skip_rset) {
ERR_FAIL_COND_MSG(!set_local, "RSET for '" + p_property + "' on yourself is not allowed by selected mode.");
return;
}
#ifdef DEBUG_ENABLED
_profile_node_data("out_rset", p_node->get_instance_id());
#endif
const Variant *vptr = &p_value;
_send_rpc(p_node, p_peer_id, p_unreliable, true, p_property, &vptr, 1);
}
Error MultiplayerAPI::send_bytes(Vector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) {
ERR_FAIL_COND_V_MSG(p_data.size() < 1, ERR_INVALID_DATA, "Trying to send an empty raw packet.");
ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), ERR_UNCONFIGURED, "Trying to send a raw packet while no network peer is active.");

View file

@ -37,6 +37,35 @@
class MultiplayerAPI : public Reference {
GDCLASS(MultiplayerAPI, Reference);
public:
enum RPCMode {
RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default)
RPC_MODE_REMOTE, // Using rpc() on it will call method in all remote peers
RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote
RPC_MODE_PUPPET, // Using rpc() on it will call method for all puppets
RPC_MODE_REMOTESYNC, // Using rpc() on it will call method in all remote peers and locally
RPC_MODE_MASTERSYNC, // Using rpc() on it will call method in the master peer and locally
RPC_MODE_PUPPETSYNC, // Using rpc() on it will call method in all puppets peers and locally
};
struct RPCConfig {
StringName name;
RPCMode rpc_mode = RPC_MODE_DISABLED;
NetworkedMultiplayerPeer::TransferMode transfer_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE;
int channel = 0;
bool operator==(RPCConfig const &p_other) const {
return name == p_other.name;
}
};
struct SortRPCConfig {
StringName::AlphCompare compare;
bool operator()(const RPCConfig &p_a, const RPCConfig &p_b) const {
return compare(p_a.name, p_b.name);
}
};
private:
//path sent caches
struct PathSentCache {
@ -72,10 +101,9 @@ protected:
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, uint32_t p_node_target, int p_packet_len);
void _process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
void _process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
void _process_raw(int p_from, const uint8_t *p_packet, int p_packet_len);
void _send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount);
void _send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount);
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);
@ -84,7 +112,6 @@ protected:
public:
enum NetworkCommands {
NETWORK_COMMAND_REMOTE_CALL = 0,
NETWORK_COMMAND_REMOTE_SET,
NETWORK_COMMAND_SIMPLIFY_PATH,
NETWORK_COMMAND_CONFIRM_PATH,
NETWORK_COMMAND_RAW,
@ -101,16 +128,6 @@ public:
NETWORK_NAME_ID_COMPRESSION_16,
};
enum RPCMode {
RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default)
RPC_MODE_REMOTE, // Using rpc() on it will call method / set property in all remote peers
RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote
RPC_MODE_PUPPET, // Using rpc() on it will call method for all puppets
RPC_MODE_REMOTESYNC, // Using rpc() on it will call method / set property in all remote peers and locally
RPC_MODE_MASTERSYNC, // Using rpc() on it will call method / set property in the master peer and locally
RPC_MODE_PUPPETSYNC, // Using rpc() on it will call method / set property in all puppets peers and locally
};
void poll();
void clear();
void set_root_node(Node *p_node);
@ -121,8 +138,6 @@ public:
// Called by Node.rpc
void rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount);
// Called by Node.rset
void rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value);
void _add_peer(int p_id);
void _del_peer(int p_id);

View file

@ -585,14 +585,6 @@ Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_nam
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) :
owner(p_owner),
language(p_language),

View file

@ -41,21 +41,6 @@ class ScriptLanguage;
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 {
enum {
MAX_LANGUAGES = 16
@ -174,17 +159,7 @@ public:
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;
virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0;
Script() {}
};
@ -225,17 +200,7 @@ public:
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 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 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 const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0;
virtual ScriptLanguage *get_language() = 0;
virtual ~ScriptInstance();
@ -445,17 +410,7 @@ public:
virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr);
virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = nullptr);
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 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 const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const { return Vector<MultiplayerAPI::RPCConfig>(); }
PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner);
~PlaceHolderScriptInstance();

View file

@ -135,16 +135,16 @@
</signals>
<constants>
<constant name="RPC_MODE_DISABLED" value="0" enum="RPCMode">
Used with [method Node.rpc_config] or [method Node.rset_config] to disable a method or property for all RPC calls, making it unavailable. Default for all methods.
Used with [method Node.rpc_config] to disable a method or property for all RPC calls, making it unavailable. Default for all methods.
</constant>
<constant name="RPC_MODE_REMOTE" value="1" enum="RPCMode">
Used with [method Node.rpc_config] or [method Node.rset_config] to set a method to be called or a property to be changed only on the remote end, not locally. Analogous to the [code]remote[/code] keyword. Calls and property changes are accepted from all remote peers, no matter if they are node's master or puppets.
Used with [method Node.rpc_config] to set a method to be called or a property to be changed only on the remote end, not locally. Analogous to the [code]remote[/code] keyword. Calls and property changes are accepted from all remote peers, no matter if they are node's master or puppets.
</constant>
<constant name="RPC_MODE_MASTER" value="2" enum="RPCMode">
Used with [method Node.rpc_config] or [method Node.rset_config] to set a method to be called or a property to be changed only on the network master for this node. Analogous to the [code]master[/code] keyword. Only accepts calls or property changes from the node's network puppets, see [method Node.set_network_master].
Used with [method Node.rpc_config] to set a method to be called or a property to be changed only on the network master for this node. Analogous to the [code]master[/code] keyword. Only accepts calls or property changes from the node's network puppets, see [method Node.set_network_master].
</constant>
<constant name="RPC_MODE_PUPPET" value="3" enum="RPCMode">
Used with [method Node.rpc_config] or [method Node.rset_config] to set a method to be called or a property to be changed only on puppets for this node. Analogous to the [code]puppet[/code] keyword. Only accepts calls or property changes from the node's network master, see [method Node.set_network_master].
Used with [method Node.rpc_config] to set a method to be called or a property to be changed only on puppets for this node. Analogous to the [code]puppet[/code] keyword. Only accepts calls or property changes from the node's network master, see [method Node.set_network_master].
</constant>
<constant name="RPC_MODE_REMOTESYNC" value="4" enum="RPCMode">
Behave like [constant RPC_MODE_REMOTE] but also make the call or property change locally. Analogous to the [code]remotesync[/code] keyword.

View file

@ -649,7 +649,7 @@
<argument index="0" name="method" type="StringName">
</argument>
<description>
Sends a remote procedure call request for the given [code]method[/code] to peers on the network (and locally), optionally sending all additional arguments as arguments to the method called by the RPC. The call request will only be received by nodes with the same [NodePath], including the exact same node name. Behaviour depends on the RPC configuration for the given method, see [method rpc_config]. Methods are not exposed to RPCs by default. See also [method rset] and [method rset_config] for properties. Returns an empty [Variant].
Sends a remote procedure call request for the given [code]method[/code] to peers on the network (and locally), optionally sending all additional arguments as arguments to the method called by the RPC. The call request will only be received by nodes with the same [NodePath], including the exact same node name. Behaviour depends on the RPC configuration for the given method, see [method rpc_config]. Methods are not exposed to RPCs by default. Returns an empty [Variant].
[b]Note:[/b] You can only safely use RPCs on clients after you received the [code]connected_to_server[/code] signal from the [SceneTree]. You also need to keep track of the connection state, either by the [SceneTree] signals like [code]server_disconnected[/code] or by checking [code]SceneTree.network_peer.get_connection_status() == CONNECTION_CONNECTED[/code].
</description>
</method>
@ -658,10 +658,14 @@
</return>
<argument index="0" name="method" type="StringName">
</argument>
<argument index="1" name="mode" type="int" enum="MultiplayerAPI.RPCMode">
<argument index="1" name="rpc_mode" type="int" enum="MultiplayerAPI.RPCMode">
</argument>
<argument index="2" name="transfer_mode" type="int" enum="NetworkedMultiplayerPeer.TransferMode" default="2">
</argument>
<argument index="3" name="channel" type="int" default="0">
</argument>
<description>
Changes the RPC mode for the given [code]method[/code] to the given [code]mode[/code]. See [enum MultiplayerAPI.RPCMode]. An alternative is annotating methods and properties with the corresponding keywords ([code]remote[/code], [code]master[/code], [code]puppet[/code], [code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code]). By default, methods are not exposed to networking (and RPCs). See also [method rset] and [method rset_config] for properties.
Changes the RPC mode for the given [code]method[/code] to the given [code]rpc_mode[/code], optionally specifying the [code]transfer_mode[/code] and [code]channel[/code] (on supported peers). See [enum MultiplayerAPI.RPCMode] and [enum NetworkedMultiplayerPeer.TransferMode]. An alternative is annotating methods and properties with the corresponding keywords ([code]remote[/code], [code]master[/code], [code]puppet[/code], [code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code]). By default, methods are not exposed to networking (and RPCs).
</description>
</method>
<method name="rpc_id" qualifiers="vararg">
@ -675,85 +679,6 @@
Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]). Returns an empty [Variant].
</description>
</method>
<method name="rpc_unreliable" qualifiers="vararg">
<return type="Variant">
</return>
<argument index="0" name="method" type="StringName">
</argument>
<description>
Sends a [method rpc] using an unreliable protocol. Returns an empty [Variant].
</description>
</method>
<method name="rpc_unreliable_id" qualifiers="vararg">
<return type="Variant">
</return>
<argument index="0" name="peer_id" type="int">
</argument>
<argument index="1" name="method" type="StringName">
</argument>
<description>
Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] using an unreliable protocol (see [method NetworkedMultiplayerPeer.set_target_peer]). Returns an empty [Variant].
</description>
</method>
<method name="rset">
<return type="void">
</return>
<argument index="0" name="property" type="StringName">
</argument>
<argument index="1" name="value" type="Variant">
</argument>
<description>
Remotely changes a property's value on other peers (and locally). Behaviour depends on the RPC configuration for the given property, see [method rset_config]. See also [method rpc] for RPCs for methods, most information applies to this method as well.
</description>
</method>
<method name="rset_config">
<return type="int">
</return>
<argument index="0" name="property" type="StringName">
</argument>
<argument index="1" name="mode" type="int" enum="MultiplayerAPI.RPCMode">
</argument>
<description>
Changes the RPC mode for the given [code]property[/code] to the given [code]mode[/code]. See [enum MultiplayerAPI.RPCMode]. An alternative is annotating methods and properties with the corresponding keywords ([code]remote[/code], [code]master[/code], [code]puppet[/code], [code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code]). By default, properties are not exposed to networking (and RPCs). See also [method rpc] and [method rpc_config] for methods.
</description>
</method>
<method name="rset_id">
<return type="void">
</return>
<argument index="0" name="peer_id" type="int">
</argument>
<argument index="1" name="property" type="StringName">
</argument>
<argument index="2" name="value" type="Variant">
</argument>
<description>
Remotely changes the property's value on a specific peer identified by [code]peer_id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]).
</description>
</method>
<method name="rset_unreliable">
<return type="void">
</return>
<argument index="0" name="property" type="StringName">
</argument>
<argument index="1" name="value" type="Variant">
</argument>
<description>
Remotely changes the property's value on other peers (and locally) using an unreliable protocol.
</description>
</method>
<method name="rset_unreliable_id">
<return type="void">
</return>
<argument index="0" name="peer_id" type="int">
</argument>
<argument index="1" name="property" type="StringName">
</argument>
<argument index="2" name="value" type="Variant">
</argument>
<description>
Remotely changes property's value on a specific peer identified by [code]peer_id[/code] using an unreliable protocol (see [method NetworkedMultiplayerPeer.set_target_peer]).
</description>
</method>
<method name="set_display_folded">
<return type="void">
</return>

View file

@ -70,8 +70,7 @@ void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char
const NativeScriptDesc *b = desc.base_data;
while (b) {
desc.rpc_count += b->rpc_count;
desc.rset_count += b->rset_count;
desc.rpc_methods.append_array(b->rpc_methods);
b = b->base_data;
}
@ -94,8 +93,6 @@ void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const
desc.destroy_func = p_destroy_func;
desc.is_tool = true;
desc.base = p_base;
desc.rpc_count = 0;
desc.rset_count = 0;
if (classes->has(p_base)) {
desc.base_data = &(*classes)[p_base];
@ -103,8 +100,7 @@ void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const
const NativeScriptDesc *b = desc.base_data;
while (b) {
desc.rpc_count += b->rpc_count;
desc.rset_count += b->rset_count;
desc.rpc_methods.append_array(b->rpc_methods);
b = b->base_data;
}
@ -126,13 +122,16 @@ void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const cha
method.method = p_method;
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);
E->get().methods.insert(p_function_name, method);
if (p_attr.rpc_type != GODOT_METHOD_RPC_MODE_DISABLED) {
MultiplayerAPI::RPCConfig nd;
nd.name = String(p_name);
nd.rpc_mode = MultiplayerAPI::RPCMode(p_attr.rpc_type);
E->get().rpc_methods.push_back(nd);
}
}
void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_nativescript_property_attributes *p_attr, godot_nativescript_property_set_func p_set_func, godot_nativescript_property_get_func p_get_func) {
@ -144,11 +143,6 @@ void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const c
NativeScriptDesc::Property property;
property.default_value = *(Variant *)&p_attr->default_value;
property.getter = p_get_func;
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.info = PropertyInfo((Variant::Type)p_attr->type,
p_path,

View file

@ -415,245 +415,11 @@ void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const {
}
}
Vector<ScriptNetData> NativeScript::get_rpc_methods() const {
Vector<ScriptNetData> v;
const Vector<MultiplayerAPI::RPCConfig> NativeScript::get_rpc_methods() const {
NativeScriptDesc *script_data = get_script_desc();
ERR_FAIL_COND_V(!script_data, Vector<MultiplayerAPI::RPCConfig>());
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;
return script_data->rpc_methods;
}
String NativeScript::get_class_documentation() const {
@ -1046,46 +812,10 @@ Ref<Script> NativeScriptInstance::get_script() const {
return script;
}
Vector<ScriptNetData> NativeScriptInstance::get_rpc_methods() const {
const Vector<MultiplayerAPI::RPCConfig> 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 {
return script->get_rpc_mode(p_method);
}
Vector<ScriptNetData> NativeScriptInstance::get_rset_properties() const {
return script->get_rset_properties();
}
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 {
return script->get_rset_mode(p_variable);
}
ScriptLanguage *NativeScriptInstance::get_language() {
return NativeScriptLanguage::get_singleton();
}

View file

@ -62,8 +62,6 @@ struct NativeScriptDesc {
godot_nativescript_property_get_func getter;
PropertyInfo info;
Variant default_value;
int rset_mode = 0;
uint16_t rset_property_id;
String documentation;
};
@ -72,9 +70,8 @@ struct NativeScriptDesc {
String documentation;
};
uint16_t rpc_count = 0;
Map<StringName, Method> methods;
uint16_t rset_count = 0;
Vector<MultiplayerAPI::RPCConfig> rpc_methods;
OrderedHashMap<StringName, Property> properties;
Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals
StringName base;
@ -178,17 +175,7 @@ public:
virtual void get_script_method_list(List<MethodInfo> *p_list) const override;
virtual void get_script_property_list(List<PropertyInfo> *p_list) const override;
virtual Vector<ScriptNetData> get_rpc_methods() const override;
virtual uint16_t get_rpc_method_id(const StringName &p_method) const override;
virtual StringName get_rpc_method(uint16_t p_id) const override;
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const override;
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override;
virtual Vector<ScriptNetData> get_rset_properties() const override;
virtual uint16_t get_rset_property_id(const StringName &p_variable) const override;
virtual StringName get_rset_property(uint16_t p_id) const override;
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const override;
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override;
virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override;
String get_class_documentation() const;
String get_method_documentation(const StringName &p_method) const;
@ -226,17 +213,7 @@ public:
String to_string(bool *r_valid);
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 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 const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const;
virtual ScriptLanguage *get_language();

View file

@ -100,46 +100,10 @@ String PluginScriptInstance::to_string(bool *r_valid) {
return str_ret;
}
Vector<ScriptNetData> PluginScriptInstance::get_rpc_methods() const {
const Vector<MultiplayerAPI::RPCConfig> 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 {
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 {
return _script->get_rset_mode(p_variable);
}
void PluginScriptInstance::refcount_incremented() {
if (_desc->refcount_decremented) {
_desc->refcount_incremented(_data);

View file

@ -71,17 +71,7 @@ public:
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 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 const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const;
virtual void refcount_incremented();
virtual bool refcount_decremented();

View file

@ -312,10 +312,9 @@ Error PluginScript::reload(bool p_keep_state) {
}
Array *methods = (Array *)&manifest.methods;
_rpc_methods.clear();
_rpc_variables.clear();
if (_ref_base_parent.is_valid()) {
/// XXX TODO Should this be _rpc_methods.append_array(...)
_rpc_methods = _ref_base_parent->get_rpc_methods();
_rpc_variables = _ref_base_parent->get_rset_properties();
}
for (int i = 0; i < methods->size(); ++i) {
Dictionary v = (*methods)[i];
@ -324,9 +323,10 @@ Error PluginScript::reload(bool p_keep_state) {
// rpc_mode is passed as an optional field and is not part of MethodInfo
Variant var = v["rpc_mode"];
if (var != Variant()) {
ScriptNetData nd;
MultiplayerAPI::RPCConfig nd;
nd.name = mi.name;
nd.mode = MultiplayerAPI::RPCMode(int(var));
nd.rpc_mode = MultiplayerAPI::RPCMode(int(var));
// TODO Transfer Channel
if (_rpc_methods.find(nd) == -1) {
_rpc_methods.push_back(nd);
}
@ -334,7 +334,7 @@ Error PluginScript::reload(bool p_keep_state) {
}
// Sort so we are 100% that they are always the same.
_rpc_methods.sort_custom<SortNetData>();
_rpc_methods.sort_custom<MultiplayerAPI::SortRPCConfig>();
Array *signals = (Array *)&manifest.signals;
for (int i = 0; i < signals->size(); ++i) {
@ -348,21 +348,8 @@ Error PluginScript::reload(bool p_keep_state) {
PropertyInfo pi = PropertyInfo::from_dict(v);
_properties_info[pi.name] = pi;
_properties_default_values[pi.name] = v["default_value"];
// rset_mode is passed as an optional field and is not part of PropertyInfo
Variant var = v["rset_mode"];
if (var != Variant()) {
ScriptNetData nd;
nd.name = pi.name;
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
/*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
@ -486,76 +473,10 @@ int PluginScript::get_member_line(const StringName &p_member) const {
return -1;
}
Vector<ScriptNetData> PluginScript::get_rpc_methods() const {
const Vector<MultiplayerAPI::RPCConfig> 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 {
ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
return get_rpc_mode_by_id(get_rpc_method_id(p_method));
}
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 {
ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
return get_rset_mode_by_id(get_rset_property_id(p_variable));
}
PluginScript::PluginScript() :
_script_list(this) {
}

View file

@ -61,8 +61,7 @@ private:
Map<StringName, PropertyInfo> _properties_info;
Map<StringName, MethodInfo> _signals_info;
Map<StringName, MethodInfo> _methods_info;
Vector<ScriptNetData> _rpc_methods;
Vector<ScriptNetData> _rpc_variables;
Vector<MultiplayerAPI::RPCConfig> _rpc_methods;
Set<Object *> _instances;
//exported members
@ -137,17 +136,7 @@ public:
virtual int get_member_line(const StringName &p_member) const override;
virtual Vector<ScriptNetData> get_rpc_methods() const override;
virtual uint16_t get_rpc_method_id(const StringName &p_method) const override;
virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const override;
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override;
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override;
virtual Vector<ScriptNetData> get_rset_properties() const override;
virtual uint16_t get_rset_property_id(const StringName &p_property) const override;
virtual StringName get_rset_property(const uint16_t p_rset_property_id) const override;
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const override;
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override;
virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override;
PluginScript();
void init(PluginScriptLanguage *language);

View file

@ -897,68 +897,10 @@ void GDScript::get_members(Set<StringName> *p_members) {
}
}
Vector<ScriptNetData> GDScript::get_rpc_methods() const {
const Vector<MultiplayerAPI::RPCConfig> 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 {
if (p_rpc_method_id >= rpc_functions.size()) {
return 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 {
if (p_rpc_method_id >= rpc_functions.size()) {
return 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 {
if (p_rset_member_id >= rpc_variables.size()) {
return 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 {
if (p_rset_member_id >= rpc_variables.size()) {
return MultiplayerAPI::RPC_MODE_DISABLED;
}
return rpc_variables[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, Callable::CallError &r_error) {
GDScript *top = this;
while (top) {
@ -1210,10 +1152,8 @@ void GDScript::_save_orphaned_subclasses() {
void GDScript::_init_rpc_methods_properties() {
// 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;
@ -1222,25 +1162,17 @@ void GDScript::_init_rpc_methods_properties() {
// 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;
MultiplayerAPI::RPCConfig nd;
nd.name = E->key();
nd.mode = E->get()->get_rpc_mode();
nd.rpc_mode = E->get()->get_rpc_mode();
// TODO
nd.transfer_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE;
nd.channel = 0;
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();
@ -1254,8 +1186,7 @@ void GDScript::_init_rpc_methods_properties() {
}
// Sort so we are 100% that they are always the same.
rpc_functions.sort_custom<SortNetData>();
rpc_variables.sort_custom<SortNetData>();
rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>();
}
GDScript::~GDScript() {
@ -1611,46 +1542,10 @@ ScriptLanguage *GDScriptInstance::get_language() {
return GDScriptLanguage::get_singleton();
}
Vector<ScriptNetData> GDScriptInstance::get_rpc_methods() const {
const Vector<MultiplayerAPI::RPCConfig> 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 {
return script->get_rpc_mode(p_method);
}
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 {
return script->get_rset_mode(p_variable);
}
void GDScriptInstance::reload_members() {
#ifdef DEBUG_ENABLED

View file

@ -86,8 +86,7 @@ class GDScript : public Script {
Map<StringName, MemberInfo> member_indices; //members are just indices to the instanced script.
Map<StringName, Ref<GDScript>> subclasses;
Map<StringName, Vector<StringName>> _signals;
Vector<ScriptNetData> rpc_functions;
Vector<ScriptNetData> rpc_variables;
Vector<MultiplayerAPI::RPCConfig> rpc_functions;
#ifdef TOOLS_ENABLED
@ -247,17 +246,7 @@ public:
virtual void get_constants(Map<StringName, Variant> *p_constants) override;
virtual void get_members(Set<StringName> *p_members) override;
virtual Vector<ScriptNetData> get_rpc_methods() const override;
virtual uint16_t get_rpc_method_id(const StringName &p_method) const override;
virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const override;
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override;
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override;
virtual Vector<ScriptNetData> get_rset_properties() const override;
virtual uint16_t get_rset_property_id(const StringName &p_variable) const override;
virtual StringName get_rset_property(const uint16_t p_variable_id) const override;
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const override;
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override;
virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override;
#ifdef TOOLS_ENABLED
virtual bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; }
@ -310,17 +299,7 @@ public:
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 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 const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const;
GDScriptInstance();
~GDScriptInstance();

View file

@ -2105,46 +2105,10 @@ bool CSharpInstance::refcount_decremented() {
return ref_dying;
}
Vector<ScriptNetData> CSharpInstance::get_rpc_methods() const {
const Vector<MultiplayerAPI::RPCConfig> CSharpInstance::get_rpc_methods() const {
return script->get_rpc_methods();
}
uint16_t CSharpInstance::get_rpc_method_id(const StringName &p_method) const {
return script->get_rpc_method_id(p_method);
}
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 {
return script->get_rpc_mode(p_method);
}
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 {
return script->get_rset_mode(p_variable);
}
void CSharpInstance::notification(int p_notification) {
GD_MONO_SCOPE_THREAD_ATTACH;
@ -3046,7 +3010,6 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
p_script->script_class->fetch_methods_with_godot_api_checks(p_script->native);
p_script->rpc_functions.clear();
p_script->rpc_variables.clear();
GDMonoClass *top = p_script->script_class;
while (top && top != p_script->native) {
@ -3060,9 +3023,12 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
if (!methods[i]->is_static()) {
MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(methods[i]);
if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
ScriptNetData nd;
MultiplayerAPI::RPCConfig nd;
nd.name = methods[i]->get_name();
nd.mode = mode;
nd.rpc_mode = mode;
// TODO Transfer mode, channel
nd.transfer_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE;
nd.channel = 0;
if (-1 == p_script->rpc_functions.find(nd)) {
p_script->rpc_functions.push_back(nd);
}
@ -3071,46 +3037,11 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
}
}
{
Vector<GDMonoField *> fields = top->get_all_fields();
for (int i = 0; i < fields.size(); i++) {
if (!fields[i]->is_static()) {
MultiplayerAPI::RPCMode mode = p_script->_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 == p_script->rpc_variables.find(nd)) {
p_script->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 = p_script->_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 == p_script->rpc_variables.find(nd)) {
p_script->rpc_variables.push_back(nd);
}
}
}
}
}
top = top->get_parent_class();
}
// Sort so we are 100% that they are always the same.
p_script->rpc_functions.sort_custom<SortNetData>();
p_script->rpc_variables.sort_custom<SortNetData>();
p_script->rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>();
p_script->load_script_signals(p_script->script_class, p_script->native);
}
@ -3543,60 +3474,10 @@ MultiplayerAPI::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_m
return MultiplayerAPI::RPC_MODE_DISABLED;
}
Vector<ScriptNetData> CSharpScript::get_rpc_methods() const {
const Vector<MultiplayerAPI::RPCConfig> 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 ferr = read_all_file_utf8(p_path, source);

View file

@ -136,8 +136,7 @@ private:
Map<StringName, EventSignal> event_signals;
bool signals_invalidated = true;
Vector<ScriptNetData> rpc_functions;
Vector<ScriptNetData> rpc_variables;
Vector<MultiplayerAPI::RPCConfig> rpc_functions;
#ifdef TOOLS_ENABLED
List<PropertyInfo> exported_members_cache; // members_cache
@ -235,17 +234,7 @@ public:
int get_member_line(const StringName &p_member) const override;
Vector<ScriptNetData> get_rpc_methods() const override;
uint16_t get_rpc_method_id(const StringName &p_method) const override;
StringName get_rpc_method(const uint16_t p_rpc_method_id) const override;
MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override;
MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override;
Vector<ScriptNetData> get_rset_properties() const override;
uint16_t get_rset_property_id(const StringName &p_variable) const override;
StringName get_rset_property(const uint16_t p_variable_id) const override;
MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const override;
MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override;
const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override;
#ifdef TOOLS_ENABLED
bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; }
@ -322,17 +311,7 @@ public:
void refcount_incremented() override;
bool refcount_decremented() override;
Vector<ScriptNetData> get_rpc_methods() const override;
uint16_t get_rpc_method_id(const StringName &p_method) const override;
StringName get_rpc_method(const uint16_t p_rpc_method_id) const override;
MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override;
MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override;
Vector<ScriptNetData> get_rset_properties() const override;
uint16_t get_rset_property_id(const StringName &p_variable) const override;
StringName get_rset_property(const uint16_t p_variable_id) const override;
MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const override;
MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override;
const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override;
void notification(int p_notification) override;
void _call_notification(int p_notification);

View file

@ -954,60 +954,10 @@ bool VisualScript::are_subnodes_edited() const {
}
#endif
Vector<ScriptNetData> VisualScript::get_rpc_methods() const {
const Vector<MultiplayerAPI::RPCConfig> 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_variables.size(), MultiplayerAPI::RPC_MODE_DISABLED);
return rpc_variables[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) {
Dictionary d = p_data;
if (d.has("base_type")) {
@ -1065,7 +1015,6 @@ void VisualScript::_set_data(const Dictionary &p_data) {
// Takes all the rpc methods.
rpc_functions.clear();
rpc_variables.clear();
List<StringName> fns;
functions.get_key_list(&fns);
for (const List<StringName>::Element *E = fns.front(); E; E = E->next()) {
@ -1073,9 +1022,10 @@ void VisualScript::_set_data(const Dictionary &p_data) {
Ref<VisualScriptFunction> vsf = nodes[functions[E->get()].func_id].node;
if (vsf.is_valid()) {
if (vsf->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) {
ScriptNetData nd;
MultiplayerAPI::RPCConfig nd;
nd.name = E->get();
nd.mode = vsf->get_rpc_mode();
nd.rpc_mode = vsf->get_rpc_mode();
nd.transfer_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE; // TODO
if (rpc_functions.find(nd) == -1) {
rpc_functions.push_back(nd);
}
@ -1085,7 +1035,7 @@ void VisualScript::_set_data(const Dictionary &p_data) {
}
// Sort so we are 100% that they are always the same.
rpc_functions.sort_custom<SortNetData>();
rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>();
}
Dictionary VisualScript::_get_data() const {
@ -1882,46 +1832,10 @@ Ref<Script> VisualScriptInstance::get_script() const {
return script;
}
Vector<ScriptNetData> VisualScriptInstance::get_rpc_methods() const {
const Vector<MultiplayerAPI::RPCConfig> 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 {
return script->get_rpc_mode(p_method);
}
Vector<ScriptNetData> VisualScriptInstance::get_rset_properties() const {
return script->get_rset_properties();
}
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 {
return script->get_rset_mode(p_variable);
}
void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_owner) {
script = p_script;
owner = p_owner;

View file

@ -234,8 +234,7 @@ private:
HashMap<StringName, Function> functions;
HashMap<StringName, Variable> variables;
Map<StringName, Vector<Argument>> custom_signals;
Vector<ScriptNetData> rpc_functions;
Vector<ScriptNetData> rpc_variables;
Vector<MultiplayerAPI::RPCConfig> rpc_functions;
Map<Object *, VisualScriptInstance *> instances;
@ -363,17 +362,7 @@ public:
virtual int get_member_line(const StringName &p_member) const override;
virtual Vector<ScriptNetData> get_rpc_methods() const override;
virtual uint16_t get_rpc_method_id(const StringName &p_method) const override;
virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const override;
virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override;
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override;
virtual Vector<ScriptNetData> get_rset_properties() const override;
virtual uint16_t get_rset_property_id(const StringName &p_property) const override;
virtual StringName get_rset_property(const uint16_t p_rset_property_id) const override;
virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const override;
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override;
virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override;
#ifdef TOOLS_ENABLED
virtual bool are_subnodes_edited() const;
@ -454,17 +443,7 @@ public:
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 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 const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const;
VisualScriptInstance();
~VisualScriptInstance();

View file

@ -737,20 +737,22 @@ public:
}
int to_id = 0;
bool reliable = true;
//bool reliable = true;
if (rpc_mode >= VisualScriptFunctionCall::RPC_RELIABLE_TO_ID) {
to_id = *p_args[0];
p_args += 1;
p_argcount -= 1;
if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) {
reliable = false;
}
} else if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE) {
reliable = false;
//if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) {
//reliable = false;
//}
}
//else if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE) {
//reliable = false;
//}
node->rpcp(to_id, !reliable, function, p_args, p_argcount);
// TODO reliable?
node->rpcp(to_id, function, p_args, p_argcount);
return true;
}

View file

@ -491,36 +491,24 @@ bool Node::is_network_master() const {
/***** RPC CONFIG ********/
uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode) {
uint16_t mid = get_node_rpc_method_id(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_methods.size() - 1) | (1 << 15);
} else {
int c_mid = (~(1 << 15)) & mid;
data.rpc_methods.write[c_mid].mode = p_mode;
return mid;
}
}
uint16_t Node::rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode) {
uint16_t pid = get_node_rset_property_id(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 {
int c_pid = (~(1 << 15)) & pid;
data.rpc_properties.write[c_pid].mode = p_mode;
return pid;
uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_rpc_mode, NetworkedMultiplayerPeer::TransferMode p_transfer_mode, int p_channel) {
for (int i = 0; i < data.rpc_methods.size(); i++) {
if (data.rpc_methods[i].name == p_method) {
MultiplayerAPI::RPCConfig &nd = data.rpc_methods.write[i];
nd.rpc_mode = p_rpc_mode;
nd.transfer_mode = p_transfer_mode;
nd.channel = p_channel;
return i | (1 << 15);
}
}
// New method
MultiplayerAPI::RPCConfig nd;
nd.name = p_method;
nd.rpc_mode = p_rpc_mode;
nd.transfer_mode = p_transfer_mode;
nd.channel = p_channel;
data.rpc_methods.push_back(nd);
return ((uint16_t)data.rpc_methods.size() - 1) | (1 << 15);
}
/***** RPC FUNCTIONS ********/
@ -536,7 +524,7 @@ void Node::rpc(const StringName &p_method, VARIANT_ARG_DECLARE) {
argc++;
}
rpcp(0, false, p_method, argptr, argc);
rpcp(0, p_method, argptr, argc);
}
void Node::rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
@ -550,35 +538,7 @@ void Node::rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE
argc++;
}
rpcp(p_peer_id, false, p_method, argptr, argc);
}
void Node::rpc_unreliable(const StringName &p_method, VARIANT_ARG_DECLARE) {
VARIANT_ARGPTRS;
int argc = 0;
for (int i = 0; i < VARIANT_ARG_MAX; i++) {
if (argptr[i]->get_type() == Variant::NIL) {
break;
}
argc++;
}
rpcp(0, true, p_method, argptr, argc);
}
void Node::rpc_unreliable_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
VARIANT_ARGPTRS;
int argc = 0;
for (int i = 0; i < VARIANT_ARG_MAX; i++) {
if (argptr[i]->get_type() == Variant::NIL) {
break;
}
argc++;
}
rpcp(p_peer_id, true, p_method, argptr, argc);
rpcp(p_peer_id, p_method, argptr, argc);
}
Variant Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
@ -597,7 +557,7 @@ Variant Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallEr
StringName method = *p_args[0];
rpcp(0, false, method, &p_args[1], p_argcount - 1);
rpcp(0, method, &p_args[1], p_argcount - 1);
r_error.error = Callable::CallError::CALL_OK;
return Variant();
@ -627,92 +587,17 @@ Variant Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::Cal
int peer_id = *p_args[0];
StringName method = *p_args[1];
rpcp(peer_id, false, method, &p_args[2], p_argcount - 2);
rpcp(peer_id, method, &p_args[2], p_argcount - 2);
r_error.error = Callable::CallError::CALL_OK;
return Variant();
}
Variant Node::_rpc_unreliable_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (p_argcount < 1) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 1;
return Variant();
}
if (p_args[0]->get_type() != Variant::STRING_NAME) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::STRING_NAME;
return Variant();
}
StringName method = *p_args[0];
rpcp(0, true, method, &p_args[1], p_argcount - 1);
r_error.error = Callable::CallError::CALL_OK;
return Variant();
}
Variant Node::_rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (p_argcount < 2) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 2;
return Variant();
}
if (p_args[0]->get_type() != Variant::INT) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::INT;
return Variant();
}
if (p_args[1]->get_type() != Variant::STRING_NAME) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 1;
r_error.expected = Variant::STRING_NAME;
return Variant();
}
int peer_id = *p_args[0];
StringName method = *p_args[1];
rpcp(peer_id, true, method, &p_args[2], p_argcount - 2);
r_error.error = Callable::CallError::CALL_OK;
return Variant();
}
void Node::rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) {
void Node::rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) {
ERR_FAIL_COND(!is_inside_tree());
get_multiplayer()->rpcp(this, p_peer_id, p_unreliable, p_method, p_arg, p_argcount);
get_multiplayer()->rpcp(this, p_peer_id, true, p_method, p_arg, p_argcount);
}
void Node::rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) {
ERR_FAIL_COND(!is_inside_tree());
get_multiplayer()->rsetp(this, p_peer_id, p_unreliable, p_property, p_value);
}
/******** RSET *********/
void Node::rset(const StringName &p_property, const Variant &p_value) {
rsetp(0, false, p_property, p_value);
}
void Node::rset_id(int p_peer_id, const StringName &p_property, const Variant &p_value) {
rsetp(p_peer_id, false, p_property, p_value);
}
void Node::rset_unreliable(const StringName &p_property, const Variant &p_value) {
rsetp(0, true, p_property, p_value);
}
void Node::rset_unreliable_id(int p_peer_id, const StringName &p_property, const Variant &p_value) {
rsetp(p_peer_id, true, p_property, p_value);
}
//////////// end of rpc
Ref<MultiplayerAPI> Node::get_multiplayer() const {
if (multiplayer.is_valid()) {
return multiplayer;
@ -731,99 +616,11 @@ void Node::set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {
multiplayer = p_multiplayer;
}
uint16_t Node::get_node_rpc_method_id(const StringName &p_method) const {
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;
Vector<MultiplayerAPI::RPCConfig> Node::get_node_rpc_methods() const {
return data.rpc_methods;
}
StringName Node::get_node_rpc_method(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].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();
}
//////////// end of rpc
bool Node::can_process_notification(int p_what) const {
switch (p_what) {
@ -2776,8 +2573,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_multiplayer"), &Node::get_multiplayer);
ClassDB::bind_method(D_METHOD("get_custom_multiplayer"), &Node::get_custom_multiplayer);
ClassDB::bind_method(D_METHOD("set_custom_multiplayer", "api"), &Node::set_custom_multiplayer);
ClassDB::bind_method(D_METHOD("rpc_config", "method", "mode"), &Node::rpc_config);
ClassDB::bind_method(D_METHOD("rset_config", "property", "mode"), &Node::rset_config);
ClassDB::bind_method(D_METHOD("rpc_config", "method", "rpc_mode", "transfer_mode", "channel"), &Node::rpc_config, DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE), DEFVAL(0));
ClassDB::bind_method(D_METHOD("set_editor_description", "editor_description"), &Node::set_editor_description);
ClassDB::bind_method(D_METHOD("get_editor_description"), &Node::get_editor_description);
@ -2794,22 +2590,13 @@ void Node::_bind_methods() {
mi.name = "rpc";
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc", &Node::_rpc_bind, mi);
mi.name = "rpc_unreliable";
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_unreliable", &Node::_rpc_unreliable_bind, mi);
mi.arguments.push_front(PropertyInfo(Variant::INT, "peer_id"));
mi.name = "rpc_id";
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_id", &Node::_rpc_id_bind, mi);
mi.name = "rpc_unreliable_id";
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_unreliable_id", &Node::_rpc_unreliable_id_bind, mi);
}
ClassDB::bind_method(D_METHOD("rset", "property", "value"), &Node::rset);
ClassDB::bind_method(D_METHOD("rset_id", "peer_id", "property", "value"), &Node::rset_id);
ClassDB::bind_method(D_METHOD("rset_unreliable", "property", "value"), &Node::rset_unreliable);
ClassDB::bind_method(D_METHOD("rset_unreliable_id", "peer_id", "property", "value"), &Node::rset_unreliable_id);
ClassDB::bind_method(D_METHOD("update_configuration_warnings"), &Node::update_configuration_warnings);
BIND_CONSTANT(NOTIFICATION_ENTER_TREE);

View file

@ -80,11 +80,6 @@ private:
SceneTree::Group *group = nullptr;
};
struct NetData {
StringName name;
MultiplayerAPI::RPCMode mode = MultiplayerAPI::RPCMode::RPC_MODE_DISABLED;
};
struct Data {
String filename;
Ref<SceneState> instance_state;
@ -116,8 +111,7 @@ private:
Node *process_owner = nullptr;
int network_master = 1; // Server by default.
Vector<NetData> rpc_methods;
Vector<NetData> rpc_properties;
Vector<MultiplayerAPI::RPCConfig> rpc_methods;
// Variables used to properly sort the node when processing, ignored otherwise.
// TODO: Should move all the stuff below to bits.
@ -179,9 +173,7 @@ private:
Array _get_groups() const;
Variant _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Variant _rpc_unreliable_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Variant _rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Variant _rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
friend class SceneTree;
@ -425,42 +417,17 @@ public:
int get_network_master() const;
bool is_network_master() const;
uint16_t rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode); // config a local method for RPC
uint16_t rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode); // config a local property for RPC
uint16_t rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_rpc_mode, NetworkedMultiplayerPeer::TransferMode p_transfer_mode, int p_channel = 0); // config a local method for RPC
Vector<MultiplayerAPI::RPCConfig> get_node_rpc_methods() const;
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_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
void rpc_unreliable_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
void rset(const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
void rset_unreliable(const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
void rset_id(int p_peer_id, const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
void rset_unreliable_id(int p_peer_id, const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
void rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount);
void rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value);
void rpc(const StringName &p_method, VARIANT_ARG_LIST); // RPC, honors RPCMode, TransferMode, channel
void rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); // RPC to specific peer(s), honors RPCMode, TransferMode, channel
void rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount);
Ref<MultiplayerAPI> get_multiplayer() const;
Ref<MultiplayerAPI> get_custom_multiplayer() const;
void set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
/// 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();
};

View file

@ -93,35 +93,8 @@ public:
Ref<Script> get_script() const override {
return Ref<Script>();
}
Vector<ScriptNetData> get_rpc_methods() const override {
return Vector<ScriptNetData>();
}
uint16_t get_rpc_method_id(const StringName &p_method) const override {
return 0;
}
StringName get_rpc_method(uint16_t p_id) const override {
return StringName();
}
MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const override {
return MultiplayerAPI::RPC_MODE_PUPPET;
}
MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override {
return MultiplayerAPI::RPC_MODE_PUPPET;
}
Vector<ScriptNetData> get_rset_properties() const override {
return Vector<ScriptNetData>();
}
uint16_t get_rset_property_id(const StringName &p_variable) const override {
return 0;
}
StringName get_rset_property(uint16_t p_id) const override {
return StringName();
}
MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const override {
return MultiplayerAPI::RPC_MODE_PUPPET;
}
MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override {
return MultiplayerAPI::RPC_MODE_PUPPET;
const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override {
return Vector<MultiplayerAPI::RPCConfig>();
}
ScriptLanguage *get_language() override {
return nullptr;