--- /dev/null
+/*
+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;
+}
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)
{
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
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),
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;
// 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);
// 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);
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
// 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;
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
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);
}
}
*/
{
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;
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);
}
}
}
/*
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);
- }
- }
- }
-
- // 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());
- }
+ SetBlocksNotSent(modified_blocks);
}
}
-
+ 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
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);
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
*/
{
JMutexAutoLock envlock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
-
ScopeProfiler sp(g_profiler, "Server: sending object messages");
// Key = object id
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;
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)
{
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)
<<std::endl;
}*/
}
+ m_clients.Unlock();
// Clear buffered_messages
for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
}
}
- } // 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;
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)
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
// 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
{
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;
<<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.");
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 "
return;
}
+ client->setPendingSerializationVersion(deployed);
+
/*
Read and check network protocol version
*/
<<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)
// 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") &&
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
*/
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
<<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);
// 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)
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;
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;
player->control.LMB = (bool)(keyPressed&128);
player->control.RMB = (bool)(keyPressed&256);
- bool cheated = playersao->checkMovementCheat();
- if(cheated){
- // Call callbacks
- m_script->on_cheat(playersao, "moved_too_fast");
- }
-
- /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
- <<"("<<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);
+ bool cheated = playersao->checkMovementCheat();
+ if(cheated){
+ // Call callbacks
+ m_script->on_cheat(playersao, "moved_too_fast");
}
+
+ /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
+ <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
+ <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
}
else if(command == TOSERVER_DELETEDBLOCKS)
{
// 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
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);
+ }
}
}
}
// 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);
break;
case InventoryLocation::DETACHED:
{
- sendDetachedInventoryToAll(loc.name);
+ sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
}
break;
default:
}
}
+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);
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;
+
+ default:
+ assert("Invalid peer change event received!" == 0);
+ break;
+ }
+ }
+}
-void Server::SendMovement(con::Connection &con, u16 peer_id)
+void Server::SendMovement(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
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);
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);
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);
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);
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);
<<"): 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);
<<"): 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);
}
/*
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)
// 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,
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
// 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);
}
}
// 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);
}
}
// 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)
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)
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)
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)
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)
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)
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)
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());
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)
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)
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)
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,
// 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());
<<"\" 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){
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);
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;
}
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);
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);
}
}
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)
/*
Send packet
*/
- m_con.Send(peer_id, 2, reply, true);
+ m_clients.send(peer_id, 2, reply, true);
}
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");
{
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.
// 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
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()
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
<<" 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);
}
}
// 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);
}
}
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)
{
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)
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)
// 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)
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 {
void Server::notifyPlayers(const std::wstring msg)
{
- BroadcastChatMessage(msg);
+ SendChatMessage(PEER_ID_INEXISTENT,msg);
}
void Server::spawnParticle(const char *playername, v3f pos,
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);
}
}
}
- SendAddParticleSpawnerAll(amount, spawntime,
+ SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
minpos, maxpos, minvel, maxvel, minacc, maxacc,
minexptime, maxexptime, minsize, maxsize,
collisiondetection, vertical, texture, 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)
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;
}
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);