Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to) { ERR_FAIL_COND_V(p_data.size() < 1, ERR_INVALID_DATA); ERR_FAIL_COND_V(!network_peer.is_valid(), ERR_UNCONFIGURED); ERR_FAIL_COND_V(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED); MAKE_ROOM(p_data.size() + 1); PoolVector<uint8_t>::Read r = p_data.read(); packet_cache[0] = NETWORK_COMMAND_RAW; memcpy(&packet_cache[1], &r[0], p_data.size()); network_peer->set_target_peer(p_to); return network_peer->put_packet(packet_cache.ptr(), p_data.size() + 1); }
Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) { ERR_EXPLAIN("Trying to send an empty raw packet."); ERR_FAIL_COND_V(p_data.size() < 1, ERR_INVALID_DATA); ERR_EXPLAIN("Trying to send a raw packet while no network peer is active."); ERR_FAIL_COND_V(!network_peer.is_valid(), ERR_UNCONFIGURED); ERR_EXPLAIN("Trying to send a raw packet via a network peer which is not connected."); ERR_FAIL_COND_V(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED); MAKE_ROOM(p_data.size() + 1); PoolVector<uint8_t>::Read r = p_data.read(); packet_cache.write[0] = NETWORK_COMMAND_RAW; memcpy(&packet_cache.write[1], &r[0], p_data.size()); network_peer->set_target_peer(p_to); network_peer->set_transfer_mode(p_mode); return network_peer->put_packet(packet_cache.ptr(), p_data.size() + 1); }
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) { if (network_peer.is_null()) { ERR_EXPLAIN("Attempt to remote call/set when networking is not active in SceneTree."); ERR_FAIL(); } if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING) { ERR_EXPLAIN("Attempt to remote call/set when networking is not connected yet in SceneTree."); ERR_FAIL(); } if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) { ERR_EXPLAIN("Attempt to remote call/set when networking is disconnected."); ERR_FAIL(); } if (p_argcount > 255) { ERR_EXPLAIN("Too many arguments >255."); ERR_FAIL(); } if (p_to != 0 && !connected_peers.has(ABS(p_to))) { if (p_to == network_peer->get_unique_id()) { ERR_EXPLAIN("Attempt to remote call/set yourself! unique ID: " + itos(network_peer->get_unique_id())); } else { ERR_EXPLAIN("Attempt to remote call unexisting ID: " + itos(p_to)); } ERR_FAIL(); } NodePath from_path = (root_node->get_path()).rel_path_to(p_from->get_path()); ERR_EXPLAIN("Unable to send RPC. Relative path is empty. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(from_path.is_empty()); // See if the path is cached. PathSentCache *psc = path_send_cache.getptr(from_path); if (!psc) { // Path is not cached, create. path_send_cache[from_path] = PathSentCache(); psc = path_send_cache.getptr(from_path); psc->id = last_send_cache_id++; } // Create base packet, lots of hardcode because it must be tight. int ofs = 0; #define MAKE_ROOM(m_amount) \ if (packet_cache.size() < m_amount) packet_cache.resize(m_amount); // Encode type. MAKE_ROOM(1); packet_cache.write[0] = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL; ofs += 1; // Encode ID. MAKE_ROOM(ofs + 4); encode_uint32(psc->id, &(packet_cache.write[ofs])); ofs += 4; // Encode function name. CharString name = String(p_name).utf8(); int len = encode_cstring(name.get_data(), NULL); MAKE_ROOM(ofs + len); encode_cstring(name.get_data(), &(packet_cache.write[ofs])); ofs += len; if (p_set) { // Set argument. Error err = encode_variant(*p_arg[0], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ERR_EXPLAIN("Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(err != OK); MAKE_ROOM(ofs + len); encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ofs += len; } else { // Call arguments. MAKE_ROOM(ofs + 1); packet_cache.write[ofs] = p_argcount; ofs += 1; for (int i = 0; i < p_argcount; i++) { Error err = encode_variant(*p_arg[i], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ERR_EXPLAIN("Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(err != OK); MAKE_ROOM(ofs + len); encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ofs += len; } } // See if all peers have cached path (is so, call can be fast). bool has_all_peers = _send_confirm_path(from_path, psc, p_to); // Take chance and set transfer mode, since all send methods will use it. network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); if (has_all_peers) { // They all have verified paths, so send fast. network_peer->set_target_peer(p_to); // To all of you. network_peer->put_packet(packet_cache.ptr(), ofs); // A message with love. } else { // Not all verified path, so send one by one. // Append path at the end, since we will need it for some packets. CharString pname = String(from_path).utf8(); int path_len = encode_cstring(pname.get_data(), NULL); MAKE_ROOM(ofs + path_len); encode_cstring(pname.get_data(), &(packet_cache.write[ofs])); for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { if (p_to < 0 && E->get() == -p_to) continue; // Continue, excluded. if (p_to > 0 && E->get() != p_to) continue; // Continue, not for this peer. Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); ERR_CONTINUE(!F); // Should never happen. network_peer->set_target_peer(E->get()); // To this one specifically. if (F->get()) { // This one confirmed path, so use id. encode_uint32(psc->id, &(packet_cache.write[1])); network_peer->put_packet(packet_cache.ptr(), ofs); } else { // This one did not confirm path yet, so use entire path (sorry!). encode_uint32(0x80000000 | ofs, &(packet_cache.write[1])); // Offset to path and flag. network_peer->put_packet(packet_cache.ptr(), ofs + path_len); } } } }