2014-01-31 00:24:00 +01:00
/*
Minetest
Copyright ( C ) 2010 - 2014 celeron55 , Perttu Ahola < celeron55 @ gmail . com >
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License along
with this program ; if not , write to the Free Software Foundation , Inc . ,
51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2014-02-13 20:17:42 +01:00
# include <sstream>
2014-01-31 00:24:00 +01:00
# include "clientiface.h"
2017-08-16 22:11:45 +02:00
# include "network/connection.h"
# include "network/serveropcodes.h"
2016-10-08 19:08:23 +02:00
# include "remoteplayer.h"
2014-01-31 00:24:00 +01:00
# include "settings.h"
# include "mapblock.h"
2017-01-08 11:01:35 +01:00
# include "serverenvironment.h"
2014-01-31 00:24:00 +01:00
# include "map.h"
# include "emerge.h"
2020-04-11 11:22:15 +02:00
# include "server/luaentity_sao.h"
2020-04-11 09:59:09 +02:00
# include "server/player_sao.h"
2014-09-11 18:22:05 -04:00
# include "log.h"
2015-04-12 04:49:13 +02:00
# include "util/srp.h"
2015-07-06 12:53:30 -04:00
# include "face_position_cache.h"
2014-01-31 00:24:00 +01:00
2014-06-28 02:02:38 -04:00
const char * ClientInterface : : statenames [ ] = {
" Invalid " ,
" Disconnecting " ,
" Denied " ,
" Created " ,
2015-08-31 13:26:40 +02:00
" AwaitingInit2 " ,
" HelloSent " ,
2014-06-28 02:02:38 -04:00
" InitDone " ,
" DefinitionsSent " ,
2015-08-31 13:26:40 +02:00
" Active " ,
" SudoMode " ,
2014-06-28 02:02:38 -04:00
} ;
std : : string ClientInterface : : state2Name ( ClientState state )
{
return statenames [ state ] ;
}
2017-10-15 00:32:17 -07:00
RemoteClient : : RemoteClient ( ) :
m_max_simul_sends ( g_settings - > getU16 ( " max_simultaneous_block_sends_per_client " ) ) ,
m_min_time_from_building (
g_settings - > getFloat ( " full_block_send_enable_min_time_from_building " ) ) ,
m_max_send_distance ( g_settings - > getS16 ( " max_block_send_distance " ) ) ,
m_block_optimize_distance ( g_settings - > getS16 ( " block_send_optimize_distance " ) ) ,
m_max_gen_distance ( g_settings - > getS16 ( " max_block_generate_distance " ) ) ,
m_occ_cull ( g_settings - > getBool ( " server_side_occlusion_culling " ) )
{
}
2014-07-12 20:20:11 +02:00
void RemoteClient : : ResendBlockIfOnWire ( v3s16 p )
{
// if this block is on wire, mark it for sending again as soon as possible
if ( m_blocks_sending . find ( p ) ! = m_blocks_sending . end ( ) ) {
SetBlockNotSent ( p ) ;
}
}
2014-06-28 02:02:38 -04:00
2017-09-30 18:54:43 -07:00
LuaEntitySAO * getAttachedObject ( PlayerSAO * sao , ServerEnvironment * env )
{
if ( ! sao - > isAttached ( ) )
return nullptr ;
int id ;
std : : string bone ;
v3f dummy ;
2020-10-04 14:10:34 +01:00
bool force_visible ;
sao - > getAttachment ( & id , & bone , & dummy , & dummy , & force_visible ) ;
2017-09-30 18:54:43 -07:00
ServerActiveObject * ao = env - > getActiveObject ( id ) ;
while ( id & & ao ) {
2020-10-04 14:10:34 +01:00
ao - > getAttachment ( & id , & bone , & dummy , & dummy , & force_visible ) ;
2017-09-30 18:54:43 -07:00
if ( id )
ao = env - > getActiveObject ( id ) ;
}
return dynamic_cast < LuaEntitySAO * > ( ao ) ;
}
2015-02-15 17:30:38 +01:00
void RemoteClient : : GetNextBlocks (
2014-01-31 00:24:00 +01:00
ServerEnvironment * env ,
EmergeManager * emerge ,
float dtime ,
std : : vector < PrioritySortedBlockTransfer > & dest )
{
// Increment timers
m_nothing_to_send_pause_timer - = dtime ;
2023-03-03 17:41:30 -08:00
m_map_send_completion_timer + = dtime ;
2014-01-31 00:24:00 +01:00
2023-03-30 09:19:13 -07:00
if ( m_map_send_completion_timer > g_settings - > getFloat ( " server_unload_unused_data_timeout " ) * 0.8f ) {
infostream < < " Server: Player " < < m_name < < " , peer_id= " < < peer_id
< < " : full map send is taking too long ( "
< < m_map_send_completion_timer
< < " s), restarting to avoid visible blocks being unloaded. "
< < std : : endl ;
m_map_send_completion_timer = 0.0f ;
m_nearest_unsent_d = 0 ;
}
2017-10-15 00:32:17 -07:00
if ( m_nothing_to_send_pause_timer > = 0 )
2014-01-31 00:24:00 +01:00
return ;
2016-10-08 16:31:22 +02:00
RemotePlayer * player = env - > getPlayer ( peer_id ) ;
2014-01-31 00:24:00 +01:00
// This can happen sometimes; clients and players are not in perfect sync.
2017-06-17 19:11:28 +02:00
if ( ! player )
2014-01-31 00:24:00 +01:00
return ;
2016-10-30 14:53:26 +01:00
PlayerSAO * sao = player - > getPlayerSAO ( ) ;
2017-06-17 19:11:28 +02:00
if ( ! sao )
2016-10-30 14:53:26 +01:00
return ;
2014-01-31 00:24:00 +01:00
// Won't send anything if already sending
2017-10-15 00:32:17 -07:00
if ( m_blocks_sending . size ( ) > = m_max_simul_sends ) {
2014-01-31 00:24:00 +01:00
//infostream<<"Not sending any blocks, Queue full."<<std::endl;
return ;
}
2016-10-30 14:53:26 +01:00
v3f playerpos = sao - > getBasePosition ( ) ;
2017-09-30 18:54:43 -07:00
// if the player is attached, get the velocity from the attached object
LuaEntitySAO * lsao = getAttachedObject ( sao , env ) ;
const v3f & playerspeed = lsao ? lsao - > getVelocity ( ) : player - > getSpeed ( ) ;
2014-01-31 00:24:00 +01:00
v3f playerspeeddir ( 0 , 0 , 0 ) ;
2017-10-15 00:32:17 -07:00
if ( playerspeed . getLength ( ) > 1.0f * BS )
2014-01-31 00:24:00 +01:00
playerspeeddir = playerspeed / playerspeed . getLength ( ) ;
// Predict to next block
2017-10-25 23:10:33 -07:00
v3f playerpos_predicted = playerpos + playerspeeddir * ( MAP_BLOCKSIZE * BS ) ;
2014-01-31 00:24:00 +01:00
v3s16 center_nodepos = floatToInt ( playerpos_predicted , BS ) ;
v3s16 center = getNodeBlockPos ( center_nodepos ) ;
// Camera position and direction
2016-10-30 14:53:26 +01:00
v3f camera_pos = sao - > getEyePosition ( ) ;
2014-01-31 00:24:00 +01:00
v3f camera_dir = v3f ( 0 , 0 , 1 ) ;
2018-11-28 03:38:50 -05:00
camera_dir . rotateYZBy ( sao - > getLookPitch ( ) ) ;
camera_dir . rotateXZBy ( sao - > getRotation ( ) . Y ) ;
2014-01-31 00:24:00 +01:00
2017-10-15 00:32:17 -07:00
u16 max_simul_sends_usually = m_max_simul_sends ;
2014-01-31 00:24:00 +01:00
/*
Check the time from last addNode / removeNode .
Decrease send rate if player is building stuff .
*/
m_time_from_building + = dtime ;
2017-10-15 00:32:17 -07:00
if ( m_time_from_building < m_min_time_from_building ) {
2014-01-31 00:24:00 +01:00
max_simul_sends_usually
= LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS ;
}
/*
Number of blocks sending + number of blocks selected for sending
*/
u32 num_blocks_selected = m_blocks_sending . size ( ) ;
/*
next time d will be continued from the d from which the nearest
unsent block was found this time .
This is because not necessarily any of the blocks found this
time are actually sent .
*/
s32 new_nearest_unsent_d = - 1 ;
2018-04-15 21:56:05 +01:00
// Get view range and camera fov (radians) from the client
2017-09-30 18:54:43 -07:00
s16 wanted_range = sao - > getWantedRange ( ) + 1 ;
2016-11-30 00:13:14 -08:00
float camera_fov = sao - > getFov ( ) ;
2020-10-21 14:46:04 -07:00
/*
Get the starting value of the block finder radius .
*/
if ( m_last_center ! = center ) {
m_nearest_unsent_d = 0 ;
m_last_center = center ;
2023-03-30 09:19:13 -07:00
m_map_send_completion_timer = 0.0f ;
2020-10-21 14:46:04 -07:00
}
// reset the unsent distance if the view angle has changed more that 10% of the fov
// (this matches isBlockInSight which allows for an extra 10%)
if ( camera_dir . dotProduct ( m_last_camera_dir ) < std : : cos ( camera_fov * 0.1f ) ) {
m_nearest_unsent_d = 0 ;
m_last_camera_dir = camera_dir ;
2023-03-30 09:19:13 -07:00
m_map_send_completion_timer = 0.0f ;
2020-10-21 14:46:04 -07:00
}
if ( m_nearest_unsent_d > 0 ) {
// make sure any blocks modified since the last time we sent blocks are resent
for ( const v3s16 & p : m_blocks_modified ) {
m_nearest_unsent_d = std : : min ( m_nearest_unsent_d , center . getDistanceFrom ( p ) ) ;
}
}
m_blocks_modified . clear ( ) ;
s16 d_start = m_nearest_unsent_d ;
2018-05-15 18:49:11 -07:00
// Distrust client-sent FOV and get server-set player object property
2018-04-15 21:56:05 +01:00
// zoom FOV (degrees) as a check to avoid hacked clients using FOV to load
// distant world.
2018-07-02 16:16:17 -07:00
// (zoom is disabled by value 0)
float prop_zoom_fov = sao - > getZoomFOV ( ) < 0.001f ?
0.0f :
std : : max ( camera_fov , sao - > getZoomFOV ( ) * core : : DEGTORAD ) ;
2018-04-15 21:56:05 +01:00
2018-05-15 18:49:11 -07:00
const s16 full_d_max = std : : min ( adjustDist ( m_max_send_distance , prop_zoom_fov ) ,
2018-04-15 21:56:05 +01:00
wanted_range ) ;
2018-05-15 18:49:11 -07:00
const s16 d_opt = std : : min ( adjustDist ( m_block_optimize_distance , prop_zoom_fov ) ,
2018-04-15 21:56:05 +01:00
wanted_range ) ;
2017-11-15 21:58:23 -08:00
const s16 d_blocks_in_sight = full_d_max * BS * MAP_BLOCKSIZE ;
2018-05-15 18:49:11 -07:00
s16 d_max_gen = std : : min ( adjustDist ( m_max_gen_distance , prop_zoom_fov ) ,
2018-04-15 21:56:05 +01:00
wanted_range ) ;
2017-11-15 21:58:23 -08:00
2020-11-06 10:54:04 -08:00
s16 d_max = full_d_max ;
// Don't loop very much at a time
s16 max_d_increment_at_time = 2 ;
if ( d_max > d_start + max_d_increment_at_time )
d_max = d_start + max_d_increment_at_time ;
2017-10-25 23:10:33 -07:00
// cos(angle between velocity and camera) * |velocity|
// Limit to 0.0f in case player moves backwards.
f32 dot = rangelim ( camera_dir . dotProduct ( playerspeed ) , 0.0f , 300.0f ) ;
// Reduce the field of view when a player moves and looks forward.
// limit max fov effect to 50%, 60% at 20n/s fly speed
camera_fov = camera_fov / ( 1 + dot / 300.0f ) ;
2014-01-31 00:24:00 +01:00
s32 nearest_emerged_d = - 1 ;
s32 nearest_emergefull_d = - 1 ;
s32 nearest_sent_d = - 1 ;
2015-01-18 23:29:19 -05:00
//bool queue_is_full = false;
2014-01-31 00:24:00 +01:00
2017-02-27 23:06:15 -08:00
const v3s16 cam_pos_nodes = floatToInt ( camera_pos , BS ) ;
2014-01-31 00:24:00 +01:00
s16 d ;
2020-11-06 10:54:04 -08:00
for ( d = d_start ; d < = d_max ; d + + ) {
2014-01-31 00:24:00 +01:00
/*
Get the border / face dot coordinates of a " d-radiused "
box
*/
2015-02-15 17:30:38 +01:00
std : : vector < v3s16 > list = FacePositionCache : : getFacePositions ( d ) ;
2014-01-31 00:24:00 +01:00
2015-02-15 17:30:38 +01:00
std : : vector < v3s16 > : : iterator li ;
2017-10-15 00:32:17 -07:00
for ( li = list . begin ( ) ; li ! = list . end ( ) ; + + li ) {
2014-01-31 00:24:00 +01:00
v3s16 p = * li + center ;
/*
Send throttling
- Don ' t allow too many simultaneous transfers
- EXCEPT when the blocks are very close
Also , don ' t send blocks that are already flying .
*/
// Start with the usual maximum
u16 max_simul_dynamic = max_simul_sends_usually ;
// If block is very close, allow full maximum
2017-10-15 00:32:17 -07:00
if ( d < = BLOCK_SEND_DISABLE_LIMITS_MAX_D )
max_simul_dynamic = m_max_simul_sends ;
2014-01-31 00:24:00 +01:00
/*
2017-03-13 21:35:29 +00:00
Do not go over max mapgen limit
2014-01-31 00:24:00 +01:00
*/
2017-03-13 21:35:29 +00:00
if ( blockpos_over_max_limit ( p ) )
2014-01-31 00:24:00 +01:00
continue ;
// If this is true, inexistent block will be made from scratch
bool generate = d < = d_max_gen ;
/*
Don ' t generate or send if not in sight
FIXME This only works if the client uses a small enough
FOV setting . The default of 72 degrees is fine .
2017-09-30 18:54:43 -07:00
Also retrieve a smaller view cone in the direction of the player ' s
movement .
( 0.1 is about 4 degrees )
2014-01-31 00:24:00 +01:00
*/
2017-03-11 20:50:14 -08:00
f32 dist ;
2017-09-30 18:54:43 -07:00
if ( ! ( isBlockInSight ( p , camera_pos , camera_dir , camera_fov ,
d_blocks_in_sight , & dist ) | |
( playerspeed . getLength ( ) > 1.0f * BS & &
isBlockInSight ( p , camera_pos , playerspeeddir , 0.1f ,
d_blocks_in_sight ) ) ) ) {
2014-01-31 00:24:00 +01:00
continue ;
}
/*
Check if map has this block
*/
MapBlock * block = env - > getMap ( ) . getBlockNoCreateNoEx ( p ) ;
2017-06-17 19:11:28 +02:00
if ( block ) {
2023-02-27 09:57:03 -08:00
// First: Reset usage timer, this block will be of use in the future.
2014-01-31 00:24:00 +01:00
block - > resetUsageTimer ( ) ;
2023-02-27 09:57:03 -08:00
}
2014-01-31 00:24:00 +01:00
2023-03-30 09:19:13 -07:00
// Don't select too many blocks for sending
if ( num_blocks_selected > = max_simul_dynamic ) {
//queue_is_full = true;
goto queue_full_break ;
}
// Don't send blocks that are currently being transferred
if ( m_blocks_sending . find ( p ) ! = m_blocks_sending . end ( ) )
continue ;
2023-02-27 09:57:03 -08:00
/*
Don ' t send already sent blocks
*/
if ( m_blocks_sent . find ( p ) ! = m_blocks_sent . end ( ) )
continue ;
2023-02-26 14:18:18 -08:00
2023-02-27 09:57:03 -08:00
bool block_not_found = false ;
if ( block ) {
2020-11-02 09:27:15 -08:00
// Check whether the block exists (with data)
2022-10-05 07:55:33 -04:00
if ( ! block - > isGenerated ( ) )
2020-11-02 09:27:15 -08:00
block_not_found = true ;
2014-01-31 00:24:00 +01:00
/*
If block is not close , don ' t send it unless it is near
ground level .
Block is near ground level if night - time mesh
differs from day - time mesh .
*/
2017-08-20 19:37:29 +02:00
if ( d > = d_opt ) {
2018-07-12 00:53:50 -07:00
if ( ! block - > getIsUnderground ( ) & & ! block - > getDayNightDiff ( ) )
2014-01-31 00:24:00 +01:00
continue ;
}
2017-02-27 23:06:15 -08:00
2023-03-05 21:33:41 -08:00
/*
Check occlusion cache first .
*/
if ( m_blocks_occ . find ( p ) ! = m_blocks_occ . end ( ) )
continue ;
2020-11-02 09:27:15 -08:00
if ( m_occ_cull & & ! block_not_found & &
2017-02-27 23:06:15 -08:00
env - > getMap ( ) . isBlockOccluded ( block , cam_pos_nodes ) ) {
2023-03-05 21:33:41 -08:00
m_blocks_occ . insert ( p ) ;
2017-02-27 23:06:15 -08:00
continue ;
}
2014-01-31 00:24:00 +01:00
}
/*
2020-05-11 20:22:32 +02:00
If block has been marked to not exist on disk ( dummy ) or is
not generated and generating new ones is not wanted , skip block .
2014-01-31 00:24:00 +01:00
*/
2020-11-02 09:27:15 -08:00
if ( ! generate & & block_not_found ) {
2014-01-31 00:24:00 +01:00
// get next one.
continue ;
}
/*
Add inexistent block to emerge queue .
*/
2020-11-02 09:27:15 -08:00
if ( block = = NULL | | block_not_found ) {
2014-01-31 00:24:00 +01:00
if ( emerge - > enqueueBlockEmerge ( peer_id , p , generate ) ) {
if ( nearest_emerged_d = = - 1 )
nearest_emerged_d = d ;
} else {
if ( nearest_emergefull_d = = - 1 )
nearest_emergefull_d = d ;
goto queue_full_break ;
}
// get next one.
continue ;
}
2017-10-15 00:32:17 -07:00
if ( nearest_sent_d = = - 1 )
2014-01-31 00:24:00 +01:00
nearest_sent_d = d ;
/*
Add block to send queue
*/
2017-03-11 20:50:14 -08:00
PrioritySortedBlockTransfer q ( ( float ) dist , p , peer_id ) ;
2014-01-31 00:24:00 +01:00
dest . push_back ( q ) ;
num_blocks_selected + = 1 ;
}
}
queue_full_break :
// If nothing was found for sending and nothing was queued for
// emerging, continue next time browsing from here
2017-10-15 00:32:17 -07:00
if ( nearest_emerged_d ! = - 1 ) {
2014-01-31 00:24:00 +01:00
new_nearest_unsent_d = nearest_emerged_d ;
2017-10-15 00:32:17 -07:00
} else if ( nearest_emergefull_d ! = - 1 ) {
2014-01-31 00:24:00 +01:00
new_nearest_unsent_d = nearest_emergefull_d ;
} else {
2017-10-15 00:32:17 -07:00
if ( d > full_d_max ) {
2014-01-31 00:24:00 +01:00
new_nearest_unsent_d = 0 ;
2017-10-15 00:32:17 -07:00
m_nothing_to_send_pause_timer = 2.0f ;
2023-03-03 17:41:30 -08:00
infostream < < " Server: Player " < < m_name < < " , RemoteClient " < < peer_id < < " : full map send completed after " < < m_map_send_completion_timer < < " s, restarting " < < std : : endl ;
m_map_send_completion_timer = 0.0f ;
2014-01-31 00:24:00 +01:00
} else {
2017-10-15 00:32:17 -07:00
if ( nearest_sent_d ! = - 1 )
2014-01-31 00:24:00 +01:00
new_nearest_unsent_d = nearest_sent_d ;
else
new_nearest_unsent_d = d ;
}
}
2023-03-05 21:33:41 -08:00
if ( new_nearest_unsent_d ! = - 1 & & m_nearest_unsent_d ! = new_nearest_unsent_d ) {
2014-01-31 00:24:00 +01:00
m_nearest_unsent_d = new_nearest_unsent_d ;
2023-03-05 21:33:41 -08:00
// if the distance has changed, clear the occlusion cache
m_blocks_occ . clear ( ) ;
}
2014-01-31 00:24:00 +01:00
}
void RemoteClient : : GotBlock ( v3s16 p )
{
2020-10-21 14:46:04 -07:00
if ( m_blocks_sending . find ( p ) ! = m_blocks_sending . end ( ) ) {
m_blocks_sending . erase ( p ) ;
// only add to sent blocks if it actually was sending
// (it might have been modified since)
2016-02-15 16:05:40 +01:00
m_blocks_sent . insert ( p ) ;
2020-10-21 14:46:04 -07:00
} else {
m_excess_gotblocks + + ;
2014-01-31 00:24:00 +01:00
}
}
void RemoteClient : : SentBlock ( v3s16 p )
{
2017-10-15 00:32:17 -07:00
if ( m_blocks_sending . find ( p ) = = m_blocks_sending . end ( ) )
m_blocks_sending [ p ] = 0.0f ;
2014-01-31 00:24:00 +01:00
else
infostream < < " RemoteClient::SentBlock(): Sent block "
" already in m_blocks_sending " < < std : : endl ;
}
void RemoteClient : : SetBlockNotSent ( v3s16 p )
{
2016-02-01 19:29:53 +01:00
m_nothing_to_send_pause_timer = 0 ;
2014-01-31 00:24:00 +01:00
2020-10-21 14:46:04 -07:00
// remove the block from sending and sent sets,
// and mark as modified if found
if ( m_blocks_sending . erase ( p ) + m_blocks_sent . erase ( p ) > 0 )
m_blocks_modified . insert ( p ) ;
2014-01-31 00:24:00 +01:00
}
void RemoteClient : : SetBlocksNotSent ( std : : map < v3s16 , MapBlock * > & blocks )
{
2016-02-01 19:29:53 +01:00
m_nothing_to_send_pause_timer = 0 ;
2014-01-31 00:24:00 +01:00
2017-08-20 19:37:29 +02:00
for ( auto & block : blocks ) {
v3s16 p = block . first ;
2020-10-21 14:46:04 -07:00
// remove the block from sending and sent sets,
// and mark as modified if found
if ( m_blocks_sending . erase ( p ) + m_blocks_sent . erase ( p ) > 0 )
m_blocks_modified . insert ( p ) ;
2014-01-31 00:24:00 +01:00
}
}
void RemoteClient : : notifyEvent ( ClientStateEvent event )
{
2014-02-13 20:17:42 +01:00
std : : ostringstream myerror ;
2014-01-31 00:24:00 +01:00
switch ( m_state )
{
2014-06-28 02:02:38 -04:00
case CS_Invalid :
2014-02-13 20:17:42 +01:00
//intentionally do nothing
2014-01-31 00:24:00 +01:00
break ;
2014-06-28 02:02:38 -04:00
case CS_Created :
2015-04-12 04:49:13 +02:00
switch ( event ) {
case CSE_Hello :
m_state = CS_HelloSent ;
break ;
2014-06-28 02:02:38 -04:00
case CSE_Disconnect :
m_state = CS_Disconnecting ;
2014-01-31 00:24:00 +01:00
break ;
2014-06-28 02:02:38 -04:00
case CSE_SetDenied :
m_state = CS_Denied ;
2014-01-31 00:24:00 +01:00
break ;
/* GotInit2 SetDefinitionsSent SetMediaSent */
default :
2014-02-13 20:17:42 +01:00
myerror < < " Created: Invalid client state transition! " < < event ;
throw ClientStateError ( myerror . str ( ) ) ;
2014-01-31 00:24:00 +01:00
}
break ;
2014-06-28 02:02:38 -04:00
case CS_Denied :
2014-01-31 00:24:00 +01:00
/* don't do anything if in denied state */
break ;
2015-04-12 04:49:13 +02:00
case CS_HelloSent :
switch ( event )
{
case CSE_AuthAccept :
m_state = CS_AwaitingInit2 ;
2022-04-27 19:55:13 +02:00
resetChosenMech ( ) ;
2015-04-12 04:49:13 +02:00
break ;
case CSE_Disconnect :
m_state = CS_Disconnecting ;
break ;
case CSE_SetDenied :
m_state = CS_Denied ;
2022-04-27 19:55:13 +02:00
resetChosenMech ( ) ;
2015-04-12 04:49:13 +02:00
break ;
default :
myerror < < " HelloSent: Invalid client state transition! " < < event ;
throw ClientStateError ( myerror . str ( ) ) ;
}
break ;
case CS_AwaitingInit2 :
2014-01-31 00:24:00 +01:00
switch ( event )
{
2014-06-28 02:02:38 -04:00
case CSE_GotInit2 :
2014-01-31 00:24:00 +01:00
confirmSerializationVersion ( ) ;
2014-06-28 02:02:38 -04:00
m_state = CS_InitDone ;
2014-01-31 00:24:00 +01:00
break ;
2014-06-28 02:02:38 -04:00
case CSE_Disconnect :
m_state = CS_Disconnecting ;
2014-01-31 00:24:00 +01:00
break ;
2014-06-28 02:02:38 -04:00
case CSE_SetDenied :
m_state = CS_Denied ;
2014-01-31 00:24:00 +01:00
break ;
/* Init SetDefinitionsSent SetMediaSent */
default :
2014-02-13 20:17:42 +01:00
myerror < < " InitSent: Invalid client state transition! " < < event ;
throw ClientStateError ( myerror . str ( ) ) ;
2014-01-31 00:24:00 +01:00
}
break ;
2014-06-28 02:02:38 -04:00
case CS_InitDone :
2014-01-31 00:24:00 +01:00
switch ( event )
{
2014-06-28 02:02:38 -04:00
case CSE_SetDefinitionsSent :
m_state = CS_DefinitionsSent ;
2014-01-31 00:24:00 +01:00
break ;
2014-06-28 02:02:38 -04:00
case CSE_Disconnect :
m_state = CS_Disconnecting ;
2014-01-31 00:24:00 +01:00
break ;
2014-06-28 02:02:38 -04:00
case CSE_SetDenied :
m_state = CS_Denied ;
2014-01-31 00:24:00 +01:00
break ;
/* Init GotInit2 SetMediaSent */
default :
2014-02-13 20:17:42 +01:00
myerror < < " InitDone: Invalid client state transition! " < < event ;
throw ClientStateError ( myerror . str ( ) ) ;
2014-01-31 00:24:00 +01:00
}
break ;
2014-06-28 02:02:38 -04:00
case CS_DefinitionsSent :
2014-01-31 00:24:00 +01:00
switch ( event )
{
2014-06-28 02:02:38 -04:00
case CSE_SetClientReady :
m_state = CS_Active ;
2014-01-31 00:24:00 +01:00
break ;
2014-06-28 02:02:38 -04:00
case CSE_Disconnect :
m_state = CS_Disconnecting ;
2014-01-31 00:24:00 +01:00
break ;
2014-06-28 02:02:38 -04:00
case CSE_SetDenied :
m_state = CS_Denied ;
2014-01-31 00:24:00 +01:00
break ;
/* Init GotInit2 SetDefinitionsSent */
default :
2014-02-13 20:17:42 +01:00
myerror < < " DefinitionsSent: Invalid client state transition! " < < event ;
throw ClientStateError ( myerror . str ( ) ) ;
2014-01-31 00:24:00 +01:00
}
break ;
2014-06-28 02:02:38 -04:00
case CS_Active :
2014-01-31 00:24:00 +01:00
switch ( event )
{
2014-06-28 02:02:38 -04:00
case CSE_SetDenied :
m_state = CS_Denied ;
2014-01-31 00:24:00 +01:00
break ;
2014-06-28 02:02:38 -04:00
case CSE_Disconnect :
m_state = CS_Disconnecting ;
2014-01-31 00:24:00 +01:00
break ;
2015-04-12 04:49:13 +02:00
case CSE_SudoSuccess :
m_state = CS_SudoMode ;
2022-04-27 19:55:13 +02:00
resetChosenMech ( ) ;
2015-04-12 04:49:13 +02:00
break ;
2014-01-31 00:24:00 +01:00
/* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
default :
2014-02-13 20:17:42 +01:00
myerror < < " Active: Invalid client state transition! " < < event ;
throw ClientStateError ( myerror . str ( ) ) ;
2014-01-31 00:24:00 +01:00
break ;
}
break ;
2015-04-12 04:49:13 +02:00
case CS_SudoMode :
switch ( event )
{
case CSE_SetDenied :
m_state = CS_Denied ;
break ;
case CSE_Disconnect :
m_state = CS_Disconnecting ;
break ;
case CSE_SudoLeave :
m_state = CS_Active ;
break ;
default :
myerror < < " Active: Invalid client state transition! " < < event ;
throw ClientStateError ( myerror . str ( ) ) ;
break ;
}
break ;
2014-06-28 02:02:38 -04:00
case CS_Disconnecting :
2014-01-31 00:24:00 +01:00
/* we are already disconnecting */
break ;
}
}
2022-04-27 19:32:51 +02:00
void RemoteClient : : resetChosenMech ( )
{
2022-04-27 19:55:13 +02:00
if ( auth_data ) {
2022-04-27 19:32:51 +02:00
srp_verifier_delete ( ( SRPVerifier * ) auth_data ) ;
auth_data = nullptr ;
}
chosen_mech = AUTH_MECHANISM_NONE ;
}
2017-05-26 14:03:36 +02:00
u64 RemoteClient : : uptime ( ) const
2014-02-13 20:17:42 +01:00
{
2017-05-26 14:03:36 +02:00
return porting : : getTimeS ( ) - m_connection_time ;
2014-02-13 20:17:42 +01:00
}
2017-08-24 08:28:54 +02:00
ClientInterface : : ClientInterface ( const std : : shared_ptr < con : : Connection > & con )
2014-01-31 00:24:00 +01:00
:
m_con ( con ) ,
m_env ( NULL ) ,
2017-10-15 00:32:17 -07:00
m_print_info_timer ( 0.0f )
2014-01-31 00:24:00 +01:00
{
}
ClientInterface : : ~ ClientInterface ( )
{
/*
Delete clients
*/
{
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock clientslock ( m_clients_mutex ) ;
2014-01-31 00:24:00 +01:00
2017-08-20 19:37:29 +02:00
for ( auto & client_it : m_clients ) {
2014-01-31 00:24:00 +01:00
// Delete client
2017-08-20 19:37:29 +02:00
delete client_it . second ;
2014-01-31 00:24:00 +01:00
}
}
}
2017-09-27 23:48:06 +02:00
std : : vector < session_t > ClientInterface : : getClientIDs ( ClientState min_state )
2014-01-31 00:24:00 +01:00
{
2017-09-27 23:48:06 +02:00
std : : vector < session_t > reply ;
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock clientslock ( m_clients_mutex ) ;
2014-01-31 00:24:00 +01:00
2017-08-16 23:48:29 +02:00
for ( const auto & m_client : m_clients ) {
if ( m_client . second - > getState ( ) > = min_state )
reply . push_back ( m_client . second - > peer_id ) ;
2014-01-31 00:24:00 +01:00
}
return reply ;
}
2018-03-08 22:58:43 +01:00
void ClientInterface : : markBlockposAsNotSent ( const v3s16 & pos )
{
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock clientslock ( m_clients_mutex ) ;
2018-03-08 22:58:43 +01:00
for ( const auto & client : m_clients ) {
if ( client . second - > getState ( ) > = CS_Active )
client . second - > SetBlockNotSent ( pos ) ;
}
}
2017-08-16 23:48:29 +02:00
/**
* Verify if user limit was reached .
* User limit count all clients from HelloSent state ( MT protocol user ) to Active state
* @ return true if user limit was reached
*/
bool ClientInterface : : isUserLimitReached ( )
{
return getClientIDs ( CS_HelloSent ) . size ( ) > = g_settings - > getU16 ( " max_users " ) ;
}
2014-01-31 00:24:00 +01:00
void ClientInterface : : step ( float dtime )
{
m_print_info_timer + = dtime ;
2017-10-15 00:32:17 -07:00
if ( m_print_info_timer > = 30.0f ) {
m_print_info_timer = 0.0f ;
2014-01-31 00:24:00 +01:00
UpdatePlayerList ( ) ;
}
}
void ClientInterface : : UpdatePlayerList ( )
{
2017-06-17 19:11:28 +02:00
if ( m_env ) {
2017-09-27 23:48:06 +02:00
std : : vector < session_t > clients = getClientIDs ( ) ;
2014-01-31 00:24:00 +01:00
m_clients_names . clear ( ) ;
2017-09-27 23:48:06 +02:00
if ( ! clients . empty ( ) )
2014-01-31 00:24:00 +01:00
infostream < < " Players: " < < std : : endl ;
2015-03-04 16:30:24 +01:00
2017-09-27 23:48:06 +02:00
for ( session_t i : clients ) {
2017-08-20 19:37:29 +02:00
RemotePlayer * player = m_env - > getPlayer ( i ) ;
2015-03-04 16:30:24 +01:00
if ( player = = NULL )
2014-01-31 00:24:00 +01:00
continue ;
2015-03-04 16:30:24 +01:00
infostream < < " * " < < player - > getName ( ) < < " \t " ;
2014-01-31 00:24:00 +01:00
{
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock clientslock ( m_clients_mutex ) ;
2017-08-20 19:37:29 +02:00
RemoteClient * client = lockedGetClientNoEx ( i ) ;
2017-06-17 19:11:28 +02:00
if ( client )
2014-01-31 00:24:00 +01:00
client - > PrintInfo ( infostream ) ;
}
2015-03-04 16:30:24 +01:00
2017-08-20 19:37:29 +02:00
m_clients_names . emplace_back ( player - > getName ( ) ) ;
2014-01-31 00:24:00 +01:00
}
}
}
2017-09-27 19:47:36 +02:00
void ClientInterface : : send ( session_t peer_id , u8 channelnum ,
NetworkPacket * pkt , bool reliable )
2014-01-31 00:24:00 +01:00
{
[Patch 2/4] Network rework: packet writing, sending and cleanups
NetworkPacket.cpp:
* Remove some deprecated functions, we must use streaming interface
* m_data converted from u8* to std::vector<u8>
* Add an exporter to forge packet to Connection object
* implement operator << std::wstring. n
* implement operator << std::string
* dynamic resize when write packet content.
* fix string writing and performances.
* create ServerCommandFactory, used by client to get useful informations about packet processing (sending).
* Reliability
* Transmit channel
* Implement putRawString for some ugly char (_INIT packet), and use it.
* Many packet read and write migrated
* Implement oldForgePacket to interface writing with current connection
* fix U8/char/bool writing
* fix string writing and performances.
* add some missing functions
* Use v3s16 read instead of reading x,y,z separately
* Add irr::video::SColor support into packets
* Add some missing handlers
* Add a template function to increase offset
* Throw a serialization error on packet reading (must be improved)
PacketFactories:
* Create ServerCommandFactory, used by client to get useful informations about packet processing (sending).
* Create ClientCommandFactory, used by server to get useful informations about packet processing (sending).
Client.cpp:
* implement NetworkPacket ::Send interface.
* Move packet handlers to a dedicated file
* Remove Client::Send(SharedBuffer)
Server.cpp:
* implement NetworkPacket ::Send interface.
* Rewrite all packets using NetworkPacket
* Move packet handlers to a dedicated file
* Remove Server::Send(SharedBuffer)
ClientIface.cpp:
* Remove sendToAll(SharedBuffer<u8>)
Connection.hpp rework:
* Remove duplicate include
* Remove duplicate negation
* Remove a useless variable
* Improve code performance by using a m_peers_list instead of scanning m_peers map
* Remove Connection::Send(SharedBuffer)
* Fix useafterfree into NetworkPacket Sending
* Remove unused Connection::sendToAll
Test.cpp:
* Remove dead code
* Update tests to use NetworkPackets
Misc:
* add new wrappers to Send packets in client, using NetworkPacket
* Add NetworkPacket methods for Connection
* coding style fix
* dead code since changes cleanup
* Use v3s16 read instead of reading x,y,z separately in some packets
* Use different files to handle packets received by client and server
* Cleanup: Remove useless includes
ok @Zeno-
Tested by @Zeno- @VanessaE and @nerzhul on running servers
2015-01-16 11:37:49 +01:00
m_con - > Send ( peer_id , channelnum , pkt , reliable ) ;
2014-01-31 00:24:00 +01:00
}
2017-04-14 15:34:01 +02:00
void ClientInterface : : sendToAll ( NetworkPacket * pkt )
2014-01-31 00:24:00 +01:00
{
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock clientslock ( m_clients_mutex ) ;
2017-08-20 19:37:29 +02:00
for ( auto & client_it : m_clients ) {
RemoteClient * client = client_it . second ;
2014-01-31 00:24:00 +01:00
[Patch 2/4] Network rework: packet writing, sending and cleanups
NetworkPacket.cpp:
* Remove some deprecated functions, we must use streaming interface
* m_data converted from u8* to std::vector<u8>
* Add an exporter to forge packet to Connection object
* implement operator << std::wstring. n
* implement operator << std::string
* dynamic resize when write packet content.
* fix string writing and performances.
* create ServerCommandFactory, used by client to get useful informations about packet processing (sending).
* Reliability
* Transmit channel
* Implement putRawString for some ugly char (_INIT packet), and use it.
* Many packet read and write migrated
* Implement oldForgePacket to interface writing with current connection
* fix U8/char/bool writing
* fix string writing and performances.
* add some missing functions
* Use v3s16 read instead of reading x,y,z separately
* Add irr::video::SColor support into packets
* Add some missing handlers
* Add a template function to increase offset
* Throw a serialization error on packet reading (must be improved)
PacketFactories:
* Create ServerCommandFactory, used by client to get useful informations about packet processing (sending).
* Create ClientCommandFactory, used by server to get useful informations about packet processing (sending).
Client.cpp:
* implement NetworkPacket ::Send interface.
* Move packet handlers to a dedicated file
* Remove Client::Send(SharedBuffer)
Server.cpp:
* implement NetworkPacket ::Send interface.
* Rewrite all packets using NetworkPacket
* Move packet handlers to a dedicated file
* Remove Server::Send(SharedBuffer)
ClientIface.cpp:
* Remove sendToAll(SharedBuffer<u8>)
Connection.hpp rework:
* Remove duplicate include
* Remove duplicate negation
* Remove a useless variable
* Improve code performance by using a m_peers_list instead of scanning m_peers map
* Remove Connection::Send(SharedBuffer)
* Fix useafterfree into NetworkPacket Sending
* Remove unused Connection::sendToAll
Test.cpp:
* Remove dead code
* Update tests to use NetworkPackets
Misc:
* add new wrappers to Send packets in client, using NetworkPacket
* Add NetworkPacket methods for Connection
* coding style fix
* dead code since changes cleanup
* Use v3s16 read instead of reading x,y,z separately in some packets
* Use different files to handle packets received by client and server
* Cleanup: Remove useless includes
ok @Zeno-
Tested by @Zeno- @VanessaE and @nerzhul on running servers
2015-01-16 11:37:49 +01:00
if ( client - > net_proto_version ! = 0 ) {
2017-04-14 15:34:01 +02:00
m_con - > Send ( client - > peer_id ,
clientCommandFactoryTable [ pkt - > getCommand ( ) ] . channel , pkt ,
clientCommandFactoryTable [ pkt - > getCommand ( ) ] . reliable ) ;
2014-01-31 00:24:00 +01:00
}
}
}
2017-09-27 19:47:36 +02:00
RemoteClient * ClientInterface : : getClientNoEx ( session_t peer_id , ClientState state_min )
2014-01-31 00:24:00 +01:00
{
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock clientslock ( m_clients_mutex ) ;
2017-06-04 21:00:04 +02:00
RemoteClientMap : : const_iterator n = m_clients . find ( peer_id ) ;
2014-01-31 00:24:00 +01:00
// The client may not exist; clients are immediately removed if their
// access is denied, and this event occurs later then.
2016-10-05 09:03:55 +02:00
if ( n = = m_clients . end ( ) )
2014-01-31 00:24:00 +01:00
return NULL ;
if ( n - > second - > getState ( ) > = state_min )
return n - > second ;
2017-08-20 19:37:29 +02:00
return NULL ;
2014-01-31 00:24:00 +01:00
}
2017-09-27 19:47:36 +02:00
RemoteClient * ClientInterface : : lockedGetClientNoEx ( session_t peer_id , ClientState state_min )
2014-01-31 00:24:00 +01:00
{
2017-06-04 21:00:04 +02:00
RemoteClientMap : : const_iterator n = m_clients . find ( peer_id ) ;
2014-01-31 00:24:00 +01:00
// The client may not exist; clients are immediately removed if their
// access is denied, and this event occurs later then.
2016-10-05 09:03:55 +02:00
if ( n = = m_clients . end ( ) )
2014-01-31 00:24:00 +01:00
return NULL ;
if ( n - > second - > getState ( ) > = state_min )
return n - > second ;
2017-08-20 19:37:29 +02:00
return NULL ;
2014-01-31 00:24:00 +01:00
}
2017-09-27 19:47:36 +02:00
ClientState ClientInterface : : getClientState ( session_t peer_id )
2014-01-31 00:24:00 +01:00
{
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock clientslock ( m_clients_mutex ) ;
2017-06-04 21:00:04 +02:00
RemoteClientMap : : const_iterator n = m_clients . find ( peer_id ) ;
2014-01-31 00:24:00 +01:00
// The client may not exist; clients are immediately removed if their
// access is denied, and this event occurs later then.
2016-10-05 09:03:55 +02:00
if ( n = = m_clients . end ( ) )
2014-06-28 02:02:38 -04:00
return CS_Invalid ;
2014-01-31 00:24:00 +01:00
return n - > second - > getState ( ) ;
}
2017-09-27 19:47:36 +02:00
void ClientInterface : : setPlayerName ( session_t peer_id , const std : : string & name )
2014-01-31 00:24:00 +01:00
{
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock clientslock ( m_clients_mutex ) ;
2017-06-04 21:00:04 +02:00
RemoteClientMap : : iterator n = m_clients . find ( peer_id ) ;
2014-01-31 00:24:00 +01:00
// The client may not exist; clients are immediately removed if their
// access is denied, and this event occurs later then.
2016-10-05 09:03:55 +02:00
if ( n ! = m_clients . end ( ) )
2014-01-31 00:24:00 +01:00
n - > second - > setName ( name ) ;
}
2017-09-27 19:47:36 +02:00
void ClientInterface : : DeleteClient ( session_t peer_id )
2014-01-31 00:24:00 +01:00
{
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock conlock ( m_clients_mutex ) ;
2014-01-31 00:24:00 +01:00
// Error check
2017-06-04 21:00:04 +02:00
RemoteClientMap : : iterator n = m_clients . find ( peer_id ) ;
2014-01-31 00:24:00 +01:00
// The client may not exist; clients are immediately removed if their
// access is denied, and this event occurs later then.
2016-10-05 09:03:55 +02:00
if ( n = = m_clients . end ( ) )
2014-01-31 00:24:00 +01:00
return ;
/*
Mark objects to be not known by the client
*/
//TODO this should be done by client destructor!!!
RemoteClient * client = n - > second ;
// Handle objects
2017-08-20 19:37:29 +02:00
for ( u16 id : client - > m_known_objects ) {
2014-01-31 00:24:00 +01:00
// Get object
ServerActiveObject * obj = m_env - > getActiveObject ( id ) ;
if ( obj & & obj - > m_known_by_count > 0 )
obj - > m_known_by_count - - ;
}
// Delete client
delete m_clients [ peer_id ] ;
m_clients . erase ( peer_id ) ;
}
2017-09-27 19:47:36 +02:00
void ClientInterface : : CreateClient ( session_t peer_id )
2014-01-31 00:24:00 +01:00
{
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock conlock ( m_clients_mutex ) ;
2014-01-31 00:24:00 +01:00
// Error check
2017-06-04 21:00:04 +02:00
RemoteClientMap : : iterator n = m_clients . find ( peer_id ) ;
2014-01-31 00:24:00 +01:00
// The client shouldn't already exist
2016-10-05 09:03:55 +02:00
if ( n ! = m_clients . end ( ) ) return ;
2014-01-31 00:24:00 +01:00
// Create client
RemoteClient * client = new RemoteClient ( ) ;
client - > peer_id = peer_id ;
m_clients [ client - > peer_id ] = client ;
}
2017-09-27 19:47:36 +02:00
void ClientInterface : : event ( session_t peer_id , ClientStateEvent event )
2014-01-31 00:24:00 +01:00
{
{
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock clientlock ( m_clients_mutex ) ;
2014-01-31 00:24:00 +01:00
// Error check
2017-06-04 21:00:04 +02:00
RemoteClientMap : : iterator n = m_clients . find ( peer_id ) ;
2014-01-31 00:24:00 +01:00
// No client to deliver event
if ( n = = m_clients . end ( ) )
return ;
n - > second - > notifyEvent ( event ) ;
}
2014-06-28 02:02:38 -04:00
if ( ( event = = CSE_SetClientReady ) | |
( event = = CSE_Disconnect ) | |
( event = = CSE_SetDenied ) )
2014-01-31 00:24:00 +01:00
{
UpdatePlayerList ( ) ;
}
}
2017-09-27 19:47:36 +02:00
u16 ClientInterface : : getProtocolVersion ( session_t peer_id )
2014-01-31 00:24:00 +01:00
{
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock conlock ( m_clients_mutex ) ;
2014-01-31 00:24:00 +01:00
// Error check
2017-06-04 21:00:04 +02:00
RemoteClientMap : : iterator n = m_clients . find ( peer_id ) ;
2014-01-31 00:24:00 +01:00
2014-02-13 20:17:42 +01:00
// No client to get version
2014-01-31 00:24:00 +01:00
if ( n = = m_clients . end ( ) )
return 0 ;
return n - > second - > net_proto_version ;
}
2014-02-13 20:17:42 +01:00
2017-09-27 19:47:36 +02:00
void ClientInterface : : setClientVersion ( session_t peer_id , u8 major , u8 minor , u8 patch ,
const std : : string & full )
2014-02-13 20:17:42 +01:00
{
2019-08-17 13:27:28 +02:00
RecursiveMutexAutoLock conlock ( m_clients_mutex ) ;
2014-02-13 20:17:42 +01:00
// Error check
2017-06-04 21:00:04 +02:00
RemoteClientMap : : iterator n = m_clients . find ( peer_id ) ;
2014-02-13 20:17:42 +01:00
// No client to set versions
if ( n = = m_clients . end ( ) )
return ;
2017-09-27 19:47:36 +02:00
n - > second - > setVersionInfo ( major , minor , patch , full ) ;
2014-02-13 20:17:42 +01:00
}