3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "clientserver.h"
25 #include "jmutexautolock.h"
27 #include "constants.h"
29 #include "materials.h"
32 #include "servercommand.h"
34 #include "content_mapnode.h"
35 #include "content_craft.h"
36 #include "content_nodemeta.h"
38 #include "serverobject.h"
43 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
45 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
47 class MapEditEventIgnorer
50 MapEditEventIgnorer(bool *flag):
59 ~MapEditEventIgnorer()
72 void * ServerThread::Thread()
76 log_register_thread("ServerThread");
78 DSTACK(__FUNCTION_NAME);
80 BEGIN_DEBUG_EXCEPTION_HANDLER
85 //TimeTaker timer("AsyncRunStep() + Receive()");
88 //TimeTaker timer("AsyncRunStep()");
89 m_server->AsyncRunStep();
92 //infostream<<"Running m_server->Receive()"<<std::endl;
95 catch(con::NoIncomingDataException &e)
98 catch(con::PeerNotFoundException &e)
100 infostream<<"Server: PeerNotFoundException"<<std::endl;
104 END_DEBUG_EXCEPTION_HANDLER(errorstream)
109 void * EmergeThread::Thread()
113 log_register_thread("EmergeThread");
115 DSTACK(__FUNCTION_NAME);
117 BEGIN_DEBUG_EXCEPTION_HANDLER
119 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
122 Get block info from queue, emerge them and send them
125 After queue is empty, exit.
129 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
133 SharedPtr<QueuedBlockEmerge> q(qptr);
139 Do not generate over-limit
141 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
142 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
143 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
144 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
145 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
146 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
149 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
151 //TimeTaker timer("block emerge");
154 Try to emerge it from somewhere.
156 If it is only wanted as optional, only loading from disk
161 Check if any peer wants it as non-optional. In that case it
164 Also decrement the emerge queue count in clients.
167 bool only_from_disk = true;
170 core::map<u16, u8>::Iterator i;
171 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
173 //u16 peer_id = i.getNode()->getKey();
176 u8 flags = i.getNode()->getValue();
177 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
178 only_from_disk = false;
183 if(enable_mapgen_debug_info)
184 infostream<<"EmergeThread: p="
185 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
186 <<"only_from_disk="<<only_from_disk<<std::endl;
188 ServerMap &map = ((ServerMap&)m_server->m_env.getMap());
190 //core::map<v3s16, MapBlock*> changed_blocks;
191 //core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
193 MapBlock *block = NULL;
194 bool got_block = true;
195 core::map<v3s16, MapBlock*> modified_blocks;
198 Fetch block from map or generate a single block
201 JMutexAutoLock envlock(m_server->m_env_mutex);
203 // Load sector if it isn't loaded
204 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
205 //map.loadSectorFull(p2d);
206 map.loadSectorMeta(p2d);
208 block = map.getBlockNoCreateNoEx(p);
209 if(!block || block->isDummy() || !block->isGenerated())
211 if(enable_mapgen_debug_info)
212 infostream<<"EmergeThread: not in memory, loading"<<std::endl;
214 // Get, load or create sector
215 /*ServerMapSector *sector =
216 (ServerMapSector*)map.createSector(p2d);*/
218 // Load/generate block
220 /*block = map.emergeBlock(p, sector, changed_blocks,
221 lighting_invalidated_blocks);*/
223 block = map.loadBlock(p);
225 if(only_from_disk == false)
227 if(block == NULL || block->isGenerated() == false)
229 if(enable_mapgen_debug_info)
230 infostream<<"EmergeThread: generating"<<std::endl;
231 block = map.generateBlock(p, modified_blocks);
235 if(enable_mapgen_debug_info)
236 infostream<<"EmergeThread: ended up with: "
237 <<analyze_block(block)<<std::endl;
246 Ignore map edit events, they will not need to be
247 sent to anybody because the block hasn't been sent
250 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
252 // Activate objects and stuff
253 m_server->m_env.activateBlock(block, 3600);
258 /*if(block->getLightingExpired()){
259 lighting_invalidated_blocks[block->getPos()] = block;
263 // TODO: Some additional checking and lighting updating,
268 JMutexAutoLock envlock(m_server->m_env_mutex);
273 Collect a list of blocks that have been modified in
274 addition to the fetched one.
278 if(lighting_invalidated_blocks.size() > 0)
280 /*infostream<<"lighting "<<lighting_invalidated_blocks.size()
281 <<" blocks"<<std::endl;*/
283 // 50-100ms for single block generation
284 //TimeTaker timer("** EmergeThread updateLighting");
286 // Update lighting without locking the environment mutex,
287 // add modified blocks to changed blocks
288 map.updateLighting(lighting_invalidated_blocks, modified_blocks);
291 // Add all from changed_blocks to modified_blocks
292 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
293 i.atEnd() == false; i++)
295 MapBlock *block = i.getNode()->getValue();
296 modified_blocks.insert(block->getPos(), block);
300 // If we got no block, there should be no invalidated blocks
303 //assert(lighting_invalidated_blocks.size() == 0);
309 Set sent status of modified blocks on clients
312 // NOTE: Server's clients are also behind the connection mutex
313 JMutexAutoLock lock(m_server->m_con_mutex);
316 Add the originally fetched block to the modified list
320 modified_blocks.insert(p, block);
324 Set the modified blocks unsent for all the clients
327 for(core::map<u16, RemoteClient*>::Iterator
328 i = m_server->m_clients.getIterator();
329 i.atEnd() == false; i++)
331 RemoteClient *client = i.getNode()->getValue();
333 if(modified_blocks.size() > 0)
335 // Remove block from sent history
336 client->SetBlocksNotSent(modified_blocks);
342 END_DEBUG_EXCEPTION_HANDLER(errorstream)
347 void RemoteClient::GetNextBlocks(Server *server, float dtime,
348 core::array<PrioritySortedBlockTransfer> &dest)
350 DSTACK(__FUNCTION_NAME);
353 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
356 m_nothing_to_send_pause_timer -= dtime;
358 if(m_nothing_to_send_pause_timer >= 0)
361 m_nearest_unsent_reset_timer = 0;
365 // Won't send anything if already sending
366 if(m_blocks_sending.size() >= g_settings->getU16
367 ("max_simultaneous_block_sends_per_client"))
369 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
373 //TimeTaker timer("RemoteClient::GetNextBlocks");
375 Player *player = server->m_env.getPlayer(peer_id);
377 assert(player != NULL);
379 v3f playerpos = player->getPosition();
380 v3f playerspeed = player->getSpeed();
381 v3f playerspeeddir(0,0,0);
382 if(playerspeed.getLength() > 1.0*BS)
383 playerspeeddir = playerspeed / playerspeed.getLength();
384 // Predict to next block
385 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
387 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
389 v3s16 center = getNodeBlockPos(center_nodepos);
391 // Camera position and direction
392 v3f camera_pos = player->getEyePosition();
393 v3f camera_dir = v3f(0,0,1);
394 camera_dir.rotateYZBy(player->getPitch());
395 camera_dir.rotateXZBy(player->getYaw());
397 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
398 <<camera_dir.Z<<")"<<std::endl;*/
401 Get the starting value of the block finder radius.
404 if(m_last_center != center)
406 m_nearest_unsent_d = 0;
407 m_last_center = center;
410 /*infostream<<"m_nearest_unsent_reset_timer="
411 <<m_nearest_unsent_reset_timer<<std::endl;*/
413 // This has to be incremented only when the nothing to send pause
415 m_nearest_unsent_reset_timer += dtime;
417 // Reset periodically to avoid possible bugs or other mishaps
418 if(m_nearest_unsent_reset_timer > 10.0)
420 m_nearest_unsent_reset_timer = 0;
421 m_nearest_unsent_d = 0;
422 /*infostream<<"Resetting m_nearest_unsent_d for "
423 <<server->getPlayerName(peer_id)<<std::endl;*/
426 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
427 s16 d_start = m_nearest_unsent_d;
429 //infostream<<"d_start="<<d_start<<std::endl;
431 u16 max_simul_sends_setting = g_settings->getU16
432 ("max_simultaneous_block_sends_per_client");
433 u16 max_simul_sends_usually = max_simul_sends_setting;
436 Check the time from last addNode/removeNode.
438 Decrease send rate if player is building stuff.
440 m_time_from_building += dtime;
441 if(m_time_from_building < g_settings->getFloat(
442 "full_block_send_enable_min_time_from_building"))
444 max_simul_sends_usually
445 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
449 Number of blocks sending + number of blocks selected for sending
451 u32 num_blocks_selected = m_blocks_sending.size();
454 next time d will be continued from the d from which the nearest
455 unsent block was found this time.
457 This is because not necessarily any of the blocks found this
458 time are actually sent.
460 s32 new_nearest_unsent_d = -1;
462 s16 d_max = g_settings->getS16("max_block_send_distance");
463 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
465 // Don't loop very much at a time
466 if(d_max > d_start+1)
468 /*if(d_max_gen > d_start+2)
469 d_max_gen = d_start+2;*/
471 //infostream<<"Starting from "<<d_start<<std::endl;
473 bool sending_something = false;
475 bool no_blocks_found_for_sending = true;
477 bool queue_is_full = false;
480 for(d = d_start; d <= d_max; d++)
482 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
485 If m_nearest_unsent_d was changed by the EmergeThread
486 (it can change it to 0 through SetBlockNotSent),
488 Else update m_nearest_unsent_d
490 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
492 d = m_nearest_unsent_d;
493 last_nearest_unsent_d = m_nearest_unsent_d;
497 Get the border/face dot coordinates of a "d-radiused"
500 core::list<v3s16> list;
501 getFacePositions(list, d);
503 core::list<v3s16>::Iterator li;
504 for(li=list.begin(); li!=list.end(); li++)
506 v3s16 p = *li + center;
510 - Don't allow too many simultaneous transfers
511 - EXCEPT when the blocks are very close
513 Also, don't send blocks that are already flying.
516 // Start with the usual maximum
517 u16 max_simul_dynamic = max_simul_sends_usually;
519 // If block is very close, allow full maximum
520 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
521 max_simul_dynamic = max_simul_sends_setting;
523 // Don't select too many blocks for sending
524 if(num_blocks_selected >= max_simul_dynamic)
526 queue_is_full = true;
527 goto queue_full_break;
530 // Don't send blocks that are currently being transferred
531 if(m_blocks_sending.find(p) != NULL)
537 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
538 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
539 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
540 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
541 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
542 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
545 // If this is true, inexistent block will be made from scratch
546 bool generate = d <= d_max_gen;
549 /*// Limit the generating area vertically to 2/3
550 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
553 // Limit the send area vertically to 2/3
554 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
560 If block is far away, don't generate it unless it is
566 // Block center y in nodes
567 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
568 // Don't generate if it's very high or very low
569 if(y < -64 || y > 64)
573 v2s16 p2d_nodes_center(
577 // Get ground height in nodes
578 s16 gh = server->m_env.getServerMap().findGroundLevel(
581 // If differs a lot, don't generate
582 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
584 // Actually, don't even send it
590 //infostream<<"d="<<d<<std::endl;
593 Don't generate or send if not in sight
594 FIXME This only works if the client uses a small enough
595 FOV setting. The default of 72 degrees is fine.
598 float camera_fov = (72.0*PI/180) * 4./3.;
599 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
605 Don't send already sent blocks
608 if(m_blocks_sent.find(p) != NULL)
615 Check if map has this block
617 MapBlock *block = server->m_env.getMap().getBlockNoCreateNoEx(p);
619 bool surely_not_found_on_disk = false;
620 bool block_is_invalid = false;
623 // Reset usage timer, this block will be of use in the future.
624 block->resetUsageTimer();
626 // Block is dummy if data doesn't exist.
627 // It means it has been not found from disk and not generated
630 surely_not_found_on_disk = true;
633 // Block is valid if lighting is up-to-date and data exists
634 if(block->isValid() == false)
636 block_is_invalid = true;
639 /*if(block->isFullyGenerated() == false)
641 block_is_invalid = true;
646 ServerMap *map = (ServerMap*)(&server->m_env.getMap());
647 v2s16 chunkpos = map->sector_to_chunk(p2d);
648 if(map->chunkNonVolatile(chunkpos) == false)
649 block_is_invalid = true;
651 if(block->isGenerated() == false)
652 block_is_invalid = true;
655 If block is not close, don't send it unless it is near
658 Block is near ground level if night-time mesh
659 differs from day-time mesh.
663 if(block->dayNightDiffed() == false)
670 If block has been marked to not exist on disk (dummy)
671 and generating new ones is not wanted, skip block.
673 if(generate == false && surely_not_found_on_disk == true)
680 Record the lowest d from which a block has been
681 found being not sent and possibly to exist
683 if(no_blocks_found_for_sending)
686 new_nearest_unsent_d = d;
689 no_blocks_found_for_sending = false;
692 Add inexistent block to emerge queue.
694 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
696 //TODO: Get value from somewhere
697 // Allow only one block in emerge queue
698 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
699 // Allow two blocks in queue per client
700 if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
702 //infostream<<"Adding block to emerge queue"<<std::endl;
704 // Add it to the emerge queue and trigger the thread
707 if(generate == false)
708 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
710 server->m_emerge_queue.addBlock(peer_id, p, flags);
711 server->m_emergethread.trigger();
719 Add block to send queue
722 PrioritySortedBlockTransfer q((float)d, p, peer_id);
726 num_blocks_selected += 1;
727 sending_something = true;
732 //infostream<<"Stopped at "<<d<<std::endl;
734 if(no_blocks_found_for_sending)
736 if(queue_is_full == false)
737 new_nearest_unsent_d = d;
740 if(new_nearest_unsent_d != -1)
741 m_nearest_unsent_d = new_nearest_unsent_d;
743 if(sending_something == false)
745 m_nothing_to_send_counter++;
746 if((s16)m_nothing_to_send_counter >=
747 g_settings->getS16("max_block_send_distance"))
749 // Pause time in seconds
750 m_nothing_to_send_pause_timer = 1.0;
751 /*infostream<<"nothing to send to "
752 <<server->getPlayerName(peer_id)
753 <<" (d="<<d<<")"<<std::endl;*/
758 m_nothing_to_send_counter = 0;
761 /*timer_result = timer.stop(true);
762 if(timer_result != 0)
763 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
766 void RemoteClient::SendObjectData(
769 core::map<v3s16, bool> &stepped_blocks
772 DSTACK(__FUNCTION_NAME);
774 // Can't send anything without knowing version
775 if(serialization_version == SER_FMT_VER_INVALID)
777 infostream<<"RemoteClient::SendObjectData(): Not sending, no version."
783 Send a TOCLIENT_OBJECTDATA packet.
787 u16 number of player positions
799 std::ostringstream os(std::ios_base::binary);
803 writeU16(buf, TOCLIENT_OBJECTDATA);
804 os.write((char*)buf, 2);
807 Get and write player data
810 // Get connected players
811 core::list<Player*> players = server->m_env.getPlayers(true);
813 // Write player count
814 u16 playercount = players.size();
815 writeU16(buf, playercount);
816 os.write((char*)buf, 2);
818 core::list<Player*>::Iterator i;
819 for(i = players.begin();
820 i != players.end(); i++)
824 v3f pf = player->getPosition();
825 v3f sf = player->getSpeed();
827 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
828 v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
829 s32 pitch_i (player->getPitch() * 100);
830 s32 yaw_i (player->getYaw() * 100);
832 writeU16(buf, player->peer_id);
833 os.write((char*)buf, 2);
834 writeV3S32(buf, position_i);
835 os.write((char*)buf, 12);
836 writeV3S32(buf, speed_i);
837 os.write((char*)buf, 12);
838 writeS32(buf, pitch_i);
839 os.write((char*)buf, 4);
840 writeS32(buf, yaw_i);
841 os.write((char*)buf, 4);
845 Get and write object data (dummy, for compatibility)
850 os.write((char*)buf, 2);
856 //infostream<<"Server: Sending object data to "<<peer_id<<std::endl;
859 std::string s = os.str();
860 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
861 // Send as unreliable
862 server->m_con.Send(peer_id, 0, data, false);
865 void RemoteClient::GotBlock(v3s16 p)
867 if(m_blocks_sending.find(p) != NULL)
868 m_blocks_sending.remove(p);
871 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
872 " m_blocks_sending"<<std::endl;*/
873 m_excess_gotblocks++;
875 m_blocks_sent.insert(p, true);
878 void RemoteClient::SentBlock(v3s16 p)
880 if(m_blocks_sending.find(p) == NULL)
881 m_blocks_sending.insert(p, 0.0);
883 infostream<<"RemoteClient::SentBlock(): Sent block"
884 " already in m_blocks_sending"<<std::endl;
887 void RemoteClient::SetBlockNotSent(v3s16 p)
889 m_nearest_unsent_d = 0;
891 if(m_blocks_sending.find(p) != NULL)
892 m_blocks_sending.remove(p);
893 if(m_blocks_sent.find(p) != NULL)
894 m_blocks_sent.remove(p);
897 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
899 m_nearest_unsent_d = 0;
901 for(core::map<v3s16, MapBlock*>::Iterator
902 i = blocks.getIterator();
903 i.atEnd()==false; i++)
905 v3s16 p = i.getNode()->getKey();
907 if(m_blocks_sending.find(p) != NULL)
908 m_blocks_sending.remove(p);
909 if(m_blocks_sent.find(p) != NULL)
910 m_blocks_sent.remove(p);
918 PlayerInfo::PlayerInfo()
924 void PlayerInfo::PrintLine(std::ostream *s)
927 (*s)<<"\""<<name<<"\" ("
928 <<(position.X/10)<<","<<(position.Y/10)
929 <<","<<(position.Z/10)<<") ";
931 (*s)<<" avg_rtt="<<avg_rtt;
935 u32 PIChecksum(core::list<PlayerInfo> &l)
937 core::list<PlayerInfo>::Iterator i;
940 for(i=l.begin(); i!=l.end(); i++)
942 checksum += a * (i->id+1);
943 checksum ^= 0x435aafcd;
954 std::string mapsavedir,
955 std::string configpath
957 m_env(new ServerMap(mapsavedir), this),
958 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
959 m_authmanager(mapsavedir+"/auth.txt"),
960 m_banmanager(mapsavedir+"/ipban.txt"),
962 m_emergethread(this),
964 m_time_of_day_send_timer(0),
966 m_mapsavedir(mapsavedir),
967 m_configpath(configpath),
968 m_shutdown_requested(false),
969 m_ignore_map_edit_events(false),
970 m_ignore_map_edit_events_peer_id(0)
972 m_liquid_transform_timer = 0.0;
973 m_print_info_timer = 0.0;
974 m_objectdata_timer = 0.0;
975 m_emergethread_trigger_timer = 0.0;
976 m_savemap_timer = 0.0;
980 m_step_dtime_mutex.Init();
983 // Register us to receive map edit events
984 m_env.getMap().addEventReceiver(this);
986 // If file exists, load environment metadata
987 if(fs::PathExists(m_mapsavedir+"/env_meta.txt"))
989 infostream<<"Server: Loading environment metadata"<<std::endl;
990 m_env.loadMeta(m_mapsavedir);
994 infostream<<"Server: Loading players"<<std::endl;
995 m_env.deSerializePlayers(m_mapsavedir);
1000 infostream<<"Server::~Server()"<<std::endl;
1003 Send shutdown message
1006 JMutexAutoLock conlock(m_con_mutex);
1008 std::wstring line = L"*** Server shutting down";
1011 Send the message to clients
1013 for(core::map<u16, RemoteClient*>::Iterator
1014 i = m_clients.getIterator();
1015 i.atEnd() == false; i++)
1017 // Get client and check that it is valid
1018 RemoteClient *client = i.getNode()->getValue();
1019 assert(client->peer_id == i.getNode()->getKey());
1020 if(client->serialization_version == SER_FMT_VER_INVALID)
1024 SendChatMessage(client->peer_id, line);
1026 catch(con::PeerNotFoundException &e)
1032 JMutexAutoLock envlock(m_env_mutex);
1037 infostream<<"Server: Saving players"<<std::endl;
1038 m_env.serializePlayers(m_mapsavedir);
1041 Save environment metadata
1043 infostream<<"Server: Saving environment metadata"<<std::endl;
1044 m_env.saveMeta(m_mapsavedir);
1056 JMutexAutoLock clientslock(m_con_mutex);
1058 for(core::map<u16, RemoteClient*>::Iterator
1059 i = m_clients.getIterator();
1060 i.atEnd() == false; i++)
1063 // NOTE: These are removed by env destructor
1065 u16 peer_id = i.getNode()->getKey();
1066 JMutexAutoLock envlock(m_env_mutex);
1067 m_env.removePlayer(peer_id);
1071 delete i.getNode()->getValue();
1076 void Server::start(unsigned short port)
1078 DSTACK(__FUNCTION_NAME);
1079 // Stop thread if already running
1082 // Initialize connection
1083 m_con.setTimeoutMs(30);
1087 m_thread.setRun(true);
1090 infostream<<"Server: Started on port "<<port<<std::endl;
1095 DSTACK(__FUNCTION_NAME);
1097 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1099 // Stop threads (set run=false first so both start stopping)
1100 m_thread.setRun(false);
1101 m_emergethread.setRun(false);
1103 m_emergethread.stop();
1105 infostream<<"Server: Threads stopped"<<std::endl;
1108 void Server::step(float dtime)
1110 DSTACK(__FUNCTION_NAME);
1115 JMutexAutoLock lock(m_step_dtime_mutex);
1116 m_step_dtime += dtime;
1120 void Server::AsyncRunStep()
1122 DSTACK(__FUNCTION_NAME);
1124 g_profiler->add("Server::AsyncRunStep (num)", 1);
1128 JMutexAutoLock lock1(m_step_dtime_mutex);
1129 dtime = m_step_dtime;
1133 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
1134 // Send blocks to clients
1141 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1143 //infostream<<"Server steps "<<dtime<<std::endl;
1144 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1147 JMutexAutoLock lock1(m_step_dtime_mutex);
1148 m_step_dtime -= dtime;
1155 m_uptime.set(m_uptime.get() + dtime);
1159 // Process connection's timeouts
1160 JMutexAutoLock lock2(m_con_mutex);
1161 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1162 m_con.RunTimeouts(dtime);
1166 // This has to be called so that the client list gets synced
1167 // with the peer list of the connection
1168 handlePeerChanges();
1172 Update m_time_of_day and overall game time
1175 JMutexAutoLock envlock(m_env_mutex);
1177 m_time_counter += dtime;
1178 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1179 u32 units = (u32)(m_time_counter*speed);
1180 m_time_counter -= (f32)units / speed;
1182 m_env.setTimeOfDay((m_env.getTimeOfDay() + units) % 24000);
1184 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1187 Send to clients at constant intervals
1190 m_time_of_day_send_timer -= dtime;
1191 if(m_time_of_day_send_timer < 0.0)
1193 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1195 //JMutexAutoLock envlock(m_env_mutex);
1196 JMutexAutoLock conlock(m_con_mutex);
1198 for(core::map<u16, RemoteClient*>::Iterator
1199 i = m_clients.getIterator();
1200 i.atEnd() == false; i++)
1202 RemoteClient *client = i.getNode()->getValue();
1203 //Player *player = m_env.getPlayer(client->peer_id);
1205 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1206 m_env.getTimeOfDay());
1208 m_con.Send(client->peer_id, 0, data, true);
1214 JMutexAutoLock lock(m_env_mutex);
1216 ScopeProfiler sp(g_profiler, "SEnv step");
1217 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1221 const float map_timer_and_unload_dtime = 5.15;
1222 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1224 JMutexAutoLock lock(m_env_mutex);
1225 // Run Map's timers and unload unused data
1226 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1227 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
1228 g_settings->getFloat("server_unload_unused_data_timeout"));
1238 m_liquid_transform_timer += dtime;
1239 if(m_liquid_transform_timer >= 1.00)
1241 m_liquid_transform_timer -= 1.00;
1243 JMutexAutoLock lock(m_env_mutex);
1245 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1247 core::map<v3s16, MapBlock*> modified_blocks;
1248 m_env.getMap().transformLiquids(modified_blocks);
1253 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1254 ServerMap &map = ((ServerMap&)m_env.getMap());
1255 map.updateLighting(modified_blocks, lighting_modified_blocks);
1257 // Add blocks modified by lighting to modified_blocks
1258 for(core::map<v3s16, MapBlock*>::Iterator
1259 i = lighting_modified_blocks.getIterator();
1260 i.atEnd() == false; i++)
1262 MapBlock *block = i.getNode()->getValue();
1263 modified_blocks.insert(block->getPos(), block);
1267 Set the modified blocks unsent for all the clients
1270 JMutexAutoLock lock2(m_con_mutex);
1272 for(core::map<u16, RemoteClient*>::Iterator
1273 i = m_clients.getIterator();
1274 i.atEnd() == false; i++)
1276 RemoteClient *client = i.getNode()->getValue();
1278 if(modified_blocks.size() > 0)
1280 // Remove block from sent history
1281 client->SetBlocksNotSent(modified_blocks);
1286 // Periodically print some info
1288 float &counter = m_print_info_timer;
1294 JMutexAutoLock lock2(m_con_mutex);
1296 if(m_clients.size() != 0)
1297 infostream<<"Players:"<<std::endl;
1298 for(core::map<u16, RemoteClient*>::Iterator
1299 i = m_clients.getIterator();
1300 i.atEnd() == false; i++)
1302 //u16 peer_id = i.getNode()->getKey();
1303 RemoteClient *client = i.getNode()->getValue();
1304 Player *player = m_env.getPlayer(client->peer_id);
1307 infostream<<"* "<<player->getName()<<"\t";
1308 client->PrintInfo(infostream);
1313 //if(g_settings->getBool("enable_experimental"))
1317 Check added and deleted active objects
1320 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1321 JMutexAutoLock envlock(m_env_mutex);
1322 JMutexAutoLock conlock(m_con_mutex);
1324 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1326 // Radius inside which objects are active
1327 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1328 radius *= MAP_BLOCKSIZE;
1330 for(core::map<u16, RemoteClient*>::Iterator
1331 i = m_clients.getIterator();
1332 i.atEnd() == false; i++)
1334 RemoteClient *client = i.getNode()->getValue();
1335 Player *player = m_env.getPlayer(client->peer_id);
1338 // This can happen if the client timeouts somehow
1339 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1341 <<" has no associated player"<<std::endl;*/
1344 v3s16 pos = floatToInt(player->getPosition(), BS);
1346 core::map<u16, bool> removed_objects;
1347 core::map<u16, bool> added_objects;
1348 m_env.getRemovedActiveObjects(pos, radius,
1349 client->m_known_objects, removed_objects);
1350 m_env.getAddedActiveObjects(pos, radius,
1351 client->m_known_objects, added_objects);
1353 // Ignore if nothing happened
1354 if(removed_objects.size() == 0 && added_objects.size() == 0)
1356 //infostream<<"active objects: none changed"<<std::endl;
1360 std::string data_buffer;
1364 // Handle removed objects
1365 writeU16((u8*)buf, removed_objects.size());
1366 data_buffer.append(buf, 2);
1367 for(core::map<u16, bool>::Iterator
1368 i = removed_objects.getIterator();
1369 i.atEnd()==false; i++)
1372 u16 id = i.getNode()->getKey();
1373 ServerActiveObject* obj = m_env.getActiveObject(id);
1375 // Add to data buffer for sending
1376 writeU16((u8*)buf, i.getNode()->getKey());
1377 data_buffer.append(buf, 2);
1379 // Remove from known objects
1380 client->m_known_objects.remove(i.getNode()->getKey());
1382 if(obj && obj->m_known_by_count > 0)
1383 obj->m_known_by_count--;
1386 // Handle added objects
1387 writeU16((u8*)buf, added_objects.size());
1388 data_buffer.append(buf, 2);
1389 for(core::map<u16, bool>::Iterator
1390 i = added_objects.getIterator();
1391 i.atEnd()==false; i++)
1394 u16 id = i.getNode()->getKey();
1395 ServerActiveObject* obj = m_env.getActiveObject(id);
1398 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1400 infostream<<"WARNING: "<<__FUNCTION_NAME
1401 <<": NULL object"<<std::endl;
1403 type = obj->getType();
1405 // Add to data buffer for sending
1406 writeU16((u8*)buf, id);
1407 data_buffer.append(buf, 2);
1408 writeU8((u8*)buf, type);
1409 data_buffer.append(buf, 1);
1412 data_buffer.append(serializeLongString(
1413 obj->getClientInitializationData()));
1415 data_buffer.append(serializeLongString(""));
1417 // Add to known objects
1418 client->m_known_objects.insert(i.getNode()->getKey(), false);
1421 obj->m_known_by_count++;
1425 SharedBuffer<u8> reply(2 + data_buffer.size());
1426 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1427 memcpy((char*)&reply[2], data_buffer.c_str(),
1428 data_buffer.size());
1430 m_con.Send(client->peer_id, 0, reply, true);
1432 infostream<<"Server: Sent object remove/add: "
1433 <<removed_objects.size()<<" removed, "
1434 <<added_objects.size()<<" added, "
1435 <<"packet size is "<<reply.getSize()<<std::endl;
1440 Collect a list of all the objects known by the clients
1441 and report it back to the environment.
1444 core::map<u16, bool> all_known_objects;
1446 for(core::map<u16, RemoteClient*>::Iterator
1447 i = m_clients.getIterator();
1448 i.atEnd() == false; i++)
1450 RemoteClient *client = i.getNode()->getValue();
1451 // Go through all known objects of client
1452 for(core::map<u16, bool>::Iterator
1453 i = client->m_known_objects.getIterator();
1454 i.atEnd()==false; i++)
1456 u16 id = i.getNode()->getKey();
1457 all_known_objects[id] = true;
1461 m_env.setKnownActiveObjects(whatever);
1467 Send object messages
1470 JMutexAutoLock envlock(m_env_mutex);
1471 JMutexAutoLock conlock(m_con_mutex);
1473 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1476 // Value = data sent by object
1477 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1479 // Get active object messages from environment
1482 ActiveObjectMessage aom = m_env.getActiveObjectMessage();
1486 core::list<ActiveObjectMessage>* message_list = NULL;
1487 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1488 n = buffered_messages.find(aom.id);
1491 message_list = new core::list<ActiveObjectMessage>;
1492 buffered_messages.insert(aom.id, message_list);
1496 message_list = n->getValue();
1498 message_list->push_back(aom);
1501 // Route data to every client
1502 for(core::map<u16, RemoteClient*>::Iterator
1503 i = m_clients.getIterator();
1504 i.atEnd()==false; i++)
1506 RemoteClient *client = i.getNode()->getValue();
1507 std::string reliable_data;
1508 std::string unreliable_data;
1509 // Go through all objects in message buffer
1510 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1511 j = buffered_messages.getIterator();
1512 j.atEnd()==false; j++)
1514 // If object is not known by client, skip it
1515 u16 id = j.getNode()->getKey();
1516 if(client->m_known_objects.find(id) == NULL)
1518 // Get message list of object
1519 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1520 // Go through every message
1521 for(core::list<ActiveObjectMessage>::Iterator
1522 k = list->begin(); k != list->end(); k++)
1524 // Compose the full new data with header
1525 ActiveObjectMessage aom = *k;
1526 std::string new_data;
1529 writeU16((u8*)&buf[0], aom.id);
1530 new_data.append(buf, 2);
1532 new_data += serializeString(aom.datastring);
1533 // Add data to buffer
1535 reliable_data += new_data;
1537 unreliable_data += new_data;
1541 reliable_data and unreliable_data are now ready.
1544 if(reliable_data.size() > 0)
1546 SharedBuffer<u8> reply(2 + reliable_data.size());
1547 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1548 memcpy((char*)&reply[2], reliable_data.c_str(),
1549 reliable_data.size());
1551 m_con.Send(client->peer_id, 0, reply, true);
1553 if(unreliable_data.size() > 0)
1555 SharedBuffer<u8> reply(2 + unreliable_data.size());
1556 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1557 memcpy((char*)&reply[2], unreliable_data.c_str(),
1558 unreliable_data.size());
1559 // Send as unreliable
1560 m_con.Send(client->peer_id, 0, reply, false);
1563 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1565 infostream<<"Server: Size of object message data: "
1566 <<"reliable: "<<reliable_data.size()
1567 <<", unreliable: "<<unreliable_data.size()
1572 // Clear buffered_messages
1573 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1574 i = buffered_messages.getIterator();
1575 i.atEnd()==false; i++)
1577 delete i.getNode()->getValue();
1581 } // enable_experimental
1584 Send queued-for-sending map edit events.
1587 // Don't send too many at a time
1590 // Single change sending is disabled if queue size is not small
1591 bool disable_single_change_sending = false;
1592 if(m_unsent_map_edit_queue.size() >= 4)
1593 disable_single_change_sending = true;
1595 bool got_any_events = false;
1597 // We'll log the amount of each
1600 while(m_unsent_map_edit_queue.size() != 0)
1602 got_any_events = true;
1604 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1606 // Players far away from the change are stored here.
1607 // Instead of sending the changes, MapBlocks are set not sent
1609 core::list<u16> far_players;
1611 if(event->type == MEET_ADDNODE)
1613 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1614 prof.add("MEET_ADDNODE", 1);
1615 if(disable_single_change_sending)
1616 sendAddNode(event->p, event->n, event->already_known_by_peer,
1619 sendAddNode(event->p, event->n, event->already_known_by_peer,
1622 else if(event->type == MEET_REMOVENODE)
1624 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1625 prof.add("MEET_REMOVENODE", 1);
1626 if(disable_single_change_sending)
1627 sendRemoveNode(event->p, event->already_known_by_peer,
1630 sendRemoveNode(event->p, event->already_known_by_peer,
1633 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1635 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1636 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1637 setBlockNotSent(event->p);
1639 else if(event->type == MEET_OTHER)
1641 infostream<<"Server: MEET_OTHER"<<std::endl;
1642 prof.add("MEET_OTHER", 1);
1643 for(core::map<v3s16, bool>::Iterator
1644 i = event->modified_blocks.getIterator();
1645 i.atEnd()==false; i++)
1647 v3s16 p = i.getNode()->getKey();
1653 prof.add("unknown", 1);
1654 infostream<<"WARNING: Server: Unknown MapEditEvent "
1655 <<((u32)event->type)<<std::endl;
1659 Set blocks not sent to far players
1661 if(far_players.size() > 0)
1663 // Convert list format to that wanted by SetBlocksNotSent
1664 core::map<v3s16, MapBlock*> modified_blocks2;
1665 for(core::map<v3s16, bool>::Iterator
1666 i = event->modified_blocks.getIterator();
1667 i.atEnd()==false; i++)
1669 v3s16 p = i.getNode()->getKey();
1670 modified_blocks2.insert(p,
1671 m_env.getMap().getBlockNoCreateNoEx(p));
1673 // Set blocks not sent
1674 for(core::list<u16>::Iterator
1675 i = far_players.begin();
1676 i != far_players.end(); i++)
1679 RemoteClient *client = getClient(peer_id);
1682 client->SetBlocksNotSent(modified_blocks2);
1688 /*// Don't send too many at a time
1690 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1696 infostream<<"Server: MapEditEvents:"<<std::endl;
1697 prof.print(infostream);
1703 Send object positions
1706 float &counter = m_objectdata_timer;
1708 if(counter >= g_settings->getFloat("objectdata_interval"))
1710 JMutexAutoLock lock1(m_env_mutex);
1711 JMutexAutoLock lock2(m_con_mutex);
1713 ScopeProfiler sp(g_profiler, "Server: sending player positions");
1715 SendObjectData(counter);
1722 Trigger emergethread (it somehow gets to a non-triggered but
1723 bysy state sometimes)
1726 float &counter = m_emergethread_trigger_timer;
1732 m_emergethread.trigger();
1736 // Save map, players and auth stuff
1738 float &counter = m_savemap_timer;
1740 if(counter >= g_settings->getFloat("server_map_save_interval"))
1744 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1747 if(m_authmanager.isModified())
1748 m_authmanager.save();
1751 if(m_banmanager.isModified())
1752 m_banmanager.save();
1755 JMutexAutoLock lock(m_env_mutex);
1757 /*// Unload unused data (delete from memory)
1758 m_env.getMap().unloadUnusedData(
1759 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1761 /*u32 deleted_count = m_env.getMap().unloadUnusedData(
1762 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1765 // Save only changed parts
1766 m_env.getMap().save(true);
1768 /*if(deleted_count > 0)
1770 infostream<<"Server: Unloaded "<<deleted_count
1771 <<" blocks from memory"<<std::endl;
1775 m_env.serializePlayers(m_mapsavedir);
1777 // Save environment metadata
1778 m_env.saveMeta(m_mapsavedir);
1783 void Server::Receive()
1785 DSTACK(__FUNCTION_NAME);
1786 u32 data_maxsize = 10000;
1787 Buffer<u8> data(data_maxsize);
1792 JMutexAutoLock conlock(m_con_mutex);
1793 datasize = m_con.Receive(peer_id, *data, data_maxsize);
1796 // This has to be called so that the client list gets synced
1797 // with the peer list of the connection
1798 handlePeerChanges();
1800 ProcessData(*data, datasize, peer_id);
1802 catch(con::InvalidIncomingDataException &e)
1804 infostream<<"Server::Receive(): "
1805 "InvalidIncomingDataException: what()="
1806 <<e.what()<<std::endl;
1808 catch(con::PeerNotFoundException &e)
1810 //NOTE: This is not needed anymore
1812 // The peer has been disconnected.
1813 // Find the associated player and remove it.
1815 /*JMutexAutoLock envlock(m_env_mutex);
1817 infostream<<"ServerThread: peer_id="<<peer_id
1818 <<" has apparently closed connection. "
1819 <<"Removing player."<<std::endl;
1821 m_env.removePlayer(peer_id);*/
1825 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1827 DSTACK(__FUNCTION_NAME);
1828 // Environment is locked first.
1829 JMutexAutoLock envlock(m_env_mutex);
1830 JMutexAutoLock conlock(m_con_mutex);
1834 peer = m_con.GetPeer(peer_id);
1836 catch(con::PeerNotFoundException &e)
1838 infostream<<"Server::ProcessData(): Cancelling: peer "
1839 <<peer_id<<" not found"<<std::endl;
1843 // drop player if is ip is banned
1844 if(m_banmanager.isIpBanned(peer->address.serializeString())){
1845 SendAccessDenied(m_con, peer_id,
1846 L"Your ip is banned. Banned name was "
1847 +narrow_to_wide(m_banmanager.getBanName(
1848 peer->address.serializeString())));
1849 m_con.deletePeer(peer_id, false);
1853 u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1861 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1863 if(command == TOSERVER_INIT)
1865 // [0] u16 TOSERVER_INIT
1866 // [2] u8 SER_FMT_VER_HIGHEST
1867 // [3] u8[20] player_name
1868 // [23] u8[28] password <--- can be sent without this, from old versions
1870 if(datasize < 2+1+PLAYERNAME_SIZE)
1873 infostream<<"Server: Got TOSERVER_INIT from "
1874 <<peer->id<<std::endl;
1876 // First byte after command is maximum supported
1877 // serialization version
1878 u8 client_max = data[2];
1879 u8 our_max = SER_FMT_VER_HIGHEST;
1880 // Use the highest version supported by both
1881 u8 deployed = core::min_(client_max, our_max);
1882 // If it's lower than the lowest supported, give up.
1883 if(deployed < SER_FMT_VER_LOWEST)
1884 deployed = SER_FMT_VER_INVALID;
1886 //peer->serialization_version = deployed;
1887 getClient(peer->id)->pending_serialization_version = deployed;
1889 if(deployed == SER_FMT_VER_INVALID)
1891 infostream<<"Server: Cannot negotiate "
1892 "serialization version with peer "
1893 <<peer_id<<std::endl;
1894 SendAccessDenied(m_con, peer_id,
1895 L"Your client is too old (map format)");
1900 Read and check network protocol version
1903 u16 net_proto_version = 0;
1904 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1906 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1909 getClient(peer->id)->net_proto_version = net_proto_version;
1911 if(net_proto_version == 0)
1913 SendAccessDenied(m_con, peer_id,
1914 L"Your client is too old. Please upgrade.");
1918 /* Uhh... this should actually be a warning but let's do it like this */
1919 if(g_settings->getBool("strict_protocol_version_checking"))
1921 if(net_proto_version < PROTOCOL_VERSION)
1923 SendAccessDenied(m_con, peer_id,
1924 L"Your client is too old. Please upgrade.");
1934 char playername[PLAYERNAME_SIZE];
1935 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1937 playername[i] = data[3+i];
1939 playername[PLAYERNAME_SIZE-1] = 0;
1941 if(playername[0]=='\0')
1943 infostream<<"Server: Player has empty name"<<std::endl;
1944 SendAccessDenied(m_con, peer_id,
1949 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1951 infostream<<"Server: Player has invalid name"<<std::endl;
1952 SendAccessDenied(m_con, peer_id,
1953 L"Name contains unallowed characters");
1958 char password[PASSWORD_SIZE];
1959 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1961 // old version - assume blank password
1966 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1968 password[i] = data[23+i];
1970 password[PASSWORD_SIZE-1] = 0;
1973 std::string checkpwd;
1974 if(m_authmanager.exists(playername))
1976 checkpwd = m_authmanager.getPassword(playername);
1980 checkpwd = g_settings->get("default_password");
1983 /*infostream<<"Server: Client gave password '"<<password
1984 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
1986 if(password != checkpwd && m_authmanager.exists(playername))
1988 infostream<<"Server: peer_id="<<peer_id
1989 <<": supplied invalid password for "
1990 <<playername<<std::endl;
1991 SendAccessDenied(m_con, peer_id, L"Invalid password");
1995 // Add player to auth manager
1996 if(m_authmanager.exists(playername) == false)
1998 infostream<<"Server: adding player "<<playername
1999 <<" to auth manager"<<std::endl;
2000 m_authmanager.add(playername);
2001 m_authmanager.setPassword(playername, checkpwd);
2002 m_authmanager.setPrivs(playername,
2003 stringToPrivs(g_settings->get("default_privs")));
2004 m_authmanager.save();
2007 // Enforce user limit.
2008 // Don't enforce for users that have some admin right
2009 if(m_clients.size() >= g_settings->getU16("max_users") &&
2010 (m_authmanager.getPrivs(playername)
2011 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 &&
2012 playername != g_settings->get("name"))
2014 SendAccessDenied(m_con, peer_id, L"Too many users.");
2019 Player *player = emergePlayer(playername, password, peer_id);
2021 // If failed, cancel
2024 infostream<<"Server: peer_id="<<peer_id
2025 <<": failed to emerge player"<<std::endl;
2030 Answer with a TOCLIENT_INIT
2033 SharedBuffer<u8> reply(2+1+6+8);
2034 writeU16(&reply[0], TOCLIENT_INIT);
2035 writeU8(&reply[2], deployed);
2036 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2037 writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2040 m_con.Send(peer_id, 0, reply, true);
2044 Send complete position information
2046 SendMovePlayer(player);
2051 if(command == TOSERVER_INIT2)
2053 infostream<<"Server: Got TOSERVER_INIT2 from "
2054 <<peer->id<<std::endl;
2057 getClient(peer->id)->serialization_version
2058 = getClient(peer->id)->pending_serialization_version;
2061 Send some initialization data
2064 // Send player info to all players
2067 // Send inventory to player
2068 UpdateCrafting(peer->id);
2069 SendInventory(peer->id);
2071 // Send player items to all players
2074 Player *player = m_env.getPlayer(peer_id);
2077 SendPlayerHP(player);
2081 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2082 m_env.getTimeOfDay());
2083 m_con.Send(peer->id, 0, data, true);
2086 // Send information about server to player in chat
2087 SendChatMessage(peer_id, getStatusString());
2089 // Send information about joining in chat
2091 std::wstring name = L"unknown";
2092 Player *player = m_env.getPlayer(peer_id);
2094 name = narrow_to_wide(player->getName());
2096 std::wstring message;
2099 message += L" joined game";
2100 BroadcastChatMessage(message);
2103 // Warnings about protocol version can be issued here
2104 if(getClient(peer->id)->net_proto_version < PROTOCOL_VERSION)
2106 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2110 Check HP, respawn if necessary
2112 HandlePlayerHP(player, 0);
2118 std::ostringstream os(std::ios_base::binary);
2119 for(core::map<u16, RemoteClient*>::Iterator
2120 i = m_clients.getIterator();
2121 i.atEnd() == false; i++)
2123 RemoteClient *client = i.getNode()->getValue();
2124 assert(client->peer_id == i.getNode()->getKey());
2125 if(client->serialization_version == SER_FMT_VER_INVALID)
2128 Player *player = m_env.getPlayer(client->peer_id);
2131 // Get name of player
2132 os<<player->getName()<<" ";
2135 actionstream<<player->getName()<<" joins game. List of players: "
2136 <<os.str()<<std::endl;
2142 if(peer_ser_ver == SER_FMT_VER_INVALID)
2144 infostream<<"Server::ProcessData(): Cancelling: Peer"
2145 " serialization format invalid or not initialized."
2146 " Skipping incoming command="<<command<<std::endl;
2150 Player *player = m_env.getPlayer(peer_id);
2153 infostream<<"Server::ProcessData(): Cancelling: "
2154 "No player for peer_id="<<peer_id
2158 if(command == TOSERVER_PLAYERPOS)
2160 if(datasize < 2+12+12+4+4)
2164 v3s32 ps = readV3S32(&data[start+2]);
2165 v3s32 ss = readV3S32(&data[start+2+12]);
2166 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2167 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2168 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2169 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2170 pitch = wrapDegrees(pitch);
2171 yaw = wrapDegrees(yaw);
2173 player->setPosition(position);
2174 player->setSpeed(speed);
2175 player->setPitch(pitch);
2176 player->setYaw(yaw);
2178 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2179 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2180 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2182 else if(command == TOSERVER_GOTBLOCKS)
2195 u16 count = data[2];
2196 for(u16 i=0; i<count; i++)
2198 if((s16)datasize < 2+1+(i+1)*6)
2199 throw con::InvalidIncomingDataException
2200 ("GOTBLOCKS length is too short");
2201 v3s16 p = readV3S16(&data[2+1+i*6]);
2202 /*infostream<<"Server: GOTBLOCKS ("
2203 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2204 RemoteClient *client = getClient(peer_id);
2205 client->GotBlock(p);
2208 else if(command == TOSERVER_DELETEDBLOCKS)
2221 u16 count = data[2];
2222 for(u16 i=0; i<count; i++)
2224 if((s16)datasize < 2+1+(i+1)*6)
2225 throw con::InvalidIncomingDataException
2226 ("DELETEDBLOCKS length is too short");
2227 v3s16 p = readV3S16(&data[2+1+i*6]);
2228 /*infostream<<"Server: DELETEDBLOCKS ("
2229 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2230 RemoteClient *client = getClient(peer_id);
2231 client->SetBlockNotSent(p);
2234 else if(command == TOSERVER_CLICK_OBJECT)
2236 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2239 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2244 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2250 [2] u8 button (0=left, 1=right)
2254 u8 button = readU8(&data[2]);
2255 u16 id = readS16(&data[3]);
2256 u16 item_i = readU16(&data[5]);
2258 ServerActiveObject *obj = m_env.getActiveObject(id);
2262 infostream<<"Server: CLICK_ACTIVEOBJECT: object not found"
2267 // Skip if object has been removed
2271 //TODO: Check that object is reasonably close
2273 // Left click, pick object up (usually)
2277 Try creating inventory item
2279 InventoryItem *item = obj->createPickedUpItem();
2283 InventoryList *ilist = player->inventory.getList("main");
2286 actionstream<<player->getName()<<" picked up "
2287 <<item->getName()<<std::endl;
2288 if(g_settings->getBool("creative_mode") == false)
2290 // Skip if inventory has no free space
2291 if(ilist->roomForItem(item) == false)
2293 infostream<<"Player inventory has no free space"<<std::endl;
2297 // Add to inventory and send inventory
2298 ilist->addItem(item);
2299 UpdateCrafting(player->peer_id);
2300 SendInventory(player->peer_id);
2303 // Remove object from environment
2304 obj->m_removed = true;
2310 Item cannot be picked up. Punch it instead.
2313 actionstream<<player->getName()<<" punches object "
2314 <<obj->getId()<<std::endl;
2316 ToolItem *titem = NULL;
2317 std::string toolname = "";
2319 InventoryList *mlist = player->inventory.getList("main");
2322 InventoryItem *item = mlist->getItem(item_i);
2323 if(item && (std::string)item->getName() == "ToolItem")
2325 titem = (ToolItem*)item;
2326 toolname = titem->getToolName();
2330 v3f playerpos = player->getPosition();
2331 v3f objpos = obj->getBasePosition();
2332 v3f dir = (objpos - playerpos).normalize();
2334 u16 wear = obj->punch(toolname, dir, player->getName());
2338 bool weared_out = titem->addWear(wear);
2340 mlist->deleteItem(item_i);
2341 SendInventory(player->peer_id);
2345 // Right click, do something with object
2348 actionstream<<player->getName()<<" right clicks object "
2349 <<obj->getId()<<std::endl;
2351 // Track hp changes super-crappily
2352 u16 oldhp = player->hp;
2355 obj->rightClick(player);
2358 if(player->hp != oldhp)
2360 SendPlayerHP(player);
2364 else if(command == TOSERVER_GROUND_ACTION)
2372 [3] v3s16 nodepos_undersurface
2373 [9] v3s16 nodepos_abovesurface
2378 2: stop digging (all parameters ignored)
2379 3: digging completed
2381 u8 action = readU8(&data[2]);
2383 p_under.X = readS16(&data[3]);
2384 p_under.Y = readS16(&data[5]);
2385 p_under.Z = readS16(&data[7]);
2387 p_over.X = readS16(&data[9]);
2388 p_over.Y = readS16(&data[11]);
2389 p_over.Z = readS16(&data[13]);
2390 u16 item_i = readU16(&data[15]);
2392 //TODO: Check that target is reasonably close
2400 NOTE: This can be used in the future to check if
2401 somebody is cheating, by checking the timing.
2408 else if(action == 2)
2411 RemoteClient *client = getClient(peer->id);
2412 JMutexAutoLock digmutex(client->m_dig_mutex);
2413 client->m_dig_tool_item = -1;
2418 3: Digging completed
2420 else if(action == 3)
2422 // Mandatory parameter; actually used for nothing
2423 core::map<v3s16, MapBlock*> modified_blocks;
2425 content_t material = CONTENT_IGNORE;
2426 u8 mineral = MINERAL_NONE;
2428 bool cannot_remove_node = false;
2432 MapNode n = m_env.getMap().getNode(p_under);
2434 mineral = n.getMineral();
2435 // Get material at position
2436 material = n.getContent();
2437 // If not yet cancelled
2438 if(cannot_remove_node == false)
2440 // If it's not diggable, do nothing
2441 if(content_diggable(material) == false)
2443 infostream<<"Server: Not finishing digging: "
2444 <<"Node not diggable"
2446 cannot_remove_node = true;
2449 // If not yet cancelled
2450 if(cannot_remove_node == false)
2452 // Get node metadata
2453 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2454 if(meta && meta->nodeRemovalDisabled() == true)
2456 infostream<<"Server: Not finishing digging: "
2457 <<"Node metadata disables removal"
2459 cannot_remove_node = true;
2463 catch(InvalidPositionException &e)
2465 infostream<<"Server: Not finishing digging: Node not found."
2466 <<" Adding block to emerge queue."
2468 m_emerge_queue.addBlock(peer_id,
2469 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2470 cannot_remove_node = true;
2473 // Make sure the player is allowed to do it
2474 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2476 infostream<<"Player "<<player->getName()<<" cannot remove node"
2477 <<" because privileges are "<<getPlayerPrivs(player)
2479 cannot_remove_node = true;
2483 If node can't be removed, set block to be re-sent to
2486 if(cannot_remove_node)
2488 infostream<<"Server: Not finishing digging."<<std::endl;
2490 // Client probably has wrong data.
2491 // Set block not sent, so that client will get
2493 infostream<<"Client "<<peer_id<<" tried to dig "
2494 <<"node; but node cannot be removed."
2495 <<" setting MapBlock not sent."<<std::endl;
2496 RemoteClient *client = getClient(peer_id);
2497 v3s16 blockpos = getNodeBlockPos(p_under);
2498 client->SetBlockNotSent(blockpos);
2503 actionstream<<player->getName()<<" digs "<<PP(p_under)
2504 <<", gets material "<<(int)material<<", mineral "
2505 <<(int)mineral<<std::endl;
2508 Send the removal to all close-by players.
2509 - If other player is close, send REMOVENODE
2510 - Otherwise set blocks not sent
2512 core::list<u16> far_players;
2513 sendRemoveNode(p_under, peer_id, &far_players, 30);
2516 Update and send inventory
2519 if(g_settings->getBool("creative_mode") == false)
2524 InventoryList *mlist = player->inventory.getList("main");
2527 InventoryItem *item = mlist->getItem(item_i);
2528 if(item && (std::string)item->getName() == "ToolItem")
2530 ToolItem *titem = (ToolItem*)item;
2531 std::string toolname = titem->getToolName();
2533 // Get digging properties for material and tool
2534 DiggingProperties prop =
2535 getDiggingProperties(material, toolname);
2537 if(prop.diggable == false)
2539 infostream<<"Server: WARNING: Player digged"
2540 <<" with impossible material + tool"
2541 <<" combination"<<std::endl;
2544 bool weared_out = titem->addWear(prop.wear);
2548 mlist->deleteItem(item_i);
2554 Add dug item to inventory
2557 InventoryItem *item = NULL;
2559 if(mineral != MINERAL_NONE)
2560 item = getDiggedMineralItem(mineral);
2565 std::string &dug_s = content_features(material).dug_item;
2568 std::istringstream is(dug_s, std::ios::binary);
2569 item = InventoryItem::deSerialize(is);
2575 // Add a item to inventory
2576 player->inventory.addItem("main", item);
2579 UpdateCrafting(player->peer_id);
2580 SendInventory(player->peer_id);
2585 if(mineral != MINERAL_NONE)
2586 item = getDiggedMineralItem(mineral);
2591 std::string &extra_dug_s = content_features(material).extra_dug_item;
2592 s32 extra_rarity = content_features(material).extra_dug_item_rarity;
2593 if(extra_dug_s != "" && extra_rarity != 0
2594 && myrand() % extra_rarity == 0)
2596 std::istringstream is(extra_dug_s, std::ios::binary);
2597 item = InventoryItem::deSerialize(is);
2603 // Add a item to inventory
2604 player->inventory.addItem("main", item);
2607 UpdateCrafting(player->peer_id);
2608 SendInventory(player->peer_id);
2614 (this takes some time so it is done after the quick stuff)
2617 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2619 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2622 Set blocks not sent to far players
2624 for(core::list<u16>::Iterator
2625 i = far_players.begin();
2626 i != far_players.end(); i++)
2629 RemoteClient *client = getClient(peer_id);
2632 client->SetBlocksNotSent(modified_blocks);
2639 else if(action == 1)
2642 InventoryList *ilist = player->inventory.getList("main");
2647 InventoryItem *item = ilist->getItem(item_i);
2649 // If there is no item, it is not possible to add it anywhere
2654 Handle material items
2656 if(std::string("MaterialItem") == item->getName())
2659 // Don't add a node if this is not a free space
2660 MapNode n2 = m_env.getMap().getNode(p_over);
2661 bool no_enough_privs =
2662 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2664 infostream<<"Player "<<player->getName()<<" cannot add node"
2665 <<" because privileges are "<<getPlayerPrivs(player)
2668 if(content_features(n2).buildable_to == false
2671 // Client probably has wrong data.
2672 // Set block not sent, so that client will get
2674 infostream<<"Client "<<peer_id<<" tried to place"
2675 <<" node in invalid position; setting"
2676 <<" MapBlock not sent."<<std::endl;
2677 RemoteClient *client = getClient(peer_id);
2678 v3s16 blockpos = getNodeBlockPos(p_over);
2679 client->SetBlockNotSent(blockpos);
2683 catch(InvalidPositionException &e)
2685 infostream<<"Server: Ignoring ADDNODE: Node not found"
2686 <<" Adding block to emerge queue."
2688 m_emerge_queue.addBlock(peer_id,
2689 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2693 // Reset build time counter
2694 getClient(peer->id)->m_time_from_building = 0.0;
2697 MaterialItem *mitem = (MaterialItem*)item;
2699 n.setContent(mitem->getMaterial());
2701 actionstream<<player->getName()<<" places material "
2702 <<(int)mitem->getMaterial()
2703 <<" at "<<PP(p_under)<<std::endl;
2705 // Calculate direction for wall mounted stuff
2706 if(content_features(n).wall_mounted)
2707 n.param2 = packDir(p_under - p_over);
2709 // Calculate the direction for furnaces and chests and stuff
2710 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2712 v3f playerpos = player->getPosition();
2713 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2714 blockpos = blockpos.normalize();
2716 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2730 Send to all close-by players
2732 core::list<u16> far_players;
2733 sendAddNode(p_over, n, 0, &far_players, 30);
2738 InventoryList *ilist = player->inventory.getList("main");
2739 if(g_settings->getBool("creative_mode") == false && ilist)
2741 // Remove from inventory and send inventory
2742 if(mitem->getCount() == 1)
2743 ilist->deleteItem(item_i);
2747 UpdateCrafting(peer_id);
2748 SendInventory(peer_id);
2754 This takes some time so it is done after the quick stuff
2756 core::map<v3s16, MapBlock*> modified_blocks;
2758 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2760 std::string p_name = std::string(player->getName());
2761 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
2764 Set blocks not sent to far players
2766 for(core::list<u16>::Iterator
2767 i = far_players.begin();
2768 i != far_players.end(); i++)
2771 RemoteClient *client = getClient(peer_id);
2774 client->SetBlocksNotSent(modified_blocks);
2778 Calculate special events
2781 /*if(n.d == CONTENT_MESE)
2784 for(s16 z=-1; z<=1; z++)
2785 for(s16 y=-1; y<=1; y++)
2786 for(s16 x=-1; x<=1; x++)
2793 Place other item (not a block)
2797 v3s16 blockpos = getNodeBlockPos(p_over);
2800 Check that the block is loaded so that the item
2801 can properly be added to the static list too
2803 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2806 infostream<<"Error while placing object: "
2807 "block not found"<<std::endl;
2812 If in creative mode, item dropping is disabled unless
2813 player has build privileges
2815 if(g_settings->getBool("creative_mode") &&
2816 (getPlayerPrivs(player) & PRIV_BUILD) == 0)
2818 infostream<<"Not allowing player to drop item: "
2819 "creative mode and no build privs"<<std::endl;
2823 // Calculate a position for it
2824 v3f pos = intToFloat(p_over, BS);
2826 pos.Y -= BS*0.25; // let it drop a bit
2828 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2829 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2834 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2838 infostream<<"WARNING: item resulted in NULL object, "
2839 <<"not placing onto map"
2844 actionstream<<player->getName()<<" places "<<item->getName()
2845 <<" at "<<PP(p_over)<<std::endl;
2847 // Add the object to the environment
2848 m_env.addActiveObject(obj);
2850 infostream<<"Placed object"<<std::endl;
2852 if(g_settings->getBool("creative_mode") == false)
2854 // Delete the right amount of items from the slot
2855 u16 dropcount = item->getDropCount();
2857 // Delete item if all gone
2858 if(item->getCount() <= dropcount)
2860 if(item->getCount() < dropcount)
2861 infostream<<"WARNING: Server: dropped more items"
2862 <<" than the slot contains"<<std::endl;
2864 InventoryList *ilist = player->inventory.getList("main");
2866 // Remove from inventory and send inventory
2867 ilist->deleteItem(item_i);
2869 // Else decrement it
2871 item->remove(dropcount);
2874 UpdateCrafting(peer_id);
2875 SendInventory(peer_id);
2883 Catch invalid actions
2887 infostream<<"WARNING: Server: Invalid action "
2888 <<action<<std::endl;
2892 else if(command == TOSERVER_RELEASE)
2901 infostream<<"TOSERVER_RELEASE ignored"<<std::endl;
2904 else if(command == TOSERVER_SIGNTEXT)
2906 infostream<<"Server: TOSERVER_SIGNTEXT not supported anymore"
2910 else if(command == TOSERVER_SIGNNODETEXT)
2912 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2920 std::string datastring((char*)&data[2], datasize-2);
2921 std::istringstream is(datastring, std::ios_base::binary);
2924 is.read((char*)buf, 6);
2925 v3s16 p = readV3S16(buf);
2926 is.read((char*)buf, 2);
2927 u16 textlen = readU16(buf);
2929 for(u16 i=0; i<textlen; i++)
2931 is.read((char*)buf, 1);
2932 text += (char)buf[0];
2935 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2938 if(meta->typeId() != CONTENT_SIGN_WALL)
2940 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2941 signmeta->setText(text);
2943 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign "
2944 <<" at "<<PP(p)<<std::endl;
2946 v3s16 blockpos = getNodeBlockPos(p);
2947 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2950 block->setChangedFlag();
2953 for(core::map<u16, RemoteClient*>::Iterator
2954 i = m_clients.getIterator();
2955 i.atEnd()==false; i++)
2957 RemoteClient *client = i.getNode()->getValue();
2958 client->SetBlockNotSent(blockpos);
2961 else if(command == TOSERVER_INVENTORY_ACTION)
2963 /*// Ignore inventory changes if in creative mode
2964 if(g_settings->getBool("creative_mode") == true)
2966 infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
2970 // Strip command and create a stream
2971 std::string datastring((char*)&data[2], datasize-2);
2972 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2973 std::istringstream is(datastring, std::ios_base::binary);
2975 InventoryAction *a = InventoryAction::deSerialize(is);
2980 c.current_player = player;
2983 Handle craftresult specially if not in creative mode
2985 bool disable_action = false;
2986 if(a->getType() == IACTION_MOVE
2987 && g_settings->getBool("creative_mode") == false)
2989 IMoveAction *ma = (IMoveAction*)a;
2990 if(ma->to_inv == "current_player" &&
2991 ma->from_inv == "current_player")
2993 InventoryList *rlist = player->inventory.getList("craftresult");
2995 InventoryList *clist = player->inventory.getList("craft");
2997 InventoryList *mlist = player->inventory.getList("main");
3000 Craftresult is no longer preview if something
3003 if(ma->to_list == "craftresult"
3004 && ma->from_list != "craftresult")
3006 // If it currently is a preview, remove
3008 if(player->craftresult_is_preview)
3010 rlist->deleteItem(0);
3012 player->craftresult_is_preview = false;
3015 Crafting takes place if this condition is true.
3017 if(player->craftresult_is_preview &&
3018 ma->from_list == "craftresult")
3020 player->craftresult_is_preview = false;
3021 clist->decrementMaterials(1);
3023 /* Print out action */
3024 InventoryList *list =
3025 player->inventory.getList("craftresult");
3027 InventoryItem *item = list->getItem(0);
3028 std::string itemname = "NULL";
3030 itemname = item->getName();
3031 actionstream<<player->getName()<<" crafts "
3032 <<itemname<<std::endl;
3035 If the craftresult is placed on itself, move it to
3036 main inventory instead of doing the action
3038 if(ma->to_list == "craftresult"
3039 && ma->from_list == "craftresult")
3041 disable_action = true;
3043 InventoryItem *item1 = rlist->changeItem(0, NULL);
3044 mlist->addItem(item1);
3047 // Disallow moving items if not allowed to build
3048 else if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3052 // if it's a locking chest, only allow the owner or server admins to move items
3053 else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3055 Strfnd fn(ma->from_inv);
3056 std::string id0 = fn.next(":");
3057 if(id0 == "nodemeta")
3060 p.X = stoi(fn.next(","));
3061 p.Y = stoi(fn.next(","));
3062 p.Z = stoi(fn.next(","));
3063 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3064 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3065 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3066 if (lcm->getOwner() != player->getName())
3071 else if (ma->to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3073 Strfnd fn(ma->to_inv);
3074 std::string id0 = fn.next(":");
3075 if(id0 == "nodemeta")
3078 p.X = stoi(fn.next(","));
3079 p.Y = stoi(fn.next(","));
3080 p.Z = stoi(fn.next(","));
3081 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3082 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3083 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3084 if (lcm->getOwner() != player->getName())
3091 if(disable_action == false)
3093 // Feed action to player inventory
3101 UpdateCrafting(player->peer_id);
3102 SendInventory(player->peer_id);
3107 infostream<<"TOSERVER_INVENTORY_ACTION: "
3108 <<"InventoryAction::deSerialize() returned NULL"
3112 else if(command == TOSERVER_CHAT_MESSAGE)
3120 std::string datastring((char*)&data[2], datasize-2);
3121 std::istringstream is(datastring, std::ios_base::binary);
3124 is.read((char*)buf, 2);
3125 u16 len = readU16(buf);
3127 std::wstring message;
3128 for(u16 i=0; i<len; i++)
3130 is.read((char*)buf, 2);
3131 message += (wchar_t)readU16(buf);
3134 // Get player name of this client
3135 std::wstring name = narrow_to_wide(player->getName());
3137 // Line to send to players
3139 // Whether to send to the player that sent the line
3140 bool send_to_sender = false;
3141 // Whether to send to other players
3142 bool send_to_others = false;
3144 // Local player gets all privileges regardless of
3145 // what's set on their account.
3146 u64 privs = getPlayerPrivs(player);
3149 if(message[0] == L'/')
3151 size_t strip_size = 1;
3152 if (message[1] == L'#') // support old-style commans
3154 message = message.substr(strip_size);
3156 WStrfnd f1(message);
3157 f1.next(L" "); // Skip over /#whatever
3158 std::wstring paramstring = f1.next(L"");
3160 ServerCommandContext *ctx = new ServerCommandContext(
3161 str_split(message, L' '),
3168 std::wstring reply(processServerCommand(ctx));
3169 send_to_sender = ctx->flags & SEND_TO_SENDER;
3170 send_to_others = ctx->flags & SEND_TO_OTHERS;
3172 if (ctx->flags & SEND_NO_PREFIX)
3175 line += L"Server: " + reply;
3182 if(privs & PRIV_SHOUT)
3188 send_to_others = true;
3192 line += L"Server: You are not allowed to shout";
3193 send_to_sender = true;
3200 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3203 Send the message to clients
3205 for(core::map<u16, RemoteClient*>::Iterator
3206 i = m_clients.getIterator();
3207 i.atEnd() == false; i++)
3209 // Get client and check that it is valid
3210 RemoteClient *client = i.getNode()->getValue();
3211 assert(client->peer_id == i.getNode()->getKey());
3212 if(client->serialization_version == SER_FMT_VER_INVALID)
3216 bool sender_selected = (peer_id == client->peer_id);
3217 if(sender_selected == true && send_to_sender == false)
3219 if(sender_selected == false && send_to_others == false)
3222 SendChatMessage(client->peer_id, line);
3226 else if(command == TOSERVER_DAMAGE)
3228 std::string datastring((char*)&data[2], datasize-2);
3229 std::istringstream is(datastring, std::ios_base::binary);
3230 u8 damage = readU8(is);
3232 if(g_settings->getBool("enable_damage"))
3234 actionstream<<player->getName()<<" damaged by "
3235 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
3238 HandlePlayerHP(player, damage);
3242 SendPlayerHP(player);
3245 else if(command == TOSERVER_PASSWORD)
3248 [0] u16 TOSERVER_PASSWORD
3249 [2] u8[28] old password
3250 [30] u8[28] new password
3253 if(datasize != 2+PASSWORD_SIZE*2)
3255 /*char password[PASSWORD_SIZE];
3256 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3257 password[i] = data[2+i];
3258 password[PASSWORD_SIZE-1] = 0;*/
3260 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3268 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3270 char c = data[2+PASSWORD_SIZE+i];
3276 infostream<<"Server: Client requests a password change from "
3277 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3279 std::string playername = player->getName();
3281 if(m_authmanager.exists(playername) == false)
3283 infostream<<"Server: playername not found in authmanager"<<std::endl;
3284 // Wrong old password supplied!!
3285 SendChatMessage(peer_id, L"playername not found in authmanager");
3289 std::string checkpwd = m_authmanager.getPassword(playername);
3291 if(oldpwd != checkpwd)
3293 infostream<<"Server: invalid old password"<<std::endl;
3294 // Wrong old password supplied!!
3295 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3299 actionstream<<player->getName()<<" changes password"<<std::endl;
3301 m_authmanager.setPassword(playername, newpwd);
3303 infostream<<"Server: password change successful for "<<playername
3305 SendChatMessage(peer_id, L"Password change successful");
3307 else if(command == TOSERVER_PLAYERITEM)
3312 u16 item = readU16(&data[2]);
3313 player->wieldItem(item);
3314 SendWieldedItem(player);
3316 else if(command == TOSERVER_RESPAWN)
3321 RespawnPlayer(player);
3323 actionstream<<player->getName()<<" respawns at "
3324 <<PP(player->getPosition()/BS)<<std::endl;
3328 infostream<<"Server::ProcessData(): Ignoring "
3329 "unknown command "<<command<<std::endl;
3333 catch(SendFailedException &e)
3335 errorstream<<"Server::ProcessData(): SendFailedException: "
3341 void Server::onMapEditEvent(MapEditEvent *event)
3343 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3344 if(m_ignore_map_edit_events)
3346 MapEditEvent *e = event->clone();
3347 m_unsent_map_edit_queue.push_back(e);
3350 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3352 if(id == "current_player")
3354 assert(c->current_player);
3355 return &(c->current_player->inventory);
3359 std::string id0 = fn.next(":");
3361 if(id0 == "nodemeta")
3364 p.X = stoi(fn.next(","));
3365 p.Y = stoi(fn.next(","));
3366 p.Z = stoi(fn.next(","));
3367 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3369 return meta->getInventory();
3370 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3371 <<"no metadata found"<<std::endl;
3375 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3378 void Server::inventoryModified(InventoryContext *c, std::string id)
3380 if(id == "current_player")
3382 assert(c->current_player);
3384 UpdateCrafting(c->current_player->peer_id);
3385 SendInventory(c->current_player->peer_id);
3390 std::string id0 = fn.next(":");
3392 if(id0 == "nodemeta")
3395 p.X = stoi(fn.next(","));
3396 p.Y = stoi(fn.next(","));
3397 p.Z = stoi(fn.next(","));
3398 v3s16 blockpos = getNodeBlockPos(p);
3400 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3402 meta->inventoryModified();
3404 for(core::map<u16, RemoteClient*>::Iterator
3405 i = m_clients.getIterator();
3406 i.atEnd()==false; i++)
3408 RemoteClient *client = i.getNode()->getValue();
3409 client->SetBlockNotSent(blockpos);
3415 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3418 core::list<PlayerInfo> Server::getPlayerInfo()
3420 DSTACK(__FUNCTION_NAME);
3421 JMutexAutoLock envlock(m_env_mutex);
3422 JMutexAutoLock conlock(m_con_mutex);
3424 core::list<PlayerInfo> list;
3426 core::list<Player*> players = m_env.getPlayers();
3428 core::list<Player*>::Iterator i;
3429 for(i = players.begin();
3430 i != players.end(); i++)
3434 Player *player = *i;
3437 con::Peer *peer = m_con.GetPeer(player->peer_id);
3438 // Copy info from peer to info struct
3440 info.address = peer->address;
3441 info.avg_rtt = peer->avg_rtt;
3443 catch(con::PeerNotFoundException &e)
3445 // Set dummy peer info
3447 info.address = Address(0,0,0,0,0);
3451 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3452 info.position = player->getPosition();
3454 list.push_back(info);
3461 void Server::peerAdded(con::Peer *peer)
3463 DSTACK(__FUNCTION_NAME);
3464 infostream<<"Server::peerAdded(): peer->id="
3465 <<peer->id<<std::endl;
3468 c.type = PEER_ADDED;
3469 c.peer_id = peer->id;
3471 m_peer_change_queue.push_back(c);
3474 void Server::deletingPeer(con::Peer *peer, bool timeout)
3476 DSTACK(__FUNCTION_NAME);
3477 infostream<<"Server::deletingPeer(): peer->id="
3478 <<peer->id<<", timeout="<<timeout<<std::endl;
3481 c.type = PEER_REMOVED;
3482 c.peer_id = peer->id;
3483 c.timeout = timeout;
3484 m_peer_change_queue.push_back(c);
3491 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3493 DSTACK(__FUNCTION_NAME);
3494 std::ostringstream os(std::ios_base::binary);
3496 writeU16(os, TOCLIENT_HP);
3500 std::string s = os.str();
3501 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3503 con.Send(peer_id, 0, data, true);
3506 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3507 const std::wstring &reason)
3509 DSTACK(__FUNCTION_NAME);
3510 std::ostringstream os(std::ios_base::binary);
3512 writeU16(os, TOCLIENT_ACCESS_DENIED);
3513 os<<serializeWideString(reason);
3516 std::string s = os.str();
3517 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3519 con.Send(peer_id, 0, data, true);
3522 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3523 bool set_camera_point_target, v3f camera_point_target)
3525 DSTACK(__FUNCTION_NAME);
3526 std::ostringstream os(std::ios_base::binary);
3528 writeU16(os, TOCLIENT_DEATHSCREEN);
3529 writeU8(os, set_camera_point_target);
3530 writeV3F1000(os, camera_point_target);
3533 std::string s = os.str();
3534 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3536 con.Send(peer_id, 0, data, true);
3540 Non-static send methods
3543 void Server::SendObjectData(float dtime)
3545 DSTACK(__FUNCTION_NAME);
3547 core::map<v3s16, bool> stepped_blocks;
3549 for(core::map<u16, RemoteClient*>::Iterator
3550 i = m_clients.getIterator();
3551 i.atEnd() == false; i++)
3553 u16 peer_id = i.getNode()->getKey();
3554 RemoteClient *client = i.getNode()->getValue();
3555 assert(client->peer_id == peer_id);
3557 if(client->serialization_version == SER_FMT_VER_INVALID)
3560 client->SendObjectData(this, dtime, stepped_blocks);
3564 void Server::SendPlayerInfos()
3566 DSTACK(__FUNCTION_NAME);
3568 //JMutexAutoLock envlock(m_env_mutex);
3570 // Get connected players
3571 core::list<Player*> players = m_env.getPlayers(true);
3573 u32 player_count = players.getSize();
3574 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3576 SharedBuffer<u8> data(datasize);
3577 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3580 core::list<Player*>::Iterator i;
3581 for(i = players.begin();
3582 i != players.end(); i++)
3584 Player *player = *i;
3586 /*infostream<<"Server sending player info for player with "
3587 "peer_id="<<player->peer_id<<std::endl;*/
3589 writeU16(&data[start], player->peer_id);
3590 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3591 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3592 start += 2+PLAYERNAME_SIZE;
3595 //JMutexAutoLock conlock(m_con_mutex);
3598 m_con.SendToAll(0, data, true);
3601 void Server::SendInventory(u16 peer_id)
3603 DSTACK(__FUNCTION_NAME);
3605 Player* player = m_env.getPlayer(peer_id);
3612 std::ostringstream os;
3613 //os.imbue(std::locale("C"));
3615 player->inventory.serialize(os);
3617 std::string s = os.str();
3619 SharedBuffer<u8> data(s.size()+2);
3620 writeU16(&data[0], TOCLIENT_INVENTORY);
3621 memcpy(&data[2], s.c_str(), s.size());
3624 m_con.Send(peer_id, 0, data, true);
3627 std::string getWieldedItemString(const Player *player)
3629 const InventoryItem *item = player->getWieldItem();
3631 return std::string("");
3632 std::ostringstream os(std::ios_base::binary);
3633 item->serialize(os);
3637 void Server::SendWieldedItem(const Player* player)
3639 DSTACK(__FUNCTION_NAME);
3643 std::ostringstream os(std::ios_base::binary);
3645 writeU16(os, TOCLIENT_PLAYERITEM);
3647 writeU16(os, player->peer_id);
3648 os<<serializeString(getWieldedItemString(player));
3651 std::string s = os.str();
3652 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3654 m_con.SendToAll(0, data, true);
3657 void Server::SendPlayerItems()
3659 DSTACK(__FUNCTION_NAME);
3661 std::ostringstream os(std::ios_base::binary);
3662 core::list<Player *> players = m_env.getPlayers(true);
3664 writeU16(os, TOCLIENT_PLAYERITEM);
3665 writeU16(os, players.size());
3666 core::list<Player *>::Iterator i;
3667 for(i = players.begin(); i != players.end(); ++i)
3670 writeU16(os, p->peer_id);
3671 os<<serializeString(getWieldedItemString(p));
3675 std::string s = os.str();
3676 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3678 m_con.SendToAll(0, data, true);
3681 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3683 DSTACK(__FUNCTION_NAME);
3685 std::ostringstream os(std::ios_base::binary);
3689 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3690 os.write((char*)buf, 2);
3693 writeU16(buf, message.size());
3694 os.write((char*)buf, 2);
3697 for(u32 i=0; i<message.size(); i++)
3701 os.write((char*)buf, 2);
3705 std::string s = os.str();
3706 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3708 m_con.Send(peer_id, 0, data, true);
3711 void Server::BroadcastChatMessage(const std::wstring &message)
3713 for(core::map<u16, RemoteClient*>::Iterator
3714 i = m_clients.getIterator();
3715 i.atEnd() == false; i++)
3717 // Get client and check that it is valid
3718 RemoteClient *client = i.getNode()->getValue();
3719 assert(client->peer_id == i.getNode()->getKey());
3720 if(client->serialization_version == SER_FMT_VER_INVALID)
3723 SendChatMessage(client->peer_id, message);
3727 void Server::SendPlayerHP(Player *player)
3729 SendHP(m_con, player->peer_id, player->hp);
3732 void Server::SendMovePlayer(Player *player)
3734 DSTACK(__FUNCTION_NAME);
3735 std::ostringstream os(std::ios_base::binary);
3737 writeU16(os, TOCLIENT_MOVE_PLAYER);
3738 writeV3F1000(os, player->getPosition());
3739 writeF1000(os, player->getPitch());
3740 writeF1000(os, player->getYaw());
3743 v3f pos = player->getPosition();
3744 f32 pitch = player->getPitch();
3745 f32 yaw = player->getYaw();
3746 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
3747 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3754 std::string s = os.str();
3755 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3757 m_con.Send(player->peer_id, 0, data, true);
3760 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3761 core::list<u16> *far_players, float far_d_nodes)
3763 float maxd = far_d_nodes*BS;
3764 v3f p_f = intToFloat(p, BS);
3768 SharedBuffer<u8> reply(replysize);
3769 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3770 writeS16(&reply[2], p.X);
3771 writeS16(&reply[4], p.Y);
3772 writeS16(&reply[6], p.Z);
3774 for(core::map<u16, RemoteClient*>::Iterator
3775 i = m_clients.getIterator();
3776 i.atEnd() == false; i++)
3778 // Get client and check that it is valid
3779 RemoteClient *client = i.getNode()->getValue();
3780 assert(client->peer_id == i.getNode()->getKey());
3781 if(client->serialization_version == SER_FMT_VER_INVALID)
3784 // Don't send if it's the same one
3785 if(client->peer_id == ignore_id)
3791 Player *player = m_env.getPlayer(client->peer_id);
3794 // If player is far away, only set modified blocks not sent
3795 v3f player_pos = player->getPosition();
3796 if(player_pos.getDistanceFrom(p_f) > maxd)
3798 far_players->push_back(client->peer_id);
3805 m_con.Send(client->peer_id, 0, reply, true);
3809 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3810 core::list<u16> *far_players, float far_d_nodes)
3812 float maxd = far_d_nodes*BS;
3813 v3f p_f = intToFloat(p, BS);
3815 for(core::map<u16, RemoteClient*>::Iterator
3816 i = m_clients.getIterator();
3817 i.atEnd() == false; i++)
3819 // Get client and check that it is valid
3820 RemoteClient *client = i.getNode()->getValue();
3821 assert(client->peer_id == i.getNode()->getKey());
3822 if(client->serialization_version == SER_FMT_VER_INVALID)
3825 // Don't send if it's the same one
3826 if(client->peer_id == ignore_id)
3832 Player *player = m_env.getPlayer(client->peer_id);
3835 // If player is far away, only set modified blocks not sent
3836 v3f player_pos = player->getPosition();
3837 if(player_pos.getDistanceFrom(p_f) > maxd)
3839 far_players->push_back(client->peer_id);
3846 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3847 SharedBuffer<u8> reply(replysize);
3848 writeU16(&reply[0], TOCLIENT_ADDNODE);
3849 writeS16(&reply[2], p.X);
3850 writeS16(&reply[4], p.Y);
3851 writeS16(&reply[6], p.Z);
3852 n.serialize(&reply[8], client->serialization_version);
3855 m_con.Send(client->peer_id, 0, reply, true);
3859 void Server::setBlockNotSent(v3s16 p)
3861 for(core::map<u16, RemoteClient*>::Iterator
3862 i = m_clients.getIterator();
3863 i.atEnd()==false; i++)
3865 RemoteClient *client = i.getNode()->getValue();
3866 client->SetBlockNotSent(p);
3870 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3872 DSTACK(__FUNCTION_NAME);
3874 v3s16 p = block->getPos();
3878 bool completely_air = true;
3879 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3880 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3881 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3883 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3885 completely_air = false;
3886 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3891 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3893 infostream<<"[completely air] ";
3894 infostream<<std::endl;
3898 Create a packet with the block in the right format
3901 std::ostringstream os(std::ios_base::binary);
3902 block->serialize(os, ver);
3903 std::string s = os.str();
3904 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3906 u32 replysize = 8 + blockdata.getSize();
3907 SharedBuffer<u8> reply(replysize);
3908 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3909 writeS16(&reply[2], p.X);
3910 writeS16(&reply[4], p.Y);
3911 writeS16(&reply[6], p.Z);
3912 memcpy(&reply[8], *blockdata, blockdata.getSize());
3914 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3915 <<": \tpacket size: "<<replysize<<std::endl;*/
3920 m_con.Send(peer_id, 1, reply, true);
3923 void Server::SendBlocks(float dtime)
3925 DSTACK(__FUNCTION_NAME);
3927 JMutexAutoLock envlock(m_env_mutex);
3928 JMutexAutoLock conlock(m_con_mutex);
3930 //TimeTaker timer("Server::SendBlocks");
3932 core::array<PrioritySortedBlockTransfer> queue;
3934 s32 total_sending = 0;
3937 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3939 for(core::map<u16, RemoteClient*>::Iterator
3940 i = m_clients.getIterator();
3941 i.atEnd() == false; i++)
3943 RemoteClient *client = i.getNode()->getValue();
3944 assert(client->peer_id == i.getNode()->getKey());
3946 total_sending += client->SendingCount();
3948 if(client->serialization_version == SER_FMT_VER_INVALID)
3951 client->GetNextBlocks(this, dtime, queue);
3956 // Lowest priority number comes first.
3957 // Lowest is most important.
3960 for(u32 i=0; i<queue.size(); i++)
3962 //TODO: Calculate limit dynamically
3963 if(total_sending >= g_settings->getS32
3964 ("max_simultaneous_block_sends_server_total"))
3967 PrioritySortedBlockTransfer q = queue[i];
3969 MapBlock *block = NULL;
3972 block = m_env.getMap().getBlockNoCreate(q.pos);
3974 catch(InvalidPositionException &e)
3979 RemoteClient *client = getClient(q.peer_id);
3981 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3983 client->SentBlock(q.pos);
3993 void Server::HandlePlayerHP(Player *player, s16 damage)
3995 if(player->hp > damage)
3997 player->hp -= damage;
3998 SendPlayerHP(player);
4002 infostream<<"Server::HandlePlayerHP(): Player "
4003 <<player->getName()<<" dies"<<std::endl;
4007 //TODO: Throw items around
4009 // Handle players that are not connected
4010 if(player->peer_id == PEER_ID_INEXISTENT){
4011 RespawnPlayer(player);
4015 SendPlayerHP(player);
4017 RemoteClient *client = getClient(player->peer_id);
4018 if(client->net_proto_version >= 3)
4020 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4024 RespawnPlayer(player);
4029 void Server::RespawnPlayer(Player *player)
4031 v3f pos = findSpawnPos(m_env.getServerMap());
4032 player->setPosition(pos);
4034 SendMovePlayer(player);
4035 SendPlayerHP(player);
4038 void Server::UpdateCrafting(u16 peer_id)
4040 DSTACK(__FUNCTION_NAME);
4042 Player* player = m_env.getPlayer(peer_id);
4046 Calculate crafting stuff
4048 if(g_settings->getBool("creative_mode") == false)
4050 InventoryList *clist = player->inventory.getList("craft");
4051 InventoryList *rlist = player->inventory.getList("craftresult");
4053 if(rlist && rlist->getUsedSlots() == 0)
4054 player->craftresult_is_preview = true;
4056 if(rlist && player->craftresult_is_preview)
4058 rlist->clearItems();
4060 if(clist && rlist && player->craftresult_is_preview)
4062 InventoryItem *items[9];
4063 for(u16 i=0; i<9; i++)
4065 items[i] = clist->getItem(i);
4068 // Get result of crafting grid
4069 InventoryItem *result = craft_get_result(items);
4071 rlist->addItem(result);
4074 } // if creative_mode == false
4077 RemoteClient* Server::getClient(u16 peer_id)
4079 DSTACK(__FUNCTION_NAME);
4080 //JMutexAutoLock lock(m_con_mutex);
4081 core::map<u16, RemoteClient*>::Node *n;
4082 n = m_clients.find(peer_id);
4083 // A client should exist for all peers
4085 return n->getValue();
4088 std::wstring Server::getStatusString()
4090 std::wostringstream os(std::ios_base::binary);
4093 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4095 os<<L", uptime="<<m_uptime.get();
4096 // Information about clients
4098 for(core::map<u16, RemoteClient*>::Iterator
4099 i = m_clients.getIterator();
4100 i.atEnd() == false; i++)
4102 // Get client and check that it is valid
4103 RemoteClient *client = i.getNode()->getValue();
4104 assert(client->peer_id == i.getNode()->getKey());
4105 if(client->serialization_version == SER_FMT_VER_INVALID)
4108 Player *player = m_env.getPlayer(client->peer_id);
4109 // Get name of player
4110 std::wstring name = L"unknown";
4112 name = narrow_to_wide(player->getName());
4113 // Add name to information string
4117 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
4118 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4119 if(g_settings->get("motd") != "")
4120 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4124 // Saves g_settings to configpath given at initialization
4125 void Server::saveConfig()
4127 if(m_configpath != "")
4128 g_settings->updateConfigFile(m_configpath.c_str());
4131 void Server::notifyPlayer(const char *name, const std::wstring msg)
4133 Player *player = m_env.getPlayer(name);
4136 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4139 v3f findSpawnPos(ServerMap &map)
4141 //return v3f(50,50,50)*BS;
4144 s16 groundheight = 0;
4147 nodepos = v2s16(0,0);
4152 // Try to find a good place a few times
4153 for(s32 i=0; i<1000; i++)
4156 // We're going to try to throw the player to this position
4157 nodepos = v2s16(-range + (myrand()%(range*2)),
4158 -range + (myrand()%(range*2)));
4159 v2s16 sectorpos = getNodeSectorPos(nodepos);
4160 // Get sector (NOTE: Don't get because it's slow)
4161 //m_env.getMap().emergeSector(sectorpos);
4162 // Get ground height at point (fallbacks to heightmap function)
4163 groundheight = map.findGroundLevel(nodepos);
4164 // Don't go underwater
4165 if(groundheight < WATER_LEVEL)
4167 //infostream<<"-> Underwater"<<std::endl;
4170 // Don't go to high places
4171 if(groundheight > WATER_LEVEL + 4)
4173 //infostream<<"-> Underwater"<<std::endl;
4177 // Found a good place
4178 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4183 // If no suitable place was not found, go above water at least.
4184 if(groundheight < WATER_LEVEL)
4185 groundheight = WATER_LEVEL;
4187 return intToFloat(v3s16(
4194 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4197 Try to get an existing player
4199 Player *player = m_env.getPlayer(name);
4202 // If player is already connected, cancel
4203 if(player->peer_id != 0)
4205 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4210 player->peer_id = peer_id;
4212 // Reset inventory to creative if in creative mode
4213 if(g_settings->getBool("creative_mode"))
4215 // Warning: double code below
4216 // Backup actual inventory
4217 player->inventory_backup = new Inventory();
4218 *(player->inventory_backup) = player->inventory;
4219 // Set creative inventory
4220 craft_set_creative_inventory(player);
4227 If player with the wanted peer_id already exists, cancel.
4229 if(m_env.getPlayer(peer_id) != NULL)
4231 infostream<<"emergePlayer(): Player with wrong name but same"
4232 " peer_id already exists"<<std::endl;
4240 player = new ServerRemotePlayer();
4241 //player->peer_id = c.peer_id;
4242 //player->peer_id = PEER_ID_INEXISTENT;
4243 player->peer_id = peer_id;
4244 player->updateName(name);
4245 m_authmanager.add(name);
4246 m_authmanager.setPassword(name, password);
4247 m_authmanager.setPrivs(name,
4248 stringToPrivs(g_settings->get("default_privs")));
4254 infostream<<"Server: Finding spawn place for player \""
4255 <<player->getName()<<"\""<<std::endl;
4257 v3f pos = findSpawnPos(m_env.getServerMap());
4259 player->setPosition(pos);
4262 Add player to environment
4265 m_env.addPlayer(player);
4268 Add stuff to inventory
4271 if(g_settings->getBool("creative_mode"))
4273 // Warning: double code above
4274 // Backup actual inventory
4275 player->inventory_backup = new Inventory();
4276 *(player->inventory_backup) = player->inventory;
4277 // Set creative inventory
4278 craft_set_creative_inventory(player);
4280 else if(g_settings->getBool("give_initial_stuff"))
4282 craft_give_initial_stuff(player);
4287 } // create new player
4290 void Server::handlePeerChange(PeerChange &c)
4292 JMutexAutoLock envlock(m_env_mutex);
4293 JMutexAutoLock conlock(m_con_mutex);
4295 if(c.type == PEER_ADDED)
4302 core::map<u16, RemoteClient*>::Node *n;
4303 n = m_clients.find(c.peer_id);
4304 // The client shouldn't already exist
4308 RemoteClient *client = new RemoteClient();
4309 client->peer_id = c.peer_id;
4310 m_clients.insert(client->peer_id, client);
4313 else if(c.type == PEER_REMOVED)
4320 core::map<u16, RemoteClient*>::Node *n;
4321 n = m_clients.find(c.peer_id);
4322 // The client should exist
4326 Mark objects to be not known by the client
4328 RemoteClient *client = n->getValue();
4330 for(core::map<u16, bool>::Iterator
4331 i = client->m_known_objects.getIterator();
4332 i.atEnd()==false; i++)
4335 u16 id = i.getNode()->getKey();
4336 ServerActiveObject* obj = m_env.getActiveObject(id);
4338 if(obj && obj->m_known_by_count > 0)
4339 obj->m_known_by_count--;
4342 // Collect information about leaving in chat
4343 std::wstring message;
4345 Player *player = m_env.getPlayer(c.peer_id);
4348 std::wstring name = narrow_to_wide(player->getName());
4351 message += L" left game";
4353 message += L" (timed out)";
4359 m_env.removePlayer(c.peer_id);
4362 // Set player client disconnected
4364 Player *player = m_env.getPlayer(c.peer_id);
4366 player->peer_id = 0;
4373 std::ostringstream os(std::ios_base::binary);
4374 for(core::map<u16, RemoteClient*>::Iterator
4375 i = m_clients.getIterator();
4376 i.atEnd() == false; i++)
4378 RemoteClient *client = i.getNode()->getValue();
4379 assert(client->peer_id == i.getNode()->getKey());
4380 if(client->serialization_version == SER_FMT_VER_INVALID)
4383 Player *player = m_env.getPlayer(client->peer_id);
4386 // Get name of player
4387 os<<player->getName()<<" ";
4390 actionstream<<player->getName()<<" "
4391 <<(c.timeout?"times out.":"leaves game.")
4392 <<" List of players: "
4393 <<os.str()<<std::endl;
4398 delete m_clients[c.peer_id];
4399 m_clients.remove(c.peer_id);
4401 // Send player info to all remaining clients
4404 // Send leave chat message to all remaining clients
4405 BroadcastChatMessage(message);
4414 void Server::handlePeerChanges()
4416 while(m_peer_change_queue.size() > 0)
4418 PeerChange c = m_peer_change_queue.pop_front();
4420 infostream<<"Server: Handling peer change: "
4421 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4424 handlePeerChange(c);
4428 u64 Server::getPlayerPrivs(Player *player)
4432 std::string playername = player->getName();
4433 // Local player gets all privileges regardless of
4434 // what's set on their account.
4435 if(g_settings->get("name") == playername)
4441 return getPlayerAuthPrivs(playername);
4445 void dedicated_server_loop(Server &server, bool &kill)
4447 DSTACK(__FUNCTION_NAME);
4449 infostream<<DTIME<<std::endl;
4450 infostream<<"========================"<<std::endl;
4451 infostream<<"Running dedicated server"<<std::endl;
4452 infostream<<"========================"<<std::endl;
4453 infostream<<std::endl;
4455 IntervalLimiter m_profiler_interval;
4459 // This is kind of a hack but can be done like this
4460 // because server.step() is very light
4462 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4467 if(server.getShutdownRequested() || kill)
4469 infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4476 float profiler_print_interval =
4477 g_settings->getFloat("profiler_print_interval");
4478 if(profiler_print_interval != 0)
4480 if(m_profiler_interval.step(0.030, profiler_print_interval))
4482 infostream<<"Profiler:"<<std::endl;
4483 g_profiler->print(infostream);
4484 g_profiler->clear();
4491 static int counter = 0;
4497 core::list<PlayerInfo> list = server.getPlayerInfo();
4498 core::list<PlayerInfo>::Iterator i;
4499 static u32 sum_old = 0;
4500 u32 sum = PIChecksum(list);
4503 infostream<<DTIME<<"Player info:"<<std::endl;
4504 for(i=list.begin(); i!=list.end(); i++)
4506 i->PrintLine(&infostream);