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.
24 #include "clientserver.h"
26 #include "jmutexautolock.h"
28 #include "constants.h"
30 #include "materials.h"
33 #include "servercommand.h"
35 #include "content_mapnode.h"
36 #include "content_craft.h"
37 #include "content_nodemeta.h"
39 #include "serverobject.h"
44 #include "scriptapi.h"
48 #include "craftitemdef.h"
50 #include "content_abm.h"
51 #include "content_sao.h" // For PlayerSAO
53 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
55 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
57 class MapEditEventIgnorer
60 MapEditEventIgnorer(bool *flag):
69 ~MapEditEventIgnorer()
82 void * ServerThread::Thread()
86 log_register_thread("ServerThread");
88 DSTACK(__FUNCTION_NAME);
90 BEGIN_DEBUG_EXCEPTION_HANDLER
95 //TimeTaker timer("AsyncRunStep() + Receive()");
98 //TimeTaker timer("AsyncRunStep()");
99 m_server->AsyncRunStep();
102 //infostream<<"Running m_server->Receive()"<<std::endl;
105 catch(con::NoIncomingDataException &e)
108 catch(con::PeerNotFoundException &e)
110 infostream<<"Server: PeerNotFoundException"<<std::endl;
114 END_DEBUG_EXCEPTION_HANDLER(errorstream)
119 void * EmergeThread::Thread()
123 log_register_thread("EmergeThread");
125 DSTACK(__FUNCTION_NAME);
127 BEGIN_DEBUG_EXCEPTION_HANDLER
129 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
132 Get block info from queue, emerge them and send them
135 After queue is empty, exit.
139 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
143 SharedPtr<QueuedBlockEmerge> q(qptr);
149 Do not generate over-limit
151 if(blockpos_over_limit(p))
154 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
156 //TimeTaker timer("block emerge");
159 Try to emerge it from somewhere.
161 If it is only wanted as optional, only loading from disk
166 Check if any peer wants it as non-optional. In that case it
169 Also decrement the emerge queue count in clients.
172 bool only_from_disk = true;
175 core::map<u16, u8>::Iterator i;
176 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
178 //u16 peer_id = i.getNode()->getKey();
181 u8 flags = i.getNode()->getValue();
182 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
183 only_from_disk = false;
188 if(enable_mapgen_debug_info)
189 infostream<<"EmergeThread: p="
190 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
191 <<"only_from_disk="<<only_from_disk<<std::endl;
193 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
195 MapBlock *block = NULL;
196 bool got_block = true;
197 core::map<v3s16, MapBlock*> modified_blocks;
200 Try to fetch block from memory or disk.
201 If not found and asked to generate, initialize generator.
204 bool started_generate = false;
205 mapgen::BlockMakeData data;
208 JMutexAutoLock envlock(m_server->m_env_mutex);
210 // Load sector if it isn't loaded
211 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
212 map.loadSectorMeta(p2d);
214 // Attempt to load block
215 block = map.getBlockNoCreateNoEx(p);
216 if(!block || block->isDummy() || !block->isGenerated())
218 if(enable_mapgen_debug_info)
219 infostream<<"EmergeThread: not in memory, "
220 <<"attempting to load from disk"<<std::endl;
222 block = map.loadBlock(p);
225 // If could not load and allowed to generate, start generation
226 // inside this same envlock
227 if(only_from_disk == false &&
228 (block == NULL || block->isGenerated() == false)){
229 if(enable_mapgen_debug_info)
230 infostream<<"EmergeThread: generating"<<std::endl;
231 started_generate = true;
233 map.initBlockMake(&data, p);
238 If generator was initialized, generate now when envlock is free.
243 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
245 TimeTaker t("mapgen::make_block()");
247 mapgen::make_block(&data);
249 if(enable_mapgen_debug_info == false)
250 t.stop(true); // Hide output
254 // Lock environment again to access the map
255 JMutexAutoLock envlock(m_server->m_env_mutex);
257 ScopeProfiler sp(g_profiler, "EmergeThread: after "
258 "mapgen::make_block (envlock)", SPT_AVG);
260 // Blit data back on map, update lighting, add mobs and
261 // whatever this does
262 map.finishBlockMake(&data, modified_blocks);
265 block = map.getBlockNoCreateNoEx(p);
268 Do some post-generate stuff
271 v3s16 minp = block->getPos()*MAP_BLOCKSIZE;
272 v3s16 maxp = minp + v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
273 scriptapi_environment_on_generated(m_server->m_lua,
276 if(enable_mapgen_debug_info)
277 infostream<<"EmergeThread: ended up with: "
278 <<analyze_block(block)<<std::endl;
281 Ignore map edit events, they will not need to be
282 sent to anybody because the block hasn't been sent
285 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
287 // Activate objects and stuff
288 m_server->m_env->activateBlock(block, 0);
296 Set sent status of modified blocks on clients
299 // NOTE: Server's clients are also behind the connection mutex
300 JMutexAutoLock lock(m_server->m_con_mutex);
303 Add the originally fetched block to the modified list
307 modified_blocks.insert(p, block);
311 Set the modified blocks unsent for all the clients
314 for(core::map<u16, RemoteClient*>::Iterator
315 i = m_server->m_clients.getIterator();
316 i.atEnd() == false; i++)
318 RemoteClient *client = i.getNode()->getValue();
320 if(modified_blocks.size() > 0)
322 // Remove block from sent history
323 client->SetBlocksNotSent(modified_blocks);
329 END_DEBUG_EXCEPTION_HANDLER(errorstream)
331 log_deregister_thread();
336 void RemoteClient::GetNextBlocks(Server *server, float dtime,
337 core::array<PrioritySortedBlockTransfer> &dest)
339 DSTACK(__FUNCTION_NAME);
342 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
345 m_nothing_to_send_pause_timer -= dtime;
346 m_nearest_unsent_reset_timer += dtime;
348 if(m_nothing_to_send_pause_timer >= 0)
353 // Won't send anything if already sending
354 if(m_blocks_sending.size() >= g_settings->getU16
355 ("max_simultaneous_block_sends_per_client"))
357 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
361 //TimeTaker timer("RemoteClient::GetNextBlocks");
363 Player *player = server->m_env->getPlayer(peer_id);
365 assert(player != NULL);
367 v3f playerpos = player->getPosition();
368 v3f playerspeed = player->getSpeed();
369 v3f playerspeeddir(0,0,0);
370 if(playerspeed.getLength() > 1.0*BS)
371 playerspeeddir = playerspeed / playerspeed.getLength();
372 // Predict to next block
373 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
375 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
377 v3s16 center = getNodeBlockPos(center_nodepos);
379 // Camera position and direction
380 v3f camera_pos = player->getEyePosition();
381 v3f camera_dir = v3f(0,0,1);
382 camera_dir.rotateYZBy(player->getPitch());
383 camera_dir.rotateXZBy(player->getYaw());
385 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
386 <<camera_dir.Z<<")"<<std::endl;*/
389 Get the starting value of the block finder radius.
392 if(m_last_center != center)
394 m_nearest_unsent_d = 0;
395 m_last_center = center;
398 /*infostream<<"m_nearest_unsent_reset_timer="
399 <<m_nearest_unsent_reset_timer<<std::endl;*/
401 // Reset periodically to workaround for some bugs or stuff
402 if(m_nearest_unsent_reset_timer > 20.0)
404 m_nearest_unsent_reset_timer = 0;
405 m_nearest_unsent_d = 0;
406 //infostream<<"Resetting m_nearest_unsent_d for "
407 // <<server->getPlayerName(peer_id)<<std::endl;
410 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
411 s16 d_start = m_nearest_unsent_d;
413 //infostream<<"d_start="<<d_start<<std::endl;
415 u16 max_simul_sends_setting = g_settings->getU16
416 ("max_simultaneous_block_sends_per_client");
417 u16 max_simul_sends_usually = max_simul_sends_setting;
420 Check the time from last addNode/removeNode.
422 Decrease send rate if player is building stuff.
424 m_time_from_building += dtime;
425 if(m_time_from_building < g_settings->getFloat(
426 "full_block_send_enable_min_time_from_building"))
428 max_simul_sends_usually
429 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
433 Number of blocks sending + number of blocks selected for sending
435 u32 num_blocks_selected = m_blocks_sending.size();
438 next time d will be continued from the d from which the nearest
439 unsent block was found this time.
441 This is because not necessarily any of the blocks found this
442 time are actually sent.
444 s32 new_nearest_unsent_d = -1;
446 s16 d_max = g_settings->getS16("max_block_send_distance");
447 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
449 // Don't loop very much at a time
450 s16 max_d_increment_at_time = 2;
451 if(d_max > d_start + max_d_increment_at_time)
452 d_max = d_start + max_d_increment_at_time;
453 /*if(d_max_gen > d_start+2)
454 d_max_gen = d_start+2;*/
456 //infostream<<"Starting from "<<d_start<<std::endl;
458 s32 nearest_emerged_d = -1;
459 s32 nearest_emergefull_d = -1;
460 s32 nearest_sent_d = -1;
461 bool queue_is_full = false;
464 for(d = d_start; d <= d_max; d++)
466 /*errorstream<<"checking d="<<d<<" for "
467 <<server->getPlayerName(peer_id)<<std::endl;*/
468 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
471 If m_nearest_unsent_d was changed by the EmergeThread
472 (it can change it to 0 through SetBlockNotSent),
474 Else update m_nearest_unsent_d
476 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
478 d = m_nearest_unsent_d;
479 last_nearest_unsent_d = m_nearest_unsent_d;
483 Get the border/face dot coordinates of a "d-radiused"
486 core::list<v3s16> list;
487 getFacePositions(list, d);
489 core::list<v3s16>::Iterator li;
490 for(li=list.begin(); li!=list.end(); li++)
492 v3s16 p = *li + center;
496 - Don't allow too many simultaneous transfers
497 - EXCEPT when the blocks are very close
499 Also, don't send blocks that are already flying.
502 // Start with the usual maximum
503 u16 max_simul_dynamic = max_simul_sends_usually;
505 // If block is very close, allow full maximum
506 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
507 max_simul_dynamic = max_simul_sends_setting;
509 // Don't select too many blocks for sending
510 if(num_blocks_selected >= max_simul_dynamic)
512 queue_is_full = true;
513 goto queue_full_break;
516 // Don't send blocks that are currently being transferred
517 if(m_blocks_sending.find(p) != NULL)
523 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
524 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
525 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
526 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
527 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
528 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
531 // If this is true, inexistent block will be made from scratch
532 bool generate = d <= d_max_gen;
535 /*// Limit the generating area vertically to 2/3
536 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
539 // Limit the send area vertically to 1/2
540 if(abs(p.Y - center.Y) > d_max / 2)
546 If block is far away, don't generate it unless it is
552 // Block center y in nodes
553 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
554 // Don't generate if it's very high or very low
555 if(y < -64 || y > 64)
559 v2s16 p2d_nodes_center(
563 // Get ground height in nodes
564 s16 gh = server->m_env->getServerMap().findGroundLevel(
567 // If differs a lot, don't generate
568 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
570 // Actually, don't even send it
576 //infostream<<"d="<<d<<std::endl;
579 Don't generate or send if not in sight
580 FIXME This only works if the client uses a small enough
581 FOV setting. The default of 72 degrees is fine.
584 float camera_fov = (72.0*PI/180) * 4./3.;
585 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
591 Don't send already sent blocks
594 if(m_blocks_sent.find(p) != NULL)
601 Check if map has this block
603 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
605 bool surely_not_found_on_disk = false;
606 bool block_is_invalid = false;
609 // Reset usage timer, this block will be of use in the future.
610 block->resetUsageTimer();
612 // Block is dummy if data doesn't exist.
613 // It means it has been not found from disk and not generated
616 surely_not_found_on_disk = true;
619 // Block is valid if lighting is up-to-date and data exists
620 if(block->isValid() == false)
622 block_is_invalid = true;
625 /*if(block->isFullyGenerated() == false)
627 block_is_invalid = true;
632 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
633 v2s16 chunkpos = map->sector_to_chunk(p2d);
634 if(map->chunkNonVolatile(chunkpos) == false)
635 block_is_invalid = true;
637 if(block->isGenerated() == false)
638 block_is_invalid = true;
641 If block is not close, don't send it unless it is near
644 Block is near ground level if night-time mesh
645 differs from day-time mesh.
649 if(block->dayNightDiffed() == false)
656 If block has been marked to not exist on disk (dummy)
657 and generating new ones is not wanted, skip block.
659 if(generate == false && surely_not_found_on_disk == true)
666 Add inexistent block to emerge queue.
668 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
670 //TODO: Get value from somewhere
671 // Allow only one block in emerge queue
672 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
673 // Allow two blocks in queue per client
674 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
676 // Make it more responsive when needing to generate stuff
677 if(surely_not_found_on_disk)
679 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
681 //infostream<<"Adding block to emerge queue"<<std::endl;
683 // Add it to the emerge queue and trigger the thread
686 if(generate == false)
687 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
689 server->m_emerge_queue.addBlock(peer_id, p, flags);
690 server->m_emergethread.trigger();
692 if(nearest_emerged_d == -1)
693 nearest_emerged_d = d;
695 if(nearest_emergefull_d == -1)
696 nearest_emergefull_d = d;
703 if(nearest_sent_d == -1)
707 Add block to send queue
710 /*errorstream<<"sending from d="<<d<<" to "
711 <<server->getPlayerName(peer_id)<<std::endl;*/
713 PrioritySortedBlockTransfer q((float)d, p, peer_id);
717 num_blocks_selected += 1;
722 //infostream<<"Stopped at "<<d<<std::endl;
724 // If nothing was found for sending and nothing was queued for
725 // emerging, continue next time browsing from here
726 if(nearest_emerged_d != -1){
727 new_nearest_unsent_d = nearest_emerged_d;
728 } else if(nearest_emergefull_d != -1){
729 new_nearest_unsent_d = nearest_emergefull_d;
731 if(d > g_settings->getS16("max_block_send_distance")){
732 new_nearest_unsent_d = 0;
733 m_nothing_to_send_pause_timer = 2.0;
734 /*infostream<<"GetNextBlocks(): d wrapped around for "
735 <<server->getPlayerName(peer_id)
736 <<"; setting to 0 and pausing"<<std::endl;*/
738 if(nearest_sent_d != -1)
739 new_nearest_unsent_d = nearest_sent_d;
741 new_nearest_unsent_d = d;
745 if(new_nearest_unsent_d != -1)
746 m_nearest_unsent_d = new_nearest_unsent_d;
748 /*timer_result = timer.stop(true);
749 if(timer_result != 0)
750 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
753 void RemoteClient::SendObjectData(
756 core::map<v3s16, bool> &stepped_blocks
759 DSTACK(__FUNCTION_NAME);
761 // Can't send anything without knowing version
762 if(serialization_version == SER_FMT_VER_INVALID)
764 infostream<<"RemoteClient::SendObjectData(): Not sending, no version."
770 Send a TOCLIENT_OBJECTDATA packet.
774 u16 number of player positions
786 std::ostringstream os(std::ios_base::binary);
790 writeU16(buf, TOCLIENT_OBJECTDATA);
791 os.write((char*)buf, 2);
794 Get and write player data
797 // Get connected players
798 core::list<Player*> players = server->m_env->getPlayers(true);
800 // Write player count
801 u16 playercount = players.size();
802 writeU16(buf, playercount);
803 os.write((char*)buf, 2);
805 core::list<Player*>::Iterator i;
806 for(i = players.begin();
807 i != players.end(); i++)
811 v3f pf = player->getPosition();
812 v3f sf = player->getSpeed();
814 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
815 v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
816 s32 pitch_i (player->getPitch() * 100);
817 s32 yaw_i (player->getYaw() * 100);
819 writeU16(buf, player->peer_id);
820 os.write((char*)buf, 2);
821 writeV3S32(buf, position_i);
822 os.write((char*)buf, 12);
823 writeV3S32(buf, speed_i);
824 os.write((char*)buf, 12);
825 writeS32(buf, pitch_i);
826 os.write((char*)buf, 4);
827 writeS32(buf, yaw_i);
828 os.write((char*)buf, 4);
832 Get and write object data (dummy, for compatibility)
837 os.write((char*)buf, 2);
843 //infostream<<"Server: Sending object data to "<<peer_id<<std::endl;
846 std::string s = os.str();
847 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
848 // Send as unreliable
849 server->m_con.Send(peer_id, 0, data, false);
852 void RemoteClient::GotBlock(v3s16 p)
854 if(m_blocks_sending.find(p) != NULL)
855 m_blocks_sending.remove(p);
858 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
859 " m_blocks_sending"<<std::endl;*/
860 m_excess_gotblocks++;
862 m_blocks_sent.insert(p, true);
865 void RemoteClient::SentBlock(v3s16 p)
867 if(m_blocks_sending.find(p) == NULL)
868 m_blocks_sending.insert(p, 0.0);
870 infostream<<"RemoteClient::SentBlock(): Sent block"
871 " already in m_blocks_sending"<<std::endl;
874 void RemoteClient::SetBlockNotSent(v3s16 p)
876 m_nearest_unsent_d = 0;
878 if(m_blocks_sending.find(p) != NULL)
879 m_blocks_sending.remove(p);
880 if(m_blocks_sent.find(p) != NULL)
881 m_blocks_sent.remove(p);
884 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
886 m_nearest_unsent_d = 0;
888 for(core::map<v3s16, MapBlock*>::Iterator
889 i = blocks.getIterator();
890 i.atEnd()==false; i++)
892 v3s16 p = i.getNode()->getKey();
894 if(m_blocks_sending.find(p) != NULL)
895 m_blocks_sending.remove(p);
896 if(m_blocks_sent.find(p) != NULL)
897 m_blocks_sent.remove(p);
905 PlayerInfo::PlayerInfo()
911 void PlayerInfo::PrintLine(std::ostream *s)
914 (*s)<<"\""<<name<<"\" ("
915 <<(position.X/10)<<","<<(position.Y/10)
916 <<","<<(position.Z/10)<<") ";
918 (*s)<<" avg_rtt="<<avg_rtt;
922 u32 PIChecksum(core::list<PlayerInfo> &l)
924 core::list<PlayerInfo>::Iterator i;
927 for(i=l.begin(); i!=l.end(); i++)
929 checksum += a * (i->id+1);
930 checksum ^= 0x435aafcd;
944 std::set<std::string> depends;
945 std::set<std::string> unsatisfied_depends;
947 ModSpec(const std::string &name_="", const std::string path_="",
948 const std::set<std::string> &depends_=std::set<std::string>()):
952 unsatisfied_depends(depends_)
956 // Get a dependency-sorted list of ModSpecs
957 static core::list<ModSpec> getMods(core::list<std::string> &modspaths)
959 std::queue<ModSpec> mods_satisfied;
960 core::list<ModSpec> mods_unsorted;
961 core::list<ModSpec> mods_sorted;
962 for(core::list<std::string>::Iterator i = modspaths.begin();
963 i != modspaths.end(); i++){
964 std::string modspath = *i;
965 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(modspath);
966 for(u32 j=0; j<dirlist.size(); j++){
969 std::string modname = dirlist[j].name;
970 std::string modpath = modspath + DIR_DELIM + modname;
971 std::set<std::string> depends;
972 std::ifstream is((modpath+DIR_DELIM+"depends.txt").c_str(),
973 std::ios_base::binary);
976 std::getline(is, dep);
981 ModSpec spec(modname, modpath, depends);
982 mods_unsorted.push_back(spec);
984 mods_satisfied.push(spec);
987 // Sort by depencencies
988 while(!mods_satisfied.empty()){
989 ModSpec mod = mods_satisfied.front();
990 mods_satisfied.pop();
991 mods_sorted.push_back(mod);
992 for(core::list<ModSpec>::Iterator i = mods_unsorted.begin();
993 i != mods_unsorted.end(); i++){
995 if(mod2.unsatisfied_depends.empty())
997 mod2.unsatisfied_depends.erase(mod.name);
998 if(!mod2.unsatisfied_depends.empty())
1000 mods_satisfied.push(mod2);
1003 // Check unsatisfied dependencies
1004 for(core::list<ModSpec>::Iterator i = mods_unsorted.begin();
1005 i != mods_unsorted.end(); i++){
1007 if(mod.unsatisfied_depends.empty())
1009 errorstream<<"mod \""<<mod.name
1010 <<"\" has unsatisfied dependencies:";
1011 for(std::set<std::string>::iterator
1012 i = mod.unsatisfied_depends.begin();
1013 i != mod.unsatisfied_depends.end(); i++){
1014 errorstream<<" \""<<(*i)<<"\"";
1016 errorstream<<". Loading nevertheless."<<std::endl;
1017 mods_sorted.push_back(mod);
1027 std::string mapsavedir,
1028 std::string configpath
1031 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
1032 m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"),
1033 m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"),
1035 m_toolmgr(createToolDefManager()),
1036 m_nodedef(createNodeDefManager()),
1037 m_craftdef(createCraftDefManager()),
1038 m_craftitemdef(createCraftItemDefManager()),
1040 m_emergethread(this),
1042 m_time_of_day_send_timer(0),
1044 m_mapsavedir(mapsavedir),
1045 m_configpath(configpath),
1046 m_shutdown_requested(false),
1047 m_ignore_map_edit_events(false),
1048 m_ignore_map_edit_events_peer_id(0)
1050 m_liquid_transform_timer = 0.0;
1051 m_print_info_timer = 0.0;
1052 m_objectdata_timer = 0.0;
1053 m_emergethread_trigger_timer = 0.0;
1054 m_savemap_timer = 0.0;
1058 m_step_dtime_mutex.Init();
1061 JMutexAutoLock envlock(m_env_mutex);
1062 JMutexAutoLock conlock(m_con_mutex);
1064 infostream<<"m_nodedef="<<m_nodedef<<std::endl;
1066 // Path to builtin.lua
1067 std::string builtinpath = porting::path_data + DIR_DELIM + "builtin.lua";
1068 // Add default global mod path
1069 m_modspaths.push_back(porting::path_data + DIR_DELIM + "mods");
1071 // Initialize scripting
1073 infostream<<"Server: Initializing scripting"<<std::endl;
1074 m_lua = script_init();
1077 scriptapi_export(m_lua, this);
1078 // Load and run builtin.lua
1079 infostream<<"Server: Loading builtin Lua stuff from \""<<builtinpath
1081 bool success = script_load(m_lua, builtinpath.c_str());
1083 errorstream<<"Server: Failed to load and run "
1084 <<builtinpath<<std::endl;
1087 // Load and run "mod" scripts
1088 core::list<ModSpec> mods = getMods(m_modspaths);
1089 for(core::list<ModSpec>::Iterator i = mods.begin();
1090 i != mods.end(); i++){
1092 infostream<<"Server: Loading mod \""<<mod.name<<"\""<<std::endl;
1093 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1094 bool success = script_load(m_lua, scriptpath.c_str());
1096 errorstream<<"Server: Failed to load and run "
1097 <<scriptpath<<std::endl;
1102 // Initialize Environment
1104 m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua,
1107 // Give environment reference to scripting api
1108 scriptapi_add_environment(m_lua, m_env);
1110 // Register us to receive map edit events
1111 m_env->getMap().addEventReceiver(this);
1113 // If file exists, load environment metadata
1114 if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt"))
1116 infostream<<"Server: Loading environment metadata"<<std::endl;
1117 m_env->loadMeta(m_mapsavedir);
1121 infostream<<"Server: Loading players"<<std::endl;
1122 m_env->deSerializePlayers(m_mapsavedir);
1125 Add some test ActiveBlockModifiers to environment
1127 add_legacy_abms(m_env, m_nodedef);
1132 infostream<<"Server::~Server()"<<std::endl;
1135 Send shutdown message
1138 JMutexAutoLock conlock(m_con_mutex);
1140 std::wstring line = L"*** Server shutting down";
1143 Send the message to clients
1145 for(core::map<u16, RemoteClient*>::Iterator
1146 i = m_clients.getIterator();
1147 i.atEnd() == false; i++)
1149 // Get client and check that it is valid
1150 RemoteClient *client = i.getNode()->getValue();
1151 assert(client->peer_id == i.getNode()->getKey());
1152 if(client->serialization_version == SER_FMT_VER_INVALID)
1156 SendChatMessage(client->peer_id, line);
1158 catch(con::PeerNotFoundException &e)
1164 JMutexAutoLock envlock(m_env_mutex);
1169 infostream<<"Server: Saving players"<<std::endl;
1170 m_env->serializePlayers(m_mapsavedir);
1173 Save environment metadata
1175 infostream<<"Server: Saving environment metadata"<<std::endl;
1176 m_env->saveMeta(m_mapsavedir);
1188 JMutexAutoLock clientslock(m_con_mutex);
1190 for(core::map<u16, RemoteClient*>::Iterator
1191 i = m_clients.getIterator();
1192 i.atEnd() == false; i++)
1195 // NOTE: These are removed by env destructor
1197 u16 peer_id = i.getNode()->getKey();
1198 JMutexAutoLock envlock(m_env_mutex);
1199 m_env->removePlayer(peer_id);
1203 delete i.getNode()->getValue();
1207 // Delete Environment
1213 delete m_craftitemdef;
1215 // Deinitialize scripting
1216 infostream<<"Server: Deinitializing scripting"<<std::endl;
1217 script_deinit(m_lua);
1220 void Server::start(unsigned short port)
1222 DSTACK(__FUNCTION_NAME);
1223 // Stop thread if already running
1226 // Initialize connection
1227 m_con.SetTimeoutMs(30);
1231 m_thread.setRun(true);
1234 infostream<<"Server: Started on port "<<port<<std::endl;
1239 DSTACK(__FUNCTION_NAME);
1241 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1243 // Stop threads (set run=false first so both start stopping)
1244 m_thread.setRun(false);
1245 m_emergethread.setRun(false);
1247 m_emergethread.stop();
1249 infostream<<"Server: Threads stopped"<<std::endl;
1252 void Server::step(float dtime)
1254 DSTACK(__FUNCTION_NAME);
1259 JMutexAutoLock lock(m_step_dtime_mutex);
1260 m_step_dtime += dtime;
1264 void Server::AsyncRunStep()
1266 DSTACK(__FUNCTION_NAME);
1268 g_profiler->add("Server::AsyncRunStep (num)", 1);
1272 JMutexAutoLock lock1(m_step_dtime_mutex);
1273 dtime = m_step_dtime;
1277 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
1278 // Send blocks to clients
1285 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1287 //infostream<<"Server steps "<<dtime<<std::endl;
1288 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1291 JMutexAutoLock lock1(m_step_dtime_mutex);
1292 m_step_dtime -= dtime;
1299 m_uptime.set(m_uptime.get() + dtime);
1303 // Process connection's timeouts
1304 JMutexAutoLock lock2(m_con_mutex);
1305 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1306 m_con.RunTimeouts(dtime);
1310 // This has to be called so that the client list gets synced
1311 // with the peer list of the connection
1312 handlePeerChanges();
1316 Update m_time_of_day and overall game time
1319 JMutexAutoLock envlock(m_env_mutex);
1321 m_time_counter += dtime;
1322 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1323 u32 units = (u32)(m_time_counter*speed);
1324 m_time_counter -= (f32)units / speed;
1326 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1328 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1331 Send to clients at constant intervals
1334 m_time_of_day_send_timer -= dtime;
1335 if(m_time_of_day_send_timer < 0.0)
1337 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1339 //JMutexAutoLock envlock(m_env_mutex);
1340 JMutexAutoLock conlock(m_con_mutex);
1342 for(core::map<u16, RemoteClient*>::Iterator
1343 i = m_clients.getIterator();
1344 i.atEnd() == false; i++)
1346 RemoteClient *client = i.getNode()->getValue();
1347 //Player *player = m_env->getPlayer(client->peer_id);
1349 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1350 m_env->getTimeOfDay());
1352 m_con.Send(client->peer_id, 0, data, true);
1358 JMutexAutoLock lock(m_env_mutex);
1360 ScopeProfiler sp(g_profiler, "SEnv step");
1361 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1365 const float map_timer_and_unload_dtime = 2.92;
1366 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1368 JMutexAutoLock lock(m_env_mutex);
1369 // Run Map's timers and unload unused data
1370 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1371 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1372 g_settings->getFloat("server_unload_unused_data_timeout"));
1383 JMutexAutoLock lock(m_env_mutex);
1384 JMutexAutoLock lock2(m_con_mutex);
1386 //float player_max_speed = BS * 4.0; // Normal speed
1387 float player_max_speed = BS * 20; // Fast speed
1388 float player_max_speed_up = BS * 20;
1390 player_max_speed *= 2.5; // Tolerance
1391 player_max_speed_up *= 2.5;
1393 for(core::map<u16, RemoteClient*>::Iterator
1394 i = m_clients.getIterator();
1395 i.atEnd() == false; i++)
1397 RemoteClient *client = i.getNode()->getValue();
1398 ServerRemotePlayer *player =
1399 static_cast<ServerRemotePlayer*>
1400 (m_env->getPlayer(client->peer_id));
1405 Check player movements
1407 NOTE: Actually the server should handle player physics like the
1408 client does and compare player's position to what is calculated
1409 on our side. This is required when eg. players fly due to an
1412 player->m_last_good_position_age += dtime;
1413 if(player->m_last_good_position_age >= 2.0){
1414 float age = player->m_last_good_position_age;
1415 v3f diff = (player->getPosition() - player->m_last_good_position);
1416 float d_vert = diff.Y;
1418 float d_horiz = diff.getLength();
1419 /*infostream<<player->getName()<<"'s horizontal speed is "
1420 <<(d_horiz/age)<<std::endl;*/
1421 if(d_horiz <= age * player_max_speed &&
1422 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1423 player->m_last_good_position = player->getPosition();
1425 actionstream<<"Player "<<player->getName()
1426 <<" moved too fast; resetting position"
1428 player->setPosition(player->m_last_good_position);
1429 SendMovePlayer(player);
1431 player->m_last_good_position_age = 0;
1435 Send player inventories and HPs if necessary
1437 if(player->m_inventory_not_sent){
1438 UpdateCrafting(player->peer_id);
1439 SendInventory(player->peer_id);
1441 if(player->m_hp_not_sent){
1442 SendPlayerHP(player);
1447 /* Transform liquids */
1448 m_liquid_transform_timer += dtime;
1449 if(m_liquid_transform_timer >= 1.00)
1451 m_liquid_transform_timer -= 1.00;
1453 JMutexAutoLock lock(m_env_mutex);
1455 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1457 core::map<v3s16, MapBlock*> modified_blocks;
1458 m_env->getMap().transformLiquids(modified_blocks);
1463 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1464 ServerMap &map = ((ServerMap&)m_env->getMap());
1465 map.updateLighting(modified_blocks, lighting_modified_blocks);
1467 // Add blocks modified by lighting to modified_blocks
1468 for(core::map<v3s16, MapBlock*>::Iterator
1469 i = lighting_modified_blocks.getIterator();
1470 i.atEnd() == false; i++)
1472 MapBlock *block = i.getNode()->getValue();
1473 modified_blocks.insert(block->getPos(), block);
1477 Set the modified blocks unsent for all the clients
1480 JMutexAutoLock lock2(m_con_mutex);
1482 for(core::map<u16, RemoteClient*>::Iterator
1483 i = m_clients.getIterator();
1484 i.atEnd() == false; i++)
1486 RemoteClient *client = i.getNode()->getValue();
1488 if(modified_blocks.size() > 0)
1490 // Remove block from sent history
1491 client->SetBlocksNotSent(modified_blocks);
1496 // Periodically print some info
1498 float &counter = m_print_info_timer;
1504 JMutexAutoLock lock2(m_con_mutex);
1506 if(m_clients.size() != 0)
1507 infostream<<"Players:"<<std::endl;
1508 for(core::map<u16, RemoteClient*>::Iterator
1509 i = m_clients.getIterator();
1510 i.atEnd() == false; i++)
1512 //u16 peer_id = i.getNode()->getKey();
1513 RemoteClient *client = i.getNode()->getValue();
1514 Player *player = m_env->getPlayer(client->peer_id);
1517 infostream<<"* "<<player->getName()<<"\t";
1518 client->PrintInfo(infostream);
1523 //if(g_settings->getBool("enable_experimental"))
1527 Check added and deleted active objects
1530 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1531 JMutexAutoLock envlock(m_env_mutex);
1532 JMutexAutoLock conlock(m_con_mutex);
1534 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1536 // Radius inside which objects are active
1537 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1538 radius *= MAP_BLOCKSIZE;
1540 for(core::map<u16, RemoteClient*>::Iterator
1541 i = m_clients.getIterator();
1542 i.atEnd() == false; i++)
1544 RemoteClient *client = i.getNode()->getValue();
1545 Player *player = m_env->getPlayer(client->peer_id);
1548 // This can happen if the client timeouts somehow
1549 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1551 <<" has no associated player"<<std::endl;*/
1554 v3s16 pos = floatToInt(player->getPosition(), BS);
1556 core::map<u16, bool> removed_objects;
1557 core::map<u16, bool> added_objects;
1558 m_env->getRemovedActiveObjects(pos, radius,
1559 client->m_known_objects, removed_objects);
1560 m_env->getAddedActiveObjects(pos, radius,
1561 client->m_known_objects, added_objects);
1563 // Ignore if nothing happened
1564 if(removed_objects.size() == 0 && added_objects.size() == 0)
1566 //infostream<<"active objects: none changed"<<std::endl;
1570 std::string data_buffer;
1574 // Handle removed objects
1575 writeU16((u8*)buf, removed_objects.size());
1576 data_buffer.append(buf, 2);
1577 for(core::map<u16, bool>::Iterator
1578 i = removed_objects.getIterator();
1579 i.atEnd()==false; i++)
1582 u16 id = i.getNode()->getKey();
1583 ServerActiveObject* obj = m_env->getActiveObject(id);
1585 // Add to data buffer for sending
1586 writeU16((u8*)buf, i.getNode()->getKey());
1587 data_buffer.append(buf, 2);
1589 // Remove from known objects
1590 client->m_known_objects.remove(i.getNode()->getKey());
1592 if(obj && obj->m_known_by_count > 0)
1593 obj->m_known_by_count--;
1596 // Handle added objects
1597 writeU16((u8*)buf, added_objects.size());
1598 data_buffer.append(buf, 2);
1599 for(core::map<u16, bool>::Iterator
1600 i = added_objects.getIterator();
1601 i.atEnd()==false; i++)
1604 u16 id = i.getNode()->getKey();
1605 ServerActiveObject* obj = m_env->getActiveObject(id);
1608 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1610 infostream<<"WARNING: "<<__FUNCTION_NAME
1611 <<": NULL object"<<std::endl;
1613 type = obj->getType();
1615 // Add to data buffer for sending
1616 writeU16((u8*)buf, id);
1617 data_buffer.append(buf, 2);
1618 writeU8((u8*)buf, type);
1619 data_buffer.append(buf, 1);
1622 data_buffer.append(serializeLongString(
1623 obj->getClientInitializationData()));
1625 data_buffer.append(serializeLongString(""));
1627 // Add to known objects
1628 client->m_known_objects.insert(i.getNode()->getKey(), false);
1631 obj->m_known_by_count++;
1635 SharedBuffer<u8> reply(2 + data_buffer.size());
1636 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1637 memcpy((char*)&reply[2], data_buffer.c_str(),
1638 data_buffer.size());
1640 m_con.Send(client->peer_id, 0, reply, true);
1642 infostream<<"Server: Sent object remove/add: "
1643 <<removed_objects.size()<<" removed, "
1644 <<added_objects.size()<<" added, "
1645 <<"packet size is "<<reply.getSize()<<std::endl;
1650 Collect a list of all the objects known by the clients
1651 and report it back to the environment.
1654 core::map<u16, bool> all_known_objects;
1656 for(core::map<u16, RemoteClient*>::Iterator
1657 i = m_clients.getIterator();
1658 i.atEnd() == false; i++)
1660 RemoteClient *client = i.getNode()->getValue();
1661 // Go through all known objects of client
1662 for(core::map<u16, bool>::Iterator
1663 i = client->m_known_objects.getIterator();
1664 i.atEnd()==false; i++)
1666 u16 id = i.getNode()->getKey();
1667 all_known_objects[id] = true;
1671 m_env->setKnownActiveObjects(whatever);
1677 Send object messages
1680 JMutexAutoLock envlock(m_env_mutex);
1681 JMutexAutoLock conlock(m_con_mutex);
1683 //ScopeProfiler sp(g_profiler, "Server: sending object messages");
1686 // Value = data sent by object
1687 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1689 // Get active object messages from environment
1692 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1696 core::list<ActiveObjectMessage>* message_list = NULL;
1697 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1698 n = buffered_messages.find(aom.id);
1701 message_list = new core::list<ActiveObjectMessage>;
1702 buffered_messages.insert(aom.id, message_list);
1706 message_list = n->getValue();
1708 message_list->push_back(aom);
1711 // Route data to every client
1712 for(core::map<u16, RemoteClient*>::Iterator
1713 i = m_clients.getIterator();
1714 i.atEnd()==false; i++)
1716 RemoteClient *client = i.getNode()->getValue();
1717 std::string reliable_data;
1718 std::string unreliable_data;
1719 // Go through all objects in message buffer
1720 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1721 j = buffered_messages.getIterator();
1722 j.atEnd()==false; j++)
1724 // If object is not known by client, skip it
1725 u16 id = j.getNode()->getKey();
1726 if(client->m_known_objects.find(id) == NULL)
1728 // Get message list of object
1729 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1730 // Go through every message
1731 for(core::list<ActiveObjectMessage>::Iterator
1732 k = list->begin(); k != list->end(); k++)
1734 // Compose the full new data with header
1735 ActiveObjectMessage aom = *k;
1736 std::string new_data;
1739 writeU16((u8*)&buf[0], aom.id);
1740 new_data.append(buf, 2);
1742 new_data += serializeString(aom.datastring);
1743 // Add data to buffer
1745 reliable_data += new_data;
1747 unreliable_data += new_data;
1751 reliable_data and unreliable_data are now ready.
1754 if(reliable_data.size() > 0)
1756 SharedBuffer<u8> reply(2 + reliable_data.size());
1757 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1758 memcpy((char*)&reply[2], reliable_data.c_str(),
1759 reliable_data.size());
1761 m_con.Send(client->peer_id, 0, reply, true);
1763 if(unreliable_data.size() > 0)
1765 SharedBuffer<u8> reply(2 + unreliable_data.size());
1766 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1767 memcpy((char*)&reply[2], unreliable_data.c_str(),
1768 unreliable_data.size());
1769 // Send as unreliable
1770 m_con.Send(client->peer_id, 0, reply, false);
1773 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1775 infostream<<"Server: Size of object message data: "
1776 <<"reliable: "<<reliable_data.size()
1777 <<", unreliable: "<<unreliable_data.size()
1782 // Clear buffered_messages
1783 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1784 i = buffered_messages.getIterator();
1785 i.atEnd()==false; i++)
1787 delete i.getNode()->getValue();
1791 } // enable_experimental
1794 Send queued-for-sending map edit events.
1797 // Don't send too many at a time
1800 // Single change sending is disabled if queue size is not small
1801 bool disable_single_change_sending = false;
1802 if(m_unsent_map_edit_queue.size() >= 4)
1803 disable_single_change_sending = true;
1805 bool got_any_events = false;
1807 // We'll log the amount of each
1810 while(m_unsent_map_edit_queue.size() != 0)
1812 got_any_events = true;
1814 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1816 // Players far away from the change are stored here.
1817 // Instead of sending the changes, MapBlocks are set not sent
1819 core::list<u16> far_players;
1821 if(event->type == MEET_ADDNODE)
1823 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1824 prof.add("MEET_ADDNODE", 1);
1825 if(disable_single_change_sending)
1826 sendAddNode(event->p, event->n, event->already_known_by_peer,
1829 sendAddNode(event->p, event->n, event->already_known_by_peer,
1832 else if(event->type == MEET_REMOVENODE)
1834 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1835 prof.add("MEET_REMOVENODE", 1);
1836 if(disable_single_change_sending)
1837 sendRemoveNode(event->p, event->already_known_by_peer,
1840 sendRemoveNode(event->p, event->already_known_by_peer,
1843 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1845 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1846 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1847 setBlockNotSent(event->p);
1849 else if(event->type == MEET_OTHER)
1851 infostream<<"Server: MEET_OTHER"<<std::endl;
1852 prof.add("MEET_OTHER", 1);
1853 for(core::map<v3s16, bool>::Iterator
1854 i = event->modified_blocks.getIterator();
1855 i.atEnd()==false; i++)
1857 v3s16 p = i.getNode()->getKey();
1863 prof.add("unknown", 1);
1864 infostream<<"WARNING: Server: Unknown MapEditEvent "
1865 <<((u32)event->type)<<std::endl;
1869 Set blocks not sent to far players
1871 if(far_players.size() > 0)
1873 // Convert list format to that wanted by SetBlocksNotSent
1874 core::map<v3s16, MapBlock*> modified_blocks2;
1875 for(core::map<v3s16, bool>::Iterator
1876 i = event->modified_blocks.getIterator();
1877 i.atEnd()==false; i++)
1879 v3s16 p = i.getNode()->getKey();
1880 modified_blocks2.insert(p,
1881 m_env->getMap().getBlockNoCreateNoEx(p));
1883 // Set blocks not sent
1884 for(core::list<u16>::Iterator
1885 i = far_players.begin();
1886 i != far_players.end(); i++)
1889 RemoteClient *client = getClient(peer_id);
1892 client->SetBlocksNotSent(modified_blocks2);
1898 /*// Don't send too many at a time
1900 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1906 infostream<<"Server: MapEditEvents:"<<std::endl;
1907 prof.print(infostream);
1913 Send object positions
1916 float &counter = m_objectdata_timer;
1918 if(counter >= g_settings->getFloat("objectdata_interval"))
1920 JMutexAutoLock lock1(m_env_mutex);
1921 JMutexAutoLock lock2(m_con_mutex);
1923 //ScopeProfiler sp(g_profiler, "Server: sending player positions");
1925 SendObjectData(counter);
1932 Trigger emergethread (it somehow gets to a non-triggered but
1933 bysy state sometimes)
1936 float &counter = m_emergethread_trigger_timer;
1942 m_emergethread.trigger();
1946 // Save map, players and auth stuff
1948 float &counter = m_savemap_timer;
1950 if(counter >= g_settings->getFloat("server_map_save_interval"))
1954 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1957 if(m_authmanager.isModified())
1958 m_authmanager.save();
1961 if(m_banmanager.isModified())
1962 m_banmanager.save();
1965 JMutexAutoLock lock(m_env_mutex);
1967 // Save changed parts of map
1968 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1971 m_env->serializePlayers(m_mapsavedir);
1973 // Save environment metadata
1974 m_env->saveMeta(m_mapsavedir);
1979 void Server::Receive()
1981 DSTACK(__FUNCTION_NAME);
1982 SharedBuffer<u8> data;
1987 JMutexAutoLock conlock(m_con_mutex);
1988 datasize = m_con.Receive(peer_id, data);
1991 // This has to be called so that the client list gets synced
1992 // with the peer list of the connection
1993 handlePeerChanges();
1995 ProcessData(*data, datasize, peer_id);
1997 catch(con::InvalidIncomingDataException &e)
1999 infostream<<"Server::Receive(): "
2000 "InvalidIncomingDataException: what()="
2001 <<e.what()<<std::endl;
2003 catch(con::PeerNotFoundException &e)
2005 //NOTE: This is not needed anymore
2007 // The peer has been disconnected.
2008 // Find the associated player and remove it.
2010 /*JMutexAutoLock envlock(m_env_mutex);
2012 infostream<<"ServerThread: peer_id="<<peer_id
2013 <<" has apparently closed connection. "
2014 <<"Removing player."<<std::endl;
2016 m_env->removePlayer(peer_id);*/
2020 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
2022 DSTACK(__FUNCTION_NAME);
2023 // Environment is locked first.
2024 JMutexAutoLock envlock(m_env_mutex);
2025 JMutexAutoLock conlock(m_con_mutex);
2028 Address address = m_con.GetPeerAddress(peer_id);
2030 // drop player if is ip is banned
2031 if(m_banmanager.isIpBanned(address.serializeString())){
2032 SendAccessDenied(m_con, peer_id,
2033 L"Your ip is banned. Banned name was "
2034 +narrow_to_wide(m_banmanager.getBanName(
2035 address.serializeString())));
2036 m_con.DeletePeer(peer_id);
2040 catch(con::PeerNotFoundException &e)
2042 infostream<<"Server::ProcessData(): Cancelling: peer "
2043 <<peer_id<<" not found"<<std::endl;
2047 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
2055 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
2057 if(command == TOSERVER_INIT)
2059 // [0] u16 TOSERVER_INIT
2060 // [2] u8 SER_FMT_VER_HIGHEST
2061 // [3] u8[20] player_name
2062 // [23] u8[28] password <--- can be sent without this, from old versions
2064 if(datasize < 2+1+PLAYERNAME_SIZE)
2067 infostream<<"Server: Got TOSERVER_INIT from "
2068 <<peer_id<<std::endl;
2070 // First byte after command is maximum supported
2071 // serialization version
2072 u8 client_max = data[2];
2073 u8 our_max = SER_FMT_VER_HIGHEST;
2074 // Use the highest version supported by both
2075 u8 deployed = core::min_(client_max, our_max);
2076 // If it's lower than the lowest supported, give up.
2077 if(deployed < SER_FMT_VER_LOWEST)
2078 deployed = SER_FMT_VER_INVALID;
2080 //peer->serialization_version = deployed;
2081 getClient(peer_id)->pending_serialization_version = deployed;
2083 if(deployed == SER_FMT_VER_INVALID)
2085 infostream<<"Server: Cannot negotiate "
2086 "serialization version with peer "
2087 <<peer_id<<std::endl;
2088 SendAccessDenied(m_con, peer_id, std::wstring(
2089 L"Your client's version is not supported.\n"
2090 L"Server version is ")
2091 + narrow_to_wide(VERSION_STRING) + L"."
2097 Read and check network protocol version
2100 u16 net_proto_version = 0;
2101 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2103 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2106 getClient(peer_id)->net_proto_version = net_proto_version;
2108 if(net_proto_version == 0)
2110 SendAccessDenied(m_con, peer_id, std::wstring(
2111 L"Your client's version is not supported.\n"
2112 L"Server version is ")
2113 + narrow_to_wide(VERSION_STRING) + L"."
2118 if(g_settings->getBool("strict_protocol_version_checking"))
2120 if(net_proto_version != PROTOCOL_VERSION)
2122 SendAccessDenied(m_con, peer_id, std::wstring(
2123 L"Your client's version is not supported.\n"
2124 L"Server version is ")
2125 + narrow_to_wide(VERSION_STRING) + L"."
2136 char playername[PLAYERNAME_SIZE];
2137 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2139 playername[i] = data[3+i];
2141 playername[PLAYERNAME_SIZE-1] = 0;
2143 if(playername[0]=='\0')
2145 infostream<<"Server: Player has empty name"<<std::endl;
2146 SendAccessDenied(m_con, peer_id,
2151 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2153 infostream<<"Server: Player has invalid name"<<std::endl;
2154 SendAccessDenied(m_con, peer_id,
2155 L"Name contains unallowed characters");
2160 char password[PASSWORD_SIZE];
2161 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2163 // old version - assume blank password
2168 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2170 password[i] = data[23+i];
2172 password[PASSWORD_SIZE-1] = 0;
2175 // Add player to auth manager
2176 if(m_authmanager.exists(playername) == false)
2178 std::wstring default_password =
2179 narrow_to_wide(g_settings->get("default_password"));
2180 std::string translated_default_password =
2181 translatePassword(playername, default_password);
2183 // If default_password is empty, allow any initial password
2184 if (default_password.length() == 0)
2185 translated_default_password = password;
2187 infostream<<"Server: adding player "<<playername
2188 <<" to auth manager"<<std::endl;
2189 m_authmanager.add(playername);
2190 m_authmanager.setPassword(playername, translated_default_password);
2191 m_authmanager.setPrivs(playername,
2192 stringToPrivs(g_settings->get("default_privs")));
2193 m_authmanager.save();
2196 std::string checkpwd = m_authmanager.getPassword(playername);
2198 /*infostream<<"Server: Client gave password '"<<password
2199 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2201 if(password != checkpwd)
2203 infostream<<"Server: peer_id="<<peer_id
2204 <<": supplied invalid password for "
2205 <<playername<<std::endl;
2206 SendAccessDenied(m_con, peer_id, L"Invalid password");
2210 // Enforce user limit.
2211 // Don't enforce for users that have some admin right
2212 if(m_clients.size() >= g_settings->getU16("max_users") &&
2213 (m_authmanager.getPrivs(playername)
2214 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2215 playername != g_settings->get("name"))
2217 SendAccessDenied(m_con, peer_id, L"Too many users.");
2222 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2224 // If failed, cancel
2227 infostream<<"Server: peer_id="<<peer_id
2228 <<": failed to emerge player"<<std::endl;
2233 PlayerSAO *sao = new PlayerSAO(m_env, player->getPosition(), player);
2234 m_env->addActiveObject(sao);
2237 Answer with a TOCLIENT_INIT
2240 SharedBuffer<u8> reply(2+1+6+8);
2241 writeU16(&reply[0], TOCLIENT_INIT);
2242 writeU8(&reply[2], deployed);
2243 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2244 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2247 m_con.Send(peer_id, 0, reply, true);
2251 Send complete position information
2253 SendMovePlayer(player);
2258 if(command == TOSERVER_INIT2)
2260 infostream<<"Server: Got TOSERVER_INIT2 from "
2261 <<peer_id<<std::endl;
2264 getClient(peer_id)->serialization_version
2265 = getClient(peer_id)->pending_serialization_version;
2268 Send some initialization data
2271 // Send tool definitions
2272 SendToolDef(m_con, peer_id, m_toolmgr);
2274 // Send node definitions
2275 SendNodeDef(m_con, peer_id, m_nodedef);
2277 // Send CraftItem definitions
2278 SendCraftItemDef(m_con, peer_id, m_craftitemdef);
2281 SendTextures(peer_id);
2283 // Send player info to all players
2286 // Send inventory to player
2287 UpdateCrafting(peer_id);
2288 SendInventory(peer_id);
2290 // Send player items to all players
2293 Player *player = m_env->getPlayer(peer_id);
2296 SendPlayerHP(player);
2300 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2301 m_env->getTimeOfDay());
2302 m_con.Send(peer_id, 0, data, true);
2305 // Send information about server to player in chat
2306 SendChatMessage(peer_id, getStatusString());
2308 // Send information about joining in chat
2310 std::wstring name = L"unknown";
2311 Player *player = m_env->getPlayer(peer_id);
2313 name = narrow_to_wide(player->getName());
2315 std::wstring message;
2318 message += L" joined game";
2319 BroadcastChatMessage(message);
2322 // Warnings about protocol version can be issued here
2323 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2325 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2329 Check HP, respawn if necessary
2331 HandlePlayerHP(player, 0);
2337 std::ostringstream os(std::ios_base::binary);
2338 for(core::map<u16, RemoteClient*>::Iterator
2339 i = m_clients.getIterator();
2340 i.atEnd() == false; i++)
2342 RemoteClient *client = i.getNode()->getValue();
2343 assert(client->peer_id == i.getNode()->getKey());
2344 if(client->serialization_version == SER_FMT_VER_INVALID)
2347 Player *player = m_env->getPlayer(client->peer_id);
2350 // Get name of player
2351 os<<player->getName()<<" ";
2354 actionstream<<player->getName()<<" joins game. List of players: "
2355 <<os.str()<<std::endl;
2361 if(peer_ser_ver == SER_FMT_VER_INVALID)
2363 infostream<<"Server::ProcessData(): Cancelling: Peer"
2364 " serialization format invalid or not initialized."
2365 " Skipping incoming command="<<command<<std::endl;
2369 Player *player = m_env->getPlayer(peer_id);
2370 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2373 infostream<<"Server::ProcessData(): Cancelling: "
2374 "No player for peer_id="<<peer_id
2378 if(command == TOSERVER_PLAYERPOS)
2380 if(datasize < 2+12+12+4+4)
2384 v3s32 ps = readV3S32(&data[start+2]);
2385 v3s32 ss = readV3S32(&data[start+2+12]);
2386 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2387 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2388 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2389 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2390 pitch = wrapDegrees(pitch);
2391 yaw = wrapDegrees(yaw);
2393 player->setPosition(position);
2394 player->setSpeed(speed);
2395 player->setPitch(pitch);
2396 player->setYaw(yaw);
2398 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2399 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2400 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2402 else if(command == TOSERVER_GOTBLOCKS)
2415 u16 count = data[2];
2416 for(u16 i=0; i<count; i++)
2418 if((s16)datasize < 2+1+(i+1)*6)
2419 throw con::InvalidIncomingDataException
2420 ("GOTBLOCKS length is too short");
2421 v3s16 p = readV3S16(&data[2+1+i*6]);
2422 /*infostream<<"Server: GOTBLOCKS ("
2423 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2424 RemoteClient *client = getClient(peer_id);
2425 client->GotBlock(p);
2428 else if(command == TOSERVER_DELETEDBLOCKS)
2441 u16 count = data[2];
2442 for(u16 i=0; i<count; i++)
2444 if((s16)datasize < 2+1+(i+1)*6)
2445 throw con::InvalidIncomingDataException
2446 ("DELETEDBLOCKS length is too short");
2447 v3s16 p = readV3S16(&data[2+1+i*6]);
2448 /*infostream<<"Server: DELETEDBLOCKS ("
2449 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2450 RemoteClient *client = getClient(peer_id);
2451 client->SetBlockNotSent(p);
2454 else if(command == TOSERVER_CLICK_OBJECT)
2456 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2459 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2461 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2464 else if(command == TOSERVER_GROUND_ACTION)
2466 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2470 else if(command == TOSERVER_RELEASE)
2472 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2475 else if(command == TOSERVER_SIGNTEXT)
2477 infostream<<"Server: SIGNTEXT not supported anymore"
2481 else if(command == TOSERVER_SIGNNODETEXT)
2483 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2491 std::string datastring((char*)&data[2], datasize-2);
2492 std::istringstream is(datastring, std::ios_base::binary);
2495 is.read((char*)buf, 6);
2496 v3s16 p = readV3S16(buf);
2497 is.read((char*)buf, 2);
2498 u16 textlen = readU16(buf);
2500 for(u16 i=0; i<textlen; i++)
2502 is.read((char*)buf, 1);
2503 text += (char)buf[0];
2506 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2510 meta->setText(text);
2512 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2513 <<" at "<<PP(p)<<std::endl;
2515 v3s16 blockpos = getNodeBlockPos(p);
2516 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2519 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2523 setBlockNotSent(blockpos);
2525 else if(command == TOSERVER_INVENTORY_ACTION)
2527 /*// Ignore inventory changes if in creative mode
2528 if(g_settings->getBool("creative_mode") == true)
2530 infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
2534 // Strip command and create a stream
2535 std::string datastring((char*)&data[2], datasize-2);
2536 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2537 std::istringstream is(datastring, std::ios_base::binary);
2539 InventoryAction *a = InventoryAction::deSerialize(is);
2542 infostream<<"TOSERVER_INVENTORY_ACTION: "
2543 <<"InventoryAction::deSerialize() returned NULL"
2549 c.current_player = player;
2552 Handle restrictions and special cases of the move action
2554 if(a->getType() == IACTION_MOVE
2555 && g_settings->getBool("creative_mode") == false)
2557 InventoryList *rlist = player->inventory.getList("craftresult");
2559 InventoryList *clist = player->inventory.getList("craft");
2561 InventoryList *mlist = player->inventory.getList("main");
2564 IMoveAction *ma = (IMoveAction*)a;
2567 Disable moving items into craftresult from elsewhere
2569 if(ma->to_inv == "current_player"
2570 && ma->to_list == "craftresult"
2571 && (ma->from_inv != "current_player"
2572 || ma->from_list != "craftresult"))
2574 infostream<<"Ignoring IMoveAction from "
2575 <<ma->from_inv<<":"<<ma->from_list
2576 <<" to "<<ma->to_inv<<":"<<ma->to_list
2577 <<" because dst is craftresult"
2578 <<" and src isn't craftresult"<<std::endl;
2584 Handle crafting (source is craftresult, which is preview)
2586 if(ma->from_inv == "current_player"
2587 && ma->from_list == "craftresult"
2588 && player->craftresult_is_preview)
2591 If the craftresult is placed on itself, crafting takes
2592 place and result is moved into main list
2594 if(ma->to_inv == "current_player"
2595 && ma->to_list == "craftresult")
2597 // Except if main list doesn't have free slots
2598 if(mlist->getFreeSlots() == 0){
2599 infostream<<"Cannot craft: Main list doesn't have"
2600 <<" free slots"<<std::endl;
2605 player->craftresult_is_preview = false;
2606 clist->decrementMaterials(1);
2608 InventoryItem *item1 = rlist->changeItem(0, NULL);
2609 mlist->addItem(item1);
2611 srp->m_inventory_not_sent = true;
2617 Disable action if there are no free slots in
2620 If the item is placed on an item that is not of the
2621 same kind, the existing item will be first moved to
2622 craftresult and immediately moved to the free slot.
2625 Inventory *inv_to = getInventory(&c, ma->to_inv);
2627 InventoryList *list_to = inv_to->getList(ma->to_list);
2629 if(list_to->getFreeSlots() == 0){
2630 infostream<<"Cannot craft: Destination doesn't have"
2631 <<" free slots"<<std::endl;
2635 }while(0); // Allow break
2640 player->craftresult_is_preview = false;
2641 clist->decrementMaterials(1);
2643 /* Print out action */
2644 InventoryItem *item = rlist->getItem(0);
2645 std::string itemstring = "NULL";
2647 itemstring = item->getItemString();
2648 actionstream<<player->getName()<<" crafts "
2649 <<itemstring<<std::endl;
2652 a->apply(&c, this, m_env);
2662 // Disallow moving items in elsewhere than player's inventory
2663 // if not allowed to build
2664 if((getPlayerPrivs(player) & PRIV_BUILD) == 0
2665 && (ma->from_inv != "current_player"
2666 || ma->to_inv != "current_player"))
2668 infostream<<"Cannot move outside of player's inventory: "
2669 <<"No build privilege"<<std::endl;
2674 // If player is not an admin, check for ownership of src
2675 if(ma->from_inv != "current_player"
2676 && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
2678 Strfnd fn(ma->from_inv);
2679 std::string id0 = fn.next(":");
2680 if(id0 == "nodemeta")
2683 p.X = stoi(fn.next(","));
2684 p.Y = stoi(fn.next(","));
2685 p.Z = stoi(fn.next(","));
2686 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2687 if(meta->getOwner() != "" &&
2688 meta->getOwner() != player->getName())
2690 infostream<<"Cannot move item: "
2691 "not owner of metadata"
2698 // If player is not an admin, check for ownership of dst
2699 if(ma->to_inv != "current_player"
2700 && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
2702 Strfnd fn(ma->to_inv);
2703 std::string id0 = fn.next(":");
2704 if(id0 == "nodemeta")
2707 p.X = stoi(fn.next(","));
2708 p.Y = stoi(fn.next(","));
2709 p.Z = stoi(fn.next(","));
2710 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2711 if(meta->getOwner() != "" &&
2712 meta->getOwner() != player->getName())
2714 infostream<<"Cannot move item: "
2715 "not owner of metadata"
2724 Handle restrictions and special cases of the drop action
2726 else if(a->getType() == IACTION_DROP)
2728 IDropAction *da = (IDropAction*)a;
2729 // Disallow dropping items if not allowed to build
2730 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2735 // If player is not an admin, check for ownership
2736 else if (da->from_inv != "current_player"
2737 && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
2739 Strfnd fn(da->from_inv);
2740 std::string id0 = fn.next(":");
2741 if(id0 == "nodemeta")
2744 p.X = stoi(fn.next(","));
2745 p.Y = stoi(fn.next(","));
2746 p.Z = stoi(fn.next(","));
2747 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2748 if(meta->getOwner() != "" &&
2749 meta->getOwner() != player->getName())
2751 infostream<<"Cannot move item: "
2752 "not owner of metadata"
2762 a->apply(&c, this, m_env);
2766 else if(command == TOSERVER_CHAT_MESSAGE)
2774 std::string datastring((char*)&data[2], datasize-2);
2775 std::istringstream is(datastring, std::ios_base::binary);
2778 is.read((char*)buf, 2);
2779 u16 len = readU16(buf);
2781 std::wstring message;
2782 for(u16 i=0; i<len; i++)
2784 is.read((char*)buf, 2);
2785 message += (wchar_t)readU16(buf);
2788 // Get player name of this client
2789 std::wstring name = narrow_to_wide(player->getName());
2792 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2793 wide_to_narrow(message));
2794 // If script ate the message, don't proceed
2798 // Line to send to players
2800 // Whether to send to the player that sent the line
2801 bool send_to_sender = false;
2802 // Whether to send to other players
2803 bool send_to_others = false;
2805 // Local player gets all privileges regardless of
2806 // what's set on their account.
2807 u64 privs = getPlayerPrivs(player);
2810 if(message[0] == L'/')
2812 size_t strip_size = 1;
2813 if (message[1] == L'#') // support old-style commans
2815 message = message.substr(strip_size);
2817 WStrfnd f1(message);
2818 f1.next(L" "); // Skip over /#whatever
2819 std::wstring paramstring = f1.next(L"");
2821 ServerCommandContext *ctx = new ServerCommandContext(
2822 str_split(message, L' '),
2829 std::wstring reply(processServerCommand(ctx));
2830 send_to_sender = ctx->flags & SEND_TO_SENDER;
2831 send_to_others = ctx->flags & SEND_TO_OTHERS;
2833 if (ctx->flags & SEND_NO_PREFIX)
2836 line += L"Server: " + reply;
2843 if(privs & PRIV_SHOUT)
2849 send_to_others = true;
2853 line += L"Server: You are not allowed to shout";
2854 send_to_sender = true;
2861 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2864 Send the message to clients
2866 for(core::map<u16, RemoteClient*>::Iterator
2867 i = m_clients.getIterator();
2868 i.atEnd() == false; i++)
2870 // Get client and check that it is valid
2871 RemoteClient *client = i.getNode()->getValue();
2872 assert(client->peer_id == i.getNode()->getKey());
2873 if(client->serialization_version == SER_FMT_VER_INVALID)
2877 bool sender_selected = (peer_id == client->peer_id);
2878 if(sender_selected == true && send_to_sender == false)
2880 if(sender_selected == false && send_to_others == false)
2883 SendChatMessage(client->peer_id, line);
2887 else if(command == TOSERVER_DAMAGE)
2889 std::string datastring((char*)&data[2], datasize-2);
2890 std::istringstream is(datastring, std::ios_base::binary);
2891 u8 damage = readU8(is);
2893 if(g_settings->getBool("enable_damage"))
2895 actionstream<<player->getName()<<" damaged by "
2896 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2899 HandlePlayerHP(player, damage);
2903 SendPlayerHP(player);
2906 else if(command == TOSERVER_PASSWORD)
2909 [0] u16 TOSERVER_PASSWORD
2910 [2] u8[28] old password
2911 [30] u8[28] new password
2914 if(datasize != 2+PASSWORD_SIZE*2)
2916 /*char password[PASSWORD_SIZE];
2917 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2918 password[i] = data[2+i];
2919 password[PASSWORD_SIZE-1] = 0;*/
2921 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2929 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2931 char c = data[2+PASSWORD_SIZE+i];
2937 infostream<<"Server: Client requests a password change from "
2938 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2940 std::string playername = player->getName();
2942 if(m_authmanager.exists(playername) == false)
2944 infostream<<"Server: playername not found in authmanager"<<std::endl;
2945 // Wrong old password supplied!!
2946 SendChatMessage(peer_id, L"playername not found in authmanager");
2950 std::string checkpwd = m_authmanager.getPassword(playername);
2952 if(oldpwd != checkpwd)
2954 infostream<<"Server: invalid old password"<<std::endl;
2955 // Wrong old password supplied!!
2956 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2960 actionstream<<player->getName()<<" changes password"<<std::endl;
2962 m_authmanager.setPassword(playername, newpwd);
2964 infostream<<"Server: password change successful for "<<playername
2966 SendChatMessage(peer_id, L"Password change successful");
2968 else if(command == TOSERVER_PLAYERITEM)
2973 u16 item = readU16(&data[2]);
2974 player->wieldItem(item);
2975 SendWieldedItem(player);
2977 else if(command == TOSERVER_RESPAWN)
2982 RespawnPlayer(player);
2984 actionstream<<player->getName()<<" respawns at "
2985 <<PP(player->getPosition()/BS)<<std::endl;
2987 else if(command == TOSERVER_INTERACT)
2989 std::string datastring((char*)&data[2], datasize-2);
2990 std::istringstream is(datastring, std::ios_base::binary);
2996 [5] u32 length of the next item
2997 [9] serialized PointedThing
2999 0: start digging (from undersurface) or use
3000 1: stop digging (all parameters ignored)
3001 2: digging completed
3002 3: place block or item (to abovesurface)
3005 u8 action = readU8(is);
3006 u16 item_i = readU16(is);
3007 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
3008 PointedThing pointed;
3009 pointed.deSerialize(tmp_is);
3011 infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<<item_i<<", pointed="<<pointed.dump()<<std::endl;
3013 v3f player_pos = srp->m_last_good_position;
3015 // Update wielded item
3016 srp->wieldItem(item_i);
3018 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
3019 v3s16 p_under = pointed.node_undersurface;
3020 v3s16 p_above = pointed.node_abovesurface;
3022 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
3023 ServerActiveObject *pointed_object = NULL;
3024 if(pointed.type == POINTEDTHING_OBJECT)
3026 pointed_object = m_env->getActiveObject(pointed.object_id);
3027 if(pointed_object == NULL)
3029 infostream<<"TOSERVER_INTERACT: "
3030 "pointed object is NULL"<<std::endl;
3037 Check that target is reasonably close
3038 (only when digging or placing things)
3040 if(action == 0 || action == 2 || action == 3)
3042 v3f pointed_pos = player_pos;
3043 if(pointed.type == POINTEDTHING_NODE)
3045 pointed_pos = intToFloat(p_under, BS);
3047 else if(pointed.type == POINTEDTHING_OBJECT)
3049 pointed_pos = pointed_object->getBasePosition();
3052 float d = player_pos.getDistanceFrom(pointed_pos);
3053 float max_d = BS * 10; // Just some large enough value
3055 actionstream<<"Player "<<player->getName()
3056 <<" tried to access "<<pointed.dump()
3058 <<"d="<<d<<", max_d="<<max_d
3059 <<". ignoring."<<std::endl;
3060 // Re-send block to revert change on client-side
3061 RemoteClient *client = getClient(peer_id);
3062 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos, BS));
3063 client->SetBlockNotSent(blockpos);
3070 Make sure the player is allowed to do it
3072 bool build_priv = (getPlayerPrivs(player) & PRIV_BUILD) != 0;
3075 infostream<<"Ignoring interaction from player "<<player->getName()
3076 <<" because privileges are "<<getPlayerPrivs(player)
3078 // NOTE: no return; here, fall through
3082 0: start digging or punch object
3086 if(pointed.type == POINTEDTHING_NODE)
3089 NOTE: This can be used in the future to check if
3090 somebody is cheating, by checking the timing.
3092 bool cannot_punch_node = !build_priv;
3094 MapNode n(CONTENT_IGNORE);
3098 n = m_env->getMap().getNode(p_under);
3100 catch(InvalidPositionException &e)
3102 infostream<<"Server: Not punching: Node not found."
3103 <<" Adding block to emerge queue."
3105 m_emerge_queue.addBlock(peer_id,
3106 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3107 cannot_punch_node = true;
3110 if(cannot_punch_node)
3116 scriptapi_environment_on_punchnode(m_lua, p_under, n, srp);
3118 else if(pointed.type == POINTEDTHING_OBJECT)
3123 // Skip if object has been removed
3124 if(pointed_object->m_removed)
3127 actionstream<<player->getName()<<" punches object "
3128 <<pointed.object_id<<std::endl;
3131 pointed_object->punch(srp);
3139 else if(action == 1)
3144 2: Digging completed
3146 else if(action == 2)
3148 // Only complete digging of nodes
3149 if(pointed.type != POINTEDTHING_NODE)
3152 // Mandatory parameter; actually used for nothing
3153 core::map<v3s16, MapBlock*> modified_blocks;
3155 content_t material = CONTENT_IGNORE;
3156 u8 mineral = MINERAL_NONE;
3158 bool cannot_remove_node = !build_priv;
3160 MapNode n(CONTENT_IGNORE);
3163 n = m_env->getMap().getNode(p_under);
3165 mineral = n.getMineral(m_nodedef);
3166 // Get material at position
3167 material = n.getContent();
3168 // If not yet cancelled
3169 if(cannot_remove_node == false)
3171 // If it's not diggable, do nothing
3172 if(m_nodedef->get(material).diggable == false)
3174 infostream<<"Server: Not finishing digging: "
3175 <<"Node not diggable"
3177 cannot_remove_node = true;
3180 // If not yet cancelled
3181 if(cannot_remove_node == false)
3183 // Get node metadata
3184 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
3185 if(meta && meta->nodeRemovalDisabled() == true)
3187 infostream<<"Server: Not finishing digging: "
3188 <<"Node metadata disables removal"
3190 cannot_remove_node = true;
3194 catch(InvalidPositionException &e)
3196 infostream<<"Server: Not finishing digging: Node not found."
3197 <<" Adding block to emerge queue."
3199 m_emerge_queue.addBlock(peer_id,
3200 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3201 cannot_remove_node = true;
3205 If node can't be removed, set block to be re-sent to
3208 if(cannot_remove_node)
3210 infostream<<"Server: Not finishing digging."<<std::endl;
3212 // Client probably has wrong data.
3213 // Set block not sent, so that client will get
3215 infostream<<"Client "<<peer_id<<" tried to dig "
3216 <<"node; but node cannot be removed."
3217 <<" setting MapBlock not sent."<<std::endl;
3218 RemoteClient *client = getClient(peer_id);
3219 v3s16 blockpos = getNodeBlockPos(p_under);
3220 client->SetBlockNotSent(blockpos);
3225 actionstream<<player->getName()<<" digs "<<PP(p_under)
3226 <<", gets material "<<(int)material<<", mineral "
3227 <<(int)mineral<<std::endl;
3230 Send the removal to all close-by players.
3231 - If other player is close, send REMOVENODE
3232 - Otherwise set blocks not sent
3234 core::list<u16> far_players;
3235 sendRemoveNode(p_under, peer_id, &far_players, 30);
3238 Update and send inventory
3241 if(g_settings->getBool("creative_mode") == false)
3246 InventoryList *mlist = player->inventory.getList("main");
3249 InventoryItem *item = mlist->getItem(item_i);
3250 if(item && (std::string)item->getName() == "ToolItem")
3252 ToolItem *titem = (ToolItem*)item;
3253 std::string toolname = titem->getToolName();
3255 // Get digging properties for material and tool
3256 ToolDiggingProperties tp =
3257 m_toolmgr->getDiggingProperties(toolname);
3258 DiggingProperties prop =
3259 getDiggingProperties(material, &tp, m_nodedef);
3261 if(prop.diggable == false)
3263 infostream<<"Server: WARNING: Player digged"
3264 <<" with impossible material + tool"
3265 <<" combination"<<std::endl;
3268 bool weared_out = titem->addWear(prop.wear);
3272 mlist->deleteItem(item_i);
3275 srp->m_inventory_not_sent = true;
3280 Add dug item to inventory
3283 InventoryItem *item = NULL;
3285 if(mineral != MINERAL_NONE)
3286 item = getDiggedMineralItem(mineral, this);
3291 const std::string &dug_s = m_nodedef->get(material).dug_item;
3294 std::istringstream is(dug_s, std::ios::binary);
3295 item = InventoryItem::deSerialize(is, this);
3301 // Add a item to inventory
3302 player->inventory.addItem("main", item);
3303 srp->m_inventory_not_sent = true;
3308 if(mineral != MINERAL_NONE)
3309 item = getDiggedMineralItem(mineral, this);
3314 const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item;
3315 s32 extra_rarity = m_nodedef->get(material).extra_dug_item_rarity;
3316 if(extra_dug_s != "" && extra_rarity != 0
3317 && myrand() % extra_rarity == 0)
3319 std::istringstream is(extra_dug_s, std::ios::binary);
3320 item = InventoryItem::deSerialize(is, this);
3326 // Add a item to inventory
3327 player->inventory.addItem("main", item);
3328 srp->m_inventory_not_sent = true;
3334 (this takes some time so it is done after the quick stuff)
3337 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
3339 m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
3342 Set blocks not sent to far players
3344 for(core::list<u16>::Iterator
3345 i = far_players.begin();
3346 i != far_players.end(); i++)
3349 RemoteClient *client = getClient(peer_id);
3352 client->SetBlocksNotSent(modified_blocks);
3358 scriptapi_environment_on_dignode(m_lua, p_under, n, srp);
3362 3: place block or right-click object
3364 else if(action == 3)
3366 if(pointed.type == POINTEDTHING_NODE)
3368 InventoryList *ilist = player->inventory.getList("main");
3373 InventoryItem *item = ilist->getItem(item_i);
3375 // If there is no item, it is not possible to add it anywhere
3380 Handle material items
3382 if(std::string("MaterialItem") == item->getName())
3384 bool cannot_place_node = !build_priv;
3387 // Don't add a node if this is not a free space
3388 MapNode n2 = m_env->getMap().getNode(p_above);
3389 if(m_nodedef->get(n2).buildable_to == false)
3391 infostream<<"Client "<<peer_id<<" tried to place"
3392 <<" node in invalid position."<<std::endl;
3393 cannot_place_node = true;
3396 catch(InvalidPositionException &e)
3398 infostream<<"Server: Ignoring ADDNODE: Node not found"
3399 <<" Adding block to emerge queue."
3401 m_emerge_queue.addBlock(peer_id,
3402 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3403 cannot_place_node = true;
3406 if(cannot_place_node)
3408 // Client probably has wrong data.
3409 // Set block not sent, so that client will get
3411 RemoteClient *client = getClient(peer_id);
3412 v3s16 blockpos = getNodeBlockPos(p_above);
3413 client->SetBlockNotSent(blockpos);
3417 // Reset build time counter
3418 getClient(peer_id)->m_time_from_building = 0.0;
3421 MaterialItem *mitem = (MaterialItem*)item;
3423 n.setContent(mitem->getMaterial());
3425 actionstream<<player->getName()<<" places material "
3426 <<(int)mitem->getMaterial()
3427 <<" at "<<PP(p_under)<<std::endl;
3429 // Calculate direction for wall mounted stuff
3430 if(m_nodedef->get(n).wall_mounted)
3431 n.param2 = packDir(p_under - p_above);
3433 // Calculate the direction for furnaces and chests and stuff
3434 if(m_nodedef->get(n).param_type == CPT_FACEDIR_SIMPLE)
3436 v3f playerpos = player->getPosition();
3437 v3f blockpos = intToFloat(p_above, BS) - playerpos;
3438 blockpos = blockpos.normalize();
3440 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
3454 Send to all close-by players
3456 core::list<u16> far_players;
3457 sendAddNode(p_above, n, 0, &far_players, 30);
3462 InventoryList *ilist = player->inventory.getList("main");
3463 if(g_settings->getBool("creative_mode") == false && ilist)
3465 // Remove from inventory and send inventory
3466 if(mitem->getCount() <= 1)
3467 ilist->deleteItem(item_i);
3470 srp->m_inventory_not_sent = true;
3476 This takes some time so it is done after the quick stuff
3478 core::map<v3s16, MapBlock*> modified_blocks;
3480 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
3482 std::string p_name = std::string(player->getName());
3483 m_env->getMap().addNodeAndUpdate(p_above, n, modified_blocks, p_name);
3486 Set blocks not sent to far players
3488 for(core::list<u16>::Iterator
3489 i = far_players.begin();
3490 i != far_players.end(); i++)
3493 RemoteClient *client = getClient(peer_id);
3496 client->SetBlocksNotSent(modified_blocks);
3502 scriptapi_environment_on_placenode(m_lua, p_above, n, srp);
3505 Calculate special events
3508 /*if(n.d == LEGN(m_nodedef, "CONTENT_MESE"))
3511 for(s16 z=-1; z<=1; z++)
3512 for(s16 y=-1; y<=1; y++)
3513 for(s16 x=-1; x<=1; x++)
3520 Place other item (not a block)
3526 infostream<<"Not allowing player to place item: "
3527 "no build privileges"<<std::endl;
3531 // Calculate a position for it
3532 v3f pos = player_pos;
3533 if(pointed.type == POINTEDTHING_NOTHING)
3535 infostream<<"Not allowing player to place item: "
3536 "pointing to nothing"<<std::endl;
3539 else if(pointed.type == POINTEDTHING_NODE)
3541 pos = intToFloat(p_above, BS);
3543 else if(pointed.type == POINTEDTHING_OBJECT)
3545 pos = pointed_object->getBasePosition();
3548 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
3549 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
3553 //pos.Y -= BS*0.25; // let it drop a bit
3556 Check that the block is loaded so that the item
3557 can properly be added to the static list too
3559 v3s16 blockpos = getNodeBlockPos(floatToInt(pos, BS));
3560 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3563 infostream<<"Error while placing item: "
3564 "block not found"<<std::endl;
3568 actionstream<<player->getName()<<" places "<<item->getName()
3569 <<" at "<<PP(pos)<<std::endl;
3574 bool remove = item->dropOrPlace(m_env, srp, pos, true, -1);
3575 if(remove && g_settings->getBool("creative_mode") == false)
3577 InventoryList *ilist = player->inventory.getList("main");
3579 // Remove from inventory and send inventory
3580 ilist->deleteItem(item_i);
3581 srp->m_inventory_not_sent = true;
3586 else if(pointed.type == POINTEDTHING_OBJECT)
3588 // Right click object
3593 // Skip if object has been removed
3594 if(pointed_object->m_removed)
3597 actionstream<<player->getName()<<" right-clicks object "
3598 <<pointed.object_id<<std::endl;
3601 pointed_object->rightClick(srp);
3609 else if(action == 4)
3611 InventoryList *ilist = player->inventory.getList("main");
3616 InventoryItem *item = ilist->getItem(item_i);
3618 // If there is no item, it is not possible to add it anywhere
3622 // Requires build privs
3625 infostream<<"Not allowing player to use item: "
3626 "no build privileges"<<std::endl;
3630 actionstream<<player->getName()<<" uses "<<item->getName()
3631 <<", pointing at "<<pointed.dump()<<std::endl;
3633 bool remove = item->use(m_env, srp, pointed);
3635 if(remove && g_settings->getBool("creative_mode") == false)
3637 InventoryList *ilist = player->inventory.getList("main");
3639 // Remove from inventory and send inventory
3640 ilist->deleteItem(item_i);
3641 srp->m_inventory_not_sent = true;
3648 Catch invalid actions
3652 infostream<<"WARNING: Server: Invalid action "
3653 <<action<<std::endl;
3656 // Complete add_to_inventory_later
3657 srp->completeAddToInventoryLater(item_i);
3661 infostream<<"Server::ProcessData(): Ignoring "
3662 "unknown command "<<command<<std::endl;
3666 catch(SendFailedException &e)
3668 errorstream<<"Server::ProcessData(): SendFailedException: "
3674 void Server::onMapEditEvent(MapEditEvent *event)
3676 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3677 if(m_ignore_map_edit_events)
3679 MapEditEvent *e = event->clone();
3680 m_unsent_map_edit_queue.push_back(e);
3683 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3685 if(id == "current_player")
3687 assert(c->current_player);
3688 return &(c->current_player->inventory);
3692 std::string id0 = fn.next(":");
3694 if(id0 == "nodemeta")
3697 p.X = stoi(fn.next(","));
3698 p.Y = stoi(fn.next(","));
3699 p.Z = stoi(fn.next(","));
3700 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3702 return meta->getInventory();
3703 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3704 <<"no metadata found"<<std::endl;
3708 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3711 void Server::inventoryModified(InventoryContext *c, std::string id)
3713 if(id == "current_player")
3715 assert(c->current_player);
3716 ServerRemotePlayer *srp =
3717 static_cast<ServerRemotePlayer*>(c->current_player);
3718 srp->m_inventory_not_sent = true;
3723 std::string id0 = fn.next(":");
3725 if(id0 == "nodemeta")
3728 p.X = stoi(fn.next(","));
3729 p.Y = stoi(fn.next(","));
3730 p.Z = stoi(fn.next(","));
3731 v3s16 blockpos = getNodeBlockPos(p);
3733 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3735 meta->inventoryModified();
3737 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3739 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3741 setBlockNotSent(blockpos);
3746 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3749 core::list<PlayerInfo> Server::getPlayerInfo()
3751 DSTACK(__FUNCTION_NAME);
3752 JMutexAutoLock envlock(m_env_mutex);
3753 JMutexAutoLock conlock(m_con_mutex);
3755 core::list<PlayerInfo> list;
3757 core::list<Player*> players = m_env->getPlayers();
3759 core::list<Player*>::Iterator i;
3760 for(i = players.begin();
3761 i != players.end(); i++)
3765 Player *player = *i;
3768 // Copy info from connection to info struct
3769 info.id = player->peer_id;
3770 info.address = m_con.GetPeerAddress(player->peer_id);
3771 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3773 catch(con::PeerNotFoundException &e)
3775 // Set dummy peer info
3777 info.address = Address(0,0,0,0,0);
3781 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3782 info.position = player->getPosition();
3784 list.push_back(info);
3791 void Server::peerAdded(con::Peer *peer)
3793 DSTACK(__FUNCTION_NAME);
3794 infostream<<"Server::peerAdded(): peer->id="
3795 <<peer->id<<std::endl;
3798 c.type = PEER_ADDED;
3799 c.peer_id = peer->id;
3801 m_peer_change_queue.push_back(c);
3804 void Server::deletingPeer(con::Peer *peer, bool timeout)
3806 DSTACK(__FUNCTION_NAME);
3807 infostream<<"Server::deletingPeer(): peer->id="
3808 <<peer->id<<", timeout="<<timeout<<std::endl;
3811 c.type = PEER_REMOVED;
3812 c.peer_id = peer->id;
3813 c.timeout = timeout;
3814 m_peer_change_queue.push_back(c);
3821 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3823 DSTACK(__FUNCTION_NAME);
3824 std::ostringstream os(std::ios_base::binary);
3826 writeU16(os, TOCLIENT_HP);
3830 std::string s = os.str();
3831 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3833 con.Send(peer_id, 0, data, true);
3836 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3837 const std::wstring &reason)
3839 DSTACK(__FUNCTION_NAME);
3840 std::ostringstream os(std::ios_base::binary);
3842 writeU16(os, TOCLIENT_ACCESS_DENIED);
3843 os<<serializeWideString(reason);
3846 std::string s = os.str();
3847 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3849 con.Send(peer_id, 0, data, true);
3852 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3853 bool set_camera_point_target, v3f camera_point_target)
3855 DSTACK(__FUNCTION_NAME);
3856 std::ostringstream os(std::ios_base::binary);
3858 writeU16(os, TOCLIENT_DEATHSCREEN);
3859 writeU8(os, set_camera_point_target);
3860 writeV3F1000(os, camera_point_target);
3863 std::string s = os.str();
3864 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3866 con.Send(peer_id, 0, data, true);
3869 void Server::SendToolDef(con::Connection &con, u16 peer_id,
3870 IToolDefManager *tooldef)
3872 DSTACK(__FUNCTION_NAME);
3873 std::ostringstream os(std::ios_base::binary);
3877 u32 length of the next item
3878 serialized ToolDefManager
3880 writeU16(os, TOCLIENT_TOOLDEF);
3881 std::ostringstream tmp_os(std::ios::binary);
3882 tooldef->serialize(tmp_os);
3883 os<<serializeLongString(tmp_os.str());
3886 std::string s = os.str();
3887 infostream<<"Server::SendToolDef(): Sending tool definitions: size="
3888 <<s.size()<<std::endl;
3889 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3891 con.Send(peer_id, 0, data, true);
3894 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3895 INodeDefManager *nodedef)
3897 DSTACK(__FUNCTION_NAME);
3898 std::ostringstream os(std::ios_base::binary);
3902 u32 length of the next item
3903 serialized NodeDefManager
3905 writeU16(os, TOCLIENT_NODEDEF);
3906 std::ostringstream tmp_os(std::ios::binary);
3907 nodedef->serialize(tmp_os);
3908 os<<serializeLongString(tmp_os.str());
3911 std::string s = os.str();
3912 infostream<<"Server::SendNodeDef(): Sending node definitions: size="
3913 <<s.size()<<std::endl;
3914 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3916 con.Send(peer_id, 0, data, true);
3919 void Server::SendCraftItemDef(con::Connection &con, u16 peer_id,
3920 ICraftItemDefManager *craftitemdef)
3922 DSTACK(__FUNCTION_NAME);
3923 std::ostringstream os(std::ios_base::binary);
3927 u32 length of the next item
3928 serialized CraftItemDefManager
3930 writeU16(os, TOCLIENT_CRAFTITEMDEF);
3931 std::ostringstream tmp_os(std::ios::binary);
3932 craftitemdef->serialize(tmp_os);
3933 os<<serializeLongString(tmp_os.str());
3936 std::string s = os.str();
3937 infostream<<"Server::SendCraftItemDef(): Sending craft item definitions: size="
3938 <<s.size()<<std::endl;
3939 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3941 con.Send(peer_id, 0, data, true);
3945 Non-static send methods
3948 void Server::SendObjectData(float dtime)
3950 DSTACK(__FUNCTION_NAME);
3952 core::map<v3s16, bool> stepped_blocks;
3954 for(core::map<u16, RemoteClient*>::Iterator
3955 i = m_clients.getIterator();
3956 i.atEnd() == false; i++)
3958 u16 peer_id = i.getNode()->getKey();
3959 RemoteClient *client = i.getNode()->getValue();
3960 assert(client->peer_id == peer_id);
3962 if(client->serialization_version == SER_FMT_VER_INVALID)
3965 client->SendObjectData(this, dtime, stepped_blocks);
3969 void Server::SendPlayerInfos()
3971 DSTACK(__FUNCTION_NAME);
3973 //JMutexAutoLock envlock(m_env_mutex);
3975 // Get connected players
3976 core::list<Player*> players = m_env->getPlayers(true);
3978 u32 player_count = players.getSize();
3979 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3981 SharedBuffer<u8> data(datasize);
3982 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3985 core::list<Player*>::Iterator i;
3986 for(i = players.begin();
3987 i != players.end(); i++)
3989 Player *player = *i;
3991 /*infostream<<"Server sending player info for player with "
3992 "peer_id="<<player->peer_id<<std::endl;*/
3994 writeU16(&data[start], player->peer_id);
3995 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3996 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3997 start += 2+PLAYERNAME_SIZE;
4000 //JMutexAutoLock conlock(m_con_mutex);
4003 m_con.SendToAll(0, data, true);
4006 void Server::SendInventory(u16 peer_id)
4008 DSTACK(__FUNCTION_NAME);
4010 ServerRemotePlayer* player =
4011 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
4014 player->m_inventory_not_sent = false;
4020 std::ostringstream os;
4021 //os.imbue(std::locale("C"));
4023 player->inventory.serialize(os);
4025 std::string s = os.str();
4027 SharedBuffer<u8> data(s.size()+2);
4028 writeU16(&data[0], TOCLIENT_INVENTORY);
4029 memcpy(&data[2], s.c_str(), s.size());
4032 m_con.Send(peer_id, 0, data, true);
4035 std::string getWieldedItemString(const Player *player)
4037 const InventoryItem *item = player->getWieldItem();
4039 return std::string("");
4040 std::ostringstream os(std::ios_base::binary);
4041 item->serialize(os);
4045 void Server::SendWieldedItem(const Player* player)
4047 DSTACK(__FUNCTION_NAME);
4051 std::ostringstream os(std::ios_base::binary);
4053 writeU16(os, TOCLIENT_PLAYERITEM);
4055 writeU16(os, player->peer_id);
4056 os<<serializeString(getWieldedItemString(player));
4059 std::string s = os.str();
4060 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4062 m_con.SendToAll(0, data, true);
4065 void Server::SendPlayerItems()
4067 DSTACK(__FUNCTION_NAME);
4069 std::ostringstream os(std::ios_base::binary);
4070 core::list<Player *> players = m_env->getPlayers(true);
4072 writeU16(os, TOCLIENT_PLAYERITEM);
4073 writeU16(os, players.size());
4074 core::list<Player *>::Iterator i;
4075 for(i = players.begin(); i != players.end(); ++i)
4078 writeU16(os, p->peer_id);
4079 os<<serializeString(getWieldedItemString(p));
4083 std::string s = os.str();
4084 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4086 m_con.SendToAll(0, data, true);
4089 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
4091 DSTACK(__FUNCTION_NAME);
4093 std::ostringstream os(std::ios_base::binary);
4097 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
4098 os.write((char*)buf, 2);
4101 writeU16(buf, message.size());
4102 os.write((char*)buf, 2);
4105 for(u32 i=0; i<message.size(); i++)
4109 os.write((char*)buf, 2);
4113 std::string s = os.str();
4114 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4116 m_con.Send(peer_id, 0, data, true);
4119 void Server::BroadcastChatMessage(const std::wstring &message)
4121 for(core::map<u16, RemoteClient*>::Iterator
4122 i = m_clients.getIterator();
4123 i.atEnd() == false; i++)
4125 // Get client and check that it is valid
4126 RemoteClient *client = i.getNode()->getValue();
4127 assert(client->peer_id == i.getNode()->getKey());
4128 if(client->serialization_version == SER_FMT_VER_INVALID)
4131 SendChatMessage(client->peer_id, message);
4135 void Server::SendPlayerHP(Player *player)
4137 SendHP(m_con, player->peer_id, player->hp);
4140 void Server::SendMovePlayer(Player *player)
4142 DSTACK(__FUNCTION_NAME);
4143 std::ostringstream os(std::ios_base::binary);
4145 writeU16(os, TOCLIENT_MOVE_PLAYER);
4146 writeV3F1000(os, player->getPosition());
4147 writeF1000(os, player->getPitch());
4148 writeF1000(os, player->getYaw());
4151 v3f pos = player->getPosition();
4152 f32 pitch = player->getPitch();
4153 f32 yaw = player->getYaw();
4154 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
4155 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
4162 std::string s = os.str();
4163 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4165 m_con.Send(player->peer_id, 0, data, true);
4168 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4169 core::list<u16> *far_players, float far_d_nodes)
4171 float maxd = far_d_nodes*BS;
4172 v3f p_f = intToFloat(p, BS);
4176 SharedBuffer<u8> reply(replysize);
4177 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4178 writeS16(&reply[2], p.X);
4179 writeS16(&reply[4], p.Y);
4180 writeS16(&reply[6], p.Z);
4182 for(core::map<u16, RemoteClient*>::Iterator
4183 i = m_clients.getIterator();
4184 i.atEnd() == false; i++)
4186 // Get client and check that it is valid
4187 RemoteClient *client = i.getNode()->getValue();
4188 assert(client->peer_id == i.getNode()->getKey());
4189 if(client->serialization_version == SER_FMT_VER_INVALID)
4192 // Don't send if it's the same one
4193 if(client->peer_id == ignore_id)
4199 Player *player = m_env->getPlayer(client->peer_id);
4202 // If player is far away, only set modified blocks not sent
4203 v3f player_pos = player->getPosition();
4204 if(player_pos.getDistanceFrom(p_f) > maxd)
4206 far_players->push_back(client->peer_id);
4213 m_con.Send(client->peer_id, 0, reply, true);
4217 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4218 core::list<u16> *far_players, float far_d_nodes)
4220 float maxd = far_d_nodes*BS;
4221 v3f p_f = intToFloat(p, BS);
4223 for(core::map<u16, RemoteClient*>::Iterator
4224 i = m_clients.getIterator();
4225 i.atEnd() == false; i++)
4227 // Get client and check that it is valid
4228 RemoteClient *client = i.getNode()->getValue();
4229 assert(client->peer_id == i.getNode()->getKey());
4230 if(client->serialization_version == SER_FMT_VER_INVALID)
4233 // Don't send if it's the same one
4234 if(client->peer_id == ignore_id)
4240 Player *player = m_env->getPlayer(client->peer_id);
4243 // If player is far away, only set modified blocks not sent
4244 v3f player_pos = player->getPosition();
4245 if(player_pos.getDistanceFrom(p_f) > maxd)
4247 far_players->push_back(client->peer_id);
4254 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4255 SharedBuffer<u8> reply(replysize);
4256 writeU16(&reply[0], TOCLIENT_ADDNODE);
4257 writeS16(&reply[2], p.X);
4258 writeS16(&reply[4], p.Y);
4259 writeS16(&reply[6], p.Z);
4260 n.serialize(&reply[8], client->serialization_version);
4263 m_con.Send(client->peer_id, 0, reply, true);
4267 void Server::setBlockNotSent(v3s16 p)
4269 for(core::map<u16, RemoteClient*>::Iterator
4270 i = m_clients.getIterator();
4271 i.atEnd()==false; i++)
4273 RemoteClient *client = i.getNode()->getValue();
4274 client->SetBlockNotSent(p);
4278 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4280 DSTACK(__FUNCTION_NAME);
4282 v3s16 p = block->getPos();
4286 bool completely_air = true;
4287 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4288 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4289 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4291 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4293 completely_air = false;
4294 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4299 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4301 infostream<<"[completely air] ";
4302 infostream<<std::endl;
4306 Create a packet with the block in the right format
4309 std::ostringstream os(std::ios_base::binary);
4310 block->serialize(os, ver);
4311 std::string s = os.str();
4312 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4314 u32 replysize = 8 + blockdata.getSize();
4315 SharedBuffer<u8> reply(replysize);
4316 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4317 writeS16(&reply[2], p.X);
4318 writeS16(&reply[4], p.Y);
4319 writeS16(&reply[6], p.Z);
4320 memcpy(&reply[8], *blockdata, blockdata.getSize());
4322 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4323 <<": \tpacket size: "<<replysize<<std::endl;*/
4328 m_con.Send(peer_id, 1, reply, true);
4331 void Server::SendBlocks(float dtime)
4333 DSTACK(__FUNCTION_NAME);
4335 JMutexAutoLock envlock(m_env_mutex);
4336 JMutexAutoLock conlock(m_con_mutex);
4338 //TimeTaker timer("Server::SendBlocks");
4340 core::array<PrioritySortedBlockTransfer> queue;
4342 s32 total_sending = 0;
4345 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4347 for(core::map<u16, RemoteClient*>::Iterator
4348 i = m_clients.getIterator();
4349 i.atEnd() == false; i++)
4351 RemoteClient *client = i.getNode()->getValue();
4352 assert(client->peer_id == i.getNode()->getKey());
4354 total_sending += client->SendingCount();
4356 if(client->serialization_version == SER_FMT_VER_INVALID)
4359 client->GetNextBlocks(this, dtime, queue);
4364 // Lowest priority number comes first.
4365 // Lowest is most important.
4368 for(u32 i=0; i<queue.size(); i++)
4370 //TODO: Calculate limit dynamically
4371 if(total_sending >= g_settings->getS32
4372 ("max_simultaneous_block_sends_server_total"))
4375 PrioritySortedBlockTransfer q = queue[i];
4377 MapBlock *block = NULL;
4380 block = m_env->getMap().getBlockNoCreate(q.pos);
4382 catch(InvalidPositionException &e)
4387 RemoteClient *client = getClient(q.peer_id);
4389 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4391 client->SentBlock(q.pos);
4397 struct SendableTexture
4403 SendableTexture(const std::string &name_="", const std::string path_="",
4404 const std::string &data_=""):
4411 void Server::SendTextures(u16 peer_id)
4413 DSTACK(__FUNCTION_NAME);
4415 infostream<<"Server::SendTextures(): Sending textures to client"<<std::endl;
4419 // Put 5kB in one bunch (this is not accurate)
4420 u32 bytes_per_bunch = 5000;
4422 core::array< core::list<SendableTexture> > texture_bunches;
4423 texture_bunches.push_back(core::list<SendableTexture>());
4425 u32 texture_size_bunch_total = 0;
4426 core::list<ModSpec> mods = getMods(m_modspaths);
4427 for(core::list<ModSpec>::Iterator i = mods.begin();
4428 i != mods.end(); i++){
4430 std::string texturepath = mod.path + DIR_DELIM + "textures";
4431 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
4432 for(u32 j=0; j<dirlist.size(); j++){
4433 if(dirlist[j].dir) // Ignode dirs
4435 std::string tname = dirlist[j].name;
4436 std::string tpath = texturepath + DIR_DELIM + tname;
4438 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4439 if(fis.good() == false){
4440 errorstream<<"Server::SendTextures(): Could not open \""
4441 <<tname<<"\" for reading"<<std::endl;
4444 std::ostringstream tmp_os(std::ios_base::binary);
4448 fis.read(buf, 1024);
4449 std::streamsize len = fis.gcount();
4450 tmp_os.write(buf, len);
4451 texture_size_bunch_total += len;
4460 errorstream<<"Server::SendTextures(): Failed to read \""
4461 <<tname<<"\""<<std::endl;
4464 /*infostream<<"Server::SendTextures(): Loaded \""
4465 <<tname<<"\""<<std::endl;*/
4467 texture_bunches[texture_bunches.size()-1].push_back(
4468 SendableTexture(tname, tpath, tmp_os.str()));
4470 // Start next bunch if got enough data
4471 if(texture_size_bunch_total >= bytes_per_bunch){
4472 texture_bunches.push_back(core::list<SendableTexture>());
4473 texture_size_bunch_total = 0;
4478 /* Create and send packets */
4480 u32 num_bunches = texture_bunches.size();
4481 for(u32 i=0; i<num_bunches; i++)
4485 u16 total number of texture bunches
4486 u16 index of this bunch
4487 u32 number of textures in this bunch
4495 std::ostringstream os(std::ios_base::binary);
4497 writeU16(os, TOCLIENT_TEXTURES);
4498 writeU16(os, num_bunches);
4500 writeU32(os, texture_bunches[i].size());
4502 for(core::list<SendableTexture>::Iterator
4503 j = texture_bunches[i].begin();
4504 j != texture_bunches[i].end(); j++){
4505 os<<serializeString(j->name);
4506 os<<serializeLongString(j->data);
4510 std::string s = os.str();
4511 infostream<<"Server::SendTextures(): bunch "<<i<<"/"<<num_bunches
4512 <<" textures="<<texture_bunches[i].size()
4513 <<" size=" <<s.size()<<std::endl;
4514 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4516 m_con.Send(peer_id, 0, data, true);
4524 void Server::HandlePlayerHP(Player *player, s16 damage)
4526 if(player->hp > damage)
4528 player->hp -= damage;
4529 SendPlayerHP(player);
4533 infostream<<"Server::HandlePlayerHP(): Player "
4534 <<player->getName()<<" dies"<<std::endl;
4538 //TODO: Throw items around
4540 // Handle players that are not connected
4541 if(player->peer_id == PEER_ID_INEXISTENT){
4542 RespawnPlayer(player);
4546 SendPlayerHP(player);
4548 RemoteClient *client = getClient(player->peer_id);
4549 if(client->net_proto_version >= 3)
4551 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4555 RespawnPlayer(player);
4560 void Server::RespawnPlayer(Player *player)
4563 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4564 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4566 v3f pos = findSpawnPos(m_env->getServerMap());
4567 player->setPosition(pos);
4568 srp->m_last_good_position = pos;
4569 srp->m_last_good_position_age = 0;
4571 SendMovePlayer(player);
4572 SendPlayerHP(player);
4575 void Server::UpdateCrafting(u16 peer_id)
4577 DSTACK(__FUNCTION_NAME);
4579 Player* player = m_env->getPlayer(peer_id);
4581 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4583 // No crafting in creative mode
4584 if(g_settings->getBool("creative_mode"))
4587 // Get the InventoryLists of the player in which we will operate
4588 InventoryList *clist = player->inventory.getList("craft");
4590 InventoryList *rlist = player->inventory.getList("craftresult");
4592 InventoryList *mlist = player->inventory.getList("main");
4595 // If the result list is not a preview and is not empty, try to
4596 // throw the item into main list
4597 if(!player->craftresult_is_preview && rlist->getUsedSlots() != 0)
4599 // Grab item out of craftresult
4600 InventoryItem *item = rlist->changeItem(0, NULL);
4601 // Try to put in main
4602 InventoryItem *leftover = mlist->addItem(item);
4603 // If there are leftovers, put them back to craftresult and
4605 delete rlist->addItem(leftover);
4606 // Inventory was modified
4607 srp->m_inventory_not_sent = true;
4610 // If result list is empty, we will make it preview what would be
4612 if(rlist->getUsedSlots() == 0)
4613 player->craftresult_is_preview = true;
4615 // If it is a preview, clear the possible old preview in it
4616 if(player->craftresult_is_preview)
4617 rlist->clearItems();
4619 // If it is a preview, find out what is the crafting result
4621 if(player->craftresult_is_preview)
4623 // Mangle crafting grid to an another format
4624 std::vector<InventoryItem*> items;
4625 for(u16 i=0; i<9; i++){
4626 if(clist->getItem(i) == NULL)
4627 items.push_back(NULL);
4629 items.push_back(clist->getItem(i)->clone());
4631 CraftPointerInput cpi(3, items);
4633 // Find out what is crafted and add it to result item slot
4634 InventoryItem *result = m_craftdef->getCraftResult(cpi, this);
4636 rlist->addItem(result);
4640 RemoteClient* Server::getClient(u16 peer_id)
4642 DSTACK(__FUNCTION_NAME);
4643 //JMutexAutoLock lock(m_con_mutex);
4644 core::map<u16, RemoteClient*>::Node *n;
4645 n = m_clients.find(peer_id);
4646 // A client should exist for all peers
4648 return n->getValue();
4651 std::wstring Server::getStatusString()
4653 std::wostringstream os(std::ios_base::binary);
4656 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4658 os<<L", uptime="<<m_uptime.get();
4659 // Information about clients
4661 for(core::map<u16, RemoteClient*>::Iterator
4662 i = m_clients.getIterator();
4663 i.atEnd() == false; i++)
4665 // Get client and check that it is valid
4666 RemoteClient *client = i.getNode()->getValue();
4667 assert(client->peer_id == i.getNode()->getKey());
4668 if(client->serialization_version == SER_FMT_VER_INVALID)
4671 Player *player = m_env->getPlayer(client->peer_id);
4672 // Get name of player
4673 std::wstring name = L"unknown";
4675 name = narrow_to_wide(player->getName());
4676 // Add name to information string
4680 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4681 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4682 if(g_settings->get("motd") != "")
4683 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4687 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4689 // Add player to auth manager
4690 if(m_authmanager.exists(name) == false)
4692 infostream<<"Server: adding player "<<name
4693 <<" to auth manager"<<std::endl;
4694 m_authmanager.add(name);
4695 m_authmanager.setPrivs(name,
4696 stringToPrivs(g_settings->get("default_privs")));
4698 // Change password and save
4699 m_authmanager.setPassword(name, translatePassword(name, password));
4700 m_authmanager.save();
4703 // Saves g_settings to configpath given at initialization
4704 void Server::saveConfig()
4706 if(m_configpath != "")
4707 g_settings->updateConfigFile(m_configpath.c_str());
4710 void Server::notifyPlayer(const char *name, const std::wstring msg)
4712 Player *player = m_env->getPlayer(name);
4715 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4718 void Server::notifyPlayers(const std::wstring msg)
4720 BroadcastChatMessage(msg);
4723 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4727 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4728 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4731 // IGameDef interface
4733 IToolDefManager* Server::getToolDefManager()
4737 INodeDefManager* Server::getNodeDefManager()
4741 ICraftDefManager* Server::getCraftDefManager()
4745 ICraftItemDefManager* Server::getCraftItemDefManager()
4747 return m_craftitemdef;
4749 ITextureSource* Server::getTextureSource()
4753 u16 Server::allocateUnknownNodeId(const std::string &name)
4755 return m_nodedef->allocateDummy(name);
4758 IWritableToolDefManager* Server::getWritableToolDefManager()
4762 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4766 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4770 IWritableCraftItemDefManager* Server::getWritableCraftItemDefManager()
4772 return m_craftitemdef;
4775 v3f findSpawnPos(ServerMap &map)
4777 //return v3f(50,50,50)*BS;
4782 nodepos = v2s16(0,0);
4787 // Try to find a good place a few times
4788 for(s32 i=0; i<1000; i++)
4791 // We're going to try to throw the player to this position
4792 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4793 -range + (myrand()%(range*2)));
4794 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4795 // Get ground height at point (fallbacks to heightmap function)
4796 s16 groundheight = map.findGroundLevel(nodepos2d);
4797 // Don't go underwater
4798 if(groundheight < WATER_LEVEL)
4800 //infostream<<"-> Underwater"<<std::endl;
4803 // Don't go to high places
4804 if(groundheight > WATER_LEVEL + 4)
4806 //infostream<<"-> Underwater"<<std::endl;
4810 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4811 bool is_good = false;
4813 for(s32 i=0; i<10; i++){
4814 v3s16 blockpos = getNodeBlockPos(nodepos);
4815 map.emergeBlock(blockpos, true);
4816 MapNode n = map.getNodeNoEx(nodepos);
4817 if(n.getContent() == CONTENT_AIR){
4828 // Found a good place
4829 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4835 return intToFloat(nodepos, BS);
4838 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4841 Try to get an existing player
4843 ServerRemotePlayer *player =
4844 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4847 // If player is already connected, cancel
4848 if(player->peer_id != 0)
4850 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4855 player->peer_id = peer_id;
4857 // Reset inventory to creative if in creative mode
4858 if(g_settings->getBool("creative_mode"))
4860 // Warning: double code below
4861 // Backup actual inventory
4862 player->inventory_backup = new Inventory();
4863 *(player->inventory_backup) = player->inventory;
4864 // Set creative inventory
4865 craft_set_creative_inventory(player, this);
4872 If player with the wanted peer_id already exists, cancel.
4874 if(m_env->getPlayer(peer_id) != NULL)
4876 infostream<<"emergePlayer(): Player with wrong name but same"
4877 " peer_id already exists"<<std::endl;
4885 /* Set player position */
4887 infostream<<"Server: Finding spawn place for player \""
4888 <<name<<"\""<<std::endl;
4890 v3f pos = findSpawnPos(m_env->getServerMap());
4892 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4894 /* Add player to environment */
4895 m_env->addPlayer(player);
4898 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4899 scriptapi_on_newplayer(m_lua, srp);
4901 /* Add stuff to inventory */
4902 if(g_settings->getBool("creative_mode"))
4904 // Warning: double code above
4905 // Backup actual inventory
4906 player->inventory_backup = new Inventory();
4907 *(player->inventory_backup) = player->inventory;
4908 // Set creative inventory
4909 craft_set_creative_inventory(player, this);
4914 } // create new player
4917 void Server::handlePeerChange(PeerChange &c)
4919 JMutexAutoLock envlock(m_env_mutex);
4920 JMutexAutoLock conlock(m_con_mutex);
4922 if(c.type == PEER_ADDED)
4929 core::map<u16, RemoteClient*>::Node *n;
4930 n = m_clients.find(c.peer_id);
4931 // The client shouldn't already exist
4935 RemoteClient *client = new RemoteClient();
4936 client->peer_id = c.peer_id;
4937 m_clients.insert(client->peer_id, client);
4940 else if(c.type == PEER_REMOVED)
4947 core::map<u16, RemoteClient*>::Node *n;
4948 n = m_clients.find(c.peer_id);
4949 // The client should exist
4953 Mark objects to be not known by the client
4955 RemoteClient *client = n->getValue();
4957 for(core::map<u16, bool>::Iterator
4958 i = client->m_known_objects.getIterator();
4959 i.atEnd()==false; i++)
4962 u16 id = i.getNode()->getKey();
4963 ServerActiveObject* obj = m_env->getActiveObject(id);
4965 if(obj && obj->m_known_by_count > 0)
4966 obj->m_known_by_count--;
4969 ServerRemotePlayer* player =
4970 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4972 // Collect information about leaving in chat
4973 std::wstring message;
4977 std::wstring name = narrow_to_wide(player->getName());
4980 message += L" left game";
4982 message += L" (timed out)";
4989 PlayerSAO *sao = player->getSAO();
4991 sao->setPlayer(NULL);
4992 sao->m_removed = true;
4994 player->setSAO(NULL);
4997 // Set player client disconnected
4999 player->peer_id = 0;
5007 std::ostringstream os(std::ios_base::binary);
5008 for(core::map<u16, RemoteClient*>::Iterator
5009 i = m_clients.getIterator();
5010 i.atEnd() == false; i++)
5012 RemoteClient *client = i.getNode()->getValue();
5013 assert(client->peer_id == i.getNode()->getKey());
5014 if(client->serialization_version == SER_FMT_VER_INVALID)
5017 Player *player = m_env->getPlayer(client->peer_id);
5020 // Get name of player
5021 os<<player->getName()<<" ";
5024 actionstream<<player->getName()<<" "
5025 <<(c.timeout?"times out.":"leaves game.")
5026 <<" List of players: "
5027 <<os.str()<<std::endl;
5032 delete m_clients[c.peer_id];
5033 m_clients.remove(c.peer_id);
5035 // Send player info to all remaining clients
5038 // Send leave chat message to all remaining clients
5039 BroadcastChatMessage(message);
5048 void Server::handlePeerChanges()
5050 while(m_peer_change_queue.size() > 0)
5052 PeerChange c = m_peer_change_queue.pop_front();
5054 infostream<<"Server: Handling peer change: "
5055 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5058 handlePeerChange(c);
5062 u64 Server::getPlayerPrivs(Player *player)
5066 std::string playername = player->getName();
5067 // Local player gets all privileges regardless of
5068 // what's set on their account.
5069 if(g_settings->get("name") == playername)
5075 return getPlayerAuthPrivs(playername);
5079 void dedicated_server_loop(Server &server, bool &kill)
5081 DSTACK(__FUNCTION_NAME);
5083 infostream<<DTIME<<std::endl;
5084 infostream<<"========================"<<std::endl;
5085 infostream<<"Running dedicated server"<<std::endl;
5086 infostream<<"========================"<<std::endl;
5087 infostream<<std::endl;
5089 IntervalLimiter m_profiler_interval;
5093 // This is kind of a hack but can be done like this
5094 // because server.step() is very light
5096 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5101 if(server.getShutdownRequested() || kill)
5103 infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
5110 float profiler_print_interval =
5111 g_settings->getFloat("profiler_print_interval");
5112 if(profiler_print_interval != 0)
5114 if(m_profiler_interval.step(0.030, profiler_print_interval))
5116 infostream<<"Profiler:"<<std::endl;
5117 g_profiler->print(infostream);
5118 g_profiler->clear();
5125 static int counter = 0;
5131 core::list<PlayerInfo> list = server.getPlayerInfo();
5132 core::list<PlayerInfo>::Iterator i;
5133 static u32 sum_old = 0;
5134 u32 sum = PIChecksum(list);
5137 infostream<<DTIME<<"Player info:"<<std::endl;
5138 for(i=list.begin(); i!=list.end(); i++)
5140 i->PrintLine(&infostream);