Add propper client initialization
-add client states to avoid server sending data to uninitialized clients -don't show uninitialized clients to other players -propper client disconnect handling Minor comment fixes in server Minor bugfixes in connection -improved peer id calculation -honor NDEBUG flag -improved disconnect handling -increased initial send window Remove some dead codemaster
parent
21f1bec724
commit
e258675eab
|
@ -308,6 +308,7 @@ set(common_SRCS
|
||||||
connection.cpp
|
connection.cpp
|
||||||
environment.cpp
|
environment.cpp
|
||||||
server.cpp
|
server.cpp
|
||||||
|
clientiface.cpp
|
||||||
socket.cpp
|
socket.cpp
|
||||||
mapblock.cpp
|
mapblock.cpp
|
||||||
mapsector.cpp
|
mapsector.cpp
|
||||||
|
|
|
@ -383,13 +383,6 @@ void Client::step(float dtime)
|
||||||
// 0ms
|
// 0ms
|
||||||
ReceiveAll();
|
ReceiveAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
//TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
|
|
||||||
// 0ms
|
|
||||||
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
|
|
||||||
m_con.RunTimeouts(dtime);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Packet counter
|
Packet counter
|
||||||
|
@ -758,6 +751,7 @@ void Client::step(float dtime)
|
||||||
if (m_media_downloader && m_media_downloader->isStarted()) {
|
if (m_media_downloader && m_media_downloader->isStarted()) {
|
||||||
m_media_downloader->step(this);
|
m_media_downloader->step(this);
|
||||||
if (m_media_downloader->isDone()) {
|
if (m_media_downloader->isDone()) {
|
||||||
|
received_media();
|
||||||
delete m_media_downloader;
|
delete m_media_downloader;
|
||||||
m_media_downloader = NULL;
|
m_media_downloader = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1610,11 +1604,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_media_downloader->step(this);
|
m_media_downloader->step(this);
|
||||||
if (m_media_downloader->isDone()) {
|
|
||||||
// might be done already if all media is in the cache
|
|
||||||
delete m_media_downloader;
|
|
||||||
m_media_downloader = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(command == TOCLIENT_MEDIA)
|
else if(command == TOCLIENT_MEDIA)
|
||||||
{
|
{
|
||||||
|
@ -1666,11 +1655,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||||
m_media_downloader->conventionalTransferDone(
|
m_media_downloader->conventionalTransferDone(
|
||||||
name, data, this);
|
name, data, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_media_downloader->isDone()) {
|
|
||||||
delete m_media_downloader;
|
|
||||||
m_media_downloader = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(command == TOCLIENT_TOOLDEF)
|
else if(command == TOCLIENT_TOOLDEF)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,769 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "clientiface.h"
|
||||||
|
#include "player.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "mapblock.h"
|
||||||
|
#include "connection.h"
|
||||||
|
#include "environment.h"
|
||||||
|
#include "map.h"
|
||||||
|
#include "emerge.h"
|
||||||
|
#include "serverobject.h" // TODO this is used for cleanup of only
|
||||||
|
|
||||||
|
#include "util/numeric.h"
|
||||||
|
|
||||||
|
#include "main.h" // for g_settings
|
||||||
|
|
||||||
|
void RemoteClient::GetNextBlocks(
|
||||||
|
ServerEnvironment *env,
|
||||||
|
EmergeManager * emerge,
|
||||||
|
float dtime,
|
||||||
|
std::vector<PrioritySortedBlockTransfer> &dest)
|
||||||
|
{
|
||||||
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
|
||||||
|
|
||||||
|
// Increment timers
|
||||||
|
m_nothing_to_send_pause_timer -= dtime;
|
||||||
|
m_nearest_unsent_reset_timer += dtime;
|
||||||
|
|
||||||
|
if(m_nothing_to_send_pause_timer >= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Player *player = env->getPlayer(peer_id);
|
||||||
|
// This can happen sometimes; clients and players are not in perfect sync.
|
||||||
|
if(player == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Won't send anything if already sending
|
||||||
|
if(m_blocks_sending.size() >= g_settings->getU16
|
||||||
|
("max_simultaneous_block_sends_per_client"))
|
||||||
|
{
|
||||||
|
//infostream<<"Not sending any blocks, Queue full."<<std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
v3f playerpos = player->getPosition();
|
||||||
|
v3f playerspeed = player->getSpeed();
|
||||||
|
v3f playerspeeddir(0,0,0);
|
||||||
|
if(playerspeed.getLength() > 1.0*BS)
|
||||||
|
playerspeeddir = playerspeed / playerspeed.getLength();
|
||||||
|
// Predict to next block
|
||||||
|
v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
|
||||||
|
|
||||||
|
v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
|
||||||
|
|
||||||
|
v3s16 center = getNodeBlockPos(center_nodepos);
|
||||||
|
|
||||||
|
// Camera position and direction
|
||||||
|
v3f camera_pos = player->getEyePosition();
|
||||||
|
v3f camera_dir = v3f(0,0,1);
|
||||||
|
camera_dir.rotateYZBy(player->getPitch());
|
||||||
|
camera_dir.rotateXZBy(player->getYaw());
|
||||||
|
|
||||||
|
/*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
|
||||||
|
<<camera_dir.Z<<")"<<std::endl;*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the starting value of the block finder radius.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(m_last_center != center)
|
||||||
|
{
|
||||||
|
m_nearest_unsent_d = 0;
|
||||||
|
m_last_center = center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*infostream<<"m_nearest_unsent_reset_timer="
|
||||||
|
<<m_nearest_unsent_reset_timer<<std::endl;*/
|
||||||
|
|
||||||
|
// Reset periodically to workaround for some bugs or stuff
|
||||||
|
if(m_nearest_unsent_reset_timer > 20.0)
|
||||||
|
{
|
||||||
|
m_nearest_unsent_reset_timer = 0;
|
||||||
|
m_nearest_unsent_d = 0;
|
||||||
|
//infostream<<"Resetting m_nearest_unsent_d for "
|
||||||
|
// <<server->getPlayerName(peer_id)<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//s16 last_nearest_unsent_d = m_nearest_unsent_d;
|
||||||
|
s16 d_start = m_nearest_unsent_d;
|
||||||
|
|
||||||
|
//infostream<<"d_start="<<d_start<<std::endl;
|
||||||
|
|
||||||
|
u16 max_simul_sends_setting = g_settings->getU16
|
||||||
|
("max_simultaneous_block_sends_per_client");
|
||||||
|
u16 max_simul_sends_usually = max_simul_sends_setting;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check the time from last addNode/removeNode.
|
||||||
|
|
||||||
|
Decrease send rate if player is building stuff.
|
||||||
|
*/
|
||||||
|
m_time_from_building += dtime;
|
||||||
|
if(m_time_from_building < g_settings->getFloat(
|
||||||
|
"full_block_send_enable_min_time_from_building"))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
s16 d_max = g_settings->getS16("max_block_send_distance");
|
||||||
|
s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
s32 nearest_emerged_d = -1;
|
||||||
|
s32 nearest_emergefull_d = -1;
|
||||||
|
s32 nearest_sent_d = -1;
|
||||||
|
bool queue_is_full = false;
|
||||||
|
|
||||||
|
s16 d;
|
||||||
|
for(d = d_start; d <= d_max; d++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Get the border/face dot coordinates of a "d-radiused"
|
||||||
|
box
|
||||||
|
*/
|
||||||
|
std::list<v3s16> list;
|
||||||
|
getFacePositions(list, d);
|
||||||
|
|
||||||
|
std::list<v3s16>::iterator li;
|
||||||
|
for(li=list.begin(); li!=list.end(); ++li)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
|
||||||
|
max_simul_dynamic = max_simul_sends_setting;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Do not go over-limit
|
||||||
|
*/
|
||||||
|
if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||||
|
|| p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||||
|
|| p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||||
|
|| p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||||
|
|| p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||||
|
|| p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If this is true, inexistent block will be made from scratch
|
||||||
|
bool generate = d <= d_max_gen;
|
||||||
|
|
||||||
|
{
|
||||||
|
/*// Limit the generating area vertically to 2/3
|
||||||
|
if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
|
||||||
|
generate = false;*/
|
||||||
|
|
||||||
|
// Limit the send area vertically to 1/2
|
||||||
|
if(abs(p.Y - center.Y) > d_max / 2)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
float camera_fov = (72.0*M_PI/180) * 4./3.;
|
||||||
|
if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Don't send already sent blocks
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(m_blocks_sent.find(p) != m_blocks_sent.end())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if map has this block
|
||||||
|
*/
|
||||||
|
MapBlock *block = env->getMap().getBlockNoCreateNoEx(p);
|
||||||
|
|
||||||
|
bool surely_not_found_on_disk = false;
|
||||||
|
bool block_is_invalid = false;
|
||||||
|
if(block != NULL)
|
||||||
|
{
|
||||||
|
// Reset usage timer, this block will be of use in the future.
|
||||||
|
block->resetUsageTimer();
|
||||||
|
|
||||||
|
// Block is dummy if data doesn't exist.
|
||||||
|
// It means it has been not found from disk and not generated
|
||||||
|
if(block->isDummy())
|
||||||
|
{
|
||||||
|
surely_not_found_on_disk = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block is valid if lighting is up-to-date and data exists
|
||||||
|
if(block->isValid() == false)
|
||||||
|
{
|
||||||
|
block_is_invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(block->isGenerated() == false)
|
||||||
|
block_is_invalid = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
if(d >= 4)
|
||||||
|
{
|
||||||
|
if(block->getDayNightDiff() == false)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If block has been marked to not exist on disk (dummy)
|
||||||
|
and generating new ones is not wanted, skip block.
|
||||||
|
*/
|
||||||
|
if(generate == false && surely_not_found_on_disk == true)
|
||||||
|
{
|
||||||
|
// get next one.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add inexistent block to emerge queue.
|
||||||
|
*/
|
||||||
|
if(block == NULL || surely_not_found_on_disk || block_is_invalid)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nearest_sent_d == -1)
|
||||||
|
nearest_sent_d = d;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add block to send queue
|
||||||
|
*/
|
||||||
|
PrioritySortedBlockTransfer q((float)d, p, peer_id);
|
||||||
|
|
||||||
|
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
|
||||||
|
if(nearest_emerged_d != -1){
|
||||||
|
new_nearest_unsent_d = nearest_emerged_d;
|
||||||
|
} else if(nearest_emergefull_d != -1){
|
||||||
|
new_nearest_unsent_d = nearest_emergefull_d;
|
||||||
|
} else {
|
||||||
|
if(d > g_settings->getS16("max_block_send_distance")){
|
||||||
|
new_nearest_unsent_d = 0;
|
||||||
|
m_nothing_to_send_pause_timer = 2.0;
|
||||||
|
} else {
|
||||||
|
if(nearest_sent_d != -1)
|
||||||
|
new_nearest_unsent_d = nearest_sent_d;
|
||||||
|
else
|
||||||
|
new_nearest_unsent_d = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(new_nearest_unsent_d != -1)
|
||||||
|
m_nearest_unsent_d = new_nearest_unsent_d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteClient::GotBlock(v3s16 p)
|
||||||
|
{
|
||||||
|
if(m_blocks_sending.find(p) != m_blocks_sending.end())
|
||||||
|
m_blocks_sending.erase(p);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_excess_gotblocks++;
|
||||||
|
}
|
||||||
|
m_blocks_sent.insert(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteClient::SentBlock(v3s16 p)
|
||||||
|
{
|
||||||
|
if(m_blocks_sending.find(p) == m_blocks_sending.end())
|
||||||
|
m_blocks_sending[p] = 0.0;
|
||||||
|
else
|
||||||
|
infostream<<"RemoteClient::SentBlock(): Sent block"
|
||||||
|
" already in m_blocks_sending"<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteClient::SetBlockNotSent(v3s16 p)
|
||||||
|
{
|
||||||
|
m_nearest_unsent_d = 0;
|
||||||
|
|
||||||
|
if(m_blocks_sending.find(p) != m_blocks_sending.end())
|
||||||
|
m_blocks_sending.erase(p);
|
||||||
|
if(m_blocks_sent.find(p) != m_blocks_sent.end())
|
||||||
|
m_blocks_sent.erase(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
|
||||||
|
{
|
||||||
|
m_nearest_unsent_d = 0;
|
||||||
|
|
||||||
|
for(std::map<v3s16, MapBlock*>::iterator
|
||||||
|
i = blocks.begin();
|
||||||
|
i != blocks.end(); ++i)
|
||||||
|
{
|
||||||
|
v3s16 p = i->first;
|
||||||
|
|
||||||
|
if(m_blocks_sending.find(p) != m_blocks_sending.end())
|
||||||
|
m_blocks_sending.erase(p);
|
||||||
|
if(m_blocks_sent.find(p) != m_blocks_sent.end())
|
||||||
|
m_blocks_sent.erase(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteClient::notifyEvent(ClientStateEvent event)
|
||||||
|
{
|
||||||
|
switch (m_state)
|
||||||
|
{
|
||||||
|
case Invalid:
|
||||||
|
assert("State update for client in invalid state" != 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Created:
|
||||||
|
switch(event)
|
||||||
|
{
|
||||||
|
case Init:
|
||||||
|
m_state = InitSent;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Disconnect:
|
||||||
|
m_state = Disconnecting;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SetDenied:
|
||||||
|
m_state = Denied;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* GotInit2 SetDefinitionsSent SetMediaSent */
|
||||||
|
default:
|
||||||
|
assert("Invalid client state transition!" == 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Denied:
|
||||||
|
/* don't do anything if in denied state */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InitSent:
|
||||||
|
switch(event)
|
||||||
|
{
|
||||||
|
case GotInit2:
|
||||||
|
confirmSerializationVersion();
|
||||||
|
m_state = InitDone;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Disconnect:
|
||||||
|
m_state = Disconnecting;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SetDenied:
|
||||||
|
m_state = Denied;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Init SetDefinitionsSent SetMediaSent */
|
||||||
|
default:
|
||||||
|
assert("Invalid client state transition!" == 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InitDone:
|
||||||
|
switch(event)
|
||||||
|
{
|
||||||
|
case SetDefinitionsSent:
|
||||||
|
m_state = DefinitionsSent;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Disconnect:
|
||||||
|
m_state = Disconnecting;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SetDenied:
|
||||||
|
m_state = Denied;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Init GotInit2 SetMediaSent */
|
||||||
|
default:
|
||||||
|
assert("Invalid client state transition!" == 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DefinitionsSent:
|
||||||
|
switch(event)
|
||||||
|
{
|
||||||
|
case SetMediaSent:
|
||||||
|
m_state = Active;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Disconnect:
|
||||||
|
m_state = Disconnecting;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SetDenied:
|
||||||
|
m_state = Denied;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Init GotInit2 SetDefinitionsSent */
|
||||||
|
default:
|
||||||
|
assert("Invalid client state transition!" == 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Active:
|
||||||
|
switch(event)
|
||||||
|
{
|
||||||
|
case SetDenied:
|
||||||
|
m_state = Denied;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Disconnect:
|
||||||
|
m_state = Disconnecting;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
|
||||||
|
default:
|
||||||
|
assert("Invalid client state transition!" == 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Disconnecting:
|
||||||
|
/* we are already disconnecting */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientInterface::ClientInterface(con::Connection* con)
|
||||||
|
:
|
||||||
|
m_con(con),
|
||||||
|
m_env(NULL),
|
||||||
|
m_print_info_timer(0.0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
ClientInterface::~ClientInterface()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Delete clients
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
JMutexAutoLock clientslock(m_clients_mutex);
|
||||||
|
|
||||||
|
for(std::map<u16, RemoteClient*>::iterator
|
||||||
|
i = m_clients.begin();
|
||||||
|
i != m_clients.end(); ++i)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Delete client
|
||||||
|
delete i->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<u16> ClientInterface::getClientIDs(ClientState min_state)
|
||||||
|
{
|
||||||
|
std::list<u16> reply;
|
||||||
|
JMutexAutoLock clientslock(m_clients_mutex);
|
||||||
|
|
||||||
|
for(std::map<u16, RemoteClient*>::iterator
|
||||||
|
i = m_clients.begin();
|
||||||
|
i != m_clients.end(); ++i)
|
||||||
|
{
|
||||||
|
if (i->second->getState() >= min_state)
|
||||||
|
reply.push_back(i->second->peer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ClientInterface::getPlayerNames()
|
||||||
|
{
|
||||||
|
return m_clients_names;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ClientInterface::step(float dtime)
|
||||||
|
{
|
||||||
|
m_print_info_timer += dtime;
|
||||||
|
if(m_print_info_timer >= 30.0)
|
||||||
|
{
|
||||||
|
m_print_info_timer = 0.0;
|
||||||
|
UpdatePlayerList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::UpdatePlayerList()
|
||||||
|
{
|
||||||
|
if (m_env != NULL)
|
||||||
|
{
|
||||||
|
std::list<u16> clients = getClientIDs();
|
||||||
|
m_clients_names.clear();
|
||||||
|
|
||||||
|
|
||||||
|
if(clients.size() != 0)
|
||||||
|
infostream<<"Players:"<<std::endl;
|
||||||
|
for(std::list<u16>::iterator
|
||||||
|
i = clients.begin();
|
||||||
|
i != clients.end(); ++i)
|
||||||
|
{
|
||||||
|
Player *player = m_env->getPlayer(*i);
|
||||||
|
if(player==NULL)
|
||||||
|
continue;
|
||||||
|
infostream<<"* "<<player->getName()<<"\t";
|
||||||
|
|
||||||
|
{
|
||||||
|
JMutexAutoLock clientslock(m_clients_mutex);
|
||||||
|
RemoteClient* client = lockedGetClientNoEx(*i);
|
||||||
|
if(client != NULL)
|
||||||
|
client->PrintInfo(infostream);
|
||||||
|
}
|
||||||
|
m_clients_names.push_back(player->getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::send(u16 peer_id,u8 channelnum,
|
||||||
|
SharedBuffer<u8> data, bool reliable)
|
||||||
|
{
|
||||||
|
m_con->Send(peer_id, channelnum, data, reliable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::sendToAll(u16 channelnum,
|
||||||
|
SharedBuffer<u8> data, bool reliable)
|
||||||
|
{
|
||||||
|
JMutexAutoLock clientslock(m_clients_mutex);
|
||||||
|
for(std::map<u16, RemoteClient*>::iterator
|
||||||
|
i = m_clients.begin();
|
||||||
|
i != m_clients.end(); ++i)
|
||||||
|
{
|
||||||
|
RemoteClient *client = i->second;
|
||||||
|
|
||||||
|
if (client->net_proto_version != 0)
|
||||||
|
{
|
||||||
|
m_con->Send(client->peer_id, channelnum, data, reliable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteClient* ClientInterface::getClientNoEx(u16 peer_id, ClientState state_min)
|
||||||
|
{
|
||||||
|
JMutexAutoLock clientslock(m_clients_mutex);
|
||||||
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
|
n = m_clients.find(peer_id);
|
||||||
|
// The client may not exist; clients are immediately removed if their
|
||||||
|
// access is denied, and this event occurs later then.
|
||||||
|
if(n == m_clients.end())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (n->second->getState() >= state_min)
|
||||||
|
return n->second;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteClient* ClientInterface::lockedGetClientNoEx(u16 peer_id, ClientState state_min)
|
||||||
|
{
|
||||||
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
|
n = m_clients.find(peer_id);
|
||||||
|
// The client may not exist; clients are immediately removed if their
|
||||||
|
// access is denied, and this event occurs later then.
|
||||||
|
if(n == m_clients.end())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (n->second->getState() >= state_min)
|
||||||
|
return n->second;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientState ClientInterface::getClientState(u16 peer_id)
|
||||||
|
{
|
||||||
|
JMutexAutoLock clientslock(m_clients_mutex);
|
||||||
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
|
n = m_clients.find(peer_id);
|
||||||
|
// The client may not exist; clients are immediately removed if their
|
||||||
|
// access is denied, and this event occurs later then.
|
||||||
|
if(n == m_clients.end())
|
||||||
|
return Invalid;
|
||||||
|
|
||||||
|
return n->second->getState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::setPlayerName(u16 peer_id,std::string name)
|
||||||
|
{
|
||||||
|
JMutexAutoLock clientslock(m_clients_mutex);
|
||||||
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
|
n = m_clients.find(peer_id);
|
||||||
|
// The client may not exist; clients are immediately removed if their
|
||||||
|
// access is denied, and this event occurs later then.
|
||||||
|
if(n != m_clients.end())
|
||||||
|
n->second->setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::DeleteClient(u16 peer_id)
|
||||||
|
{
|
||||||
|
JMutexAutoLock conlock(m_clients_mutex);
|
||||||
|
|
||||||
|
// Error check
|
||||||
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
|
n = m_clients.find(peer_id);
|
||||||
|
// The client may not exist; clients are immediately removed if their
|
||||||
|
// access is denied, and this event occurs later then.
|
||||||
|
if(n == m_clients.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Mark objects to be not known by the client
|
||||||
|
*/
|
||||||
|
//TODO this should be done by client destructor!!!
|
||||||
|
RemoteClient *client = n->second;
|
||||||
|
// Handle objects
|
||||||
|
for(std::set<u16>::iterator
|
||||||
|
i = client->m_known_objects.begin();
|
||||||
|
i != client->m_known_objects.end(); ++i)
|
||||||
|
{
|
||||||
|
// Get object
|
||||||
|
u16 id = *i;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::CreateClient(u16 peer_id)
|
||||||
|
{
|
||||||
|
JMutexAutoLock conlock(m_clients_mutex);
|
||||||
|
|
||||||
|
// Error check
|
||||||
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
|
n = m_clients.find(peer_id);
|
||||||
|
// The client shouldn't already exist
|
||||||
|
if(n != m_clients.end()) return;
|
||||||
|
|
||||||
|
// Create client
|
||||||
|
RemoteClient *client = new RemoteClient();
|
||||||
|
client->peer_id = peer_id;
|
||||||
|
m_clients[client->peer_id] = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientInterface::event(u16 peer_id, ClientStateEvent event)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
JMutexAutoLock clientlock(m_clients_mutex);
|
||||||
|
|
||||||
|
// Error check
|
||||||
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
|
n = m_clients.find(peer_id);
|
||||||
|
|
||||||
|
// No client to deliver event
|
||||||
|
if (n == m_clients.end())
|
||||||
|
return;
|
||||||
|
n->second->notifyEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((event == SetMediaSent) || (event == Disconnect) || (event == SetDenied))
|
||||||
|
{
|
||||||
|
UpdatePlayerList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 ClientInterface::getProtocolVersion(u16 peer_id)
|
||||||
|
{
|
||||||
|
JMutexAutoLock conlock(m_clients_mutex);
|
||||||
|
|
||||||
|
// Error check
|
||||||
|
std::map<u16, RemoteClient*>::iterator n;
|
||||||
|
n = m_clients.find(peer_id);
|
||||||
|
|
||||||
|
// No client to deliver event
|
||||||
|
if (n == m_clients.end())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return n->second->net_proto_version;
|
||||||
|
}
|
|
@ -0,0 +1,306 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
#ifndef _CLIENTIFACE_H_
|
||||||
|
#define _CLIENTIFACE_H_
|
||||||
|
|
||||||
|
#include "irr_v3d.h" // for irrlicht datatypes
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "serialization.h" // for SER_FMT_VER_INVALID
|
||||||
|
#include "jthread/jmutex.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
class MapBlock;
|
||||||
|
class ServerEnvironment;
|
||||||
|
class EmergeManager;
|
||||||
|
|
||||||
|
namespace con {
|
||||||
|
class Connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ClientState
|
||||||
|
{
|
||||||
|
Invalid,
|
||||||
|
Disconnecting,
|
||||||
|
Denied,
|
||||||
|
Created,
|
||||||
|
InitSent,
|
||||||
|
InitDone,
|
||||||
|
DefinitionsSent,
|
||||||
|
Active
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ClientStateEvent
|
||||||
|
{
|
||||||
|
Init,
|
||||||
|
GotInit2,
|
||||||
|
SetDenied,
|
||||||
|
SetDefinitionsSent,
|
||||||
|
SetMediaSent,
|
||||||
|
Disconnect
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Used for queueing and sorting block transfers in containers
|
||||||
|
|
||||||
|
Lower priority number means higher priority.
|
||||||
|
*/
|
||||||
|
struct PrioritySortedBlockTransfer
|
||||||
|
{
|
||||||
|
PrioritySortedBlockTransfer(float a_priority, v3s16 a_pos, u16 a_peer_id)
|
||||||
|
{
|
||||||
|
priority = a_priority;
|
||||||
|
pos = a_pos;
|
||||||
|
peer_id = a_peer_id;
|
||||||
|
}
|
||||||
|
bool operator < (const PrioritySortedBlockTransfer &other) const
|
||||||
|
{
|
||||||
|
return priority < other.priority;
|
||||||
|
}
|
||||||
|
float priority;
|
||||||
|
v3s16 pos;
|
||||||
|
u16 peer_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RemoteClient
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// peer_id=0 means this client has no associated peer
|
||||||
|
// NOTE: If client is made allowed to exist while peer doesn't,
|
||||||
|
// this has to be set to 0 when there is no peer.
|
||||||
|
// Also, the client must be moved to some other container.
|
||||||
|
u16 peer_id;
|
||||||
|
// The serialization version to use with the client
|
||||||
|
u8 serialization_version;
|
||||||
|
//
|
||||||
|
u16 net_proto_version;
|
||||||
|
|
||||||
|
RemoteClient():
|
||||||
|
peer_id(PEER_ID_INEXISTENT),
|
||||||
|
serialization_version(SER_FMT_VER_INVALID),
|
||||||
|
net_proto_version(0),
|
||||||
|
m_time_from_building(9999),
|
||||||
|
m_pending_serialization_version(SER_FMT_VER_INVALID),
|
||||||
|
m_state(Created),
|
||||||
|
m_nearest_unsent_d(0),
|
||||||
|
m_nearest_unsent_reset_timer(0.0),
|
||||||
|
m_excess_gotblocks(0),
|
||||||
|
m_nothing_to_send_counter(0),
|
||||||
|
m_nothing_to_send_pause_timer(0.0),
|
||||||
|
m_name("")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~RemoteClient()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Finds block that should be sent next to the client.
|
||||||
|
Environment should be locked when this is called.
|
||||||
|
dtime is used for resetting send radius at slow interval
|
||||||
|
*/
|
||||||
|
void GetNextBlocks(ServerEnvironment *env, EmergeManager* emerge,
|
||||||
|
float dtime, std::vector<PrioritySortedBlockTransfer> &dest);
|
||||||
|
|
||||||
|
void GotBlock(v3s16 p);
|
||||||
|
|
||||||
|
void SentBlock(v3s16 p);
|
||||||
|
|
||||||
|
void SetBlockNotSent(v3s16 p);
|
||||||
|
void SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks);
|
||||||
|
|
||||||
|
s32 SendingCount()
|
||||||
|
{
|
||||||
|
return m_blocks_sending.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increments timeouts and removes timed-out blocks from list
|
||||||
|
// NOTE: This doesn't fix the server-not-sending-block bug
|
||||||
|
// because it is related to emerging, not sending.
|
||||||
|
//void RunSendingTimeouts(float dtime, float timeout);
|
||||||
|
|
||||||
|
void PrintInfo(std::ostream &o)
|
||||||
|
{
|
||||||
|
o<<"RemoteClient "<<peer_id<<": "
|
||||||
|
<<"m_blocks_sent.size()="<<m_blocks_sent.size()
|
||||||
|
<<", m_blocks_sending.size()="<<m_blocks_sending.size()
|
||||||
|
<<", m_nearest_unsent_d="<<m_nearest_unsent_d
|
||||||
|
<<", m_excess_gotblocks="<<m_excess_gotblocks
|
||||||
|
<<std::endl;
|
||||||
|
m_excess_gotblocks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time from last placing or removing blocks
|
||||||
|
float m_time_from_building;
|
||||||
|
|
||||||
|
/*
|
||||||
|
List of active objects that the client knows of.
|
||||||
|
Value is dummy.
|
||||||
|
*/
|
||||||
|
std::set<u16> m_known_objects;
|
||||||
|
|
||||||
|
ClientState getState()
|
||||||
|
{ return m_state; }
|
||||||
|
|
||||||
|
std::string getName()
|
||||||
|
{ return m_name; }
|
||||||
|
|
||||||
|
void setName(std::string name)
|
||||||
|
{ m_name = name; }
|
||||||
|
|
||||||
|
/* update internal client state */
|
||||||
|
void notifyEvent(ClientStateEvent event);
|
||||||
|
|
||||||
|
/* set expected serialization version */
|
||||||
|
void setPendingSerializationVersion(u8 version)
|
||||||
|
{ m_pending_serialization_version = version; }
|
||||||
|
|
||||||
|
void confirmSerializationVersion()
|
||||||
|
{ serialization_version = m_pending_serialization_version; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Version is stored in here after INIT before INIT2
|
||||||
|
u8 m_pending_serialization_version;
|
||||||
|
|
||||||
|
/* current state of client */
|
||||||
|
ClientState m_state;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Blocks that have been sent to client.
|
||||||
|
- These don't have to be sent again.
|
||||||
|
- A block is cleared from here when client says it has
|
||||||
|
deleted it from it's memory
|
||||||
|
|
||||||
|
Key is position, value is dummy.
|
||||||
|
No MapBlock* is stored here because the blocks can get deleted.
|
||||||
|
*/
|
||||||
|
std::set<v3s16> m_blocks_sent;
|
||||||
|
s16 m_nearest_unsent_d;
|
||||||
|
v3s16 m_last_center;
|
||||||
|
float m_nearest_unsent_reset_timer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Blocks that are currently on the line.
|
||||||
|
This is used for throttling the sending of blocks.
|
||||||
|
- The size of this list is limited to some value
|
||||||
|
Block is added when it is sent with BLOCKDATA.
|
||||||
|
Block is removed when GOTBLOCKS is received.
|
||||||
|
Value is time from sending. (not used at the moment)
|
||||||
|
*/
|
||||||
|
std::map<v3s16, float> m_blocks_sending;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Count of excess GotBlocks().
|
||||||
|
There is an excess amount because the client sometimes
|
||||||
|
gets a block so late that the server sends it again,
|
||||||
|
and the client then sends two GOTBLOCKs.
|
||||||
|
This is resetted by PrintInfo()
|
||||||
|
*/
|
||||||
|
u32 m_excess_gotblocks;
|
||||||
|
|
||||||
|
// CPU usage optimization
|
||||||
|
u32 m_nothing_to_send_counter;
|
||||||
|
float m_nothing_to_send_pause_timer;
|
||||||
|
std::string m_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClientInterface {
|
||||||
|
public:
|
||||||
|
|
||||||
|
friend class Server;
|
||||||
|
|
||||||
|
ClientInterface(con::Connection* con);
|
||||||
|
~ClientInterface();
|
||||||
|
|
||||||
|
/* run sync step */
|
||||||
|
void step(float dtime);
|
||||||
|
|
||||||
|
/* get list of active client id's */
|
||||||
|
std::list<u16> getClientIDs(ClientState min_state=Active);
|
||||||
|
|
||||||
|
/* get list of client player names */
|
||||||
|
std::vector<std::string> getPlayerNames();
|
||||||
|
|
||||||
|
/* send message to client */
|
||||||
|
void send(u16 peer_id, u8 channelnum, SharedBuffer<u8> data, bool reliable);
|
||||||
|
|
||||||
|
/* send to all clients */
|
||||||
|
void sendToAll(u16 channelnum, SharedBuffer<u8> data, bool reliable);
|
||||||
|
|
||||||
|
/* delete a client */
|
||||||
|
void DeleteClient(u16 peer_id);
|
||||||
|
|
||||||
|
/* create client */
|
||||||
|
void CreateClient(u16 peer_id);
|
||||||
|
|
||||||
|
/* get a client by peer_id */
|
||||||
|
RemoteClient* getClientNoEx(u16 peer_id, ClientState state_min=Active);
|
||||||
|
|
||||||
|
/* get client by peer_id (make sure you have list lock before!*/
|
||||||
|
RemoteClient* lockedGetClientNoEx(u16 peer_id, ClientState state_min=Active);
|
||||||
|
|
||||||
|
/* get state of client by id*/
|
||||||
|
ClientState getClientState(u16 peer_id);
|
||||||
|
|
||||||
|
/* set client playername */
|
||||||
|
void setPlayerName(u16 peer_id,std::string name);
|
||||||
|
|
||||||
|
/* get protocol version of client */
|
||||||
|
u16 getProtocolVersion(u16 peer_id);
|
||||||
|
|
||||||
|
/* event to update client state */
|
||||||
|
void event(u16 peer_id, ClientStateEvent event);
|
||||||
|
|
||||||
|
/* set environment */
|
||||||
|
void setEnv(ServerEnvironment* env)
|
||||||
|
{ assert(m_env == 0); m_env = env; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//TODO find way to avoid this functions
|
||||||
|
void Lock()
|
||||||
|
{ m_clients_mutex.Lock(); }
|
||||||
|
void Unlock()
|
||||||
|
{ m_clients_mutex.Unlock(); }
|
||||||
|
|
||||||
|
std::map<u16, RemoteClient*>& getClientList()
|
||||||
|
{ return m_clients; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* update internal player list */
|
||||||
|
void UpdatePlayerList();
|
||||||
|
|
||||||
|
// Connection
|
||||||
|
con::Connection* m_con;
|
||||||
|
JMutex m_clients_mutex;
|
||||||
|
// Connected clients (behind the con mutex)
|
||||||
|
std::map<u16, RemoteClient*> m_clients;
|
||||||
|
std::vector<std::string> m_clients_names; //for announcing masterserver
|
||||||
|
|
||||||
|
// Environment
|
||||||
|
ServerEnvironment *m_env;
|
||||||
|
JMutex m_env_mutex;
|
||||||
|
|
||||||
|
float m_print_info_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -480,13 +480,7 @@ void ClientMediaDownloader::startConventionalTransfers(Client *client)
|
||||||
{
|
{
|
||||||
assert(m_httpfetch_active == 0);
|
assert(m_httpfetch_active == 0);
|
||||||
|
|
||||||
if (m_uncached_received_count == m_uncached_count) {
|
if (m_uncached_received_count != m_uncached_count) {
|
||||||
// In this case all media was found in the cache or
|
|
||||||
// has been downloaded from some remote server;
|
|
||||||
// report this fact to the server
|
|
||||||
client->received_media();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Some media files have not been received yet, use the
|
// Some media files have not been received yet, use the
|
||||||
// conventional slow method (minetest protocol) to get them
|
// conventional slow method (minetest protocol) to get them
|
||||||
std::list<std::string> file_requests;
|
std::list<std::string> file_requests;
|
||||||
|
|
|
@ -34,6 +34,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
namespace con
|
namespace con
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* defines used for debugging and profiling */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define LOG(a) a
|
||||||
|
#define PROFILE(a)
|
||||||
|
#undef DEBUG_CONNECTION_KBPS
|
||||||
|
#else
|
||||||
/* this mutex is used to achieve log message consistency */
|
/* this mutex is used to achieve log message consistency */
|
||||||
JMutex log_message_mutex;
|
JMutex log_message_mutex;
|
||||||
#define LOG(a) \
|
#define LOG(a) \
|
||||||
|
@ -41,15 +49,10 @@ JMutex log_message_mutex;
|
||||||
JMutexAutoLock loglock(log_message_mutex); \
|
JMutexAutoLock loglock(log_message_mutex); \
|
||||||
a; \
|
a; \
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
/* defines used for debugging and profiling */
|
|
||||||
/******************************************************************************/
|
|
||||||
#define PROFILE(a) a
|
#define PROFILE(a) a
|
||||||
//#define PROFILE(a)
|
|
||||||
|
|
||||||
//#define DEBUG_CONNECTION_KBPS
|
//#define DEBUG_CONNECTION_KBPS
|
||||||
#undef DEBUG_CONNECTION_KBPS
|
#undef DEBUG_CONNECTION_KBPS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static inline float CALC_DTIME(unsigned int lasttime, unsigned int curtime) {
|
static inline float CALC_DTIME(unsigned int lasttime, unsigned int curtime) {
|
||||||
|
@ -960,15 +963,12 @@ void Peer::Drop()
|
||||||
|
|
||||||
UDPPeer::UDPPeer(u16 a_id, Address a_address, Connection* connection) :
|
UDPPeer::UDPPeer(u16 a_id, Address a_address, Connection* connection) :
|
||||||
Peer(a_address,a_id,connection),
|
Peer(a_address,a_id,connection),
|
||||||
|
m_pending_disconnect(false),
|
||||||
resend_timeout(0.5),
|
resend_timeout(0.5),
|
||||||
m_legacy_peer(true)
|
m_legacy_peer(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UDPPeer::~UDPPeer()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UDPPeer::getAddress(MTProtocols type,Address& toset)
|
bool UDPPeer::getAddress(MTProtocols type,Address& toset)
|
||||||
{
|
{
|
||||||
if ((type == UDP) || (type == MINETEST_RELIABLE_UDP) || (type == PRIMARY))
|
if ((type == UDP) || (type == MINETEST_RELIABLE_UDP) || (type == PRIMARY))
|
||||||
|
@ -980,6 +980,15 @@ bool UDPPeer::getAddress(MTProtocols type,Address& toset)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDPPeer::setNonLegacyPeer()
|
||||||
|
{
|
||||||
|
m_legacy_peer = false;
|
||||||
|
for(unsigned int i=0; i< CHANNEL_COUNT; i++)
|
||||||
|
{
|
||||||
|
channels->setWindowSize(g_settings->getU16("max_packets_per_iteration"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UDPPeer::reportRTT(float rtt)
|
void UDPPeer::reportRTT(float rtt)
|
||||||
{
|
{
|
||||||
if (rtt < 0.0) {
|
if (rtt < 0.0) {
|
||||||
|
@ -1014,6 +1023,9 @@ bool UDPPeer::Ping(float dtime,SharedBuffer<u8>& data)
|
||||||
void UDPPeer::PutReliableSendCommand(ConnectionCommand &c,
|
void UDPPeer::PutReliableSendCommand(ConnectionCommand &c,
|
||||||
unsigned int max_packet_size)
|
unsigned int max_packet_size)
|
||||||
{
|
{
|
||||||
|
if (m_pending_disconnect)
|
||||||
|
return;
|
||||||
|
|
||||||
if ( channels[c.channelnum].queued_commands.empty() &&
|
if ( channels[c.channelnum].queued_commands.empty() &&
|
||||||
/* don't queue more packets then window size */
|
/* don't queue more packets then window size */
|
||||||
(channels[c.channelnum].queued_reliables.size()
|
(channels[c.channelnum].queued_reliables.size()
|
||||||
|
@ -1040,6 +1052,9 @@ bool UDPPeer::processReliableSendCommand(
|
||||||
ConnectionCommand &c,
|
ConnectionCommand &c,
|
||||||
unsigned int max_packet_size)
|
unsigned int max_packet_size)
|
||||||
{
|
{
|
||||||
|
if (m_pending_disconnect)
|
||||||
|
return true;
|
||||||
|
|
||||||
u32 chunksize_max = max_packet_size
|
u32 chunksize_max = max_packet_size
|
||||||
- BASE_HEADER_SIZE
|
- BASE_HEADER_SIZE
|
||||||
- RELIABLE_HEADER_SIZE;
|
- RELIABLE_HEADER_SIZE;
|
||||||
|
@ -1564,7 +1579,6 @@ void ConnectionSendThread::processReliableCommand(ConnectionCommand &c)
|
||||||
case CONNCMD_SERVE:
|
case CONNCMD_SERVE:
|
||||||
case CONNCMD_CONNECT:
|
case CONNCMD_CONNECT:
|
||||||
case CONNCMD_DISCONNECT:
|
case CONNCMD_DISCONNECT:
|
||||||
case CONNCMD_DELETE_PEER:
|
|
||||||
case CONCMD_ACK:
|
case CONCMD_ACK:
|
||||||
assert("Got command that shouldn't be reliable as reliable command" == 0);
|
assert("Got command that shouldn't be reliable as reliable command" == 0);
|
||||||
default:
|
default:
|
||||||
|
@ -1606,10 +1620,6 @@ void ConnectionSendThread::processNonReliableCommand(ConnectionCommand &c)
|
||||||
LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_SEND_TO_ALL"<<std::endl);
|
LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_SEND_TO_ALL"<<std::endl);
|
||||||
sendToAll(c.channelnum, c.data);
|
sendToAll(c.channelnum, c.data);
|
||||||
return;
|
return;
|
||||||
case CONNCMD_DELETE_PEER:
|
|
||||||
LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_DELETE_PEER"<<std::endl);
|
|
||||||
m_connection->deletePeer(c.peer_id, false);
|
|
||||||
return;
|
|
||||||
case CONCMD_ACK:
|
case CONCMD_ACK:
|
||||||
LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONCMD_ACK"<<std::endl);
|
LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONCMD_ACK"<<std::endl);
|
||||||
sendAsPacket(c.peer_id,c.channelnum,c.data,true);
|
sendAsPacket(c.peer_id,c.channelnum,c.data,true);
|
||||||
|
@ -1686,6 +1696,18 @@ void ConnectionSendThread::disconnect_peer(u16 peer_id)
|
||||||
writeU8(&data[0], TYPE_CONTROL);
|
writeU8(&data[0], TYPE_CONTROL);
|
||||||
writeU8(&data[1], CONTROLTYPE_DISCO);
|
writeU8(&data[1], CONTROLTYPE_DISCO);
|
||||||
sendAsPacket(peer_id, 0,data,false);
|
sendAsPacket(peer_id, 0,data,false);
|
||||||
|
|
||||||
|
PeerHelper peer = m_connection->getPeerNoEx(peer_id);
|
||||||
|
|
||||||
|
if (!peer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (dynamic_cast<UDPPeer*>(&peer) == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic_cast<UDPPeer*>(&peer)->m_pending_disconnect = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionSendThread::send(u16 peer_id, u8 channelnum,
|
void ConnectionSendThread::send(u16 peer_id, u8 channelnum,
|
||||||
|
@ -1764,6 +1786,8 @@ void ConnectionSendThread::sendToAllReliable(ConnectionCommand &c)
|
||||||
void ConnectionSendThread::sendPackets(float dtime)
|
void ConnectionSendThread::sendPackets(float dtime)
|
||||||
{
|
{
|
||||||
std::list<u16> peerIds = m_connection->getPeerIDs();
|
std::list<u16> peerIds = m_connection->getPeerIDs();
|
||||||
|
std::list<u16> pendingDisconnect;
|
||||||
|
std::map<u16,bool> pending_unreliable;
|
||||||
|
|
||||||
for(std::list<u16>::iterator
|
for(std::list<u16>::iterator
|
||||||
j = peerIds.begin();
|
j = peerIds.begin();
|
||||||
|
@ -1782,6 +1806,11 @@ void ConnectionSendThread::sendPackets(float dtime)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dynamic_cast<UDPPeer*>(&peer)->m_pending_disconnect)
|
||||||
|
{
|
||||||
|
pendingDisconnect.push_back(*j);
|
||||||
|
}
|
||||||
|
|
||||||
PROFILE(std::stringstream peerIdentifier);
|
PROFILE(std::stringstream peerIdentifier);
|
||||||
PROFILE(peerIdentifier << "sendPackets[" << m_connection->getDesc() << ";" << *j << ";RELIABLE]");
|
PROFILE(peerIdentifier << "sendPackets[" << m_connection->getDesc() << ";" << *j << ";RELIABLE]");
|
||||||
PROFILE(ScopeProfiler peerprofiler(g_profiler, peerIdentifier.str(), SPT_AVG));
|
PROFILE(ScopeProfiler peerprofiler(g_profiler, peerIdentifier.str(), SPT_AVG));
|
||||||
|
@ -1877,6 +1906,17 @@ void ConnectionSendThread::sendPackets(float dtime)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_outgoing_queue.push_back(packet);
|
m_outgoing_queue.push_back(packet);
|
||||||
|
pending_unreliable[packet.peer_id] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::list<u16>::iterator
|
||||||
|
k = pendingDisconnect.begin();
|
||||||
|
k != pendingDisconnect.end(); ++k)
|
||||||
|
{
|
||||||
|
if (!pending_unreliable[*k])
|
||||||
|
{
|
||||||
|
m_connection->deletePeer(*k,false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1986,11 +2026,10 @@ void * ConnectionReceiveThread::Thread()
|
||||||
// Receive packets from the network and buffers and create ConnectionEvents
|
// Receive packets from the network and buffers and create ConnectionEvents
|
||||||
void ConnectionReceiveThread::receive()
|
void ConnectionReceiveThread::receive()
|
||||||
{
|
{
|
||||||
/* now reorder reliables */
|
// use IPv6 minimum allowed MTU as receive buffer size as this is
|
||||||
u32 datasize = m_max_packet_size * 2; // Double it just to be safe
|
// theoretical reliable upper boundary of a udp packet for all IPv6 enabled
|
||||||
// TODO: We can not know how many layers of header there are.
|
// infrastructure
|
||||||
// For now, just assume there are no other than the base headers.
|
unsigned int packet_maxsize = 1500;
|
||||||
u32 packet_maxsize = datasize + BASE_HEADER_SIZE;
|
|
||||||
SharedBuffer<u8> packetdata(packet_maxsize);
|
SharedBuffer<u8> packetdata(packet_maxsize);
|
||||||
|
|
||||||
bool packet_queued = true;
|
bool packet_queued = true;
|
||||||
|
@ -2126,7 +2165,7 @@ void ConnectionReceiveThread::receive()
|
||||||
|
|
||||||
LOG(dout_con<<m_connection->getDesc()
|
LOG(dout_con<<m_connection->getDesc()
|
||||||
<<" ProcessPacket from peer_id: " << peer_id
|
<<" ProcessPacket from peer_id: " << peer_id
|
||||||
<< ",channel: " << channelnum << ", returned "
|
<< ",channel: " << (channelnum & 0xFF) << ", returned "
|
||||||
<< resultdata.getSize() << " bytes" <<std::endl);
|
<< resultdata.getSize() << " bytes" <<std::endl);
|
||||||
|
|
||||||
ConnectionEvent e;
|
ConnectionEvent e;
|
||||||
|
@ -2262,6 +2301,10 @@ SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
|
||||||
}
|
}
|
||||||
//put bytes for max bandwidth calculation
|
//put bytes for max bandwidth calculation
|
||||||
channel->UpdateBytesSent(p.data.getSize(),1);
|
channel->UpdateBytesSent(p.data.getSize(),1);
|
||||||
|
if (channel->outgoing_reliables_sent.size() == 0)
|
||||||
|
{
|
||||||
|
m_connection->TriggerSend();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(NotFoundException &e){
|
catch(NotFoundException &e){
|
||||||
LOG(derr_con<<m_connection->getDesc()
|
LOG(derr_con<<m_connection->getDesc()
|
||||||
|
@ -2534,7 +2577,8 @@ Connection::Connection(u32 protocol_id, u32 max_packet_size, float timeout,
|
||||||
m_info_mutex(),
|
m_info_mutex(),
|
||||||
m_bc_peerhandler(0),
|
m_bc_peerhandler(0),
|
||||||
m_bc_receive_timeout(0),
|
m_bc_receive_timeout(0),
|
||||||
m_shutting_down(false)
|
m_shutting_down(false),
|
||||||
|
m_next_remote_peer_id(2)
|
||||||
{
|
{
|
||||||
m_udpSocket.setTimeoutMs(5);
|
m_udpSocket.setTimeoutMs(5);
|
||||||
|
|
||||||
|
@ -2554,7 +2598,8 @@ Connection::Connection(u32 protocol_id, u32 max_packet_size, float timeout,
|
||||||
m_info_mutex(),
|
m_info_mutex(),
|
||||||
m_bc_peerhandler(peerhandler),
|
m_bc_peerhandler(peerhandler),
|
||||||
m_bc_receive_timeout(0),
|
m_bc_receive_timeout(0),
|
||||||
m_shutting_down(false)
|
m_shutting_down(false),
|
||||||
|
m_next_remote_peer_id(2)
|
||||||
|
|
||||||
{
|
{
|
||||||
m_udpSocket.setTimeoutMs(5);
|
m_udpSocket.setTimeoutMs(5);
|
||||||
|
@ -2810,11 +2855,6 @@ void Connection::Send(u16 peer_id, u8 channelnum,
|
||||||
putCommand(c);
|
putCommand(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::RunTimeouts(float dtime)
|
|
||||||
{
|
|
||||||
// No-op
|
|
||||||
}
|
|
||||||
|
|
||||||
Address Connection::GetPeerAddress(u16 peer_id)
|
Address Connection::GetPeerAddress(u16 peer_id)
|
||||||
{
|
{
|
||||||
PeerHelper peer = getPeerNoEx(peer_id);
|
PeerHelper peer = getPeerNoEx(peer_id);
|
||||||
|
@ -2838,47 +2878,44 @@ u16 Connection::createPeer(Address& sender, MTProtocols protocol, int fd)
|
||||||
// Somebody wants to make a new connection
|
// Somebody wants to make a new connection
|
||||||
|
|
||||||
// Get a unique peer id (2 or higher)
|
// Get a unique peer id (2 or higher)
|
||||||
u16 peer_id_new = 2;
|
u16 peer_id_new = m_next_remote_peer_id;
|
||||||
u16 overflow = MAX_UDP_PEERS;
|
u16 overflow = MAX_UDP_PEERS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Find an unused peer id
|
Find an unused peer id
|
||||||
*/
|
*/
|
||||||
bool out_of_ids = false;
|
|
||||||
for(;;)
|
|
||||||
{
|
{
|
||||||
// Check if exists
|
JMutexAutoLock lock(m_peers_mutex);
|
||||||
if(m_peers.find(peer_id_new) == m_peers.end())
|
bool out_of_ids = false;
|
||||||
break;
|
for(;;)
|
||||||
// Check for overflow
|
{
|
||||||
if(peer_id_new == overflow){
|
// Check if exists
|
||||||
out_of_ids = true;
|
if(m_peers.find(peer_id_new) == m_peers.end())
|
||||||
break;
|
break;
|
||||||
|
// Check for overflow
|
||||||
|
if(peer_id_new == overflow){
|
||||||
|
out_of_ids = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
peer_id_new++;
|
||||||
}
|
}
|
||||||
peer_id_new++;
|
if(out_of_ids){
|
||||||
}
|
errorstream<<getDesc()<<" ran out of peer ids"<<std::endl;
|
||||||
if(out_of_ids){
|
return PEER_ID_INEXISTENT;
|
||||||
errorstream<<getDesc()<<" ran out of peer ids"<<std::endl;
|
}
|
||||||
return PEER_ID_INEXISTENT;
|
|
||||||
|
// Create a peer
|
||||||
|
Peer *peer = 0;
|
||||||
|
peer = new UDPPeer(peer_id_new, sender, this);
|
||||||
|
|
||||||
|
m_peers[peer->id] = peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_next_remote_peer_id = (peer_id_new +1) % MAX_UDP_PEERS;
|
||||||
|
|
||||||
LOG(dout_con<<getDesc()
|
LOG(dout_con<<getDesc()
|
||||||
<<"createPeer(): giving peer_id="<<peer_id_new<<std::endl);
|
<<"createPeer(): giving peer_id="<<peer_id_new<<std::endl);
|
||||||
|
|
||||||
// Create a peer
|
|
||||||
Peer *peer = 0;
|
|
||||||
|
|
||||||
peer = new UDPPeer(peer_id_new, sender, this);
|
|
||||||
|
|
||||||
m_peers_mutex.Lock();
|
|
||||||
m_peers[peer->id] = peer;
|
|
||||||
m_peers_mutex.Unlock();
|
|
||||||
|
|
||||||
// Create peer addition event
|
|
||||||
ConnectionEvent e;
|
|
||||||
e.peerAdded(peer_id_new, sender);
|
|
||||||
putEvent(e);
|
|
||||||
|
|
||||||
ConnectionCommand cmd;
|
ConnectionCommand cmd;
|
||||||
SharedBuffer<u8> reply(4);
|
SharedBuffer<u8> reply(4);
|
||||||
writeU8(&reply[0], TYPE_CONTROL);
|
writeU8(&reply[0], TYPE_CONTROL);
|
||||||
|
@ -2887,17 +2924,15 @@ u16 Connection::createPeer(Address& sender, MTProtocols protocol, int fd)
|
||||||
cmd.createPeer(peer_id_new,reply);
|
cmd.createPeer(peer_id_new,reply);
|
||||||
this->putCommand(cmd);
|
this->putCommand(cmd);
|
||||||
|
|
||||||
|
// Create peer addition event
|
||||||
|
ConnectionEvent e;
|
||||||
|
e.peerAdded(peer_id_new, sender);
|
||||||
|
putEvent(e);
|
||||||
|
|
||||||
// We're now talking to a valid peer_id
|
// We're now talking to a valid peer_id
|
||||||
return peer_id_new;
|
return peer_id_new;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::DeletePeer(u16 peer_id)
|
|
||||||
{
|
|
||||||
ConnectionCommand c;
|
|
||||||
c.deletePeer(peer_id);
|
|
||||||
putCommand(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Connection::PrintInfo(std::ostream &out)
|
void Connection::PrintInfo(std::ostream &out)
|
||||||
{
|
{
|
||||||
m_info_mutex.Lock();
|
m_info_mutex.Lock();
|
||||||
|
@ -2915,6 +2950,13 @@ const std::string Connection::getDesc()
|
||||||
return std::string("con(")+itos(m_udpSocket.GetHandle())+"/"+itos(m_peer_id)+")";
|
return std::string("con(")+itos(m_udpSocket.GetHandle())+"/"+itos(m_peer_id)+")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Connection::DisconnectPeer(u16 peer_id)
|
||||||
|
{
|
||||||
|
ConnectionCommand discon;
|
||||||
|
discon.disconnect_peer(peer_id);
|
||||||
|
putCommand(discon);
|
||||||
|
}
|
||||||
|
|
||||||
void Connection::sendAck(u16 peer_id, u8 channelnum, u16 seqnum) {
|
void Connection::sendAck(u16 peer_id, u8 channelnum, u16 seqnum) {
|
||||||
|
|
||||||
assert(channelnum < CHANNEL_COUNT);
|
assert(channelnum < CHANNEL_COUNT);
|
||||||
|
|
|
@ -71,14 +71,6 @@ public:
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*class ThrottlingException : public BaseException
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ThrottlingException(const char *s):
|
|
||||||
BaseException(s)
|
|
||||||
{}
|
|
||||||
};*/
|
|
||||||
|
|
||||||
class InvalidIncomingDataException : public BaseException
|
class InvalidIncomingDataException : public BaseException
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -406,7 +398,6 @@ enum ConnectionCommandType{
|
||||||
CONNCMD_DISCONNECT_PEER,
|
CONNCMD_DISCONNECT_PEER,
|
||||||
CONNCMD_SEND,
|
CONNCMD_SEND,
|
||||||
CONNCMD_SEND_TO_ALL,
|
CONNCMD_SEND_TO_ALL,
|
||||||
CONNCMD_DELETE_PEER,
|
|
||||||
CONCMD_ACK,
|
CONCMD_ACK,
|
||||||
CONCMD_CREATE_PEER,
|
CONCMD_CREATE_PEER,
|
||||||
CONCMD_DISABLE_LEGACY
|
CONCMD_DISABLE_LEGACY
|
||||||
|
@ -460,11 +451,6 @@ struct ConnectionCommand
|
||||||
data = data_;
|
data = data_;
|
||||||
reliable = reliable_;
|
reliable = reliable_;
|
||||||
}
|
}
|
||||||
void deletePeer(u16 peer_id_)
|
|
||||||
{
|
|
||||||
type = CONNCMD_DELETE_PEER;
|
|
||||||
peer_id = peer_id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ack(u16 peer_id_, u8 channelnum_, SharedBuffer<u8> data_)
|
void ack(u16 peer_id_, u8 channelnum_, SharedBuffer<u8> data_)
|
||||||
{
|
{
|
||||||
|
@ -580,16 +566,29 @@ private:
|
||||||
|
|
||||||
class Peer;
|
class Peer;
|
||||||
|
|
||||||
|
enum PeerChangeType
|
||||||
|
{
|
||||||
|
PEER_ADDED,
|
||||||
|
PEER_REMOVED
|
||||||
|
};
|
||||||
|
struct PeerChange
|
||||||
|
{
|
||||||
|
PeerChangeType type;
|
||||||
|
u16 peer_id;
|
||||||
|
bool timeout;
|
||||||
|
};
|
||||||
|
|
||||||
class PeerHandler
|
class PeerHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PeerHandler()
|
PeerHandler()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
virtual ~PeerHandler()
|
virtual ~PeerHandler()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is called after the Peer has been inserted into the
|
This is called after the Peer has been inserted into the
|
||||||
Connection's peer container.
|
Connection's peer container.
|
||||||
|
@ -771,7 +770,7 @@ public:
|
||||||
friend class ConnectionSendThread;
|
friend class ConnectionSendThread;
|
||||||
|
|
||||||
UDPPeer(u16 a_id, Address a_address, Connection* connection);
|
UDPPeer(u16 a_id, Address a_address, Connection* connection);
|
||||||
virtual ~UDPPeer();
|
virtual ~UDPPeer() {};
|
||||||
|
|
||||||
void PutReliableSendCommand(ConnectionCommand &c,
|
void PutReliableSendCommand(ConnectionCommand &c,
|
||||||
unsigned int max_packet_size);
|
unsigned int max_packet_size);
|
||||||
|
@ -781,8 +780,7 @@ public:
|
||||||
|
|
||||||
bool getAddress(MTProtocols type, Address& toset);
|
bool getAddress(MTProtocols type, Address& toset);
|
||||||
|
|
||||||
void setNonLegacyPeer()
|
void setNonLegacyPeer();
|
||||||
{ m_legacy_peer = false; }
|
|
||||||
|
|
||||||
bool getLegacyPeer()
|
bool getLegacyPeer()
|
||||||
{ return m_legacy_peer; }
|
{ return m_legacy_peer; }
|
||||||
|
@ -793,6 +791,8 @@ public:
|
||||||
SharedBuffer<u8> addSpiltPacket(u8 channel,
|
SharedBuffer<u8> addSpiltPacket(u8 channel,
|
||||||
BufferedPacket toadd,
|
BufferedPacket toadd,
|
||||||
bool reliable);
|
bool reliable);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/*
|
/*
|
||||||
Calculates avg_rtt and resend_timeout.
|
Calculates avg_rtt and resend_timeout.
|
||||||
|
@ -813,6 +813,7 @@ protected:
|
||||||
bool Ping(float dtime,SharedBuffer<u8>& data);
|
bool Ping(float dtime,SharedBuffer<u8>& data);
|
||||||
|
|
||||||
Channel channels[CHANNEL_COUNT];
|
Channel channels[CHANNEL_COUNT];
|
||||||
|
bool m_pending_disconnect;
|
||||||
private:
|
private:
|
||||||
// This is changed dynamically
|
// This is changed dynamically
|
||||||
float resend_timeout;
|
float resend_timeout;
|
||||||
|
@ -1002,13 +1003,12 @@ public:
|
||||||
u32 Receive(u16 &peer_id, SharedBuffer<u8> &data);
|
u32 Receive(u16 &peer_id, SharedBuffer<u8> &data);
|
||||||
void SendToAll(u8 channelnum, SharedBuffer<u8> data, bool reliable);
|
void SendToAll(u8 channelnum, SharedBuffer<u8> data, bool reliable);
|
||||||
void Send(u16 peer_id, u8 channelnum, SharedBuffer<u8> data, bool reliable);
|
void Send(u16 peer_id, u8 channelnum, SharedBuffer<u8> data, bool reliable);
|
||||||
void RunTimeouts(float dtime); // dummy
|
|
||||||
u16 GetPeerID(){ return m_peer_id; }
|
u16 GetPeerID(){ return m_peer_id; }
|
||||||
Address GetPeerAddress(u16 peer_id);
|
Address GetPeerAddress(u16 peer_id);
|
||||||
float GetPeerAvgRTT(u16 peer_id);
|
float GetPeerAvgRTT(u16 peer_id);
|
||||||
void DeletePeer(u16 peer_id);
|
|
||||||
const u32 GetProtocolID() const { return m_protocol_id; };
|
const u32 GetProtocolID() const { return m_protocol_id; };
|
||||||
const std::string getDesc();
|
const std::string getDesc();
|
||||||
|
void DisconnectPeer(u16 peer_id);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PeerHelper getPeer(u16 peer_id);
|
PeerHelper getPeer(u16 peer_id);
|
||||||
|
@ -1033,6 +1033,8 @@ protected:
|
||||||
|
|
||||||
void putEvent(ConnectionEvent &e);
|
void putEvent(ConnectionEvent &e);
|
||||||
|
|
||||||
|
void TriggerSend()
|
||||||
|
{ m_sendThread.Trigger(); }
|
||||||
private:
|
private:
|
||||||
std::list<Peer*> getPeers();
|
std::list<Peer*> getPeers();
|
||||||
|
|
||||||
|
@ -1054,6 +1056,8 @@ private:
|
||||||
int m_bc_receive_timeout;
|
int m_bc_receive_timeout;
|
||||||
|
|
||||||
bool m_shutting_down;
|
bool m_shutting_down;
|
||||||
|
|
||||||
|
u16 m_next_remote_peer_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -592,23 +592,12 @@ void *EmergeThread::Thread() {
|
||||||
/*
|
/*
|
||||||
Set sent status of modified blocks on clients
|
Set sent status of modified blocks on clients
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// NOTE: Server's clients are also behind the connection mutex
|
|
||||||
//conlock: consistently takes 30-40ms to acquire
|
|
||||||
JMutexAutoLock lock(m_server->m_con_mutex);
|
|
||||||
// Add the originally fetched block to the modified list
|
// Add the originally fetched block to the modified list
|
||||||
if (block)
|
if (block)
|
||||||
modified_blocks[p] = block;
|
modified_blocks[p] = block;
|
||||||
|
|
||||||
// Set the modified blocks unsent for all the clients
|
if (modified_blocks.size() > 0) {
|
||||||
for (std::map<u16, RemoteClient*>::iterator
|
m_server->SetBlocksNotSent(modified_blocks);
|
||||||
i = m_server->m_clients.begin();
|
|
||||||
i != m_server->m_clients.end(); ++i) {
|
|
||||||
RemoteClient *client = i->second;
|
|
||||||
if (modified_blocks.size() > 0) {
|
|
||||||
// Remove block from sent history
|
|
||||||
client->SetBlocksNotSent(modified_blocks);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (VersionMismatchException &e) {
|
catch (VersionMismatchException &e) {
|
||||||
|
|
1786
src/server.cpp
1786
src/server.cpp
File diff suppressed because it is too large
Load Diff
310
src/server.h
310
src/server.h
|
@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
#include "util/thread.h"
|
#include "util/thread.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
|
#include "clientiface.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -53,14 +54,19 @@ class EmergeManager;
|
||||||
class GameScripting;
|
class GameScripting;
|
||||||
class ServerEnvironment;
|
class ServerEnvironment;
|
||||||
struct SimpleSoundSpec;
|
struct SimpleSoundSpec;
|
||||||
|
class ServerThread;
|
||||||
|
|
||||||
|
enum ClientDeletionReason {
|
||||||
|
CDR_LEAVE,
|
||||||
|
CDR_TIMEOUT,
|
||||||
|
CDR_DENY
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Some random functions
|
Some random functions
|
||||||
*/
|
*/
|
||||||
v3f findSpawnPos(ServerMap &map);
|
v3f findSpawnPos(ServerMap &map);
|
||||||
|
|
||||||
|
|
||||||
class MapEditEventIgnorer
|
class MapEditEventIgnorer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -111,31 +117,6 @@ private:
|
||||||
VoxelArea *m_ignorevariable;
|
VoxelArea *m_ignorevariable;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Server;
|
|
||||||
class ServerThread;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Used for queueing and sorting block transfers in containers
|
|
||||||
|
|
||||||
Lower priority number means higher priority.
|
|
||||||
*/
|
|
||||||
struct PrioritySortedBlockTransfer
|
|
||||||
{
|
|
||||||
PrioritySortedBlockTransfer(float a_priority, v3s16 a_pos, u16 a_peer_id)
|
|
||||||
{
|
|
||||||
priority = a_priority;
|
|
||||||
pos = a_pos;
|
|
||||||
peer_id = a_peer_id;
|
|
||||||
}
|
|
||||||
bool operator < (const PrioritySortedBlockTransfer &other) const
|
|
||||||
{
|
|
||||||
return priority < other.priority;
|
|
||||||
}
|
|
||||||
float priority;
|
|
||||||
v3s16 pos;
|
|
||||||
u16 peer_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MediaInfo
|
struct MediaInfo
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
|
@ -182,134 +163,6 @@ struct ServerPlayingSound
|
||||||
std::set<u16> clients; // peer ids
|
std::set<u16> clients; // peer ids
|
||||||
};
|
};
|
||||||
|
|
||||||
class RemoteClient
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// peer_id=0 means this client has no associated peer
|
|
||||||
// NOTE: If client is made allowed to exist while peer doesn't,
|
|
||||||
// this has to be set to 0 when there is no peer.
|
|
||||||
// Also, the client must be moved to some other container.
|
|
||||||
u16 peer_id;
|
|
||||||
// The serialization version to use with the client
|
|
||||||
u8 serialization_version;
|
|
||||||
//
|
|
||||||
u16 net_proto_version;
|
|
||||||
// Version is stored in here after INIT before INIT2
|
|
||||||
u8 pending_serialization_version;
|
|
||||||
|
|
||||||
bool definitions_sent;
|
|
||||||
|
|
||||||
bool denied;
|
|
||||||
|
|
||||||
RemoteClient():
|
|
||||||
m_time_from_building(9999),
|
|
||||||
m_excess_gotblocks(0)
|
|
||||||
{
|
|
||||||
peer_id = 0;
|
|
||||||
serialization_version = SER_FMT_VER_INVALID;
|
|
||||||
net_proto_version = 0;
|
|
||||||
pending_serialization_version = SER_FMT_VER_INVALID;
|
|
||||||
definitions_sent = false;
|
|
||||||
denied = false;
|
|
||||||
m_nearest_unsent_d = 0;
|
|
||||||
m_nearest_unsent_reset_timer = 0.0;
|
|
||||||
m_nothing_to_send_counter = 0;
|
|
||||||
m_nothing_to_send_pause_timer = 0;
|
|
||||||
}
|
|
||||||
~RemoteClient()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Finds block that should be sent next to the client.
|
|
||||||
Environment should be locked when this is called.
|
|
||||||
dtime is used for resetting send radius at slow interval
|
|
||||||
*/
|
|
||||||
void GetNextBlocks(Server *server, float dtime,
|
|
||||||
std::vector<PrioritySortedBlockTransfer> &dest);
|
|
||||||
|
|
||||||
void GotBlock(v3s16 p);
|
|
||||||
|
|
||||||
void SentBlock(v3s16 p);
|
|
||||||
|
|
||||||
void SetBlockNotSent(v3s16 p);
|
|
||||||
void SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks);
|
|
||||||
|
|
||||||
s32 SendingCount()
|
|
||||||
{
|
|
||||||
return m_blocks_sending.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increments timeouts and removes timed-out blocks from list
|
|
||||||
// NOTE: This doesn't fix the server-not-sending-block bug
|
|
||||||
// because it is related to emerging, not sending.
|
|
||||||
//void RunSendingTimeouts(float dtime, float timeout);
|
|
||||||
|
|
||||||
void PrintInfo(std::ostream &o)
|
|
||||||
{
|
|
||||||
o<<"RemoteClient "<<peer_id<<": "
|
|
||||||
<<"m_blocks_sent.size()="<<m_blocks_sent.size()
|
|
||||||
<<", m_blocks_sending.size()="<<m_blocks_sending.size()
|
|
||||||
<<", m_nearest_unsent_d="<<m_nearest_unsent_d
|
|
||||||
<<", m_excess_gotblocks="<<m_excess_gotblocks
|
|
||||||
<<std::endl;
|
|
||||||
m_excess_gotblocks = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time from last placing or removing blocks
|
|
||||||
float m_time_from_building;
|
|
||||||
|
|
||||||
/*JMutex m_dig_mutex;
|
|
||||||
float m_dig_time_remaining;
|
|
||||||
// -1 = not digging
|
|
||||||
s16 m_dig_tool_item;
|
|
||||||
v3s16 m_dig_position;*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
List of active objects that the client knows of.
|
|
||||||
Value is dummy.
|
|
||||||
*/
|
|
||||||
std::set<u16> m_known_objects;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/*
|
|
||||||
Blocks that have been sent to client.
|
|
||||||
- These don't have to be sent again.
|
|
||||||
- A block is cleared from here when client says it has
|
|
||||||
deleted it from it's memory
|
|
||||||
|
|
||||||
Key is position, value is dummy.
|
|
||||||
No MapBlock* is stored here because the blocks can get deleted.
|
|
||||||
*/
|
|
||||||
std::set<v3s16> m_blocks_sent;
|
|
||||||
s16 m_nearest_unsent_d;
|
|
||||||
v3s16 m_last_center;
|
|
||||||
float m_nearest_unsent_reset_timer;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Blocks that are currently on the line.
|
|
||||||
This is used for throttling the sending of blocks.
|
|
||||||
- The size of this list is limited to some value
|
|
||||||
Block is added when it is sent with BLOCKDATA.
|
|
||||||
Block is removed when GOTBLOCKS is received.
|
|
||||||
Value is time from sending. (not used at the moment)
|
|
||||||
*/
|
|
||||||
std::map<v3s16, float> m_blocks_sending;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Count of excess GotBlocks().
|
|
||||||
There is an excess amount because the client sometimes
|
|
||||||
gets a block so late that the server sends it again,
|
|
||||||
and the client then sends two GOTBLOCKs.
|
|
||||||
This is resetted by PrintInfo()
|
|
||||||
*/
|
|
||||||
u32 m_excess_gotblocks;
|
|
||||||
|
|
||||||
// CPU usage optimization
|
|
||||||
u32 m_nothing_to_send_counter;
|
|
||||||
float m_nothing_to_send_pause_timer;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Server : public con::PeerHandler, public MapEventReceiver,
|
class Server : public con::PeerHandler, public MapEventReceiver,
|
||||||
public InventoryManager, public IGameDef
|
public InventoryManager, public IGameDef
|
||||||
{
|
{
|
||||||
|
@ -337,11 +190,6 @@ public:
|
||||||
// Environment must be locked when called
|
// Environment must be locked when called
|
||||||
void setTimeOfDay(u32 time);
|
void setTimeOfDay(u32 time);
|
||||||
|
|
||||||
bool getShutdownRequested()
|
|
||||||
{
|
|
||||||
return m_shutdown_requested;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Shall be called with the environment locked.
|
Shall be called with the environment locked.
|
||||||
This is accessed by the map, which is inside the environment,
|
This is accessed by the map, which is inside the environment,
|
||||||
|
@ -358,17 +206,20 @@ public:
|
||||||
// Connection must be locked when called
|
// Connection must be locked when called
|
||||||
std::wstring getStatusString();
|
std::wstring getStatusString();
|
||||||
|
|
||||||
void requestShutdown(void)
|
// read shutdown state
|
||||||
{
|
inline bool getShutdownRequested()
|
||||||
m_shutdown_requested = true;
|
{ return m_shutdown_requested; }
|
||||||
}
|
|
||||||
|
// request server to shutdown
|
||||||
|
inline void requestShutdown(void)
|
||||||
|
{ m_shutdown_requested = true; }
|
||||||
|
|
||||||
// Returns -1 if failed, sound handle on success
|
// Returns -1 if failed, sound handle on success
|
||||||
// Envlock + conlock
|
// Envlock
|
||||||
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms);
|
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms);
|
||||||
void stopSound(s32 handle);
|
void stopSound(s32 handle);
|
||||||
|
|
||||||
// Envlock + conlock
|
// Envlock
|
||||||
std::set<std::string> getPlayerEffectivePrivs(const std::string &name);
|
std::set<std::string> getPlayerEffectivePrivs(const std::string &name);
|
||||||
bool checkPriv(const std::string &name, const std::string &priv);
|
bool checkPriv(const std::string &name, const std::string &priv);
|
||||||
void reportPrivsModified(const std::string &name=""); // ""=all
|
void reportPrivsModified(const std::string &name=""); // ""=all
|
||||||
|
@ -378,12 +229,6 @@ public:
|
||||||
void unsetIpBanned(const std::string &ip_or_name);
|
void unsetIpBanned(const std::string &ip_or_name);
|
||||||
std::string getBanDescription(const std::string &ip_or_name);
|
std::string getBanDescription(const std::string &ip_or_name);
|
||||||
|
|
||||||
Address getPeerAddress(u16 peer_id)
|
|
||||||
{
|
|
||||||
return m_con.GetPeerAddress(peer_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Envlock and conlock should be locked when calling this
|
|
||||||
void notifyPlayer(const char *name, const std::wstring msg, const bool prepend);
|
void notifyPlayer(const char *name, const std::wstring msg, const bool prepend);
|
||||||
void notifyPlayers(const std::wstring msg);
|
void notifyPlayers(const std::wstring msg);
|
||||||
void spawnParticle(const char *playername,
|
void spawnParticle(const char *playername,
|
||||||
|
@ -451,15 +296,14 @@ public:
|
||||||
const ModSpec* getModSpec(const std::string &modname);
|
const ModSpec* getModSpec(const std::string &modname);
|
||||||
void getModNames(std::list<std::string> &modlist);
|
void getModNames(std::list<std::string> &modlist);
|
||||||
std::string getBuiltinLuaPath();
|
std::string getBuiltinLuaPath();
|
||||||
|
inline std::string getWorldPath()
|
||||||
|
{ return m_path_world; }
|
||||||
|
|
||||||
std::string getWorldPath(){ return m_path_world; }
|
inline bool isSingleplayer()
|
||||||
|
{ return m_simple_singleplayer_mode; }
|
||||||
|
|
||||||
bool isSingleplayer(){ return m_simple_singleplayer_mode; }
|
inline void setAsyncFatalError(const std::string &error)
|
||||||
|
{ m_async_fatal_error.set(error); }
|
||||||
void setAsyncFatalError(const std::string &error)
|
|
||||||
{
|
|
||||||
m_async_fatal_error.set(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool showFormspec(const char *name, const std::string &formspec, const std::string &formname);
|
bool showFormspec(const char *name, const std::string &formspec, const std::string &formname);
|
||||||
Map & getMap() { return m_env->getMap(); }
|
Map & getMap() { return m_env->getMap(); }
|
||||||
|
@ -473,41 +317,32 @@ public:
|
||||||
void hudSetHotbarImage(Player *player, std::string name);
|
void hudSetHotbarImage(Player *player, std::string name);
|
||||||
void hudSetHotbarSelectedImage(Player *player, std::string name);
|
void hudSetHotbarSelectedImage(Player *player, std::string name);
|
||||||
|
|
||||||
private:
|
inline Address getPeerAddress(u16 peer_id)
|
||||||
|
{ return m_con.GetPeerAddress(peer_id); }
|
||||||
|
|
||||||
// con::PeerHandler implementation.
|
/* con::PeerHandler implementation. */
|
||||||
// These queue stuff to be processed by handlePeerChanges().
|
|
||||||
// As of now, these create and remove clients and players.
|
|
||||||
void peerAdded(con::Peer *peer);
|
void peerAdded(con::Peer *peer);
|
||||||
void deletingPeer(con::Peer *peer, bool timeout);
|
void deletingPeer(con::Peer *peer, bool timeout);
|
||||||
|
|
||||||
/*
|
private:
|
||||||
Static send methods
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void SendMovement(con::Connection &con, u16 peer_id);
|
friend class EmergeThread;
|
||||||
static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
|
friend class RemoteClient;
|
||||||
static void SendBreath(con::Connection &con, u16 peer_id, u16 breath);
|
|
||||||
static void SendAccessDenied(con::Connection &con, u16 peer_id,
|
|
||||||
const std::wstring &reason);
|
|
||||||
static void SendDeathscreen(con::Connection &con, u16 peer_id,
|
|
||||||
bool set_camera_point_target, v3f camera_point_target);
|
|
||||||
static void SendItemDef(con::Connection &con, u16 peer_id,
|
|
||||||
IItemDefManager *itemdef, u16 protocol_version);
|
|
||||||
static void SendNodeDef(con::Connection &con, u16 peer_id,
|
|
||||||
INodeDefManager *nodedef, u16 protocol_version);
|
|
||||||
|
|
||||||
/*
|
void SendMovement(u16 peer_id);
|
||||||
Non-static send methods.
|
void SendHP(u16 peer_id, u8 hp);
|
||||||
Conlock should be always used.
|
void SendBreath(u16 peer_id, u16 breath);
|
||||||
Envlock usage is documented badly but it's easy to figure out
|
void SendAccessDenied(u16 peer_id,const std::wstring &reason);
|
||||||
which ones access the environment.
|
void SendDeathscreen(u16 peer_id,bool set_camera_point_target, v3f camera_point_target);
|
||||||
*/
|
void SendItemDef(u16 peer_id,IItemDefManager *itemdef, u16 protocol_version);
|
||||||
|
void SendNodeDef(u16 peer_id,INodeDefManager *nodedef, u16 protocol_version);
|
||||||
|
|
||||||
|
/* mark blocks not sent for all clients */
|
||||||
|
void SetBlocksNotSent(std::map<v3s16, MapBlock *>& block);
|
||||||
|
|
||||||
// Envlock and conlock should be locked when calling these
|
// Envlock and conlock should be locked when calling these
|
||||||
void SendInventory(u16 peer_id);
|
void SendInventory(u16 peer_id);
|
||||||
void SendChatMessage(u16 peer_id, const std::wstring &message);
|
void SendChatMessage(u16 peer_id, const std::wstring &message);
|
||||||
void BroadcastChatMessage(const std::wstring &message);
|
|
||||||
void SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed);
|
void SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed);
|
||||||
void SendPlayerHP(u16 peer_id);
|
void SendPlayerHP(u16 peer_id);
|
||||||
void SendPlayerBreath(u16 peer_id);
|
void SendPlayerBreath(u16 peer_id);
|
||||||
|
@ -546,10 +381,9 @@ private:
|
||||||
const std::list<std::string> &tosend);
|
const std::list<std::string> &tosend);
|
||||||
|
|
||||||
void sendDetachedInventory(const std::string &name, u16 peer_id);
|
void sendDetachedInventory(const std::string &name, u16 peer_id);
|
||||||
void sendDetachedInventoryToAll(const std::string &name);
|
|
||||||
void sendDetachedInventories(u16 peer_id);
|
void sendDetachedInventories(u16 peer_id);
|
||||||
|
|
||||||
// Adds a ParticleSpawner on peer with peer_id
|
// Adds a ParticleSpawner on peer with peer_id (PEER_ID_INEXISTENT == all)
|
||||||
void SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime,
|
void SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime,
|
||||||
v3f minpos, v3f maxpos,
|
v3f minpos, v3f maxpos,
|
||||||
v3f minvel, v3f maxvel,
|
v3f minvel, v3f maxvel,
|
||||||
|
@ -558,32 +392,14 @@ private:
|
||||||
float minsize, float maxsize,
|
float minsize, float maxsize,
|
||||||
bool collisiondetection, bool vertical, std::string texture, u32 id);
|
bool collisiondetection, bool vertical, std::string texture, u32 id);
|
||||||
|
|
||||||
// Adds a ParticleSpawner on all peers
|
|
||||||
void SendAddParticleSpawnerAll(u16 amount, float spawntime,
|
|
||||||
v3f minpos, v3f maxpos,
|
|
||||||
v3f minvel, v3f maxvel,
|
|
||||||
v3f minacc, v3f maxacc,
|
|
||||||
float minexptime, float maxexptime,
|
|
||||||
float minsize, float maxsize,
|
|
||||||
bool collisiondetection, bool vertical, std::string texture, u32 id);
|
|
||||||
|
|
||||||
// Deletes ParticleSpawner on a single client
|
|
||||||
void SendDeleteParticleSpawner(u16 peer_id, u32 id);
|
void SendDeleteParticleSpawner(u16 peer_id, u32 id);
|
||||||
|
|
||||||
// Deletes ParticleSpawner on all clients
|
// Spawns particle on peer with peer_id (PEER_ID_INEXISTENT == all)
|
||||||
void SendDeleteParticleSpawnerAll(u32 id);
|
|
||||||
|
|
||||||
// Spawns particle on single client
|
|
||||||
void SendSpawnParticle(u16 peer_id,
|
void SendSpawnParticle(u16 peer_id,
|
||||||
v3f pos, v3f velocity, v3f acceleration,
|
v3f pos, v3f velocity, v3f acceleration,
|
||||||
float expirationtime, float size,
|
float expirationtime, float size,
|
||||||
bool collisiondetection, bool vertical, std::string texture);
|
bool collisiondetection, bool vertical, std::string texture);
|
||||||
|
|
||||||
// Spawns particle on all clients
|
|
||||||
void SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
|
|
||||||
float expirationtime, float size,
|
|
||||||
bool collisiondetection, bool vertical, std::string texture);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Something random
|
Something random
|
||||||
*/
|
*/
|
||||||
|
@ -591,19 +407,12 @@ private:
|
||||||
void DiePlayer(u16 peer_id);
|
void DiePlayer(u16 peer_id);
|
||||||
void RespawnPlayer(u16 peer_id);
|
void RespawnPlayer(u16 peer_id);
|
||||||
void DenyAccess(u16 peer_id, const std::wstring &reason);
|
void DenyAccess(u16 peer_id, const std::wstring &reason);
|
||||||
|
|
||||||
enum ClientDeletionReason {
|
|
||||||
CDR_LEAVE,
|
|
||||||
CDR_TIMEOUT,
|
|
||||||
CDR_DENY
|
|
||||||
};
|
|
||||||
void DeleteClient(u16 peer_id, ClientDeletionReason reason);
|
void DeleteClient(u16 peer_id, ClientDeletionReason reason);
|
||||||
|
|
||||||
void UpdateCrafting(u16 peer_id);
|
void UpdateCrafting(u16 peer_id);
|
||||||
|
|
||||||
// When called, connection mutex should be locked
|
// When called, connection mutex should be locked
|
||||||
RemoteClient* getClient(u16 peer_id);
|
RemoteClient* getClient(u16 peer_id,ClientState state_min=Active);
|
||||||
RemoteClient* getClientNoEx(u16 peer_id);
|
RemoteClient* getClientNoEx(u16 peer_id,ClientState state_min=Active);
|
||||||
|
|
||||||
// When called, environment mutex should be locked
|
// When called, environment mutex should be locked
|
||||||
std::string getPlayerName(u16 peer_id);
|
std::string getPlayerName(u16 peer_id);
|
||||||
|
@ -618,9 +427,6 @@ private:
|
||||||
*/
|
*/
|
||||||
PlayerSAO *emergePlayer(const char *name, u16 peer_id);
|
PlayerSAO *emergePlayer(const char *name, u16 peer_id);
|
||||||
|
|
||||||
// Locks environment and connection by its own
|
|
||||||
struct PeerChange;
|
|
||||||
void handlePeerChange(PeerChange &c);
|
|
||||||
void handlePeerChanges();
|
void handlePeerChanges();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -648,19 +454,12 @@ private:
|
||||||
float m_savemap_timer;
|
float m_savemap_timer;
|
||||||
IntervalLimiter m_map_timer_and_unload_interval;
|
IntervalLimiter m_map_timer_and_unload_interval;
|
||||||
|
|
||||||
// NOTE: If connection and environment are both to be locked,
|
|
||||||
// environment shall be locked first.
|
|
||||||
|
|
||||||
// Environment
|
// Environment
|
||||||
ServerEnvironment *m_env;
|
ServerEnvironment *m_env;
|
||||||
JMutex m_env_mutex;
|
JMutex m_env_mutex;
|
||||||
|
|
||||||
// Connection
|
// server connection
|
||||||
con::Connection m_con;
|
con::Connection m_con;
|
||||||
JMutex m_con_mutex;
|
|
||||||
// Connected clients (behind the con mutex)
|
|
||||||
std::map<u16, RemoteClient*> m_clients;
|
|
||||||
std::vector<std::string> m_clients_names; //for announcing masterserver
|
|
||||||
|
|
||||||
// Ban checking
|
// Ban checking
|
||||||
BanManager *m_banmanager;
|
BanManager *m_banmanager;
|
||||||
|
@ -701,6 +500,7 @@ private:
|
||||||
float m_step_dtime;
|
float m_step_dtime;
|
||||||
JMutex m_step_dtime_mutex;
|
JMutex m_step_dtime_mutex;
|
||||||
|
|
||||||
|
// current server step lag counter
|
||||||
float m_lag;
|
float m_lag;
|
||||||
|
|
||||||
// The server mainly operates in this thread
|
// The server mainly operates in this thread
|
||||||
|
@ -715,23 +515,17 @@ private:
|
||||||
// Uptime of server in seconds
|
// Uptime of server in seconds
|
||||||
MutexedVariable<double> m_uptime;
|
MutexedVariable<double> m_uptime;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Client interface
|
||||||
|
*/
|
||||||
|
ClientInterface m_clients;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Peer change queue.
|
Peer change queue.
|
||||||
Queues stuff from peerAdded() and deletingPeer() to
|
Queues stuff from peerAdded() and deletingPeer() to
|
||||||
handlePeerChanges()
|
handlePeerChanges()
|
||||||
*/
|
*/
|
||||||
enum PeerChangeType
|
Queue<con::PeerChange> m_peer_change_queue;
|
||||||
{
|
|
||||||
PEER_ADDED,
|
|
||||||
PEER_REMOVED
|
|
||||||
};
|
|
||||||
struct PeerChange
|
|
||||||
{
|
|
||||||
PeerChangeType type;
|
|
||||||
u16 peer_id;
|
|
||||||
bool timeout;
|
|
||||||
};
|
|
||||||
Queue<PeerChange> m_peer_change_queue;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Random stuff
|
Random stuff
|
||||||
|
@ -776,9 +570,7 @@ private:
|
||||||
*/
|
*/
|
||||||
u16 m_ignore_map_edit_events_peer_id;
|
u16 m_ignore_map_edit_events_peer_id;
|
||||||
|
|
||||||
friend class EmergeThread;
|
// media files known to server
|
||||||
friend class RemoteClient;
|
|
||||||
|
|
||||||
std::map<std::string,MediaInfo> m_media;
|
std::map<std::string,MediaInfo> m_media;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue