aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsapier <Sapier at GMX dot net>2014-01-31 00:24:00 +0100
committersapier <Sapier at GMX dot net>2014-01-31 18:44:43 +0100
commite258675eabc874d31bc9c6cf49e4bbc1f7f3f417 (patch)
tree2d9dfd872c8b88db13cfdeaa0503b3d88545d179 /src
parent21f1bec72433748e220d19e97a846df83340518e (diff)
downloadminetest-e258675eabc874d31bc9c6cf49e4bbc1f7f3f417.tar.gz
minetest-e258675eabc874d31bc9c6cf49e4bbc1f7f3f417.tar.bz2
minetest-e258675eabc874d31bc9c6cf49e4bbc1f7f3f417.zip
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
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/client.cpp18
-rw-r--r--src/clientiface.cpp769
-rw-r--r--src/clientiface.h306
-rw-r--r--src/clientmedia.cpp8
-rw-r--r--src/connection.cpp170
-rw-r--r--src/connection.h44
-rw-r--r--src/emerge.cpp15
-rw-r--r--src/server.cpp1732
-rw-r--r--src/server.h310
10 files changed, 1791 insertions, 1582 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f0b98f44b..025b549cf 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -308,6 +308,7 @@ set(common_SRCS
connection.cpp
environment.cpp
server.cpp
+ clientiface.cpp
socket.cpp
mapblock.cpp
mapsector.cpp
diff --git a/src/client.cpp b/src/client.cpp
index 6c4d9eea8..cc1ec2a98 100644
--- a/src/client.cpp
+++ b/src/client.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)
{
diff --git a/src/clientiface.cpp b/src/clientiface.cpp
new file mode 100644
index 000000000..2468ef333
--- /dev/null
+++ b/src/clientiface.cpp
@@ -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;
+}
diff --git a/src/clientiface.h b/src/clientiface.h
new file mode 100644
index 000000000..a2315b3bd
--- /dev/null
+++ b/src/clientiface.h
@@ -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
diff --git a/src/clientmedia.cpp b/src/clientmedia.cpp
index 8260d5f5a..dcae44023 100644
--- a/src/clientmedia.cpp
+++ b/src/clientmedia.cpp
@@ -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;
diff --git a/src/connection.cpp b/src/connection.cpp
index 2e126a770..92f9f8ec2 100644
--- a/src/connection.cpp
+++ b/src/connection.cpp
@@ -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,46 +2878,43 @@ 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++;
+ }
+ if(out_of_ids){
+ errorstream<<getDesc()<<" ran out of peer ids"<<std::endl;
+ return PEER_ID_INEXISTENT;
}
- peer_id_new++;
- }
- if(out_of_ids){
- errorstream<<getDesc()<<" ran out of peer ids"<<std::endl;
- return PEER_ID_INEXISTENT;
- }
-
- LOG(dout_con<<getDesc()
- <<"createPeer(): giving peer_id="<<peer_id_new<<std::endl);
- // Create a peer
- Peer *peer = 0;
+ // Create a peer
+ Peer *peer = 0;
+ peer = new UDPPeer(peer_id_new, sender, this);
- peer = new UDPPeer(peer_id_new, sender, this);
+ m_peers[peer->id] = peer;
+ }
- m_peers_mutex.Lock();
- m_peers[peer->id] = peer;
- m_peers_mutex.Unlock();
+ m_next_remote_peer_id = (peer_id_new +1) % MAX_UDP_PEERS;
- // Create peer addition event
- ConnectionEvent e;
- e.peerAdded(peer_id_new, sender);
- putEvent(e);
+ LOG(dout_con<<getDesc()
+ <<"createPeer(): giving peer_id="<<peer_id_new<<std::endl);
ConnectionCommand cmd;
SharedBuffer<u8> reply(4);
@@ -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);
diff --git a/src/connection.h b/src/connection.h
index e43d93fb3..c9474032d 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -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
diff --git a/src/emerge.cpp b/src/emerge.cpp
index bd9b7c7bd..f63bc5dfe 100644
--- a/src/emerge.cpp
+++ b/src/emerge.cpp
@@ -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) {
diff --git a/src/server.cpp b/src/server.cpp
index 9fb0455eb..ce0b44110 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -104,13 +104,10 @@ void * ServerThread::Thread()
try{
//TimeTaker timer("AsyncRunStep() + Receive()");
- {
- //TimeTaker timer("AsyncRunStep()");
- m_server->AsyncRunStep();
- }
+ m_server->AsyncRunStep();
- //infostream<<"Running m_server->Receive()"<<std::endl;
m_server->Receive();
+
}
catch(con::NoIncomingDataException &e)
{
@@ -158,481 +155,7 @@ v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
return v3f(0,0,0);
}
-void RemoteClient::GetNextBlocks(Server *server, float dtime,
- std::vector<PrioritySortedBlockTransfer> &dest)
-{
- DSTACK(__FUNCTION_NAME);
-
- /*u32 timer_result;
- TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
-
- // 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 = server->m_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;
- }
-
- //TimeTaker timer("RemoteClient::GetNextBlocks");
-
- 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;
- /*if(d_max_gen > d_start+2)
- d_max_gen = d_start+2;*/
-
- //infostream<<"Starting from "<<d_start<<std::endl;
-
- 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++)
- {
- /*errorstream<<"checking d="<<d<<" for "
- <<server->getPlayerName(peer_id)<<std::endl;*/
- //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
-
- /*
- If m_nearest_unsent_d was changed by the EmergeThread
- (it can change it to 0 through SetBlockNotSent),
- update our d to it.
- Else update m_nearest_unsent_d
- */
- /*if(m_nearest_unsent_d != last_nearest_unsent_d)
- {
- d = m_nearest_unsent_d;
- last_nearest_unsent_d = m_nearest_unsent_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;
- }
-
-#if 0
- /*
- If block is far away, don't generate it unless it is
- near ground level.
- */
- if(d >= 4)
- {
- #if 1
- // Block center y in nodes
- f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
- // Don't generate if it's very high or very low
- if(y < -64 || y > 64)
- generate = false;
- #endif
- #if 0
- v2s16 p2d_nodes_center(
- MAP_BLOCKSIZE*p.X,
- MAP_BLOCKSIZE*p.Z);
-
- // Get ground height in nodes
- s16 gh = server->m_env->getServerMap().findGroundLevel(
- p2d_nodes_center);
-
- // If differs a lot, don't generate
- if(fabs(gh - y) > MAP_BLOCKSIZE*2)
- generate = false;
- // Actually, don't even send it
- //continue;
- #endif
- }
-#endif
-
- //infostream<<"d="<<d<<std::endl;
-#if 1
- /*
- 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;
- }
-#endif
- /*
- 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 = server->m_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->isFullyGenerated() == false)
- {
- block_is_invalid = true;
- }*/
-
-#if 0
- v2s16 p2d(p.X, p.Z);
- ServerMap *map = (ServerMap*)(&server->m_env->getMap());
- v2s16 chunkpos = map->sector_to_chunk(p2d);
- if(map->chunkNonVolatile(chunkpos) == false)
- block_is_invalid = true;
-#endif
- if(block->isGenerated() == false)
- block_is_invalid = true;
-#if 1
- /*
- 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;
- }
-#endif
- }
-
- /*
- 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)
- {
- /* //TODO: Get value from somewhere
- // Allow only one block in emerge queue
- //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
- // Allow two blocks in queue per client
- //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
- u32 max_emerge = 5;
- // Make it more responsive when needing to generate stuff
- if(surely_not_found_on_disk)
- max_emerge = 1;
- if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
- {
- //infostream<<"Adding block to emerge queue"<<std::endl;
-
- // Add it to the emerge queue and trigger the thread
-
- u8 flags = 0;
- if(generate == false)
- flags |= BLOCK_EMERGE_FLAG_FROMDISK;
-
- server->m_emerge_queue.addBlock(peer_id, p, flags);
- server->m_emergethread.trigger();
-
- if(nearest_emerged_d == -1)
- nearest_emerged_d = d;
- } else {
- if(nearest_emergefull_d == -1)
- nearest_emergefull_d = d;
- goto queue_full_break;
- }
- */
-
- if (server->m_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
- */
-
- /*errorstream<<"sending from d="<<d<<" to "
- <<server->getPlayerName(peer_id)<<std::endl;*/
-
- PrioritySortedBlockTransfer q((float)d, p, peer_id);
-
- dest.push_back(q);
-
- num_blocks_selected += 1;
- }
- }
-queue_full_break:
-
- //infostream<<"Stopped at "<<d<<std::endl;
-
- // 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;
- /*infostream<<"GetNextBlocks(): d wrapped around for "
- <<server->getPlayerName(peer_id)
- <<"; setting to 0 and pausing"<<std::endl;*/
- } 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;
-
- /*timer_result = timer.stop(true);
- if(timer_result != 0)
- infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
-}
-
-void RemoteClient::GotBlock(v3s16 p)
-{
- if(m_blocks_sending.find(p) != m_blocks_sending.end())
- m_blocks_sending.erase(p);
- else
- {
- /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
- " m_blocks_sending"<<std::endl;*/
- 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);
- }
-}
/*
Server
@@ -648,8 +171,11 @@ Server::Server(
m_simple_singleplayer_mode(simple_singleplayer_mode),
m_async_fatal_error(""),
m_env(NULL),
- m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT,
- g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
+ m_con(PROTOCOL_ID,
+ 512,
+ CONNECTION_TIMEOUT,
+ g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"),
+ this),
m_banmanager(NULL),
m_rollback(NULL),
m_rollback_sink_enabled(true),
@@ -663,9 +189,11 @@ Server::Server(
m_thread(NULL),
m_time_of_day_send_timer(0),
m_uptime(0),
+ m_clients(&m_con),
m_shutdown_requested(false),
m_ignore_map_edit_events(false),
m_ignore_map_edit_events_peer_id(0)
+
{
m_liquid_transform_timer = 0.0;
m_liquid_transform_every = 1.0;
@@ -768,10 +296,8 @@ Server::Server(
// Lock environment
JMutexAutoLock envlock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
// Initialize scripting
-
infostream<<"Server: Initializing Lua"<<std::endl;
m_script = new GameScripting(this);
@@ -818,11 +344,13 @@ Server::Server(
// Initialize Environment
ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
m_env = new ServerEnvironment(servermap, m_script, this, m_emerge);
-
+
+ m_clients.setEnv(m_env);
+
// Run some callbacks after the MG params have been set up but before activation
MapgenParams *mgparams = servermap->getMapgenParams();
m_script->environment_OnMapgenInit(mgparams);
-
+
// Initialize mapgens
m_emerge->initMapgens(mgparams);
servermap->setMapgenParams(m_emerge->params);
@@ -860,34 +388,12 @@ Server::~Server()
Send shutdown message
*/
{
- JMutexAutoLock conlock(m_con_mutex);
-
std::wstring line = L"*** Server shutting down";
-
- /*
- Send the message to clients
- */
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
- {
- // Get client and check that it is valid
- RemoteClient *client = i->second;
- assert(client->peer_id == i->first);
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
-
- try{
- SendChatMessage(client->peer_id, line);
- }
- catch(con::PeerNotFoundException &e)
- {}
- }
+ SendChatMessage(PEER_ID_INEXISTENT, line);
}
{
JMutexAutoLock envlock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
/*
Execute script shutdown hooks
@@ -921,22 +427,6 @@ Server::~Server()
// requested blocks to be emerged
m_emerge->stopThreads();
- /*
- Delete clients
- */
- {
- JMutexAutoLock clientslock(m_con_mutex);
-
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
- {
-
- // Delete client
- delete i->second;
- }
- }
-
// Delete things in the reverse order of creation
delete m_env;
@@ -1061,18 +551,7 @@ void Server::AsyncRunStep(bool initial_step)
m_uptime.set(m_uptime.get() + dtime);
}
- {
- // Process connection's timeouts
- JMutexAutoLock lock2(m_con_mutex);
- ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
- m_con.RunTimeouts(dtime);
- }
-
- {
- // This has to be called so that the client list gets synced
- // with the peer list of the connection
- handlePeerChanges();
- }
+ handlePeerChanges();
/*
Update time of day and overall game time
@@ -1090,20 +569,9 @@ void Server::AsyncRunStep(bool initial_step)
if(m_time_of_day_send_timer < 0.0)
{
m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
-
- //JMutexAutoLock envlock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
-
u16 time = m_env->getTimeOfDay();
float time_speed = g_settings->getFloat("time_speed");
-
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
- {
- RemoteClient *client = i->second;
- SendTimeOfDay(client->peer_id, time, time_speed);
- }
+ SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
}
}
@@ -1144,16 +612,16 @@ void Server::AsyncRunStep(bool initial_step)
*/
{
JMutexAutoLock lock(m_env_mutex);
- JMutexAutoLock lock2(m_con_mutex);
+
+ std::list<u16> clientids = m_clients.getClientIDs();
ScopeProfiler sp(g_profiler, "Server: handle players");
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
+ for(std::list<u16>::iterator
+ i = clientids.begin();
+ i != clientids.end(); ++i)
{
- RemoteClient *client = i->second;
- PlayerSAO *playersao = getPlayerSAO(client->peer_id);
+ PlayerSAO *playersao = getPlayerSAO(*i);
if(playersao == NULL)
continue;
@@ -1163,28 +631,28 @@ void Server::AsyncRunStep(bool initial_step)
if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
{
if(playersao->getHP() == 0)
- DiePlayer(client->peer_id);
+ DiePlayer(*i);
else
- SendPlayerHP(client->peer_id);
+ SendPlayerHP(*i);
}
/*
Send player breath if changed
*/
if(playersao->m_breath_not_sent){
- SendPlayerBreath(client->peer_id);
+ SendPlayerBreath(*i);
}
/*
Send player inventories if necessary
*/
if(playersao->m_moved){
- SendMovePlayer(client->peer_id);
+ SendMovePlayer(*i);
playersao->m_moved = false;
}
if(playersao->m_inventory_not_sent){
- UpdateCrafting(client->peer_id);
- SendInventory(client->peer_id);
+ UpdateCrafting(*i);
+ SendInventory(*i);
}
}
}
@@ -1221,77 +689,43 @@ void Server::AsyncRunStep(bool initial_step)
/*
Set the modified blocks unsent for all the clients
*/
-
- JMutexAutoLock lock2(m_con_mutex);
-
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
+ if(modified_blocks.size() > 0)
{
- RemoteClient *client = i->second;
-
- if(modified_blocks.size() > 0)
- {
- // Remove block from sent history
- client->SetBlocksNotSent(modified_blocks);
- }
+ SetBlocksNotSent(modified_blocks);
}
}
-
- // Periodically print some info
- {
- float &counter = m_print_info_timer;
- counter += dtime;
- if(counter >= 30.0)
- {
- counter = 0.0;
-
- JMutexAutoLock lock2(m_con_mutex);
- m_clients_names.clear();
- if(m_clients.size() != 0)
- infostream<<"Players:"<<std::endl;
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
- {
- //u16 peer_id = i.getNode()->getKey();
- RemoteClient *client = i->second;
- Player *player = m_env->getPlayer(client->peer_id);
- if(player==NULL)
- continue;
- infostream<<"* "<<player->getName()<<"\t";
- client->PrintInfo(infostream);
- m_clients_names.push_back(player->getName());
- }
- }
- }
-
+ m_clients.step(dtime);
m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
#if USE_CURL
// send masterserver announce
{
float &counter = m_masterserver_timer;
- if(!isSingleplayer() && (!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
+ if(!isSingleplayer() && (!counter || counter >= 300.0) &&
+ g_settings->getBool("server_announce") == true)
{
- ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_names, m_uptime.get(), m_env->getGameTime(), m_lag, m_gamespec.id, m_mods);
+ ServerList::sendAnnounce(!counter ? "start" : "update",
+ m_clients.getPlayerNames(),
+ m_uptime.get(),
+ m_env->getGameTime(),
+ m_lag,
+ m_gamespec.id,
+ m_mods);
counter = 0.01;
}
counter += dtime;
}
#endif
- //if(g_settings->getBool("enable_experimental"))
- {
-
/*
Check added and deleted active objects
*/
{
//infostream<<"Server: Checking added and deleted active objects"<<std::endl;
JMutexAutoLock envlock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
+ m_clients.Lock();
+ std::map<u16, RemoteClient*> clients = m_clients.getClientList();
ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
// Radius inside which objects are active
@@ -1299,14 +733,14 @@ void Server::AsyncRunStep(bool initial_step)
radius *= MAP_BLOCKSIZE;
for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
+ i = clients.begin();
+ i != clients.end(); ++i)
{
RemoteClient *client = i->second;
// If definitions and textures have not been sent, don't
// send objects either
- if(!client->definitions_sent)
+ if (client->getState() < DefinitionsSent)
continue;
Player *player = m_env->getPlayer(client->peer_id);
@@ -1404,14 +838,14 @@ void Server::AsyncRunStep(bool initial_step)
memcpy((char*)&reply[2], data_buffer.c_str(),
data_buffer.size());
// Send as reliable
- m_con.Send(client->peer_id, 0, reply, true);
+ m_clients.send(client->peer_id, 0, reply, true);
verbosestream<<"Server: Sent object remove/add: "
<<removed_objects.size()<<" removed, "
<<added_objects.size()<<" added, "
<<"packet size is "<<reply.getSize()<<std::endl;
}
-
+ m_clients.Unlock();
#if 0
/*
Collect a list of all the objects known by the clients
@@ -1445,8 +879,6 @@ void Server::AsyncRunStep(bool initial_step)
*/
{
JMutexAutoLock envlock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
-
ScopeProfiler sp(g_profiler, "Server: sending object messages");
// Key = object id
@@ -1475,10 +907,12 @@ void Server::AsyncRunStep(bool initial_step)
message_list->push_back(aom);
}
+ m_clients.Lock();
+ std::map<u16, RemoteClient*> clients = m_clients.getClientList();
// Route data to every client
for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
+ i = clients.begin();
+ i != clients.end(); ++i)
{
RemoteClient *client = i->second;
std::string reliable_data;
@@ -1525,7 +959,7 @@ void Server::AsyncRunStep(bool initial_step)
memcpy((char*)&reply[2], reliable_data.c_str(),
reliable_data.size());
// Send as reliable
- m_con.Send(client->peer_id, 0, reply, true);
+ m_clients.send(client->peer_id, 0, reply, true);
}
if(unreliable_data.size() > 0)
{
@@ -1534,7 +968,7 @@ void Server::AsyncRunStep(bool initial_step)
memcpy((char*)&reply[2], unreliable_data.c_str(),
unreliable_data.size());
// Send as unreliable
- m_con.Send(client->peer_id, 1, reply, false);
+ m_clients.send(client->peer_id, 1, reply, false);
}
/*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
@@ -1545,6 +979,7 @@ void Server::AsyncRunStep(bool initial_step)
<<std::endl;
}*/
}
+ m_clients.Unlock();
// Clear buffered_messages
for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
@@ -1555,15 +990,12 @@ void Server::AsyncRunStep(bool initial_step)
}
}
- } // enable_experimental
-
/*
Send queued-for-sending map edit events.
*/
{
- // We will be accessing the environment and the connection
+ // We will be accessing the environment
JMutexAutoLock lock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
// Don't send too many at a time
//u32 count = 0;
@@ -1731,15 +1163,7 @@ void Server::Receive()
u16 peer_id;
u32 datasize;
try{
- {
- JMutexAutoLock conlock(m_con_mutex);
- datasize = m_con.Receive(peer_id, data);
- }
-
- // This has to be called so that the client list gets synced
- // with the peer list of the connection
- handlePeerChanges();
-
+ datasize = m_con.Receive(peer_id,data);
ProcessData(*data, datasize, peer_id);
}
catch(con::InvalidIncomingDataException &e)
@@ -1770,13 +1194,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
DSTACK(__FUNCTION_NAME);
// Environment is locked first.
JMutexAutoLock envlock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
ScopeProfiler sp(g_profiler, "Server::ProcessData");
std::string addr_s;
try{
- Address address = m_con.GetPeerAddress(peer_id);
+ Address address = getPeerAddress(peer_id);
addr_s = address.serializeString();
// drop player if is ip is banned
@@ -1788,19 +1211,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// This actually doesn't seem to transfer to the client
DenyAccess(peer_id, L"Your ip is banned. Banned name was "
+narrow_to_wide(ban_name));
- m_con.DeletePeer(peer_id);
return;
}
}
catch(con::PeerNotFoundException &e)
{
- infostream<<"Server::ProcessData(): Cancelling: peer "
+ errorstream<<"Server::ProcessData(): Cancelling: peer "
<<peer_id<<" not found"<<std::endl;
return;
}
- u8 peer_ser_ver = getClient(peer_id)->serialization_version;
-
try
{
@@ -1819,8 +1239,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if(datasize < 2+1+PLAYERNAME_SIZE)
return;
+ RemoteClient* client = getClient(peer_id,Created);
+
// If net_proto_version is set, this client has already been handled
- if(getClient(peer_id)->net_proto_version != 0){
+ if(client->getState() > Created)
+ {
verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
<<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
return;
@@ -1830,8 +1253,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<peer_id<<")"<<std::endl;
// Do not allow multiple players in simple singleplayer mode.
- // This isn't a perfect way to do it, but will suffice for now.
- if(m_simple_singleplayer_mode && m_clients.size() > 1){
+ // This isn't a perfect way to do it, but will suffice for now
+ if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
infostream<<"Server: Not allowing another client ("<<addr_s
<<") to connect in simple singleplayer mode"<<std::endl;
DenyAccess(peer_id, L"Running in simple singleplayer mode.");
@@ -1848,9 +1271,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if(deployed < SER_FMT_VER_LOWEST)
deployed = SER_FMT_VER_INVALID;
- //peer->serialization_version = deployed;
- getClient(peer_id)->pending_serialization_version = deployed;
-
if(deployed == SER_FMT_VER_INVALID)
{
actionstream<<"Server: A mismatched client tried to connect from "
@@ -1865,6 +1285,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
return;
}
+ client->setPendingSerializationVersion(deployed);
+
/*
Read and check network protocol version
*/
@@ -1898,7 +1320,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<min_net_proto_version<<", max: "<<max_net_proto_version
<<", chosen: "<<net_proto_version<<std::endl;
- getClient(peer_id)->net_proto_version = net_proto_version;
+ client->net_proto_version = net_proto_version;
if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
@@ -2019,7 +1441,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Enforce user limit.
// Don't enforce for users that have some admin right
- if(m_clients.size() >= g_settings->getU16("max_users") &&
+ if(m_clients.getClientIDs(Created).size() >= g_settings->getU16("max_users") &&
!checkPriv(playername, "server") &&
!checkPriv(playername, "ban") &&
!checkPriv(playername, "privs") &&
@@ -2075,28 +1497,19 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
return;
}
- // Get player
- PlayerSAO *playersao = emergePlayer(playername, peer_id);
+ RemotePlayer *player =
+ static_cast<RemotePlayer*>(m_env->getPlayer(playername));
- // If failed, cancel
- if(playersao == NULL)
- {
- RemotePlayer *player =
- static_cast<RemotePlayer*>(m_env->getPlayer(playername));
- if(player && player->peer_id != 0){
- errorstream<<"Server: "<<playername<<": Failed to emerge player"
- <<" (player allocated to an another client)"<<std::endl;
- DenyAccess(peer_id, L"Another client is connected with this "
- L"name. If your client closed unexpectedly, try again in "
- L"a minute.");
- } else {
- errorstream<<"Server: "<<playername<<": Failed to emerge player"
- <<std::endl;
- DenyAccess(peer_id, L"Could not allocate player.");
- }
- return;
+ if(player && player->peer_id != 0){
+ errorstream<<"Server: "<<playername<<": Failed to emerge player"
+ <<" (player allocated to an another client)"<<std::endl;
+ DenyAccess(peer_id, L"Another client is connected with this "
+ L"name. If your client closed unexpectedly, try again in "
+ L"a minute.");
}
+ m_clients.setPlayerName(peer_id,playername);
+
/*
Answer with a TOCLIENT_INIT
*/
@@ -2104,37 +1517,27 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
SharedBuffer<u8> reply(2+1+6+8+4);
writeU16(&reply[0], TOCLIENT_INIT);
writeU8(&reply[2], deployed);
- writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
+ //send dummy pos for legacy reasons only
+ writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
// Send as reliable
- m_con.Send(peer_id, 0, reply, true);
+ m_clients.send(peer_id, 0, reply, true);
+ m_clients.event(peer_id, Init);
}
- /*
- Send complete position information
- */
- SendMovePlayer(peer_id);
-
return;
}
if(command == TOSERVER_INIT2)
{
+
verbosestream<<"Server: Got TOSERVER_INIT2 from "
<<peer_id<<std::endl;
- Player *player = m_env->getPlayer(peer_id);
- if(!player){
- verbosestream<<"Server: TOSERVER_INIT2: "
- <<"Player not found; ignoring."<<std::endl;
- return;
- }
-
- RemoteClient *client = getClient(peer_id);
- client->serialization_version =
- getClient(peer_id)->pending_serialization_version;
+ m_clients.event(peer_id, GotInit2);
+ u16 protocol_version = m_clients.getProtocolVersion(peer_id);
/*
Send some initialization data
@@ -2144,17 +1547,105 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<getPlayerName(peer_id)<<std::endl;
// Send player movement settings
- SendMovement(m_con, peer_id);
+ SendMovement(peer_id);
// Send item definitions
- SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
+ SendItemDef(peer_id, m_itemdef, protocol_version);
// Send node definitions
- SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
+ SendNodeDef(peer_id, m_nodedef, protocol_version);
+
+ m_clients.event(peer_id, SetDefinitionsSent);
// Send media announcement
sendMediaAnnouncement(peer_id);
+ // Send detached inventories
+ sendDetachedInventories(peer_id);
+
+ // Send time of day
+ u16 time = m_env->getTimeOfDay();
+ float time_speed = g_settings->getFloat("time_speed");
+ SendTimeOfDay(peer_id, time, time_speed);
+
+ // Warnings about protocol version can be issued here
+ if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
+ {
+ SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
+ L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
+ }
+
+ return;
+ }
+
+ u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
+
+ if(peer_ser_ver == SER_FMT_VER_INVALID)
+ {
+ errorstream<<"Server::ProcessData(): Cancelling: Peer"
+ " serialization format invalid or not initialized."
+ " Skipping incoming command="<<command<<std::endl;
+ return;
+ }
+
+ /* Handle commands relate to client startup */
+ if(command == TOSERVER_REQUEST_MEDIA) {
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ std::list<std::string> tosend;
+ u16 numfiles = readU16(is);
+
+ infostream<<"Sending "<<numfiles<<" files to "
+ <<getPlayerName(peer_id)<<std::endl;
+ verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
+
+ for(int i = 0; i < numfiles; i++) {
+ std::string name = deSerializeString(is);
+ tosend.push_back(name);
+ verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
+ <<name<<std::endl;
+ }
+
+ sendRequestedMedia(peer_id, tosend);
+ return;
+ }
+ else if(command == TOSERVER_RECEIVED_MEDIA) {
+ std::string playername = "";
+ PlayerSAO *playersao = NULL;
+ m_clients.Lock();
+ RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,DefinitionsSent);
+ if (client != NULL) {
+ playername = client->getName();
+ playersao = emergePlayer(playername.c_str(), peer_id);
+ }
+ m_clients.Unlock();
+
+ RemotePlayer *player =
+ static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
+
+ // If failed, cancel
+ if((playersao == NULL) || (player == NULL))
+ {
+ if(player && player->peer_id != 0){
+ errorstream<<"Server: "<<playername<<": Failed to emerge player"
+ <<" (player allocated to an another client)"<<std::endl;
+ DenyAccess(peer_id, L"Another client is connected with this "
+ L"name. If your client closed unexpectedly, try again in "
+ L"a minute.");
+ } else {
+ errorstream<<"Server: "<<playername<<": Failed to emerge player"
+ <<std::endl;
+ DenyAccess(peer_id, L"Could not allocate player.");
+ }
+ return;
+ }
+
+ /*
+ Send complete position information
+ */
+ SendMovePlayer(peer_id);
+
// Send privileges
SendPlayerPrivileges(peer_id);
@@ -2172,19 +1663,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Send Breath
SendPlayerBreath(peer_id);
- // Send detached inventories
- sendDetachedInventories(peer_id);
-
// Show death screen if necessary
if(player->hp == 0)
- SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
-
- // Send time of day
- {
- u16 time = m_env->getTimeOfDay();
- float time_speed = g_settings->getFloat("time_speed");
- SendTimeOfDay(peer_id, time, time_speed);
- }
+ SendDeathscreen(peer_id, false, v3f(0,0,0));
// Note things in chat if not in simple singleplayer mode
if(!m_simple_singleplayer_mode)
@@ -2203,56 +1684,74 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
message += L"*** ";
message += name;
message += L" joined the game.";
- BroadcastChatMessage(message);
+ SendChatMessage(PEER_ID_INEXISTENT,message);
}
}
- // Warnings about protocol version can be issued here
- if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
- {
- SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
- L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
- }
-
+ actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. " << std::endl;
/*
Print out action
*/
{
- std::ostringstream os(std::ios_base::binary);
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
+ std::vector<std::string> names = m_clients.getPlayerNames();
+
+ actionstream<<player->getName()<<" ["<<addr_s<<"] "
+ <<"joins game. List of players: ";
+
+ for (std::vector<std::string>::iterator i = names.begin();
+ i != names.end(); i++)
{
- RemoteClient *client = i->second;
- assert(client->peer_id == i->first);
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
- // Get player
- Player *player = m_env->getPlayer(client->peer_id);
- if(!player)
- continue;
- // Get name of player
- os<<player->getName()<<" ";
+ actionstream << *i << " ";
}
- actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
- <<os.str()<<std::endl;
+ actionstream<<std::endl;
}
+ m_clients.event(peer_id,SetMediaSent);
+ m_script->on_joinplayer(playersao);
return;
}
+ else if(command == TOSERVER_GOTBLOCKS)
+ {
+ if(datasize < 2+1)
+ return;
- if(peer_ser_ver == SER_FMT_VER_INVALID)
+ /*
+ [0] u16 command
+ [2] u8 count
+ [3] v3s16 pos_0
+ [3+6] v3s16 pos_1
+ ...
+ */
+
+ u16 count = data[2];
+ for(u16 i=0; i<count; i++)
+ {
+ if((s16)datasize < 2+1+(i+1)*6)
+ throw con::InvalidIncomingDataException
+ ("GOTBLOCKS length is too short");
+ v3s16 p = readV3S16(&data[2+1+i*6]);
+ /*infostream<<"Server: GOTBLOCKS ("
+ <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
+ RemoteClient *client = getClient(peer_id);
+ client->GotBlock(p);
+ }
+ return;
+ }
+
+ if (m_clients.getClientState(peer_id) < Active)
{
- infostream<<"Server::ProcessData(): Cancelling: Peer"
- " serialization format invalid or not initialized."
- " Skipping incoming command="<<command<<std::endl;
+ if (command == TOSERVER_PLAYERPOS) return;
+
+ errorstream<<"Got packet command: " << command << " for peer id "
+ << peer_id << " but client isn't active yet. Dropping packet "
+ <<std::endl;
return;
}
Player *player = m_env->getPlayer(peer_id);
if(player == NULL){
- infostream<<"Server::ProcessData(): Cancelling: "
+ errorstream<<"Server::ProcessData(): Cancelling: "
"No player for peer_id="<<peer_id
<<std::endl;
return;
@@ -2260,7 +1759,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
PlayerSAO *playersao = player->getPlayerSAO();
if(playersao == NULL){
- infostream<<"Server::ProcessData(): Cancelling: "
+ errorstream<<"Server::ProcessData(): Cancelling: "
"No player object for peer_id="<<peer_id
<<std::endl;
return;
@@ -2309,32 +1808,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
<<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
}
- else if(command == TOSERVER_GOTBLOCKS)
- {
- if(datasize < 2+1)
- return;
-
- /*
- [0] u16 command
- [2] u8 count
- [3] v3s16 pos_0
- [3+6] v3s16 pos_1
- ...
- */
-
- u16 count = data[2];
- for(u16 i=0; i<count; i++)
- {
- if((s16)datasize < 2+1+(i+1)*6)
- throw con::InvalidIncomingDataException
- ("GOTBLOCKS length is too short");
- v3s16 p = readV3S16(&data[2+1+i*6]);
- /*infostream<<"Server: GOTBLOCKS ("
- <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
- RemoteClient *client = getClient(peer_id);
- client->GotBlock(p);
- }
- }
else if(command == TOSERVER_DELETEDBLOCKS)
{
if(datasize < 2+1)
@@ -2577,16 +2050,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Line to send to players
std::wstring line;
// Whether to send to the player that sent the line
- bool send_to_sender = false;
- // Whether to send to other players
- bool send_to_others = false;
+ bool send_to_sender_only = false;
// Commands are implemented in Lua, so only catch invalid
// commands that were not "eaten" and send an error back
if(message[0] == L'/')
{
message = message.substr(1);
- send_to_sender = true;
+ send_to_sender_only = true;
if(message.length() == 0)
line += L"-!- Empty command";
else
@@ -2599,39 +2070,37 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
line += name;
line += L"> ";
line += message;
- send_to_others = true;
} else {
line += L"-!- You don't have permission to shout.";
- send_to_sender = true;
+ send_to_sender_only = true;
}
}
if(line != L"")
{
- if(send_to_others)
- actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
-
/*
- Send the message to clients
+ Send the message to sender
*/
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
+ if (send_to_sender_only)
{
- // Get client and check that it is valid
- RemoteClient *client = i->second;
- assert(client->peer_id == i->first);
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
+ SendChatMessage(peer_id, line);
+ }
+ /*
+ Send the message to others
+ */
+ else
+ {
+ actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
- // Filter recipient
- bool sender_selected = (peer_id == client->peer_id);
- if(sender_selected == true && send_to_sender == false)
- continue;
- if(sender_selected == false && send_to_others == false)
- continue;
+ std::list<u16> clients = m_clients.getClientIDs();
- SendChatMessage(client->peer_id, line);
+ for(std::list<u16>::iterator
+ i = clients.begin();
+ i != clients.end(); ++i)
+ {
+ if (*i != peer_id)
+ SendChatMessage(*i, line);
+ }
}
}
}
@@ -2748,33 +2217,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// ActiveObject is added to environment in AsyncRunStep after
// the previous addition has been succesfully removed
}
- else if(command == TOSERVER_REQUEST_MEDIA) {
- std::string datastring((char*)&data[2], datasize-2);
- std::istringstream is(datastring, std::ios_base::binary);
-
- std::list<std::string> tosend;
- u16 numfiles = readU16(is);
-
- infostream<<"Sending "<<numfiles<<" files to "
- <<getPlayerName(peer_id)<<std::endl;
- verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
-
- for(int i = 0; i < numfiles; i++) {
- std::string name = deSerializeString(is);
- tosend.push_back(name);
- verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
- <<name<<std::endl;
- }
-
- sendRequestedMedia(peer_id, tosend);
-
- // Now the client should know about everything
- // (definitions and files)
- getClient(peer_id)->definitions_sent = true;
- }
- else if(command == TOSERVER_RECEIVED_MEDIA) {
- getClient(peer_id)->definitions_sent = true;
- }
else if(command == TOSERVER_INTERACT)
{
std::string datastring((char*)&data[2], datasize-2);
@@ -3313,7 +2755,7 @@ void Server::setInventoryModified(const InventoryLocation &loc)
break;
case InventoryLocation::DETACHED:
{
- sendDetachedInventoryToAll(loc.name);
+ sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
}
break;
default:
@@ -3321,14 +2763,29 @@ void Server::setInventoryModified(const InventoryLocation &loc)
}
}
+void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
+{
+ std::list<u16> clients = m_clients.getClientIDs();
+ m_clients.Lock();
+ // Set the modified blocks unsent for all the clients
+ for (std::list<u16>::iterator
+ i = clients.begin();
+ i != clients.end(); ++i) {
+ RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
+ if (client != NULL)
+ client->SetBlocksNotSent(block);
+ }
+ m_clients.Unlock();
+}
+
void Server::peerAdded(con::Peer *peer)
{
DSTACK(__FUNCTION_NAME);
verbosestream<<"Server::peerAdded(): peer->id="
<<peer->id<<std::endl;
- PeerChange c;
- c.type = PEER_ADDED;
+ con::PeerChange c;
+ c.type = con::PEER_ADDED;
c.peer_id = peer->id;
c.timeout = false;
m_peer_change_queue.push_back(c);
@@ -3340,18 +2797,42 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
verbosestream<<"Server::deletingPeer(): peer->id="
<<peer->id<<", timeout="<<timeout<<std::endl;
- PeerChange c;
- c.type = PEER_REMOVED;
+ m_clients.event(peer->id,Disconnect);
+ con::PeerChange c;
+ c.type = con::PEER_REMOVED;
c.peer_id = peer->id;
c.timeout = timeout;
m_peer_change_queue.push_back(c);
}
-/*
- Static send methods
-*/
+void Server::handlePeerChanges()
+{
+ while(m_peer_change_queue.size() > 0)
+ {
+ con::PeerChange c = m_peer_change_queue.pop_front();
+
+ verbosestream<<"Server: Handling peer change: "
+ <<"id="<<c.peer_id<<", timeout="<<c.timeout
+ <<std::endl;
+
+ switch(c.type)
+ {
+ case con::PEER_ADDED:
+ m_clients.CreateClient(c.peer_id);
+ break;
+
+ case con::PEER_REMOVED:
+ DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
+ break;
-void Server::SendMovement(con::Connection &con, u16 peer_id)
+ default:
+ assert("Invalid peer change event received!" == 0);
+ break;
+ }
+ }
+}
+
+void Server::SendMovement(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
@@ -3374,10 +2855,10 @@ void Server::SendMovement(con::Connection &con, u16 peer_id)
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
-void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
+void Server::SendHP(u16 peer_id, u8 hp)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
@@ -3389,10 +2870,10 @@ void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
-void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
+void Server::SendBreath(u16 peer_id, u16 breath)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
@@ -3404,11 +2885,10 @@ void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
-void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
- const std::wstring &reason)
+void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
@@ -3420,11 +2900,11 @@ void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
-void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
- bool set_camera_point_target, v3f camera_point_target)
+void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
+ v3f camera_point_target)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
@@ -3437,10 +2917,10 @@ void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
-void Server::SendItemDef(con::Connection &con, u16 peer_id,
+void Server::SendItemDef(u16 peer_id,
IItemDefManager *itemdef, u16 protocol_version)
{
DSTACK(__FUNCTION_NAME);
@@ -3464,10 +2944,10 @@ void Server::SendItemDef(con::Connection &con, u16 peer_id,
<<"): size="<<s.size()<<std::endl;
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
-void Server::SendNodeDef(con::Connection &con, u16 peer_id,
+void Server::SendNodeDef(u16 peer_id,
INodeDefManager *nodedef, u16 protocol_version)
{
DSTACK(__FUNCTION_NAME);
@@ -3491,7 +2971,7 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id,
<<"): size="<<s.size()<<std::endl;
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
/*
@@ -3521,7 +3001,7 @@ void Server::SendInventory(u16 peer_id)
memcpy(&data[2], s.c_str(), s.size());
// Send as reliable
- m_con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
@@ -3550,8 +3030,16 @@ void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
- // Send as reliable
- m_con.Send(peer_id, 0, data, true);
+
+ if (peer_id != PEER_ID_INEXISTENT)
+ {
+ // Send as reliable
+ m_clients.send(peer_id, 0, data, true);
+ }
+ else
+ {
+ m_clients.sendToAll(0,data,true);
+ }
}
void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
@@ -3572,7 +3060,7 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- m_con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
// Spawns a particle on peer with peer_id
@@ -3596,27 +3084,15 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
- // Send as reliable
- m_con.Send(peer_id, 0, data, true);
-}
-// Spawns a particle on all peers
-void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
- float expirationtime, float size, bool collisiondetection,
- bool vertical, std::string texture)
-{
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); i++)
+ if (peer_id != PEER_ID_INEXISTENT)
{
- // Get client and check that it is valid
- RemoteClient *client = i->second;
- assert(client->peer_id == i->first);
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
-
- SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
- expirationtime, size, collisiondetection, vertical, texture);
+ // Send as reliable
+ m_clients.send(peer_id, 0, data, true);
+ }
+ else
+ {
+ m_clients.sendToAll(0,data,true);
}
}
@@ -3650,28 +3126,14 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
- // Send as reliable
- m_con.Send(peer_id, 0, data, true);
-}
-// Adds a ParticleSpawner on all peers
-void Server::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)
-{
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); i++)
+ if (peer_id != PEER_ID_INEXISTENT)
{
- // Get client and check that it is valid
- RemoteClient *client = i->second;
- assert(client->peer_id == i->first);
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
-
- SendAddParticleSpawner(client->peer_id, amount, spawntime,
- minpos, maxpos, minvel, maxvel, minacc, maxacc,
- minexptime, maxexptime, minsize, maxsize, collisiondetection, vertical, texture, id);
+ // Send as reliable
+ m_clients.send(peer_id, 0, data, true);
+ }
+ else {
+ m_clients.sendToAll(0,data,true);
}
}
@@ -3687,24 +3149,15 @@ void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
- // Send as reliable
- m_con.Send(peer_id, 0, data, true);
-}
-void Server::SendDeleteParticleSpawnerAll(u32 id)
-{
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); i++)
- {
- // Get client and check that it is valid
- RemoteClient *client = i->second;
- assert(client->peer_id == i->first);
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
-
- SendDeleteParticleSpawner(client->peer_id, id);
+ if (peer_id != PEER_ID_INEXISTENT) {
+ // Send as reliable
+ m_clients.send(peer_id, 0, data, true);
+ }
+ else {
+ m_clients.sendToAll(0,data,true);
}
+
}
void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
@@ -3730,7 +3183,7 @@ void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- m_con.Send(peer_id, 1, data, true);
+ m_clients.send(peer_id, 1, data, true);
}
void Server::SendHUDRemove(u16 peer_id, u32 id)
@@ -3746,7 +3199,7 @@ void Server::SendHUDRemove(u16 peer_id, u32 id)
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- m_con.Send(peer_id, 1, data, true);
+ m_clients.send(peer_id, 1, data, true);
}
void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
@@ -3783,7 +3236,7 @@ void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value
std::string s = os.str();
SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
// Send as reliable
- m_con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
@@ -3799,7 +3252,7 @@ void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
std::string s = os.str();
SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
// Send as reliable
- m_con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
@@ -3815,23 +3268,7 @@ void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
std::string s = os.str();
SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
// Send as reliable
- m_con.Send(peer_id, 0, data, true);
-}
-
-void Server::BroadcastChatMessage(const std::wstring &message)
-{
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
- {
- // Get client and check that it is valid
- RemoteClient *client = i->second;
- assert(client->peer_id == i->first);
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
-
- SendChatMessage(client->peer_id, message);
- }
+ m_clients.send(peer_id, 0, data, true);
}
void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
@@ -3844,8 +3281,13 @@ void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
writeU16(&data[2], time);
writeF1000(&data[4], time_speed);
- // Send as reliable
- m_con.Send(peer_id, 0, data, true);
+ if (peer_id == PEER_ID_INEXISTENT) {
+ m_clients.sendToAll(0,data,true);
+ }
+ else {
+ // Send as reliable
+ m_clients.send(peer_id, 0, data, true);
+ }
}
void Server::SendPlayerHP(u16 peer_id)
@@ -3854,7 +3296,7 @@ void Server::SendPlayerHP(u16 peer_id)
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
playersao->m_hp_not_sent = false;
- SendHP(m_con, peer_id, playersao->getHP());
+ SendHP(peer_id, playersao->getHP());
// Send to other clients
std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
@@ -3868,7 +3310,7 @@ void Server::SendPlayerBreath(u16 peer_id)
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
playersao->m_breath_not_sent = false;
- SendBreath(m_con, peer_id, playersao->getBreath());
+ SendBreath(peer_id, playersao->getBreath());
}
void Server::SendMovePlayer(u16 peer_id)
@@ -3898,7 +3340,7 @@ void Server::SendMovePlayer(u16 peer_id)
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- m_con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
void Server::SendPlayerPrivileges(u16 peer_id)
@@ -3923,7 +3365,7 @@ void Server::SendPlayerPrivileges(u16 peer_id)
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- m_con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
void Server::SendPlayerInventoryFormspec(u16 peer_id)
@@ -3941,7 +3383,7 @@ void Server::SendPlayerInventoryFormspec(u16 peer_id)
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- m_con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
s32 Server::playSound(const SimpleSoundSpec &spec,
@@ -3953,8 +3395,9 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
// If position is not found while it should be, cancel sound
if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
return -1;
+
// Filter destination clients
- std::set<RemoteClient*> dst_clients;
+ std::list<u16> dst_clients;
if(params.to_player != "")
{
Player *player = m_env->getPlayer(params.to_player.c_str());
@@ -3968,16 +3411,16 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
<<"\" not connected"<<std::endl;
return -1;
}
- RemoteClient *client = getClient(player->peer_id);
- dst_clients.insert(client);
+ dst_clients.push_back(player->peer_id);
}
else
{
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin(); i != m_clients.end(); ++i)
+ std::list<u16> clients = m_clients.getClientIDs();
+
+ for(std::list<u16>::iterator
+ i = clients.begin(); i != clients.end(); ++i)
{
- RemoteClient *client = i->second;
- Player *player = m_env->getPlayer(client->peer_id);
+ Player *player = m_env->getPlayer(*i);
if(!player)
continue;
if(pos_exists){
@@ -3985,20 +3428,21 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
params.max_hear_distance)
continue;
}
- dst_clients.insert(client);
+ dst_clients.push_back(*i);
}
}
if(dst_clients.size() == 0)
return -1;
+
// Create the sound
s32 id = m_next_sound_id++;
// The sound will exist as a reference in m_playing_sounds
m_playing_sounds[id] = ServerPlayingSound();
ServerPlayingSound &psound = m_playing_sounds[id];
psound.params = params;
- for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
+ for(std::list<u16>::iterator i = dst_clients.begin();
i != dst_clients.end(); i++)
- psound.clients.insert((*i)->peer_id);
+ psound.clients.insert(*i);
// Create packet
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_PLAY_SOUND);
@@ -4013,10 +3457,10 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send
- for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
+ for(std::list<u16>::iterator i = dst_clients.begin();
i != dst_clients.end(); i++){
// Send as reliable
- m_con.Send((*i)->peer_id, 0, data, true);
+ m_clients.send(*i, 0, data, true);
}
return id;
}
@@ -4039,7 +3483,7 @@ void Server::stopSound(s32 handle)
for(std::set<u16>::iterator i = psound.clients.begin();
i != psound.clients.end(); i++){
// Send as reliable
- m_con.Send(*i, 0, data, true);
+ m_clients.send(*i, 0, data, true);
}
// Remove sound reference
m_playing_sounds.erase(i);
@@ -4059,38 +3503,29 @@ void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
writeS16(&reply[4], p.Y);
writeS16(&reply[6], p.Z);
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
+ std::list<u16> clients = m_clients.getClientIDs();
+ for(std::list<u16>::iterator
+ i = clients.begin();
+ i != clients.end(); ++i)
{
- // Get client and check that it is valid
- RemoteClient *client = i->second;
- assert(client->peer_id == i->first);
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
-
- // Don't send if it's the same one
- if(client->peer_id == ignore_id)
- continue;
-
if(far_players)
{
// Get player
- Player *player = m_env->getPlayer(client->peer_id);
+ Player *player = m_env->getPlayer(*i);
if(player)
{
// If player is far away, only set modified blocks not sent
v3f player_pos = player->getPosition();
if(player_pos.getDistanceFrom(p_f) > maxd)
{
- far_players->push_back(client->peer_id);
+ far_players->push_back(*i);
continue;
}
}
}
// Send as reliable
- m_con.Send(client->peer_id, 0, reply, true);
+ m_clients.send(*i, 0, reply, true);
}
}
@@ -4101,69 +3536,71 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
float maxd = far_d_nodes*BS;
v3f p_f = intToFloat(p, BS);
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
- {
- // Get client and check that it is valid
- RemoteClient *client = i->second;
- assert(client->peer_id == i->first);
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
-
- // Don't send if it's the same one
- if(client->peer_id == ignore_id)
- continue;
+ std::list<u16> clients = m_clients.getClientIDs();
+ for(std::list<u16>::iterator
+ i = clients.begin();
+ i != clients.end(); ++i)
+ {
if(far_players)
{
// Get player
- Player *player = m_env->getPlayer(client->peer_id);
+ Player *player = m_env->getPlayer(*i);
if(player)
{
// If player is far away, only set modified blocks not sent
v3f player_pos = player->getPosition();
if(player_pos.getDistanceFrom(p_f) > maxd)
{
- far_players->push_back(client->peer_id);
+ far_players->push_back(*i);
continue;
}
}
}
-
- // Create packet
- u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
- SharedBuffer<u8> reply(replysize);
- writeU16(&reply[0], TOCLIENT_ADDNODE);
- writeS16(&reply[2], p.X);
- writeS16(&reply[4], p.Y);
- writeS16(&reply[6], p.Z);
- n.serialize(&reply[8], client->serialization_version);
- u32 index = 8 + MapNode::serializedLength(client->serialization_version);
- writeU8(&reply[index], remove_metadata ? 0 : 1);
-
- if (!remove_metadata) {
- if (client->net_proto_version <= 21) {
- // Old clients always clear metadata; fix it
- // by sending the full block again.
- client->SetBlockNotSent(p);
+ SharedBuffer<u8> reply(0);
+ m_clients.Lock();
+ RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
+ if (client != 0)
+ {
+ // Create packet
+ u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
+ reply = SharedBuffer<u8>(replysize);
+ writeU16(&reply[0], TOCLIENT_ADDNODE);
+ writeS16(&reply[2], p.X);
+ writeS16(&reply[4], p.Y);
+ writeS16(&reply[6], p.Z);
+ n.serialize(&reply[8], client->serialization_version);
+ u32 index = 8 + MapNode::serializedLength(client->serialization_version);
+ writeU8(&reply[index], remove_metadata ? 0 : 1);
+
+ if (!remove_metadata) {
+ if (client->net_proto_version <= 21) {
+ // Old clients always clear metadata; fix it
+ // by sending the full block again.
+ client->SetBlockNotSent(p);
+ }
}
}
+ m_clients.Unlock();
// Send as reliable
- m_con.Send(client->peer_id, 0, reply, true);
+ if (reply.getSize() > 0)
+ m_clients.send(*i, 0, reply, true);
}
}
void Server::setBlockNotSent(v3s16 p)
{
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
+ std::list<u16> clients = m_clients.getClientIDs();
+ m_clients.Lock();
+ for(std::list<u16>::iterator
+ i = clients.begin();
+ i != clients.end(); ++i)
{
- RemoteClient *client = i->second;
+ RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
client->SetBlockNotSent(p);
}
+ m_clients.Unlock();
}
void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
@@ -4217,7 +3654,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto
/*
Send packet
*/
- m_con.Send(peer_id, 2, reply, true);
+ m_clients.send(peer_id, 2, reply, true);
}
void Server::SendBlocks(float dtime)
@@ -4225,7 +3662,7 @@ void Server::SendBlocks(float dtime)
DSTACK(__FUNCTION_NAME);
JMutexAutoLock envlock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
+ //TODO check if one big lock could be faster then multiple small ones
ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
@@ -4236,25 +3673,22 @@ void Server::SendBlocks(float dtime)
{
ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
+ std::list<u16> clients = m_clients.getClientIDs();
+
+ m_clients.Lock();
+ for(std::list<u16>::iterator
+ i = clients.begin();
+ i != clients.end(); ++i)
{
- RemoteClient *client = i->second;
- assert(client->peer_id == i->first);
+ RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
- // If definitions and textures have not been sent, don't
- // send MapBlocks either
- if(!client->definitions_sent)
- continue;
+ if (client == NULL)
+ return;
total_sending += client->SendingCount();
-
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
-
- client->GetNextBlocks(this, dtime, queue);
+ client->GetNextBlocks(m_env,m_emerge, dtime, queue);
}
+ m_clients.Unlock();
}
// Sort.
@@ -4262,6 +3696,7 @@ void Server::SendBlocks(float dtime)
// Lowest is most important.
std::sort(queue.begin(), queue.end());
+ m_clients.Lock();
for(u32 i=0; i<queue.size(); i++)
{
//TODO: Calculate limit dynamically
@@ -4281,18 +3716,17 @@ void Server::SendBlocks(float dtime)
continue;
}
- RemoteClient *client = getClientNoEx(q.peer_id);
+ RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
+
if(!client)
continue;
- if(client->denied)
- continue;
SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
client->SentBlock(q.pos);
-
total_sending++;
}
+ m_clients.Unlock();
}
void Server::fillMediaCache()
@@ -4449,7 +3883,7 @@ void Server::sendMediaAnnouncement(u16 peer_id)
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- m_con.Send(peer_id, 0, data, true);
+ m_clients.send(peer_id, 0, data, true);
}
struct SendableMedia
@@ -4579,7 +4013,7 @@ void Server::sendRequestedMedia(u16 peer_id,
<<" size=" <<s.size()<<std::endl;
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
- m_con.Send(peer_id, 2, data, true);
+ m_clients.send(peer_id, 2, data, true);
}
}
@@ -4599,19 +4033,15 @@ void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
- // Send as reliable
- m_con.Send(peer_id, 0, data, true);
-}
-void Server::sendDetachedInventoryToAll(const std::string &name)
-{
- DSTACK(__FUNCTION_NAME);
-
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i){
- RemoteClient *client = i->second;
- sendDetachedInventory(name, client->peer_id);
+ if (peer_id != PEER_ID_INEXISTENT)
+ {
+ // Send as reliable
+ m_clients.send(peer_id, 0, data, true);
+ }
+ else
+ {
+ m_clients.sendToAll(0,data,true);
}
}
@@ -4649,7 +4079,7 @@ void Server::DiePlayer(u16 peer_id)
m_script->on_dieplayer(playersao);
SendPlayerHP(peer_id);
- SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
+ SendDeathscreen(peer_id, false, v3f(0,0,0));
}
void Server::RespawnPlayer(u16 peer_id)
@@ -4676,132 +4106,93 @@ void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
{
DSTACK(__FUNCTION_NAME);
- SendAccessDenied(m_con, peer_id, reason);
-
- RemoteClient *client = getClientNoEx(peer_id);
- if(client)
- client->denied = true;
-
- // If there are way too many clients, get rid of denied new ones immediately
- if((int)m_clients.size() > 2 * g_settings->getU16("max_users")){
- verbosestream<<"Server: DenyAccess: Too many clients; getting rid of "
- <<"peer_id="<<peer_id<<" immediately"<<std::endl;
- // Delete peer to stop sending it data
- m_con.DeletePeer(peer_id);
- // Delete client also to stop block sends and other stuff
- DeleteClient(peer_id, CDR_DENY);
- }
+ SendAccessDenied(peer_id, reason);
+ m_clients.event(peer_id,SetDenied);
+ m_con.DisconnectPeer(peer_id);
}
void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
{
DSTACK(__FUNCTION_NAME);
-
- // 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
- */
- 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--;
- }
-
- /*
- Clear references to playing sounds
- */
- for(std::map<s32, ServerPlayingSound>::iterator
- i = m_playing_sounds.begin();
- i != m_playing_sounds.end();)
+ std::wstring message;
{
- ServerPlayingSound &psound = i->second;
- psound.clients.erase(peer_id);
- if(psound.clients.size() == 0)
- m_playing_sounds.erase(i++);
- else
- i++;
- }
+ /*
+ Clear references to playing sounds
+ */
+ for(std::map<s32, ServerPlayingSound>::iterator
+ i = m_playing_sounds.begin();
+ i != m_playing_sounds.end();)
+ {
+ ServerPlayingSound &psound = i->second;
+ psound.clients.erase(peer_id);
+ if(psound.clients.size() == 0)
+ m_playing_sounds.erase(i++);
+ else
+ i++;
+ }
- Player *player = m_env->getPlayer(peer_id);
+ Player *player = m_env->getPlayer(peer_id);
- // Collect information about leaving in chat
- std::wstring message;
- {
- if(player != NULL && reason != CDR_DENY)
+ // Collect information about leaving in chat
{
- std::wstring name = narrow_to_wide(player->getName());
- message += L"*** ";
- message += name;
- message += L" left the game.";
- if(reason == CDR_TIMEOUT)
- message += L" (timed out)";
+ if(player != NULL && reason != CDR_DENY)
+ {
+ std::wstring name = narrow_to_wide(player->getName());
+ message += L"*** ";
+ message += name;
+ message += L" left the game.";
+ if(reason == CDR_TIMEOUT)
+ message += L" (timed out)";
+ }
}
- }
- /* Run scripts and remove from environment */
- {
- if(player != NULL)
+ /* Run scripts and remove from environment */
{
- PlayerSAO *playersao = player->getPlayerSAO();
- assert(playersao);
+ if(player != NULL)
+ {
+ PlayerSAO *playersao = player->getPlayerSAO();
+ assert(playersao);
- m_script->on_leaveplayer(playersao);
+ m_script->on_leaveplayer(playersao);
- playersao->disconnected();
+ playersao->disconnected();
+ }
}
- }
- /*
- Print out action
- */
- {
- if(player != NULL && reason != CDR_DENY)
+ /*
+ Print out action
+ */
{
- std::ostringstream os(std::ios_base::binary);
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i)
+ if(player != NULL && reason != CDR_DENY)
{
- RemoteClient *client = i->second;
- assert(client->peer_id == i->first);
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
- // Get player
- Player *player = m_env->getPlayer(client->peer_id);
- if(!player)
- continue;
- // Get name of player
- os<<player->getName()<<" ";
- }
+ std::ostringstream os(std::ios_base::binary);
+ std::list<u16> clients = m_clients.getClientIDs();
+
+ for(std::list<u16>::iterator
+ i = clients.begin();
+ i != clients.end(); ++i)
+ {
+ // Get player
+ Player *player = m_env->getPlayer(*i);
+ if(!player)
+ continue;
+ // Get name of player
+ os<<player->getName()<<" ";
+ }
- actionstream<<player->getName()<<" "
- <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
- <<" List of players: "<<os.str()<<std::endl;
+ actionstream<<player->getName()<<" "
+ <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
+ <<" List of players: "<<os.str()<<std::endl;
+ }
}
+ m_env_mutex.Lock();
+ m_clients.DeleteClient(peer_id);
+ m_env_mutex.Unlock();
}
- // Delete client
- delete m_clients[peer_id];
- m_clients.erase(peer_id);
-
// Send leave chat message to all remaining clients
if(message.length() != 0)
- BroadcastChatMessage(message);
+ SendChatMessage(PEER_ID_INEXISTENT,message);
}
void Server::UpdateCrafting(u16 peer_id)
@@ -4825,22 +4216,17 @@ void Server::UpdateCrafting(u16 peer_id)
plist->changeItem(0, preview);
}
-RemoteClient* Server::getClient(u16 peer_id)
+RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
{
- RemoteClient *client = getClientNoEx(peer_id);
+ RemoteClient *client = getClientNoEx(peer_id,state_min);
if(!client)
throw ClientNotFoundException("Client not found");
+
return client;
}
-RemoteClient* Server::getClientNoEx(u16 peer_id)
+RemoteClient* Server::getClientNoEx(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;
- return n->second;
+ return m_clients.getClientNoEx(peer_id, state_min);
}
std::string Server::getPlayerName(u16 peer_id)
@@ -4870,19 +4256,14 @@ std::wstring Server::getStatusString()
// Max lag estimate
os<<L", max_lag="<<m_env->getMaxLagEstimate();
// Information about clients
- std::map<u16, RemoteClient*>::iterator i;
- bool first;
+ bool first = true;
os<<L", clients={";
- for(i = m_clients.begin(), first = true;
- i != m_clients.end(); ++i)
+ std::list<u16> clients = m_clients.getClientIDs();
+ for(std::list<u16>::iterator i = clients.begin();
+ i != clients.end(); ++i)
{
- // Get client and check that it is valid
- RemoteClient *client = i->second;
- assert(client->peer_id == i->first);
- if(client->serialization_version == SER_FMT_VER_INVALID)
- continue;
// Get player
- Player *player = m_env->getPlayer(client->peer_id);
+ Player *player = m_env->getPlayer(*i);
// Get name of player
std::wstring name = L"unknown";
if(player != NULL)
@@ -4918,11 +4299,11 @@ bool Server::checkPriv(const std::string &name, const std::string &priv)
void Server::reportPrivsModified(const std::string &name)
{
if(name == ""){
- for(std::map<u16, RemoteClient*>::iterator
- i = m_clients.begin();
- i != m_clients.end(); ++i){
- RemoteClient *client = i->second;
- Player *player = m_env->getPlayer(client->peer_id);
+ std::list<u16> clients = m_clients.getClientIDs();
+ for(std::list<u16>::iterator
+ i = clients.begin();
+ i != clients.end(); ++i){
+ Player *player = m_env->getPlayer(*i);
reportPrivsModified(player->getName());
}
} else {
@@ -5056,7 +4437,7 @@ void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
void Server::notifyPlayers(const std::wstring msg)
{
- BroadcastChatMessage(msg);
+ SendChatMessage(PEER_ID_INEXISTENT,msg);
}
void Server::spawnParticle(const char *playername, v3f pos,
@@ -5075,7 +4456,7 @@ void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size,
bool collisiondetection, bool vertical, std::string texture)
{
- SendSpawnParticleAll(pos, velocity, acceleration,
+ SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
expirationtime, size, collisiondetection, vertical, texture);
}
@@ -5134,7 +4515,7 @@ u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
}
}
- SendAddParticleSpawnerAll(amount, spawntime,
+ SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
minpos, maxpos, minvel, maxvel, minacc, maxacc,
minexptime, maxexptime, minsize, maxsize,
collisiondetection, vertical, texture, id);
@@ -5161,7 +4542,7 @@ void Server::deleteParticleSpawnerAll(u32 id)
std::remove(m_particlespawner_ids.begin(),
m_particlespawner_ids.end(), id),
m_particlespawner_ids.end());
- SendDeleteParticleSpawnerAll(id);
+ SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
}
Inventory* Server::createDetachedInventory(const std::string &name)
@@ -5175,7 +4556,8 @@ Inventory* Server::createDetachedInventory(const std::string &name)
Inventory *inv = new Inventory(m_itemdef);
assert(inv);
m_detached_inventories[name] = inv;
- sendDetachedInventoryToAll(name);
+ //TODO find a better way to do this
+ sendDetachedInventory(name,PEER_ID_INEXISTENT);
return inv;
}
@@ -5444,63 +4826,9 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
if(newplayer)
m_script->on_newplayer(playersao);
- m_script->on_joinplayer(playersao);
-
return playersao;
}
-void Server::handlePeerChange(PeerChange &c)
-{
- JMutexAutoLock envlock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
-
- if(c.type == PEER_ADDED)
- {
- /*
- Add
- */
-
- // Error check
- std::map<u16, RemoteClient*>::iterator n;
- n = m_clients.find(c.peer_id);
- // The client shouldn't already exist
- assert(n == m_clients.end());
-
- // Create client
- RemoteClient *client = new RemoteClient();
- client->peer_id = c.peer_id;
- m_clients[client->peer_id] = client;
-
- } // PEER_ADDED
- else if(c.type == PEER_REMOVED)
- {
- /*
- Delete
- */
-
- DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
-
- } // PEER_REMOVED
- else
- {
- assert(0);
- }
-}
-
-void Server::handlePeerChanges()
-{
- while(m_peer_change_queue.size() > 0)
- {
- PeerChange c = m_peer_change_queue.pop_front();
-
- verbosestream<<"Server: Handling peer change: "
- <<"id="<<c.peer_id<<", timeout="<<c.timeout
- <<std::endl;
-
- handlePeerChange(c);
- }
-}
-
void dedicated_server_loop(Server &server, bool &kill)
{
DSTACK(__FUNCTION_NAME);
diff --git a/src/server.h b/src/server.h
index 1163400f7..94b0b6a2d 100644
--- a/src/server.h
+++ b/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 &params);
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; }
-
- bool isSingleplayer(){ return m_simple_singleplayer_mode; }
+ inline 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
@@ -716,22 +516,16 @@ private:
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;
/*