2021-10-08 14:13:06 +02:00
/*************************************************************************/
/* scene_replication_interface.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
# include "scene_replication_interface.h"
2022-09-30 22:35:56 +02:00
# include "scene_multiplayer.h"
2021-10-08 14:13:06 +02:00
# include "core/io/marshalls.h"
# include "scene/main/node.h"
2022-09-30 22:35:56 +02:00
# include "scene/scene_string_names.h"
2021-10-08 14:13:06 +02:00
# define MAKE_ROOM(m_amount) \
if ( packet_cache . size ( ) < m_amount ) \
packet_cache . resize ( m_amount ) ;
2022-09-30 22:35:56 +02:00
SceneReplicationInterface : : TrackedNode & SceneReplicationInterface : : _track ( const ObjectID & p_id ) {
if ( ! tracked_nodes . has ( p_id ) ) {
tracked_nodes [ p_id ] = TrackedNode ( p_id ) ;
Node * node = get_id_as < Node > ( p_id ) ;
node - > connect ( SceneStringNames : : get_singleton ( ) - > tree_exited , callable_mp ( this , & SceneReplicationInterface : : _untrack ) . bind ( p_id ) , Node : : CONNECT_ONE_SHOT ) ;
}
return tracked_nodes [ p_id ] ;
}
void SceneReplicationInterface : : _untrack ( const ObjectID & p_id ) {
if ( ! tracked_nodes . has ( p_id ) ) {
return ;
}
uint32_t net_id = tracked_nodes [ p_id ] . net_id ;
uint32_t peer = tracked_nodes [ p_id ] . remote_peer ;
tracked_nodes . erase ( p_id ) ;
// If it was spawned by a remote, remove it from the received nodes.
if ( peer & & peers_info . has ( peer ) ) {
peers_info [ peer ] . recv_nodes . erase ( net_id ) ;
}
// If we spawned or synced it, we need to remove it from any peer it was sent to.
if ( net_id | | peer = = 0 ) {
for ( KeyValue < int , PeerInfo > & E : peers_info ) {
E . value . spawn_nodes . erase ( p_id ) ;
}
}
}
void SceneReplicationInterface : : _free_remotes ( const PeerInfo & p_info ) {
for ( const KeyValue < uint32_t , ObjectID > & E : p_info . recv_nodes ) {
Node * node = tracked_nodes . has ( E . value ) ? get_id_as < Node > ( E . value ) : nullptr ;
2021-10-08 14:13:06 +02:00
ERR_CONTINUE ( ! node ) ;
2022-10-24 23:07:02 +02:00
node - > queue_free ( ) ;
2021-10-08 14:13:06 +02:00
}
}
void SceneReplicationInterface : : on_peer_change ( int p_id , bool p_connected ) {
if ( p_connected ) {
2022-09-30 22:35:56 +02:00
peers_info [ p_id ] = PeerInfo ( ) ;
for ( const ObjectID & oid : spawned_nodes ) {
2022-07-09 20:45:30 +02:00
_update_spawn_visibility ( p_id , oid ) ;
2021-10-08 14:13:06 +02:00
}
2022-09-30 22:35:56 +02:00
for ( const ObjectID & oid : sync_nodes ) {
_update_sync_visibility ( p_id , get_id_as < MultiplayerSynchronizer > ( oid ) ) ;
2021-10-08 14:13:06 +02:00
}
} else {
2022-09-30 22:35:56 +02:00
ERR_FAIL_COND ( ! peers_info . has ( p_id ) ) ;
_free_remotes ( peers_info [ p_id ] ) ;
peers_info . erase ( p_id ) ;
2021-10-08 14:13:06 +02:00
}
}
void SceneReplicationInterface : : on_reset ( ) {
2022-09-30 22:35:56 +02:00
for ( const KeyValue < int , PeerInfo > & E : peers_info ) {
_free_remotes ( E . value ) ;
2021-10-08 14:13:06 +02:00
}
2022-09-30 22:35:56 +02:00
peers_info . clear ( ) ;
// Tracked nodes are cleared on deletion, here we only reset the ids so they can be later re-assigned.
for ( KeyValue < ObjectID , TrackedNode > & E : tracked_nodes ) {
TrackedNode & tobj = E . value ;
tobj . net_id = 0 ;
tobj . remote_peer = 0 ;
}
for ( const ObjectID & oid : sync_nodes ) {
MultiplayerSynchronizer * sync = get_id_as < MultiplayerSynchronizer > ( oid ) ;
ERR_CONTINUE ( ! sync ) ;
sync - > reset ( ) ;
}
last_net_id = 0 ;
2021-10-08 14:13:06 +02:00
}
void SceneReplicationInterface : : on_network_process ( ) {
uint64_t msec = OS : : get_singleton ( ) - > get_ticks_msec ( ) ;
2022-09-30 22:35:56 +02:00
for ( KeyValue < int , PeerInfo > & E : peers_info ) {
const HashSet < ObjectID > to_sync = E . value . sync_nodes ;
if ( to_sync . is_empty ( ) ) {
continue ; // Nothing to sync
}
uint16_t sync_net_time = + + E . value . last_sent_sync ;
_send_sync ( E . key , to_sync , sync_net_time , msec ) ;
2021-10-08 14:13:06 +02:00
}
}
Error SceneReplicationInterface : : on_spawn ( Object * p_obj , Variant p_config ) {
Node * node = Object : : cast_to < Node > ( p_obj ) ;
ERR_FAIL_COND_V ( ! node | | p_config . get_type ( ) ! = Variant : : OBJECT , ERR_INVALID_PARAMETER ) ;
MultiplayerSpawner * spawner = Object : : cast_to < MultiplayerSpawner > ( p_config . get_validated_object ( ) ) ;
ERR_FAIL_COND_V ( ! spawner , ERR_INVALID_PARAMETER ) ;
2022-09-30 22:35:56 +02:00
// Track node.
2022-07-09 20:45:30 +02:00
const ObjectID oid = node - > get_instance_id ( ) ;
2022-09-30 22:35:56 +02:00
TrackedNode & tobj = _track ( oid ) ;
ERR_FAIL_COND_V ( tobj . spawner ! = ObjectID ( ) , ERR_ALREADY_IN_USE ) ;
tobj . spawner = spawner - > get_instance_id ( ) ;
spawned_nodes . insert ( oid ) ;
2022-07-09 20:45:30 +02:00
if ( multiplayer - > has_multiplayer_peer ( ) & & spawner - > is_multiplayer_authority ( ) ) {
2022-09-30 22:35:56 +02:00
if ( tobj . net_id = = 0 ) {
tobj . net_id = + + last_net_id ;
}
2022-07-09 20:45:30 +02:00
_update_spawn_visibility ( 0 , oid ) ;
}
return OK ;
2021-10-08 14:13:06 +02:00
}
Error SceneReplicationInterface : : on_despawn ( Object * p_obj , Variant p_config ) {
Node * node = Object : : cast_to < Node > ( p_obj ) ;
ERR_FAIL_COND_V ( ! node | | p_config . get_type ( ) ! = Variant : : OBJECT , ERR_INVALID_PARAMETER ) ;
MultiplayerSpawner * spawner = Object : : cast_to < MultiplayerSpawner > ( p_config . get_validated_object ( ) ) ;
ERR_FAIL_COND_V ( ! p_obj | | ! spawner , ERR_INVALID_PARAMETER ) ;
2022-07-09 20:45:30 +02:00
// Forcibly despawn to all peers that knowns me.
int len = 0 ;
Error err = _make_despawn_packet ( node , len ) ;
ERR_FAIL_COND_V ( err ! = OK , ERR_BUG ) ;
const ObjectID oid = p_obj - > get_instance_id ( ) ;
2022-09-30 22:35:56 +02:00
for ( const KeyValue < int , PeerInfo > & E : peers_info ) {
if ( ! E . value . spawn_nodes . has ( oid ) ) {
2022-07-09 20:45:30 +02:00
continue ;
}
2022-09-30 22:35:56 +02:00
_send_raw ( packet_cache . ptr ( ) , len , E . key , true ) ;
2022-07-09 20:45:30 +02:00
}
// Also remove spawner tracking from the replication state.
2022-09-30 22:35:56 +02:00
ERR_FAIL_COND_V ( ! tracked_nodes . has ( oid ) , ERR_INVALID_PARAMETER ) ;
TrackedNode & tobj = _track ( oid ) ;
ERR_FAIL_COND_V ( tobj . spawner ! = spawner - > get_instance_id ( ) , ERR_INVALID_PARAMETER ) ;
tobj . spawner = ObjectID ( ) ;
spawned_nodes . erase ( oid ) ;
for ( KeyValue < int , PeerInfo > & E : peers_info ) {
E . value . spawn_nodes . erase ( oid ) ;
}
return OK ;
2021-10-08 14:13:06 +02:00
}
Error SceneReplicationInterface : : on_replication_start ( Object * p_obj , Variant p_config ) {
Node * node = Object : : cast_to < Node > ( p_obj ) ;
ERR_FAIL_COND_V ( ! node | | p_config . get_type ( ) ! = Variant : : OBJECT , ERR_INVALID_PARAMETER ) ;
MultiplayerSynchronizer * sync = Object : : cast_to < MultiplayerSynchronizer > ( p_config . get_validated_object ( ) ) ;
ERR_FAIL_COND_V ( ! sync , ERR_INVALID_PARAMETER ) ;
2022-07-09 20:45:30 +02:00
2022-09-30 22:35:56 +02:00
// Add to synchronizer list.
TrackedNode & tobj = _track ( p_obj - > get_instance_id ( ) ) ;
const ObjectID sid = sync - > get_instance_id ( ) ;
tobj . synchronizers . insert ( sid ) ;
sync_nodes . insert ( sid ) ;
// Update visibility.
sync - > connect ( " visibility_changed " , callable_mp ( this , & SceneReplicationInterface : : _visibility_changed ) . bind ( sync - > get_instance_id ( ) ) ) ;
_update_sync_visibility ( 0 , sync ) ;
if ( pending_spawn = = p_obj - > get_instance_id ( ) & & sync - > get_multiplayer_authority ( ) = = pending_spawn_remote ) {
// Try to apply synchronizer Net ID
ERR_FAIL_COND_V_MSG ( pending_sync_net_ids . is_empty ( ) , ERR_INVALID_DATA , vformat ( " The MultiplayerSynchronizer at path \" %s \" is unable to process the pending spawn since it has no network ID. This might happen when changing the multiplayer authority during the \" _ready \" callback. Make sure to only change the authority of multiplayer synchronizers during \" _enter_tree \" or the \" _spawn_custom \" callback of their multiplayer spawner. " , sync - > get_path ( ) ) ) ;
ERR_FAIL_COND_V ( ! peers_info . has ( pending_spawn_remote ) , ERR_INVALID_DATA ) ;
uint32_t net_id = pending_sync_net_ids [ 0 ] ;
pending_sync_net_ids . pop_front ( ) ;
peers_info [ pending_spawn_remote ] . recv_sync_ids [ net_id ] = sync - > get_instance_id ( ) ;
// Try to apply spawn state (before ready).
if ( pending_buffer_size > 0 ) {
ERR_FAIL_COND_V ( ! node | | sync - > get_replication_config ( ) . is_null ( ) , ERR_UNCONFIGURED ) ;
int consumed = 0 ;
const List < NodePath > props = sync - > get_replication_config ( ) - > get_spawn_properties ( ) ;
Vector < Variant > vars ;
vars . resize ( props . size ( ) ) ;
Error err = MultiplayerAPI : : decode_and_decompress_variants ( vars , pending_buffer , pending_buffer_size , consumed ) ;
ERR_FAIL_COND_V ( err , err ) ;
if ( consumed > 0 ) {
pending_buffer + = consumed ;
pending_buffer_size - = consumed ;
err = MultiplayerSynchronizer : : set_state ( props , node , vars ) ;
ERR_FAIL_COND_V ( err , err ) ;
}
}
2021-10-08 14:13:06 +02:00
}
return OK ;
}
Error SceneReplicationInterface : : on_replication_stop ( Object * p_obj , Variant p_config ) {
Node * node = Object : : cast_to < Node > ( p_obj ) ;
ERR_FAIL_COND_V ( ! node | | p_config . get_type ( ) ! = Variant : : OBJECT , ERR_INVALID_PARAMETER ) ;
MultiplayerSynchronizer * sync = Object : : cast_to < MultiplayerSynchronizer > ( p_config . get_validated_object ( ) ) ;
2022-07-09 20:45:30 +02:00
ERR_FAIL_COND_V ( ! sync , ERR_INVALID_PARAMETER ) ;
sync - > disconnect ( " visibility_changed " , callable_mp ( this , & SceneReplicationInterface : : _visibility_changed ) ) ;
2022-09-30 22:35:56 +02:00
// Untrack synchronizer.
const ObjectID oid = node - > get_instance_id ( ) ;
const ObjectID sid = sync - > get_instance_id ( ) ;
ERR_FAIL_COND_V ( ! tracked_nodes . has ( oid ) , ERR_INVALID_PARAMETER ) ;
TrackedNode & tobj = _track ( oid ) ;
tobj . synchronizers . erase ( sid ) ;
sync_nodes . erase ( sid ) ;
for ( KeyValue < int , PeerInfo > & E : peers_info ) {
E . value . sync_nodes . erase ( sid ) ;
if ( sync - > get_net_id ( ) ) {
E . value . recv_sync_ids . erase ( sync - > get_net_id ( ) ) ;
}
}
return OK ;
2021-10-08 14:13:06 +02:00
}
2022-09-30 22:35:56 +02:00
void SceneReplicationInterface : : _visibility_changed ( int p_peer , ObjectID p_sid ) {
MultiplayerSynchronizer * sync = get_id_as < MultiplayerSynchronizer > ( p_sid ) ;
ERR_FAIL_COND ( ! sync ) ; // Bug.
Node * node = sync - > get_root_node ( ) ;
ERR_FAIL_COND ( ! node ) ; // Bug.
const ObjectID oid = node - > get_instance_id ( ) ;
if ( spawned_nodes . has ( oid ) ) {
_update_spawn_visibility ( p_peer , oid ) ;
2022-07-09 20:45:30 +02:00
}
2022-09-30 22:35:56 +02:00
_update_sync_visibility ( p_peer , sync ) ;
2022-07-09 20:45:30 +02:00
}
2022-09-30 22:35:56 +02:00
Error SceneReplicationInterface : : _update_sync_visibility ( int p_peer , MultiplayerSynchronizer * p_sync ) {
ERR_FAIL_COND_V ( ! p_sync , ERR_BUG ) ;
if ( ! multiplayer - > has_multiplayer_peer ( ) | | ! p_sync - > is_multiplayer_authority ( ) ) {
return OK ;
}
const ObjectID & sid = p_sync - > get_instance_id ( ) ;
bool is_visible = p_sync - > is_visible_to ( p_peer ) ;
2022-07-09 20:45:30 +02:00
if ( p_peer = = 0 ) {
2022-09-30 22:35:56 +02:00
for ( KeyValue < int , PeerInfo > & E : peers_info ) {
2022-07-09 20:45:30 +02:00
// Might be visible to this specific peer.
2022-10-16 13:26:13 +02:00
bool is_visible_to_peer = is_visible | | p_sync - > is_visible_to ( E . key ) ;
if ( is_visible_to_peer = = E . value . sync_nodes . has ( sid ) ) {
2022-07-09 20:45:30 +02:00
continue ;
}
2022-10-16 13:26:13 +02:00
if ( is_visible_to_peer ) {
2022-09-30 22:35:56 +02:00
E . value . sync_nodes . insert ( sid ) ;
2022-07-09 20:45:30 +02:00
} else {
2022-09-30 22:35:56 +02:00
E . value . sync_nodes . erase ( sid ) ;
2022-07-09 20:45:30 +02:00
}
}
return OK ;
} else {
2022-09-30 22:35:56 +02:00
ERR_FAIL_COND_V ( ! peers_info . has ( p_peer ) , ERR_INVALID_PARAMETER ) ;
if ( is_visible = = peers_info [ p_peer ] . sync_nodes . has ( sid ) ) {
2022-07-09 20:45:30 +02:00
return OK ;
}
if ( is_visible ) {
2022-09-30 22:35:56 +02:00
peers_info [ p_peer ] . sync_nodes . insert ( sid ) ;
2022-07-09 20:45:30 +02:00
} else {
2022-09-30 22:35:56 +02:00
peers_info [ p_peer ] . sync_nodes . erase ( sid ) ;
2022-07-09 20:45:30 +02:00
}
2022-09-30 22:35:56 +02:00
return OK ;
2022-07-09 20:45:30 +02:00
}
}
Error SceneReplicationInterface : : _update_spawn_visibility ( int p_peer , const ObjectID & p_oid ) {
2022-09-30 22:35:56 +02:00
const TrackedNode * tnode = tracked_nodes . getptr ( p_oid ) ;
ERR_FAIL_COND_V ( ! tnode , ERR_BUG ) ;
MultiplayerSpawner * spawner = get_id_as < MultiplayerSpawner > ( tnode - > spawner ) ;
Node * node = get_id_as < Node > ( p_oid ) ;
2022-07-09 20:45:30 +02:00
ERR_FAIL_COND_V ( ! node | | ! spawner | | ! spawner - > is_multiplayer_authority ( ) , ERR_BUG ) ;
2022-09-30 22:35:56 +02:00
ERR_FAIL_COND_V ( ! tracked_nodes . has ( p_oid ) , ERR_BUG ) ;
const HashSet < ObjectID > synchronizers = tracked_nodes [ p_oid ] . synchronizers ;
bool is_visible = true ;
for ( const ObjectID & sid : synchronizers ) {
MultiplayerSynchronizer * sync = get_id_as < MultiplayerSynchronizer > ( sid ) ;
ERR_CONTINUE ( ! sync ) ;
if ( ! sync - > is_multiplayer_authority ( ) ) {
continue ;
}
// Spawn visibility is composed using OR when multiple synchronizers are present.
if ( sync - > is_visible_to ( p_peer ) ) {
is_visible = true ;
break ;
}
is_visible = false ;
}
2022-07-09 20:45:30 +02:00
// Spawn (and despawn) when needed.
HashSet < int > to_spawn ;
HashSet < int > to_despawn ;
if ( p_peer ) {
2022-09-30 22:35:56 +02:00
ERR_FAIL_COND_V ( ! peers_info . has ( p_peer ) , ERR_INVALID_PARAMETER ) ;
if ( is_visible = = peers_info [ p_peer ] . spawn_nodes . has ( p_oid ) ) {
2022-07-09 20:45:30 +02:00
return OK ;
}
if ( is_visible ) {
to_spawn . insert ( p_peer ) ;
} else {
to_despawn . insert ( p_peer ) ;
}
} else {
// Check visibility for each peers.
2022-09-30 22:35:56 +02:00
for ( const KeyValue < int , PeerInfo > & E : peers_info ) {
if ( is_visible ) {
// This is fast, since the the object is visibile to everyone, we don't need to check each peer.
if ( E . value . spawn_nodes . has ( p_oid ) ) {
// Already spawned.
continue ;
}
to_spawn . insert ( E . key ) ;
2022-07-09 20:45:30 +02:00
} else {
2022-09-30 22:35:56 +02:00
// Need to check visibility for each peer.
_update_spawn_visibility ( E . key , p_oid ) ;
2022-07-09 20:45:30 +02:00
}
}
}
if ( to_spawn . size ( ) ) {
int len = 0 ;
2022-09-30 22:35:56 +02:00
_make_spawn_packet ( node , spawner , len ) ;
2022-07-09 20:45:30 +02:00
for ( int pid : to_spawn ) {
2022-09-30 22:35:56 +02:00
ERR_CONTINUE ( ! peers_info . has ( pid ) ) ;
2022-07-09 20:45:30 +02:00
int path_id ;
2022-07-12 23:12:42 +02:00
multiplayer - > get_path_cache ( ) - > send_object_cache ( spawner , pid , path_id ) ;
2022-07-09 20:45:30 +02:00
_send_raw ( packet_cache . ptr ( ) , len , pid , true ) ;
2022-09-30 22:35:56 +02:00
peers_info [ pid ] . spawn_nodes . insert ( p_oid ) ;
2022-07-09 20:45:30 +02:00
}
}
if ( to_despawn . size ( ) ) {
int len = 0 ;
_make_despawn_packet ( node , len ) ;
for ( int pid : to_despawn ) {
2022-09-30 22:35:56 +02:00
ERR_CONTINUE ( ! peers_info . has ( pid ) ) ;
peers_info [ pid ] . spawn_nodes . erase ( p_oid ) ;
2022-07-09 20:45:30 +02:00
_send_raw ( packet_cache . ptr ( ) , len , pid , true ) ;
}
}
return OK ;
}
2021-10-08 14:13:06 +02:00
Error SceneReplicationInterface : : _send_raw ( const uint8_t * p_buffer , int p_size , int p_peer , bool p_reliable ) {
ERR_FAIL_COND_V ( ! p_buffer | | p_size < 1 , ERR_INVALID_PARAMETER ) ;
ERR_FAIL_COND_V ( ! multiplayer , ERR_UNCONFIGURED ) ;
ERR_FAIL_COND_V ( ! multiplayer - > has_multiplayer_peer ( ) , ERR_UNCONFIGURED ) ;
2022-02-06 02:29:08 +01:00
# ifdef DEBUG_ENABLED
multiplayer - > profile_bandwidth ( " out " , p_size ) ;
# endif
2021-10-08 14:13:06 +02:00
Ref < MultiplayerPeer > peer = multiplayer - > get_multiplayer_peer ( ) ;
peer - > set_transfer_channel ( 0 ) ;
2022-07-12 23:12:42 +02:00
peer - > set_transfer_mode ( p_reliable ? MultiplayerPeer : : TRANSFER_MODE_RELIABLE : MultiplayerPeer : : TRANSFER_MODE_UNRELIABLE ) ;
2022-10-08 20:50:19 +02:00
return multiplayer - > send_command ( p_peer , p_buffer , p_size ) ;
2021-10-08 14:13:06 +02:00
}
2022-09-30 22:35:56 +02:00
Error SceneReplicationInterface : : _make_spawn_packet ( Node * p_node , MultiplayerSpawner * p_spawner , int & r_len ) {
ERR_FAIL_COND_V ( ! multiplayer | | ! p_node | | ! p_spawner , ERR_BUG ) ;
2021-10-08 14:13:06 +02:00
const ObjectID oid = p_node - > get_instance_id ( ) ;
2022-09-30 22:35:56 +02:00
const TrackedNode * tnode = tracked_nodes . getptr ( oid ) ;
ERR_FAIL_COND_V ( ! tnode , ERR_INVALID_PARAMETER ) ;
2022-07-09 20:45:30 +02:00
2022-09-30 22:35:56 +02:00
uint32_t nid = tnode - > net_id ;
2022-07-09 20:45:30 +02:00
ERR_FAIL_COND_V ( ! nid , ERR_UNCONFIGURED ) ;
2021-10-08 14:13:06 +02:00
// Prepare custom arg and scene_id
2022-09-30 22:35:56 +02:00
uint8_t scene_id = p_spawner - > find_spawnable_scene_index_from_object ( oid ) ;
2021-10-08 14:13:06 +02:00
bool is_custom = scene_id = = MultiplayerSpawner : : INVALID_ID ;
2022-09-30 22:35:56 +02:00
Variant spawn_arg = p_spawner - > get_spawn_argument ( oid ) ;
2021-10-08 14:13:06 +02:00
int spawn_arg_size = 0 ;
if ( is_custom ) {
Error err = MultiplayerAPI : : encode_and_compress_variant ( spawn_arg , nullptr , spawn_arg_size , false ) ;
ERR_FAIL_COND_V ( err , err ) ;
}
// Prepare spawn state.
2022-09-30 22:35:56 +02:00
List < NodePath > state_props ;
List < uint32_t > sync_ids ;
const HashSet < ObjectID > synchronizers = tnode - > synchronizers ;
for ( const ObjectID & sid : synchronizers ) {
MultiplayerSynchronizer * sync = get_id_as < MultiplayerSynchronizer > ( sid ) ;
if ( ! sync - > is_multiplayer_authority ( ) ) {
continue ;
}
ERR_CONTINUE ( ! sync ) ;
ERR_FAIL_COND_V ( sync - > get_replication_config ( ) . is_null ( ) , ERR_BUG ) ;
for ( const NodePath & prop : sync - > get_replication_config ( ) - > get_spawn_properties ( ) ) {
state_props . push_back ( prop ) ;
}
// Ensure the synchronizer has an ID.
if ( sync - > get_net_id ( ) = = 0 ) {
sync - > set_net_id ( + + last_net_id ) ;
}
sync_ids . push_back ( sync - > get_net_id ( ) ) ;
}
2021-10-08 14:13:06 +02:00
int state_size = 0 ;
Vector < Variant > state_vars ;
Vector < const Variant * > state_varp ;
2022-09-30 22:35:56 +02:00
if ( state_props . size ( ) ) {
Error err = MultiplayerSynchronizer : : get_state ( state_props , p_node , state_vars , state_varp ) ;
2021-10-08 14:13:06 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Unable to retrieve spawn state. " ) ;
err = MultiplayerAPI : : encode_and_compress_variants ( state_varp . ptrw ( ) , state_varp . size ( ) , nullptr , state_size ) ;
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Unable to encode spawn state. " ) ;
}
2022-07-09 20:45:30 +02:00
// Encode scene ID, path ID, net ID, node name.
2022-09-30 22:35:56 +02:00
int path_id = multiplayer - > get_path_cache ( ) - > make_object_cache ( p_spawner ) ;
2021-10-08 14:13:06 +02:00
CharString cname = p_node - > get_name ( ) . operator String ( ) . utf8 ( ) ;
int nlen = encode_cstring ( cname . get_data ( ) , nullptr ) ;
2022-09-30 22:35:56 +02:00
MAKE_ROOM ( 1 + 1 + 4 + 4 + 4 + 4 * sync_ids . size ( ) + 4 + nlen + ( is_custom ? 4 + spawn_arg_size : 0 ) + state_size ) ;
2021-10-08 14:13:06 +02:00
uint8_t * ptr = packet_cache . ptrw ( ) ;
2022-07-12 23:12:42 +02:00
ptr [ 0 ] = ( uint8_t ) SceneMultiplayer : : NETWORK_COMMAND_SPAWN ;
2021-10-08 14:13:06 +02:00
ptr [ 1 ] = scene_id ;
int ofs = 2 ;
ofs + = encode_uint32 ( path_id , & ptr [ ofs ] ) ;
ofs + = encode_uint32 ( nid , & ptr [ ofs ] ) ;
2022-09-30 22:35:56 +02:00
ofs + = encode_uint32 ( sync_ids . size ( ) , & ptr [ ofs ] ) ;
2021-10-08 14:13:06 +02:00
ofs + = encode_uint32 ( nlen , & ptr [ ofs ] ) ;
2022-09-30 22:35:56 +02:00
for ( uint32_t snid : sync_ids ) {
ofs + = encode_uint32 ( snid , & ptr [ ofs ] ) ;
}
2021-10-08 14:13:06 +02:00
ofs + = encode_cstring ( cname . get_data ( ) , & ptr [ ofs ] ) ;
// Write args
if ( is_custom ) {
ofs + = encode_uint32 ( spawn_arg_size , & ptr [ ofs ] ) ;
Error err = MultiplayerAPI : : encode_and_compress_variant ( spawn_arg , & ptr [ ofs ] , spawn_arg_size , false ) ;
ERR_FAIL_COND_V ( err , err ) ;
ofs + = spawn_arg_size ;
}
// Write state.
if ( state_size ) {
Error err = MultiplayerAPI : : encode_and_compress_variants ( state_varp . ptrw ( ) , state_varp . size ( ) , & ptr [ ofs ] , state_size ) ;
ERR_FAIL_COND_V ( err , err ) ;
ofs + = state_size ;
}
2022-07-09 20:45:30 +02:00
r_len = ofs ;
return OK ;
2021-10-08 14:13:06 +02:00
}
2022-07-09 20:45:30 +02:00
Error SceneReplicationInterface : : _make_despawn_packet ( Node * p_node , int & r_len ) {
2021-10-08 14:13:06 +02:00
const ObjectID oid = p_node - > get_instance_id ( ) ;
2022-09-30 22:35:56 +02:00
const TrackedNode * tnode = tracked_nodes . getptr ( oid ) ;
ERR_FAIL_COND_V ( ! tnode , ERR_INVALID_PARAMETER ) ;
2021-10-08 14:13:06 +02:00
MAKE_ROOM ( 5 ) ;
uint8_t * ptr = packet_cache . ptrw ( ) ;
2022-07-12 23:12:42 +02:00
ptr [ 0 ] = ( uint8_t ) SceneMultiplayer : : NETWORK_COMMAND_DESPAWN ;
2021-10-08 14:13:06 +02:00
int ofs = 1 ;
2022-09-30 22:35:56 +02:00
uint32_t nid = tnode - > net_id ;
2021-10-08 14:13:06 +02:00
ofs + = encode_uint32 ( nid , & ptr [ ofs ] ) ;
2022-07-09 20:45:30 +02:00
r_len = ofs ;
return OK ;
2021-10-08 14:13:06 +02:00
}
Error SceneReplicationInterface : : on_spawn_receive ( int p_from , const uint8_t * p_buffer , int p_buffer_len ) {
2022-09-30 22:35:56 +02:00
ERR_FAIL_COND_V_MSG ( p_buffer_len < 18 , ERR_INVALID_DATA , " Invalid spawn packet received " ) ;
2021-10-08 14:13:06 +02:00
int ofs = 1 ; // The spawn/despawn command.
uint8_t scene_id = p_buffer [ ofs ] ;
ofs + = 1 ;
uint32_t node_target = decode_uint32 ( & p_buffer [ ofs ] ) ;
ofs + = 4 ;
2022-07-12 23:12:42 +02:00
MultiplayerSpawner * spawner = Object : : cast_to < MultiplayerSpawner > ( multiplayer - > get_path_cache ( ) - > get_cached_object ( p_from , node_target ) ) ;
2021-10-08 14:13:06 +02:00
ERR_FAIL_COND_V ( ! spawner , ERR_DOES_NOT_EXIST ) ;
ERR_FAIL_COND_V ( p_from ! = spawner - > get_multiplayer_authority ( ) , ERR_UNAUTHORIZED ) ;
uint32_t net_id = decode_uint32 ( & p_buffer [ ofs ] ) ;
ofs + = 4 ;
2022-09-30 22:35:56 +02:00
uint32_t sync_len = decode_uint32 ( & p_buffer [ ofs ] ) ;
ofs + = 4 ;
2021-10-08 14:13:06 +02:00
uint32_t name_len = decode_uint32 ( & p_buffer [ ofs ] ) ;
ofs + = 4 ;
2022-09-30 22:35:56 +02:00
ERR_FAIL_COND_V_MSG ( name_len + ( sync_len * 4 ) > uint32_t ( p_buffer_len - ofs ) , ERR_INVALID_DATA , vformat ( " Invalid spawn packet size: %d, wants: %d " , p_buffer_len , ofs + name_len + ( sync_len * 4 ) ) ) ;
List < uint32_t > sync_ids ;
for ( uint32_t i = 0 ; i < sync_len ; i + + ) {
sync_ids . push_back ( decode_uint32 ( & p_buffer [ ofs ] ) ) ;
ofs + = 4 ;
}
2021-10-08 14:13:06 +02:00
ERR_FAIL_COND_V_MSG ( name_len < 1 , ERR_INVALID_DATA , " Zero spawn name size. " ) ;
// We need to make sure no trickery happens here, but we want to allow autogenerated ("@") node names.
const String name = String : : utf8 ( ( const char * ) & p_buffer [ ofs ] , name_len ) ;
ERR_FAIL_COND_V_MSG ( name . validate_node_name ( ) ! = name , ERR_INVALID_DATA , vformat ( " Invalid node name received: '%s'. Make sure to add nodes via 'add_child(node, true)' remotely. " , name ) ) ;
ofs + = name_len ;
// Check that we can spawn.
Node * parent = spawner - > get_node_or_null ( spawner - > get_spawn_path ( ) ) ;
ERR_FAIL_COND_V ( ! parent , ERR_UNCONFIGURED ) ;
ERR_FAIL_COND_V ( parent - > has_node ( name ) , ERR_INVALID_DATA ) ;
Node * node = nullptr ;
if ( scene_id = = MultiplayerSpawner : : INVALID_ID ) {
// Custom spawn.
ERR_FAIL_COND_V ( p_buffer_len - ofs < 4 , ERR_INVALID_DATA ) ;
uint32_t arg_size = decode_uint32 ( & p_buffer [ ofs ] ) ;
ofs + = 4 ;
ERR_FAIL_COND_V ( arg_size > uint32_t ( p_buffer_len - ofs ) , ERR_INVALID_DATA ) ;
Variant v ;
Error err = MultiplayerAPI : : decode_and_decompress_variant ( v , & p_buffer [ ofs ] , arg_size , nullptr , false ) ;
ERR_FAIL_COND_V ( err ! = OK , err ) ;
ofs + = arg_size ;
node = spawner - > instantiate_custom ( v ) ;
} else {
// Scene based spawn.
node = spawner - > instantiate_scene ( scene_id ) ;
}
ERR_FAIL_COND_V ( ! node , ERR_UNAUTHORIZED ) ;
node - > set_name ( name ) ;
2022-09-30 22:35:56 +02:00
// Add and track remote
ERR_FAIL_COND_V ( ! peers_info . has ( p_from ) , ERR_UNAVAILABLE ) ;
ERR_FAIL_COND_V ( peers_info [ p_from ] . recv_nodes . has ( net_id ) , ERR_ALREADY_IN_USE ) ;
ObjectID oid = node - > get_instance_id ( ) ;
TrackedNode & tobj = _track ( oid ) ;
tobj . spawner = spawner - > get_instance_id ( ) ;
tobj . net_id = net_id ;
tobj . remote_peer = p_from ;
peers_info [ p_from ] . recv_nodes [ net_id ] = oid ;
2021-10-08 14:13:06 +02:00
// The initial state will be applied during the sync config (i.e. before _ready).
2022-09-30 22:35:56 +02:00
pending_spawn = node - > get_instance_id ( ) ;
pending_spawn_remote = p_from ;
pending_buffer_size = p_buffer_len - ofs ;
pending_buffer = pending_buffer_size > 0 ? & p_buffer [ ofs ] : nullptr ;
pending_sync_net_ids = sync_ids ;
2021-10-08 14:13:06 +02:00
parent - > add_child ( node ) ;
2022-07-29 01:30:30 +02:00
spawner - > emit_signal ( SNAME ( " spawned " ) , node ) ;
2021-10-08 14:13:06 +02:00
pending_spawn = ObjectID ( ) ;
2022-09-30 22:35:56 +02:00
pending_spawn_remote = 0 ;
2021-10-08 14:13:06 +02:00
pending_buffer = nullptr ;
pending_buffer_size = 0 ;
2022-09-30 22:35:56 +02:00
if ( pending_sync_net_ids . size ( ) ) {
pending_sync_net_ids . clear ( ) ;
ERR_FAIL_V ( ERR_INVALID_DATA ) ; // Should have been consumed.
}
2021-10-08 14:13:06 +02:00
return OK ;
}
Error SceneReplicationInterface : : on_despawn_receive ( int p_from , const uint8_t * p_buffer , int p_buffer_len ) {
ERR_FAIL_COND_V_MSG ( p_buffer_len < 5 , ERR_INVALID_DATA , " Invalid spawn packet received " ) ;
int ofs = 1 ; // The spawn/despawn command.
uint32_t net_id = decode_uint32 ( & p_buffer [ ofs ] ) ;
ofs + = 4 ;
2022-09-30 22:35:56 +02:00
// Untrack remote
ERR_FAIL_COND_V ( ! peers_info . has ( p_from ) , ERR_UNAUTHORIZED ) ;
PeerInfo & pinfo = peers_info [ p_from ] ;
ERR_FAIL_COND_V ( ! pinfo . recv_nodes . has ( net_id ) , ERR_UNAUTHORIZED ) ;
Node * node = get_id_as < Node > ( pinfo . recv_nodes [ net_id ] ) ;
2021-10-08 14:13:06 +02:00
ERR_FAIL_COND_V ( ! node , ERR_BUG ) ;
2022-09-30 22:35:56 +02:00
pinfo . recv_nodes . erase ( net_id ) ;
2022-07-29 01:30:30 +02:00
2022-09-30 22:35:56 +02:00
const ObjectID oid = node - > get_instance_id ( ) ;
ERR_FAIL_COND_V ( ! tracked_nodes . has ( oid ) , ERR_BUG ) ;
MultiplayerSpawner * spawner = get_id_as < MultiplayerSpawner > ( tracked_nodes [ oid ] . spawner ) ;
2022-07-29 01:30:30 +02:00
ERR_FAIL_COND_V ( ! spawner , ERR_DOES_NOT_EXIST ) ;
ERR_FAIL_COND_V ( p_from ! = spawner - > get_multiplayer_authority ( ) , ERR_UNAUTHORIZED ) ;
2022-04-23 22:01:01 +02:00
if ( node - > get_parent ( ) ! = nullptr ) {
node - > get_parent ( ) - > remove_child ( node ) ;
}
2022-10-24 23:07:02 +02:00
node - > queue_free ( ) ;
2022-07-29 01:30:30 +02:00
spawner - > emit_signal ( SNAME ( " despawned " ) , node ) ;
2021-10-08 14:13:06 +02:00
return OK ;
}
2022-09-30 22:35:56 +02:00
void SceneReplicationInterface : : _send_sync ( int p_peer , const HashSet < ObjectID > p_synchronizers , uint16_t p_sync_net_time , uint64_t p_msec ) {
2021-10-08 14:13:06 +02:00
MAKE_ROOM ( sync_mtu ) ;
uint8_t * ptr = packet_cache . ptrw ( ) ;
2022-07-12 23:12:42 +02:00
ptr [ 0 ] = SceneMultiplayer : : NETWORK_COMMAND_SYNC ;
2021-10-08 14:13:06 +02:00
int ofs = 1 ;
2022-09-30 22:35:56 +02:00
ofs + = encode_uint16 ( p_sync_net_time , & ptr [ 1 ] ) ;
2021-10-08 14:13:06 +02:00
// Can only send updates for already notified nodes.
// This is a lazy implementation, we could optimize much more here with by grouping by replication config.
2022-09-30 22:35:56 +02:00
for ( const ObjectID & oid : p_synchronizers ) {
MultiplayerSynchronizer * sync = get_id_as < MultiplayerSynchronizer > ( oid ) ;
ERR_CONTINUE ( ! sync | | ! sync - > get_replication_config ( ) . is_valid ( ) | | ! sync - > is_multiplayer_authority ( ) ) ;
if ( ! sync - > update_outbound_sync_time ( p_msec ) ) {
2021-10-08 14:13:06 +02:00
continue ; // nothing to sync.
}
2022-09-30 22:35:56 +02:00
Node * node = sync - > get_root_node ( ) ;
2021-10-08 14:13:06 +02:00
ERR_CONTINUE ( ! node ) ;
2022-09-30 22:35:56 +02:00
uint32_t net_id = sync - > get_net_id ( ) ;
2022-07-09 20:45:30 +02:00
if ( net_id = = 0 | | ( net_id & 0x80000000 ) ) {
int path_id = 0 ;
2022-07-12 23:12:42 +02:00
bool verified = multiplayer - > get_path_cache ( ) - > send_object_cache ( sync , p_peer , path_id ) ;
2022-07-09 20:45:30 +02:00
ERR_CONTINUE_MSG ( path_id < 0 , " This should never happen! " ) ;
if ( net_id = = 0 ) {
// First time path based ID.
net_id = path_id | 0x80000000 ;
2022-09-30 22:35:56 +02:00
sync - > set_net_id ( net_id | 0x80000000 ) ;
2022-07-09 20:45:30 +02:00
}
if ( ! verified ) {
// The path based sync is not yet confirmed, skipping.
continue ;
}
}
2021-10-08 14:13:06 +02:00
int size ;
Vector < Variant > vars ;
Vector < const Variant * > varp ;
const List < NodePath > props = sync - > get_replication_config ( ) - > get_sync_properties ( ) ;
Error err = MultiplayerSynchronizer : : get_state ( props , node , vars , varp ) ;
ERR_CONTINUE_MSG ( err ! = OK , " Unable to retrieve sync state. " ) ;
err = MultiplayerAPI : : encode_and_compress_variants ( varp . ptrw ( ) , varp . size ( ) , nullptr , size ) ;
ERR_CONTINUE_MSG ( err ! = OK , " Unable to encode sync state. " ) ;
// TODO Handle single state above MTU.
ERR_CONTINUE_MSG ( size > 3 + 4 + 4 + sync_mtu , vformat ( " Node states bigger then MTU will not be sent (%d > %d): %s " , size , sync_mtu , node - > get_path ( ) ) ) ;
if ( ofs + 4 + 4 + size > sync_mtu ) {
// Send what we got, and reset write.
_send_raw ( packet_cache . ptr ( ) , ofs , p_peer , false ) ;
ofs = 3 ;
}
if ( size ) {
2022-09-30 22:35:56 +02:00
ofs + = encode_uint32 ( sync - > get_net_id ( ) , & ptr [ ofs ] ) ;
2021-10-08 14:13:06 +02:00
ofs + = encode_uint32 ( size , & ptr [ ofs ] ) ;
MultiplayerAPI : : encode_and_compress_variants ( varp . ptrw ( ) , varp . size ( ) , & ptr [ ofs ] , size ) ;
ofs + = size ;
}
}
if ( ofs > 3 ) {
// Got some left over to send.
_send_raw ( packet_cache . ptr ( ) , ofs , p_peer , false ) ;
}
}
Error SceneReplicationInterface : : on_sync_receive ( int p_from , const uint8_t * p_buffer , int p_buffer_len ) {
ERR_FAIL_COND_V_MSG ( p_buffer_len < 11 , ERR_INVALID_DATA , " Invalid sync packet received " ) ;
uint16_t time = decode_uint16 ( & p_buffer [ 1 ] ) ;
int ofs = 3 ;
while ( ofs + 8 < p_buffer_len ) {
uint32_t net_id = decode_uint32 ( & p_buffer [ ofs ] ) ;
ofs + = 4 ;
uint32_t size = decode_uint32 ( & p_buffer [ ofs ] ) ;
ofs + = 4 ;
2022-09-30 22:35:56 +02:00
MultiplayerSynchronizer * sync = nullptr ;
2021-10-08 14:13:06 +02:00
if ( net_id & 0x80000000 ) {
2022-09-30 22:35:56 +02:00
sync = Object : : cast_to < MultiplayerSynchronizer > ( multiplayer - > get_path_cache ( ) - > get_cached_object ( p_from , net_id & 0x7FFFFFFF ) ) ;
} else if ( peers_info [ p_from ] . recv_sync_ids . has ( net_id ) ) {
const ObjectID & sid = peers_info [ p_from ] . recv_sync_ids [ net_id ] ;
sync = get_id_as < MultiplayerSynchronizer > ( sid ) ;
2021-10-08 14:13:06 +02:00
}
2022-09-30 22:35:56 +02:00
if ( ! sync ) {
2021-10-08 14:13:06 +02:00
// Not received yet.
ofs + = size ;
continue ;
}
2022-09-30 22:35:56 +02:00
Node * node = sync - > get_root_node ( ) ;
if ( sync - > get_multiplayer_authority ( ) ! = p_from | | ! node ) {
ERR_CONTINUE ( true ) ;
}
if ( ! sync - > update_inbound_sync_time ( time ) ) {
2021-10-08 14:13:06 +02:00
// State is too old.
ofs + = size ;
continue ;
}
ERR_FAIL_COND_V ( size > uint32_t ( p_buffer_len - ofs ) , ERR_BUG ) ;
const List < NodePath > props = sync - > get_replication_config ( ) - > get_sync_properties ( ) ;
Vector < Variant > vars ;
vars . resize ( props . size ( ) ) ;
int consumed ;
Error err = MultiplayerAPI : : decode_and_decompress_variants ( vars , & p_buffer [ ofs ] , size , consumed ) ;
ERR_FAIL_COND_V ( err , err ) ;
err = MultiplayerSynchronizer : : set_state ( props , node , vars ) ;
ERR_FAIL_COND_V ( err , err ) ;
ofs + = size ;
}
return OK ;
}