mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 10:03:45 +01:00
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 code
This commit is contained in:
parent
21f1bec724
commit
e258675eab
@ -308,6 +308,7 @@ set(common_SRCS
|
||||
connection.cpp
|
||||
environment.cpp
|
||||
server.cpp
|
||||
clientiface.cpp
|
||||
socket.cpp
|
||||
mapblock.cpp
|
||||
mapsector.cpp
|
||||
|
@ -383,13 +383,6 @@ void Client::step(float dtime)
|
||||
// 0ms
|
||||
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
|
||||
@ -758,6 +751,7 @@ void Client::step(float dtime)
|
||||
if (m_media_downloader && m_media_downloader->isStarted()) {
|
||||
m_media_downloader->step(this);
|
||||
if (m_media_downloader->isDone()) {
|
||||
received_media();
|
||||
delete m_media_downloader;
|
||||
m_media_downloader = NULL;
|
||||
}
|
||||
@ -1610,11 +1604,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -1666,11 +1655,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
m_media_downloader->conventionalTransferDone(
|
||||
name, data, this);
|
||||
}
|
||||
|
||||
if (m_media_downloader->isDone()) {
|
||||
delete m_media_downloader;
|
||||
m_media_downloader = NULL;
|
||||
}
|
||||
}
|
||||
else if(command == TOCLIENT_TOOLDEF)
|
||||
{
|
||||
|
769
src/clientiface.cpp
Normal file
769
src/clientiface.cpp
Normal file
@ -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;
|
||||
}
|
306
src/clientiface.h
Normal file
306
src/clientiface.h
Normal file
@ -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);
|
||||
|
||||
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 {
|
||||
if (m_uncached_received_count != m_uncached_count) {
|
||||
// Some media files have not been received yet, use the
|
||||
// conventional slow method (minetest protocol) to get them
|
||||
std::list<std::string> file_requests;
|
||||
|
@ -34,6 +34,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
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 */
|
||||
JMutex log_message_mutex;
|
||||
#define LOG(a) \
|
||||
@ -41,15 +49,10 @@ JMutex log_message_mutex;
|
||||
JMutexAutoLock loglock(log_message_mutex); \
|
||||
a; \
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* defines used for debugging and profiling */
|
||||
/******************************************************************************/
|
||||
#define PROFILE(a) a
|
||||
//#define PROFILE(a)
|
||||
|
||||
//#define DEBUG_CONNECTION_KBPS
|
||||
#undef DEBUG_CONNECTION_KBPS
|
||||
#endif
|
||||
|
||||
|
||||
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) :
|
||||
Peer(a_address,a_id,connection),
|
||||
m_pending_disconnect(false),
|
||||
resend_timeout(0.5),
|
||||
m_legacy_peer(true)
|
||||
{
|
||||
}
|
||||
|
||||
UDPPeer::~UDPPeer()
|
||||
{
|
||||
}
|
||||
|
||||
bool UDPPeer::getAddress(MTProtocols type,Address& toset)
|
||||
{
|
||||
if ((type == UDP) || (type == MINETEST_RELIABLE_UDP) || (type == PRIMARY))
|
||||
@ -980,6 +980,15 @@ bool UDPPeer::getAddress(MTProtocols type,Address& toset)
|
||||
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)
|
||||
{
|
||||
if (rtt < 0.0) {
|
||||
@ -1014,6 +1023,9 @@ bool UDPPeer::Ping(float dtime,SharedBuffer<u8>& data)
|
||||
void UDPPeer::PutReliableSendCommand(ConnectionCommand &c,
|
||||
unsigned int max_packet_size)
|
||||
{
|
||||
if (m_pending_disconnect)
|
||||
return;
|
||||
|
||||
if ( channels[c.channelnum].queued_commands.empty() &&
|
||||
/* don't queue more packets then window size */
|
||||
(channels[c.channelnum].queued_reliables.size()
|
||||
@ -1040,6 +1052,9 @@ bool UDPPeer::processReliableSendCommand(
|
||||
ConnectionCommand &c,
|
||||
unsigned int max_packet_size)
|
||||
{
|
||||
if (m_pending_disconnect)
|
||||
return true;
|
||||
|
||||
u32 chunksize_max = max_packet_size
|
||||
- BASE_HEADER_SIZE
|
||||
- RELIABLE_HEADER_SIZE;
|
||||
@ -1564,7 +1579,6 @@ void ConnectionSendThread::processReliableCommand(ConnectionCommand &c)
|
||||
case CONNCMD_SERVE:
|
||||
case CONNCMD_CONNECT:
|
||||
case CONNCMD_DISCONNECT:
|
||||
case CONNCMD_DELETE_PEER:
|
||||
case CONCMD_ACK:
|
||||
assert("Got command that shouldn't be reliable as reliable command" == 0);
|
||||
default:
|
||||
@ -1606,10 +1620,6 @@ void ConnectionSendThread::processNonReliableCommand(ConnectionCommand &c)
|
||||
LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_SEND_TO_ALL"<<std::endl);
|
||||
sendToAll(c.channelnum, c.data);
|
||||
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:
|
||||
LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONCMD_ACK"<<std::endl);
|
||||
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[1], CONTROLTYPE_DISCO);
|
||||
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,
|
||||
@ -1764,6 +1786,8 @@ void ConnectionSendThread::sendToAllReliable(ConnectionCommand &c)
|
||||
void ConnectionSendThread::sendPackets(float dtime)
|
||||
{
|
||||
std::list<u16> peerIds = m_connection->getPeerIDs();
|
||||
std::list<u16> pendingDisconnect;
|
||||
std::map<u16,bool> pending_unreliable;
|
||||
|
||||
for(std::list<u16>::iterator
|
||||
j = peerIds.begin();
|
||||
@ -1782,6 +1806,11 @@ void ConnectionSendThread::sendPackets(float dtime)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dynamic_cast<UDPPeer*>(&peer)->m_pending_disconnect)
|
||||
{
|
||||
pendingDisconnect.push_back(*j);
|
||||
}
|
||||
|
||||
PROFILE(std::stringstream peerIdentifier);
|
||||
PROFILE(peerIdentifier << "sendPackets[" << m_connection->getDesc() << ";" << *j << ";RELIABLE]");
|
||||
PROFILE(ScopeProfiler peerprofiler(g_profiler, peerIdentifier.str(), SPT_AVG));
|
||||
@ -1877,6 +1906,17 @@ void ConnectionSendThread::sendPackets(float dtime)
|
||||
}
|
||||
else {
|
||||
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
|
||||
void ConnectionReceiveThread::receive()
|
||||
{
|
||||
/* now reorder reliables */
|
||||
u32 datasize = m_max_packet_size * 2; // Double it just to be safe
|
||||
// TODO: We can not know how many layers of header there are.
|
||||
// For now, just assume there are no other than the base headers.
|
||||
u32 packet_maxsize = datasize + BASE_HEADER_SIZE;
|
||||
// use IPv6 minimum allowed MTU as receive buffer size as this is
|
||||
// theoretical reliable upper boundary of a udp packet for all IPv6 enabled
|
||||
// infrastructure
|
||||
unsigned int packet_maxsize = 1500;
|
||||
SharedBuffer<u8> packetdata(packet_maxsize);
|
||||
|
||||
bool packet_queued = true;
|
||||
@ -2126,7 +2165,7 @@ void ConnectionReceiveThread::receive()
|
||||
|
||||
LOG(dout_con<<m_connection->getDesc()
|
||||
<<" ProcessPacket from peer_id: " << peer_id
|
||||
<< ",channel: " << channelnum << ", returned "
|
||||
<< ",channel: " << (channelnum & 0xFF) << ", returned "
|
||||
<< resultdata.getSize() << " bytes" <<std::endl);
|
||||
|
||||
ConnectionEvent e;
|
||||
@ -2262,6 +2301,10 @@ SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
|
||||
}
|
||||
//put bytes for max bandwidth calculation
|
||||
channel->UpdateBytesSent(p.data.getSize(),1);
|
||||
if (channel->outgoing_reliables_sent.size() == 0)
|
||||
{
|
||||
m_connection->TriggerSend();
|
||||
}
|
||||
}
|
||||
catch(NotFoundException &e){
|
||||
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_bc_peerhandler(0),
|
||||
m_bc_receive_timeout(0),
|
||||
m_shutting_down(false)
|
||||
m_shutting_down(false),
|
||||
m_next_remote_peer_id(2)
|
||||
{
|
||||
m_udpSocket.setTimeoutMs(5);
|
||||
|
||||
@ -2554,7 +2598,8 @@ Connection::Connection(u32 protocol_id, u32 max_packet_size, float timeout,
|
||||
m_info_mutex(),
|
||||
m_bc_peerhandler(peerhandler),
|
||||
m_bc_receive_timeout(0),
|
||||
m_shutting_down(false)
|
||||
m_shutting_down(false),
|
||||
m_next_remote_peer_id(2)
|
||||
|
||||
{
|
||||
m_udpSocket.setTimeoutMs(5);
|
||||
@ -2810,11 +2855,6 @@ void Connection::Send(u16 peer_id, u8 channelnum,
|
||||
putCommand(c);
|
||||
}
|
||||
|
||||
void Connection::RunTimeouts(float dtime)
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
Address Connection::GetPeerAddress(u16 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
|
||||
|
||||
// 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;
|
||||
|
||||
/*
|
||||
Find an unused peer id
|
||||
*/
|
||||
bool out_of_ids = false;
|
||||
for(;;)
|
||||
{
|
||||
// Check if exists
|
||||
if(m_peers.find(peer_id_new) == m_peers.end())
|
||||
break;
|
||||
// Check for overflow
|
||||
if(peer_id_new == overflow){
|
||||
out_of_ids = true;
|
||||
break;
|
||||
JMutexAutoLock lock(m_peers_mutex);
|
||||
bool out_of_ids = false;
|
||||
for(;;)
|
||||
{
|
||||
// Check if exists
|
||||
if(m_peers.find(peer_id_new) == m_peers.end())
|
||||
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;
|
||||
return PEER_ID_INEXISTENT;
|
||||
if(out_of_ids){
|
||||
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()
|
||||
<<"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;
|
||||
SharedBuffer<u8> reply(4);
|
||||
writeU8(&reply[0], TYPE_CONTROL);
|
||||
@ -2887,17 +2924,15 @@ u16 Connection::createPeer(Address& sender, MTProtocols protocol, int fd)
|
||||
cmd.createPeer(peer_id_new,reply);
|
||||
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
|
||||
return peer_id_new;
|
||||
}
|
||||
|
||||
void Connection::DeletePeer(u16 peer_id)
|
||||
{
|
||||
ConnectionCommand c;
|
||||
c.deletePeer(peer_id);
|
||||
putCommand(c);
|
||||
}
|
||||
|
||||
void Connection::PrintInfo(std::ostream &out)
|
||||
{
|
||||
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)+")";
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
assert(channelnum < CHANNEL_COUNT);
|
||||
|
@ -71,14 +71,6 @@ public:
|
||||
{}
|
||||
};
|
||||
|
||||
/*class ThrottlingException : public BaseException
|
||||
{
|
||||
public:
|
||||
ThrottlingException(const char *s):
|
||||
BaseException(s)
|
||||
{}
|
||||
};*/
|
||||
|
||||
class InvalidIncomingDataException : public BaseException
|
||||
{
|
||||
public:
|
||||
@ -406,7 +398,6 @@ enum ConnectionCommandType{
|
||||
CONNCMD_DISCONNECT_PEER,
|
||||
CONNCMD_SEND,
|
||||
CONNCMD_SEND_TO_ALL,
|
||||
CONNCMD_DELETE_PEER,
|
||||
CONCMD_ACK,
|
||||
CONCMD_CREATE_PEER,
|
||||
CONCMD_DISABLE_LEGACY
|
||||
@ -460,11 +451,6 @@ struct ConnectionCommand
|
||||
data = data_;
|
||||
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_)
|
||||
{
|
||||
@ -580,16 +566,29 @@ private:
|
||||
|
||||
class Peer;
|
||||
|
||||
enum PeerChangeType
|
||||
{
|
||||
PEER_ADDED,
|
||||
PEER_REMOVED
|
||||
};
|
||||
struct PeerChange
|
||||
{
|
||||
PeerChangeType type;
|
||||
u16 peer_id;
|
||||
bool timeout;
|
||||
};
|
||||
|
||||
class PeerHandler
|
||||
{
|
||||
public:
|
||||
|
||||
PeerHandler()
|
||||
{
|
||||
}
|
||||
virtual ~PeerHandler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This is called after the Peer has been inserted into the
|
||||
Connection's peer container.
|
||||
@ -771,7 +770,7 @@ public:
|
||||
friend class ConnectionSendThread;
|
||||
|
||||
UDPPeer(u16 a_id, Address a_address, Connection* connection);
|
||||
virtual ~UDPPeer();
|
||||
virtual ~UDPPeer() {};
|
||||
|
||||
void PutReliableSendCommand(ConnectionCommand &c,
|
||||
unsigned int max_packet_size);
|
||||
@ -781,8 +780,7 @@ public:
|
||||
|
||||
bool getAddress(MTProtocols type, Address& toset);
|
||||
|
||||
void setNonLegacyPeer()
|
||||
{ m_legacy_peer = false; }
|
||||
void setNonLegacyPeer();
|
||||
|
||||
bool getLegacyPeer()
|
||||
{ return m_legacy_peer; }
|
||||
@ -793,6 +791,8 @@ public:
|
||||
SharedBuffer<u8> addSpiltPacket(u8 channel,
|
||||
BufferedPacket toadd,
|
||||
bool reliable);
|
||||
|
||||
|
||||
protected:
|
||||
/*
|
||||
Calculates avg_rtt and resend_timeout.
|
||||
@ -813,6 +813,7 @@ protected:
|
||||
bool Ping(float dtime,SharedBuffer<u8>& data);
|
||||
|
||||
Channel channels[CHANNEL_COUNT];
|
||||
bool m_pending_disconnect;
|
||||
private:
|
||||
// This is changed dynamically
|
||||
float resend_timeout;
|
||||
@ -1002,13 +1003,12 @@ public:
|
||||
u32 Receive(u16 &peer_id, SharedBuffer<u8> &data);
|
||||
void SendToAll(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; }
|
||||
Address GetPeerAddress(u16 peer_id);
|
||||
float GetPeerAvgRTT(u16 peer_id);
|
||||
void DeletePeer(u16 peer_id);
|
||||
const u32 GetProtocolID() const { return m_protocol_id; };
|
||||
const std::string getDesc();
|
||||
void DisconnectPeer(u16 peer_id);
|
||||
|
||||
protected:
|
||||
PeerHelper getPeer(u16 peer_id);
|
||||
@ -1033,6 +1033,8 @@ protected:
|
||||
|
||||
void putEvent(ConnectionEvent &e);
|
||||
|
||||
void TriggerSend()
|
||||
{ m_sendThread.Trigger(); }
|
||||
private:
|
||||
std::list<Peer*> getPeers();
|
||||
|
||||
@ -1054,6 +1056,8 @@ private:
|
||||
int m_bc_receive_timeout;
|
||||
|
||||
bool m_shutting_down;
|
||||
|
||||
u16 m_next_remote_peer_id;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -592,23 +592,12 @@ void *EmergeThread::Thread() {
|
||||
/*
|
||||
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
|
||||
if (block)
|
||||
modified_blocks[p] = block;
|
||||
|
||||
// Set the modified blocks unsent for all the clients
|
||||
for (std::map<u16, RemoteClient*>::iterator
|
||||
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);
|
||||
}
|
||||
if (modified_blocks.size() > 0) {
|
||||
m_server->SetBlocksNotSent(modified_blocks);
|
||||
}
|
||||
}
|
||||
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/thread.h"
|
||||
#include "environment.h"
|
||||
#include "clientiface.h"
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
@ -53,14 +54,19 @@ class EmergeManager;
|
||||
class GameScripting;
|
||||
class ServerEnvironment;
|
||||
struct SimpleSoundSpec;
|
||||
class ServerThread;
|
||||
|
||||
enum ClientDeletionReason {
|
||||
CDR_LEAVE,
|
||||
CDR_TIMEOUT,
|
||||
CDR_DENY
|
||||
};
|
||||
|
||||
/*
|
||||
Some random functions
|
||||
*/
|
||||
v3f findSpawnPos(ServerMap &map);
|
||||
|
||||
|
||||
class MapEditEventIgnorer
|
||||
{
|
||||
public:
|
||||
@ -111,31 +117,6 @@ private:
|
||||
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
|
||||
{
|
||||
std::string path;
|
||||
@ -182,134 +163,6 @@ struct ServerPlayingSound
|
||||
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,
|
||||
public InventoryManager, public IGameDef
|
||||
{
|
||||
@ -337,11 +190,6 @@ public:
|
||||
// Environment must be locked when called
|
||||
void setTimeOfDay(u32 time);
|
||||
|
||||
bool getShutdownRequested()
|
||||
{
|
||||
return m_shutdown_requested;
|
||||
}
|
||||
|
||||
/*
|
||||
Shall be called with the environment locked.
|
||||
This is accessed by the map, which is inside the environment,
|
||||
@ -358,17 +206,20 @@ public:
|
||||
// Connection must be locked when called
|
||||
std::wstring getStatusString();
|
||||
|
||||
void requestShutdown(void)
|
||||
{
|
||||
m_shutdown_requested = true;
|
||||
}
|
||||
// read shutdown state
|
||||
inline bool getShutdownRequested()
|
||||
{ return m_shutdown_requested; }
|
||||
|
||||
// request server to shutdown
|
||||
inline void requestShutdown(void)
|
||||
{ m_shutdown_requested = true; }
|
||||
|
||||
// Returns -1 if failed, sound handle on success
|
||||
// Envlock + conlock
|
||||
// Envlock
|
||||
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms);
|
||||
void stopSound(s32 handle);
|
||||
|
||||
// Envlock + conlock
|
||||
// Envlock
|
||||
std::set<std::string> getPlayerEffectivePrivs(const std::string &name);
|
||||
bool checkPriv(const std::string &name, const std::string &priv);
|
||||
void reportPrivsModified(const std::string &name=""); // ""=all
|
||||
@ -378,12 +229,6 @@ public:
|
||||
void unsetIpBanned(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 notifyPlayers(const std::wstring msg);
|
||||
void spawnParticle(const char *playername,
|
||||
@ -451,15 +296,14 @@ public:
|
||||
const ModSpec* getModSpec(const std::string &modname);
|
||||
void getModNames(std::list<std::string> &modlist);
|
||||
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; }
|
||||
|
||||
void setAsyncFatalError(const std::string &error)
|
||||
{
|
||||
m_async_fatal_error.set(error);
|
||||
}
|
||||
inline 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);
|
||||
Map & getMap() { return m_env->getMap(); }
|
||||
@ -473,41 +317,32 @@ public:
|
||||
void hudSetHotbarImage(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.
|
||||
// These queue stuff to be processed by handlePeerChanges().
|
||||
// As of now, these create and remove clients and players.
|
||||
/* con::PeerHandler implementation. */
|
||||
void peerAdded(con::Peer *peer);
|
||||
void deletingPeer(con::Peer *peer, bool timeout);
|
||||
|
||||
/*
|
||||
Static send methods
|
||||
*/
|
||||
private:
|
||||
|
||||
static void SendMovement(con::Connection &con, u16 peer_id);
|
||||
static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
|
||||
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);
|
||||
friend class EmergeThread;
|
||||
friend class RemoteClient;
|
||||
|
||||
/*
|
||||
Non-static send methods.
|
||||
Conlock should be always used.
|
||||
Envlock usage is documented badly but it's easy to figure out
|
||||
which ones access the environment.
|
||||
*/
|
||||
void SendMovement(u16 peer_id);
|
||||
void SendHP(u16 peer_id, u8 hp);
|
||||
void SendBreath(u16 peer_id, u16 breath);
|
||||
void SendAccessDenied(u16 peer_id,const std::wstring &reason);
|
||||
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
|
||||
void SendInventory(u16 peer_id);
|
||||
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 SendPlayerHP(u16 peer_id);
|
||||
void SendPlayerBreath(u16 peer_id);
|
||||
@ -546,10 +381,9 @@ private:
|
||||
const std::list<std::string> &tosend);
|
||||
|
||||
void sendDetachedInventory(const std::string &name, u16 peer_id);
|
||||
void sendDetachedInventoryToAll(const std::string &name);
|
||||
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,
|
||||
v3f minpos, v3f maxpos,
|
||||
v3f minvel, v3f maxvel,
|
||||
@ -558,32 +392,14 @@ private:
|
||||
float minsize, float maxsize,
|
||||
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);
|
||||
|
||||
// Deletes ParticleSpawner on all clients
|
||||
void SendDeleteParticleSpawnerAll(u32 id);
|
||||
|
||||
// Spawns particle on single client
|
||||
// Spawns particle on peer with peer_id (PEER_ID_INEXISTENT == all)
|
||||
void SendSpawnParticle(u16 peer_id,
|
||||
v3f pos, v3f velocity, v3f acceleration,
|
||||
float expirationtime, float size,
|
||||
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
|
||||
*/
|
||||
@ -591,19 +407,12 @@ private:
|
||||
void DiePlayer(u16 peer_id);
|
||||
void RespawnPlayer(u16 peer_id);
|
||||
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 UpdateCrafting(u16 peer_id);
|
||||
|
||||
// When called, connection mutex should be locked
|
||||
RemoteClient* getClient(u16 peer_id);
|
||||
RemoteClient* getClientNoEx(u16 peer_id);
|
||||
RemoteClient* getClient(u16 peer_id,ClientState state_min=Active);
|
||||
RemoteClient* getClientNoEx(u16 peer_id,ClientState state_min=Active);
|
||||
|
||||
// When called, environment mutex should be locked
|
||||
std::string getPlayerName(u16 peer_id);
|
||||
@ -618,9 +427,6 @@ private:
|
||||
*/
|
||||
PlayerSAO *emergePlayer(const char *name, u16 peer_id);
|
||||
|
||||
// Locks environment and connection by its own
|
||||
struct PeerChange;
|
||||
void handlePeerChange(PeerChange &c);
|
||||
void handlePeerChanges();
|
||||
|
||||
/*
|
||||
@ -648,19 +454,12 @@ private:
|
||||
float m_savemap_timer;
|
||||
IntervalLimiter m_map_timer_and_unload_interval;
|
||||
|
||||
// NOTE: If connection and environment are both to be locked,
|
||||
// environment shall be locked first.
|
||||
|
||||
// Environment
|
||||
ServerEnvironment *m_env;
|
||||
JMutex m_env_mutex;
|
||||
|
||||
// Connection
|
||||
// server connection
|
||||
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
|
||||
BanManager *m_banmanager;
|
||||
@ -701,6 +500,7 @@ private:
|
||||
float m_step_dtime;
|
||||
JMutex m_step_dtime_mutex;
|
||||
|
||||
// current server step lag counter
|
||||
float m_lag;
|
||||
|
||||
// The server mainly operates in this thread
|
||||
@ -715,23 +515,17 @@ private:
|
||||
// Uptime of server in seconds
|
||||
MutexedVariable<double> m_uptime;
|
||||
|
||||
/*
|
||||
Client interface
|
||||
*/
|
||||
ClientInterface m_clients;
|
||||
|
||||
/*
|
||||
Peer change queue.
|
||||
Queues stuff from peerAdded() and deletingPeer() to
|
||||
handlePeerChanges()
|
||||
*/
|
||||
enum PeerChangeType
|
||||
{
|
||||
PEER_ADDED,
|
||||
PEER_REMOVED
|
||||
};
|
||||
struct PeerChange
|
||||
{
|
||||
PeerChangeType type;
|
||||
u16 peer_id;
|
||||
bool timeout;
|
||||
};
|
||||
Queue<PeerChange> m_peer_change_queue;
|
||||
Queue<con::PeerChange> m_peer_change_queue;
|
||||
|
||||
/*
|
||||
Random stuff
|
||||
@ -776,9 +570,7 @@ private:
|
||||
*/
|
||||
u16 m_ignore_map_edit_events_peer_id;
|
||||
|
||||
friend class EmergeThread;
|
||||
friend class RemoteClient;
|
||||
|
||||
// media files known to server
|
||||
std::map<std::string,MediaInfo> m_media;
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user