3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "clientserver.h"
25 #include "jmutexautolock.h"
27 #include "constants.h"
29 #include "materials.h"
32 #include "servercommand.h"
34 #include "content_mapnode.h"
35 #include "content_craft.h"
36 #include "content_nodemeta.h"
38 #include "serverobject.h"
43 #include "scriptapi.h"
48 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
50 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
52 class MapEditEventIgnorer
55 MapEditEventIgnorer(bool *flag):
64 ~MapEditEventIgnorer()
77 void * ServerThread::Thread()
81 log_register_thread("ServerThread");
83 DSTACK(__FUNCTION_NAME);
85 BEGIN_DEBUG_EXCEPTION_HANDLER
90 //TimeTaker timer("AsyncRunStep() + Receive()");
93 //TimeTaker timer("AsyncRunStep()");
94 m_server->AsyncRunStep();
97 //infostream<<"Running m_server->Receive()"<<std::endl;
100 catch(con::NoIncomingDataException &e)
103 catch(con::PeerNotFoundException &e)
105 infostream<<"Server: PeerNotFoundException"<<std::endl;
109 END_DEBUG_EXCEPTION_HANDLER(errorstream)
114 void * EmergeThread::Thread()
118 log_register_thread("EmergeThread");
120 DSTACK(__FUNCTION_NAME);
122 BEGIN_DEBUG_EXCEPTION_HANDLER
124 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
127 Get block info from queue, emerge them and send them
130 After queue is empty, exit.
134 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
138 SharedPtr<QueuedBlockEmerge> q(qptr);
144 Do not generate over-limit
146 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
147 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
148 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
149 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
150 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
151 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
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 //core::map<v3s16, MapBlock*> changed_blocks;
196 //core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
198 MapBlock *block = NULL;
199 bool got_block = true;
200 core::map<v3s16, MapBlock*> modified_blocks;
203 Fetch block from map or generate a single block
206 JMutexAutoLock envlock(m_server->m_env_mutex);
208 // Load sector if it isn't loaded
209 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
210 //map.loadSectorFull(p2d);
211 map.loadSectorMeta(p2d);
213 block = map.getBlockNoCreateNoEx(p);
214 if(!block || block->isDummy() || !block->isGenerated())
216 if(enable_mapgen_debug_info)
217 infostream<<"EmergeThread: not in memory, loading"<<std::endl;
219 // Get, load or create sector
220 /*ServerMapSector *sector =
221 (ServerMapSector*)map.createSector(p2d);*/
223 // Load/generate block
225 /*block = map.emergeBlock(p, sector, changed_blocks,
226 lighting_invalidated_blocks);*/
228 block = map.loadBlock(p);
230 if(only_from_disk == false)
232 if(block == NULL || block->isGenerated() == false)
234 if(enable_mapgen_debug_info)
235 infostream<<"EmergeThread: generating"<<std::endl;
236 block = map.generateBlock(p, modified_blocks);
240 if(enable_mapgen_debug_info)
241 infostream<<"EmergeThread: ended up with: "
242 <<analyze_block(block)<<std::endl;
251 Ignore map edit events, they will not need to be
252 sent to anybody because the block hasn't been sent
255 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
257 // Activate objects and stuff
258 m_server->m_env->activateBlock(block, 3600);
263 /*if(block->getLightingExpired()){
264 lighting_invalidated_blocks[block->getPos()] = block;
268 // TODO: Some additional checking and lighting updating,
273 JMutexAutoLock envlock(m_server->m_env_mutex);
278 Collect a list of blocks that have been modified in
279 addition to the fetched one.
283 if(lighting_invalidated_blocks.size() > 0)
285 /*infostream<<"lighting "<<lighting_invalidated_blocks.size()
286 <<" blocks"<<std::endl;*/
288 // 50-100ms for single block generation
289 //TimeTaker timer("** EmergeThread updateLighting");
291 // Update lighting without locking the environment mutex,
292 // add modified blocks to changed blocks
293 map.updateLighting(lighting_invalidated_blocks, modified_blocks);
296 // Add all from changed_blocks to modified_blocks
297 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
298 i.atEnd() == false; i++)
300 MapBlock *block = i.getNode()->getValue();
301 modified_blocks.insert(block->getPos(), block);
305 // If we got no block, there should be no invalidated blocks
308 //assert(lighting_invalidated_blocks.size() == 0);
314 Set sent status of modified blocks on clients
317 // NOTE: Server's clients are also behind the connection mutex
318 JMutexAutoLock lock(m_server->m_con_mutex);
321 Add the originally fetched block to the modified list
325 modified_blocks.insert(p, block);
329 Set the modified blocks unsent for all the clients
332 for(core::map<u16, RemoteClient*>::Iterator
333 i = m_server->m_clients.getIterator();
334 i.atEnd() == false; i++)
336 RemoteClient *client = i.getNode()->getValue();
338 if(modified_blocks.size() > 0)
340 // Remove block from sent history
341 client->SetBlocksNotSent(modified_blocks);
347 END_DEBUG_EXCEPTION_HANDLER(errorstream)
352 void RemoteClient::GetNextBlocks(Server *server, float dtime,
353 core::array<PrioritySortedBlockTransfer> &dest)
355 DSTACK(__FUNCTION_NAME);
358 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
361 m_nothing_to_send_pause_timer -= dtime;
362 m_nearest_unsent_reset_timer += dtime;
364 if(m_nothing_to_send_pause_timer >= 0)
369 // Won't send anything if already sending
370 if(m_blocks_sending.size() >= g_settings->getU16
371 ("max_simultaneous_block_sends_per_client"))
373 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
377 //TimeTaker timer("RemoteClient::GetNextBlocks");
379 Player *player = server->m_env->getPlayer(peer_id);
381 assert(player != NULL);
383 v3f playerpos = player->getPosition();
384 v3f playerspeed = player->getSpeed();
385 v3f playerspeeddir(0,0,0);
386 if(playerspeed.getLength() > 1.0*BS)
387 playerspeeddir = playerspeed / playerspeed.getLength();
388 // Predict to next block
389 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
391 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
393 v3s16 center = getNodeBlockPos(center_nodepos);
395 // Camera position and direction
396 v3f camera_pos = player->getEyePosition();
397 v3f camera_dir = v3f(0,0,1);
398 camera_dir.rotateYZBy(player->getPitch());
399 camera_dir.rotateXZBy(player->getYaw());
401 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
402 <<camera_dir.Z<<")"<<std::endl;*/
405 Get the starting value of the block finder radius.
408 if(m_last_center != center)
410 m_nearest_unsent_d = 0;
411 m_last_center = center;
414 /*infostream<<"m_nearest_unsent_reset_timer="
415 <<m_nearest_unsent_reset_timer<<std::endl;*/
417 // Reset periodically to workaround for some bugs or stuff
418 if(m_nearest_unsent_reset_timer > 20.0)
420 m_nearest_unsent_reset_timer = 0;
421 m_nearest_unsent_d = 0;
422 //infostream<<"Resetting m_nearest_unsent_d for "
423 // <<server->getPlayerName(peer_id)<<std::endl;
426 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
427 s16 d_start = m_nearest_unsent_d;
429 //infostream<<"d_start="<<d_start<<std::endl;
431 u16 max_simul_sends_setting = g_settings->getU16
432 ("max_simultaneous_block_sends_per_client");
433 u16 max_simul_sends_usually = max_simul_sends_setting;
436 Check the time from last addNode/removeNode.
438 Decrease send rate if player is building stuff.
440 m_time_from_building += dtime;
441 if(m_time_from_building < g_settings->getFloat(
442 "full_block_send_enable_min_time_from_building"))
444 max_simul_sends_usually
445 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
449 Number of blocks sending + number of blocks selected for sending
451 u32 num_blocks_selected = m_blocks_sending.size();
454 next time d will be continued from the d from which the nearest
455 unsent block was found this time.
457 This is because not necessarily any of the blocks found this
458 time are actually sent.
460 s32 new_nearest_unsent_d = -1;
462 s16 d_max = g_settings->getS16("max_block_send_distance");
463 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
465 // Don't loop very much at a time
466 s16 max_d_increment_at_time = 2;
467 if(d_max > d_start + max_d_increment_at_time)
468 d_max = d_start + max_d_increment_at_time;
469 /*if(d_max_gen > d_start+2)
470 d_max_gen = d_start+2;*/
472 //infostream<<"Starting from "<<d_start<<std::endl;
474 s32 nearest_emerged_d = -1;
475 s32 nearest_emergefull_d = -1;
476 s32 nearest_sent_d = -1;
477 bool queue_is_full = false;
480 for(d = d_start; d <= d_max; d++)
482 /*errorstream<<"checking d="<<d<<" for "
483 <<server->getPlayerName(peer_id)<<std::endl;*/
484 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
487 If m_nearest_unsent_d was changed by the EmergeThread
488 (it can change it to 0 through SetBlockNotSent),
490 Else update m_nearest_unsent_d
492 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
494 d = m_nearest_unsent_d;
495 last_nearest_unsent_d = m_nearest_unsent_d;
499 Get the border/face dot coordinates of a "d-radiused"
502 core::list<v3s16> list;
503 getFacePositions(list, d);
505 core::list<v3s16>::Iterator li;
506 for(li=list.begin(); li!=list.end(); li++)
508 v3s16 p = *li + center;
512 - Don't allow too many simultaneous transfers
513 - EXCEPT when the blocks are very close
515 Also, don't send blocks that are already flying.
518 // Start with the usual maximum
519 u16 max_simul_dynamic = max_simul_sends_usually;
521 // If block is very close, allow full maximum
522 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
523 max_simul_dynamic = max_simul_sends_setting;
525 // Don't select too many blocks for sending
526 if(num_blocks_selected >= max_simul_dynamic)
528 queue_is_full = true;
529 goto queue_full_break;
532 // Don't send blocks that are currently being transferred
533 if(m_blocks_sending.find(p) != NULL)
539 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
540 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
541 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
542 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
543 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
544 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
547 // If this is true, inexistent block will be made from scratch
548 bool generate = d <= d_max_gen;
551 /*// Limit the generating area vertically to 2/3
552 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
555 // Limit the send area vertically to 1/2
556 if(abs(p.Y - center.Y) > d_max / 2)
562 If block is far away, don't generate it unless it is
568 // Block center y in nodes
569 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
570 // Don't generate if it's very high or very low
571 if(y < -64 || y > 64)
575 v2s16 p2d_nodes_center(
579 // Get ground height in nodes
580 s16 gh = server->m_env->getServerMap().findGroundLevel(
583 // If differs a lot, don't generate
584 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
586 // Actually, don't even send it
592 //infostream<<"d="<<d<<std::endl;
595 Don't generate or send if not in sight
596 FIXME This only works if the client uses a small enough
597 FOV setting. The default of 72 degrees is fine.
600 float camera_fov = (72.0*PI/180) * 4./3.;
601 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
607 Don't send already sent blocks
610 if(m_blocks_sent.find(p) != NULL)
617 Check if map has this block
619 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
621 bool surely_not_found_on_disk = false;
622 bool block_is_invalid = false;
625 // Reset usage timer, this block will be of use in the future.
626 block->resetUsageTimer();
628 // Block is dummy if data doesn't exist.
629 // It means it has been not found from disk and not generated
632 surely_not_found_on_disk = true;
635 // Block is valid if lighting is up-to-date and data exists
636 if(block->isValid() == false)
638 block_is_invalid = true;
641 /*if(block->isFullyGenerated() == false)
643 block_is_invalid = true;
648 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
649 v2s16 chunkpos = map->sector_to_chunk(p2d);
650 if(map->chunkNonVolatile(chunkpos) == false)
651 block_is_invalid = true;
653 if(block->isGenerated() == false)
654 block_is_invalid = true;
657 If block is not close, don't send it unless it is near
660 Block is near ground level if night-time mesh
661 differs from day-time mesh.
665 if(block->dayNightDiffed() == false)
672 If block has been marked to not exist on disk (dummy)
673 and generating new ones is not wanted, skip block.
675 if(generate == false && surely_not_found_on_disk == true)
682 Add inexistent block to emerge queue.
684 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
686 //TODO: Get value from somewhere
687 // Allow only one block in emerge queue
688 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
689 // Allow two blocks in queue per client
690 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
692 // Make it more responsive when needing to generate stuff
693 if(surely_not_found_on_disk)
695 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
697 //infostream<<"Adding block to emerge queue"<<std::endl;
699 // Add it to the emerge queue and trigger the thread
702 if(generate == false)
703 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
705 server->m_emerge_queue.addBlock(peer_id, p, flags);
706 server->m_emergethread.trigger();
708 if(nearest_emerged_d == -1)
709 nearest_emerged_d = d;
711 if(nearest_emergefull_d == -1)
712 nearest_emergefull_d = d;
719 if(nearest_sent_d == -1)
723 Add block to send queue
726 /*errorstream<<"sending from d="<<d<<" to "
727 <<server->getPlayerName(peer_id)<<std::endl;*/
729 PrioritySortedBlockTransfer q((float)d, p, peer_id);
733 num_blocks_selected += 1;
738 //infostream<<"Stopped at "<<d<<std::endl;
740 // If nothing was found for sending and nothing was queued for
741 // emerging, continue next time browsing from here
742 if(nearest_emerged_d != -1){
743 new_nearest_unsent_d = nearest_emerged_d;
744 } else if(nearest_emergefull_d != -1){
745 new_nearest_unsent_d = nearest_emergefull_d;
747 if(d > g_settings->getS16("max_block_send_distance")){
748 new_nearest_unsent_d = 0;
749 m_nothing_to_send_pause_timer = 2.0;
750 /*infostream<<"GetNextBlocks(): d wrapped around for "
751 <<server->getPlayerName(peer_id)
752 <<"; setting to 0 and pausing"<<std::endl;*/
754 if(nearest_sent_d != -1)
755 new_nearest_unsent_d = nearest_sent_d;
757 new_nearest_unsent_d = d;
761 if(new_nearest_unsent_d != -1)
762 m_nearest_unsent_d = new_nearest_unsent_d;
764 /*timer_result = timer.stop(true);
765 if(timer_result != 0)
766 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
769 void RemoteClient::SendObjectData(
772 core::map<v3s16, bool> &stepped_blocks
775 DSTACK(__FUNCTION_NAME);
777 // Can't send anything without knowing version
778 if(serialization_version == SER_FMT_VER_INVALID)
780 infostream<<"RemoteClient::SendObjectData(): Not sending, no version."
786 Send a TOCLIENT_OBJECTDATA packet.
790 u16 number of player positions
802 std::ostringstream os(std::ios_base::binary);
806 writeU16(buf, TOCLIENT_OBJECTDATA);
807 os.write((char*)buf, 2);
810 Get and write player data
813 // Get connected players
814 core::list<Player*> players = server->m_env->getPlayers(true);
816 // Write player count
817 u16 playercount = players.size();
818 writeU16(buf, playercount);
819 os.write((char*)buf, 2);
821 core::list<Player*>::Iterator i;
822 for(i = players.begin();
823 i != players.end(); i++)
827 v3f pf = player->getPosition();
828 v3f sf = player->getSpeed();
830 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
831 v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
832 s32 pitch_i (player->getPitch() * 100);
833 s32 yaw_i (player->getYaw() * 100);
835 writeU16(buf, player->peer_id);
836 os.write((char*)buf, 2);
837 writeV3S32(buf, position_i);
838 os.write((char*)buf, 12);
839 writeV3S32(buf, speed_i);
840 os.write((char*)buf, 12);
841 writeS32(buf, pitch_i);
842 os.write((char*)buf, 4);
843 writeS32(buf, yaw_i);
844 os.write((char*)buf, 4);
848 Get and write object data (dummy, for compatibility)
853 os.write((char*)buf, 2);
859 //infostream<<"Server: Sending object data to "<<peer_id<<std::endl;
862 std::string s = os.str();
863 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
864 // Send as unreliable
865 server->m_con.Send(peer_id, 0, data, false);
868 void RemoteClient::GotBlock(v3s16 p)
870 if(m_blocks_sending.find(p) != NULL)
871 m_blocks_sending.remove(p);
874 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
875 " m_blocks_sending"<<std::endl;*/
876 m_excess_gotblocks++;
878 m_blocks_sent.insert(p, true);
881 void RemoteClient::SentBlock(v3s16 p)
883 if(m_blocks_sending.find(p) == NULL)
884 m_blocks_sending.insert(p, 0.0);
886 infostream<<"RemoteClient::SentBlock(): Sent block"
887 " already in m_blocks_sending"<<std::endl;
890 void RemoteClient::SetBlockNotSent(v3s16 p)
892 m_nearest_unsent_d = 0;
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);
900 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
902 m_nearest_unsent_d = 0;
904 for(core::map<v3s16, MapBlock*>::Iterator
905 i = blocks.getIterator();
906 i.atEnd()==false; i++)
908 v3s16 p = i.getNode()->getKey();
910 if(m_blocks_sending.find(p) != NULL)
911 m_blocks_sending.remove(p);
912 if(m_blocks_sent.find(p) != NULL)
913 m_blocks_sent.remove(p);
921 PlayerInfo::PlayerInfo()
927 void PlayerInfo::PrintLine(std::ostream *s)
930 (*s)<<"\""<<name<<"\" ("
931 <<(position.X/10)<<","<<(position.Y/10)
932 <<","<<(position.Z/10)<<") ";
934 (*s)<<" avg_rtt="<<avg_rtt;
938 u32 PIChecksum(core::list<PlayerInfo> &l)
940 core::list<PlayerInfo>::Iterator i;
943 for(i=l.begin(); i!=l.end(); i++)
945 checksum += a * (i->id+1);
946 checksum ^= 0x435aafcd;
957 ModSpec(const std::string &name_="", const std::string path_=""):
963 static core::list<ModSpec> getMods(core::list<std::string> &modspaths)
965 core::list<ModSpec> mods;
966 for(core::list<std::string>::Iterator i = modspaths.begin();
967 i != modspaths.end(); i++){
968 std::string modspath = *i;
969 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(modspath);
970 for(u32 j=0; j<dirlist.size(); j++){
973 std::string modname = dirlist[j].name;
974 std::string modpath = modspath + DIR_DELIM + modname;
975 mods.push_back(ModSpec(modname, modpath));
986 std::string mapsavedir,
987 std::string configpath
990 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
991 m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"),
992 m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"),
994 m_toolmgr(createToolDefManager()),
995 m_nodedef(createNodeDefManager()),
996 m_craftdef(createCraftDefManager()),
998 m_emergethread(this),
1000 m_time_of_day_send_timer(0),
1002 m_mapsavedir(mapsavedir),
1003 m_configpath(configpath),
1004 m_shutdown_requested(false),
1005 m_ignore_map_edit_events(false),
1006 m_ignore_map_edit_events_peer_id(0)
1008 m_liquid_transform_timer = 0.0;
1009 m_print_info_timer = 0.0;
1010 m_objectdata_timer = 0.0;
1011 m_emergethread_trigger_timer = 0.0;
1012 m_savemap_timer = 0.0;
1016 m_step_dtime_mutex.Init();
1019 JMutexAutoLock envlock(m_env_mutex);
1020 JMutexAutoLock conlock(m_con_mutex);
1022 infostream<<"m_nodedef="<<m_nodedef<<std::endl;
1024 // Path to builtin.lua
1025 std::string builtinpath = porting::path_data + DIR_DELIM + "builtin.lua";
1026 // Add default global mod path
1027 m_modspaths.push_back(porting::path_data + DIR_DELIM + "mods");
1029 // Initialize scripting
1031 infostream<<"Server: Initializing scripting"<<std::endl;
1032 m_lua = script_init();
1035 scriptapi_export(m_lua, this);
1036 // Load and run builtin.lua
1037 infostream<<"Server: Loading builtin Lua stuff from \""<<builtinpath
1039 bool success = script_load(m_lua, builtinpath.c_str());
1041 errorstream<<"Server: Failed to load and run "
1042 <<builtinpath<<std::endl;
1045 // Load and run "mod" scripts
1046 core::list<ModSpec> mods = getMods(m_modspaths);
1047 for(core::list<ModSpec>::Iterator i = mods.begin();
1048 i != mods.end(); i++){
1050 infostream<<"Server: Loading mod \""<<mod.name<<"\""<<std::endl;
1051 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1052 bool success = script_load(m_lua, scriptpath.c_str());
1054 errorstream<<"Server: Failed to load and run "
1055 <<scriptpath<<std::endl;
1060 // Initialize Environment
1062 m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua, this);
1064 // Give environment reference to scripting api
1065 scriptapi_add_environment(m_lua, m_env);
1067 // Register us to receive map edit events
1068 m_env->getMap().addEventReceiver(this);
1070 // If file exists, load environment metadata
1071 if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt"))
1073 infostream<<"Server: Loading environment metadata"<<std::endl;
1074 m_env->loadMeta(m_mapsavedir);
1078 infostream<<"Server: Loading players"<<std::endl;
1079 m_env->deSerializePlayers(m_mapsavedir);
1084 infostream<<"Server::~Server()"<<std::endl;
1087 Send shutdown message
1090 JMutexAutoLock conlock(m_con_mutex);
1092 std::wstring line = L"*** Server shutting down";
1095 Send the message to clients
1097 for(core::map<u16, RemoteClient*>::Iterator
1098 i = m_clients.getIterator();
1099 i.atEnd() == false; i++)
1101 // Get client and check that it is valid
1102 RemoteClient *client = i.getNode()->getValue();
1103 assert(client->peer_id == i.getNode()->getKey());
1104 if(client->serialization_version == SER_FMT_VER_INVALID)
1108 SendChatMessage(client->peer_id, line);
1110 catch(con::PeerNotFoundException &e)
1116 JMutexAutoLock envlock(m_env_mutex);
1121 infostream<<"Server: Saving players"<<std::endl;
1122 m_env->serializePlayers(m_mapsavedir);
1125 Save environment metadata
1127 infostream<<"Server: Saving environment metadata"<<std::endl;
1128 m_env->saveMeta(m_mapsavedir);
1140 JMutexAutoLock clientslock(m_con_mutex);
1142 for(core::map<u16, RemoteClient*>::Iterator
1143 i = m_clients.getIterator();
1144 i.atEnd() == false; i++)
1147 // NOTE: These are removed by env destructor
1149 u16 peer_id = i.getNode()->getKey();
1150 JMutexAutoLock envlock(m_env_mutex);
1151 m_env->removePlayer(peer_id);
1155 delete i.getNode()->getValue();
1159 // Delete Environment
1165 // Deinitialize scripting
1166 infostream<<"Server: Deinitializing scripting"<<std::endl;
1167 script_deinit(m_lua);
1170 void Server::start(unsigned short port)
1172 DSTACK(__FUNCTION_NAME);
1173 // Stop thread if already running
1176 // Initialize connection
1177 m_con.SetTimeoutMs(30);
1181 m_thread.setRun(true);
1184 infostream<<"Server: Started on port "<<port<<std::endl;
1189 DSTACK(__FUNCTION_NAME);
1191 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1193 // Stop threads (set run=false first so both start stopping)
1194 m_thread.setRun(false);
1195 m_emergethread.setRun(false);
1197 m_emergethread.stop();
1199 infostream<<"Server: Threads stopped"<<std::endl;
1202 void Server::step(float dtime)
1204 DSTACK(__FUNCTION_NAME);
1209 JMutexAutoLock lock(m_step_dtime_mutex);
1210 m_step_dtime += dtime;
1214 void Server::AsyncRunStep()
1216 DSTACK(__FUNCTION_NAME);
1218 g_profiler->add("Server::AsyncRunStep (num)", 1);
1222 JMutexAutoLock lock1(m_step_dtime_mutex);
1223 dtime = m_step_dtime;
1227 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
1228 // Send blocks to clients
1235 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1237 //infostream<<"Server steps "<<dtime<<std::endl;
1238 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1241 JMutexAutoLock lock1(m_step_dtime_mutex);
1242 m_step_dtime -= dtime;
1249 m_uptime.set(m_uptime.get() + dtime);
1253 // Process connection's timeouts
1254 JMutexAutoLock lock2(m_con_mutex);
1255 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1256 m_con.RunTimeouts(dtime);
1260 // This has to be called so that the client list gets synced
1261 // with the peer list of the connection
1262 handlePeerChanges();
1266 Update m_time_of_day and overall game time
1269 JMutexAutoLock envlock(m_env_mutex);
1271 m_time_counter += dtime;
1272 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1273 u32 units = (u32)(m_time_counter*speed);
1274 m_time_counter -= (f32)units / speed;
1276 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1278 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1281 Send to clients at constant intervals
1284 m_time_of_day_send_timer -= dtime;
1285 if(m_time_of_day_send_timer < 0.0)
1287 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1289 //JMutexAutoLock envlock(m_env_mutex);
1290 JMutexAutoLock conlock(m_con_mutex);
1292 for(core::map<u16, RemoteClient*>::Iterator
1293 i = m_clients.getIterator();
1294 i.atEnd() == false; i++)
1296 RemoteClient *client = i.getNode()->getValue();
1297 //Player *player = m_env->getPlayer(client->peer_id);
1299 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1300 m_env->getTimeOfDay());
1302 m_con.Send(client->peer_id, 0, data, true);
1308 JMutexAutoLock lock(m_env_mutex);
1310 ScopeProfiler sp(g_profiler, "SEnv step");
1311 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1315 const float map_timer_and_unload_dtime = 2.92;
1316 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1318 JMutexAutoLock lock(m_env_mutex);
1319 // Run Map's timers and unload unused data
1320 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1321 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1322 g_settings->getFloat("server_unload_unused_data_timeout"));
1332 m_liquid_transform_timer += dtime;
1333 if(m_liquid_transform_timer >= 1.00)
1335 m_liquid_transform_timer -= 1.00;
1337 JMutexAutoLock lock(m_env_mutex);
1339 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1341 core::map<v3s16, MapBlock*> modified_blocks;
1342 m_env->getMap().transformLiquids(modified_blocks);
1347 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1348 ServerMap &map = ((ServerMap&)m_env->getMap());
1349 map.updateLighting(modified_blocks, lighting_modified_blocks);
1351 // Add blocks modified by lighting to modified_blocks
1352 for(core::map<v3s16, MapBlock*>::Iterator
1353 i = lighting_modified_blocks.getIterator();
1354 i.atEnd() == false; i++)
1356 MapBlock *block = i.getNode()->getValue();
1357 modified_blocks.insert(block->getPos(), block);
1361 Set the modified blocks unsent for all the clients
1364 JMutexAutoLock lock2(m_con_mutex);
1366 for(core::map<u16, RemoteClient*>::Iterator
1367 i = m_clients.getIterator();
1368 i.atEnd() == false; i++)
1370 RemoteClient *client = i.getNode()->getValue();
1372 if(modified_blocks.size() > 0)
1374 // Remove block from sent history
1375 client->SetBlocksNotSent(modified_blocks);
1380 // Periodically print some info
1382 float &counter = m_print_info_timer;
1388 JMutexAutoLock lock2(m_con_mutex);
1390 if(m_clients.size() != 0)
1391 infostream<<"Players:"<<std::endl;
1392 for(core::map<u16, RemoteClient*>::Iterator
1393 i = m_clients.getIterator();
1394 i.atEnd() == false; i++)
1396 //u16 peer_id = i.getNode()->getKey();
1397 RemoteClient *client = i.getNode()->getValue();
1398 Player *player = m_env->getPlayer(client->peer_id);
1401 infostream<<"* "<<player->getName()<<"\t";
1402 client->PrintInfo(infostream);
1407 //if(g_settings->getBool("enable_experimental"))
1411 Check added and deleted active objects
1414 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1415 JMutexAutoLock envlock(m_env_mutex);
1416 JMutexAutoLock conlock(m_con_mutex);
1418 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1420 // Radius inside which objects are active
1421 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1422 radius *= MAP_BLOCKSIZE;
1424 for(core::map<u16, RemoteClient*>::Iterator
1425 i = m_clients.getIterator();
1426 i.atEnd() == false; i++)
1428 RemoteClient *client = i.getNode()->getValue();
1429 Player *player = m_env->getPlayer(client->peer_id);
1432 // This can happen if the client timeouts somehow
1433 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1435 <<" has no associated player"<<std::endl;*/
1438 v3s16 pos = floatToInt(player->getPosition(), BS);
1440 core::map<u16, bool> removed_objects;
1441 core::map<u16, bool> added_objects;
1442 m_env->getRemovedActiveObjects(pos, radius,
1443 client->m_known_objects, removed_objects);
1444 m_env->getAddedActiveObjects(pos, radius,
1445 client->m_known_objects, added_objects);
1447 // Ignore if nothing happened
1448 if(removed_objects.size() == 0 && added_objects.size() == 0)
1450 //infostream<<"active objects: none changed"<<std::endl;
1454 std::string data_buffer;
1458 // Handle removed objects
1459 writeU16((u8*)buf, removed_objects.size());
1460 data_buffer.append(buf, 2);
1461 for(core::map<u16, bool>::Iterator
1462 i = removed_objects.getIterator();
1463 i.atEnd()==false; i++)
1466 u16 id = i.getNode()->getKey();
1467 ServerActiveObject* obj = m_env->getActiveObject(id);
1469 // Add to data buffer for sending
1470 writeU16((u8*)buf, i.getNode()->getKey());
1471 data_buffer.append(buf, 2);
1473 // Remove from known objects
1474 client->m_known_objects.remove(i.getNode()->getKey());
1476 if(obj && obj->m_known_by_count > 0)
1477 obj->m_known_by_count--;
1480 // Handle added objects
1481 writeU16((u8*)buf, added_objects.size());
1482 data_buffer.append(buf, 2);
1483 for(core::map<u16, bool>::Iterator
1484 i = added_objects.getIterator();
1485 i.atEnd()==false; i++)
1488 u16 id = i.getNode()->getKey();
1489 ServerActiveObject* obj = m_env->getActiveObject(id);
1492 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1494 infostream<<"WARNING: "<<__FUNCTION_NAME
1495 <<": NULL object"<<std::endl;
1497 type = obj->getType();
1499 // Add to data buffer for sending
1500 writeU16((u8*)buf, id);
1501 data_buffer.append(buf, 2);
1502 writeU8((u8*)buf, type);
1503 data_buffer.append(buf, 1);
1506 data_buffer.append(serializeLongString(
1507 obj->getClientInitializationData()));
1509 data_buffer.append(serializeLongString(""));
1511 // Add to known objects
1512 client->m_known_objects.insert(i.getNode()->getKey(), false);
1515 obj->m_known_by_count++;
1519 SharedBuffer<u8> reply(2 + data_buffer.size());
1520 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1521 memcpy((char*)&reply[2], data_buffer.c_str(),
1522 data_buffer.size());
1524 m_con.Send(client->peer_id, 0, reply, true);
1526 infostream<<"Server: Sent object remove/add: "
1527 <<removed_objects.size()<<" removed, "
1528 <<added_objects.size()<<" added, "
1529 <<"packet size is "<<reply.getSize()<<std::endl;
1534 Collect a list of all the objects known by the clients
1535 and report it back to the environment.
1538 core::map<u16, bool> all_known_objects;
1540 for(core::map<u16, RemoteClient*>::Iterator
1541 i = m_clients.getIterator();
1542 i.atEnd() == false; i++)
1544 RemoteClient *client = i.getNode()->getValue();
1545 // Go through all known objects of client
1546 for(core::map<u16, bool>::Iterator
1547 i = client->m_known_objects.getIterator();
1548 i.atEnd()==false; i++)
1550 u16 id = i.getNode()->getKey();
1551 all_known_objects[id] = true;
1555 m_env->setKnownActiveObjects(whatever);
1561 Send object messages
1564 JMutexAutoLock envlock(m_env_mutex);
1565 JMutexAutoLock conlock(m_con_mutex);
1567 //ScopeProfiler sp(g_profiler, "Server: sending object messages");
1570 // Value = data sent by object
1571 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1573 // Get active object messages from environment
1576 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1580 core::list<ActiveObjectMessage>* message_list = NULL;
1581 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1582 n = buffered_messages.find(aom.id);
1585 message_list = new core::list<ActiveObjectMessage>;
1586 buffered_messages.insert(aom.id, message_list);
1590 message_list = n->getValue();
1592 message_list->push_back(aom);
1595 // Route data to every client
1596 for(core::map<u16, RemoteClient*>::Iterator
1597 i = m_clients.getIterator();
1598 i.atEnd()==false; i++)
1600 RemoteClient *client = i.getNode()->getValue();
1601 std::string reliable_data;
1602 std::string unreliable_data;
1603 // Go through all objects in message buffer
1604 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1605 j = buffered_messages.getIterator();
1606 j.atEnd()==false; j++)
1608 // If object is not known by client, skip it
1609 u16 id = j.getNode()->getKey();
1610 if(client->m_known_objects.find(id) == NULL)
1612 // Get message list of object
1613 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1614 // Go through every message
1615 for(core::list<ActiveObjectMessage>::Iterator
1616 k = list->begin(); k != list->end(); k++)
1618 // Compose the full new data with header
1619 ActiveObjectMessage aom = *k;
1620 std::string new_data;
1623 writeU16((u8*)&buf[0], aom.id);
1624 new_data.append(buf, 2);
1626 new_data += serializeString(aom.datastring);
1627 // Add data to buffer
1629 reliable_data += new_data;
1631 unreliable_data += new_data;
1635 reliable_data and unreliable_data are now ready.
1638 if(reliable_data.size() > 0)
1640 SharedBuffer<u8> reply(2 + reliable_data.size());
1641 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1642 memcpy((char*)&reply[2], reliable_data.c_str(),
1643 reliable_data.size());
1645 m_con.Send(client->peer_id, 0, reply, true);
1647 if(unreliable_data.size() > 0)
1649 SharedBuffer<u8> reply(2 + unreliable_data.size());
1650 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1651 memcpy((char*)&reply[2], unreliable_data.c_str(),
1652 unreliable_data.size());
1653 // Send as unreliable
1654 m_con.Send(client->peer_id, 0, reply, false);
1657 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1659 infostream<<"Server: Size of object message data: "
1660 <<"reliable: "<<reliable_data.size()
1661 <<", unreliable: "<<unreliable_data.size()
1666 // Clear buffered_messages
1667 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1668 i = buffered_messages.getIterator();
1669 i.atEnd()==false; i++)
1671 delete i.getNode()->getValue();
1675 } // enable_experimental
1678 Send queued-for-sending map edit events.
1681 // Don't send too many at a time
1684 // Single change sending is disabled if queue size is not small
1685 bool disable_single_change_sending = false;
1686 if(m_unsent_map_edit_queue.size() >= 4)
1687 disable_single_change_sending = true;
1689 bool got_any_events = false;
1691 // We'll log the amount of each
1694 while(m_unsent_map_edit_queue.size() != 0)
1696 got_any_events = true;
1698 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1700 // Players far away from the change are stored here.
1701 // Instead of sending the changes, MapBlocks are set not sent
1703 core::list<u16> far_players;
1705 if(event->type == MEET_ADDNODE)
1707 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1708 prof.add("MEET_ADDNODE", 1);
1709 if(disable_single_change_sending)
1710 sendAddNode(event->p, event->n, event->already_known_by_peer,
1713 sendAddNode(event->p, event->n, event->already_known_by_peer,
1716 else if(event->type == MEET_REMOVENODE)
1718 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1719 prof.add("MEET_REMOVENODE", 1);
1720 if(disable_single_change_sending)
1721 sendRemoveNode(event->p, event->already_known_by_peer,
1724 sendRemoveNode(event->p, event->already_known_by_peer,
1727 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1729 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1730 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1731 setBlockNotSent(event->p);
1733 else if(event->type == MEET_OTHER)
1735 infostream<<"Server: MEET_OTHER"<<std::endl;
1736 prof.add("MEET_OTHER", 1);
1737 for(core::map<v3s16, bool>::Iterator
1738 i = event->modified_blocks.getIterator();
1739 i.atEnd()==false; i++)
1741 v3s16 p = i.getNode()->getKey();
1747 prof.add("unknown", 1);
1748 infostream<<"WARNING: Server: Unknown MapEditEvent "
1749 <<((u32)event->type)<<std::endl;
1753 Set blocks not sent to far players
1755 if(far_players.size() > 0)
1757 // Convert list format to that wanted by SetBlocksNotSent
1758 core::map<v3s16, MapBlock*> modified_blocks2;
1759 for(core::map<v3s16, bool>::Iterator
1760 i = event->modified_blocks.getIterator();
1761 i.atEnd()==false; i++)
1763 v3s16 p = i.getNode()->getKey();
1764 modified_blocks2.insert(p,
1765 m_env->getMap().getBlockNoCreateNoEx(p));
1767 // Set blocks not sent
1768 for(core::list<u16>::Iterator
1769 i = far_players.begin();
1770 i != far_players.end(); i++)
1773 RemoteClient *client = getClient(peer_id);
1776 client->SetBlocksNotSent(modified_blocks2);
1782 /*// Don't send too many at a time
1784 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1790 infostream<<"Server: MapEditEvents:"<<std::endl;
1791 prof.print(infostream);
1797 Send object positions
1800 float &counter = m_objectdata_timer;
1802 if(counter >= g_settings->getFloat("objectdata_interval"))
1804 JMutexAutoLock lock1(m_env_mutex);
1805 JMutexAutoLock lock2(m_con_mutex);
1807 //ScopeProfiler sp(g_profiler, "Server: sending player positions");
1809 SendObjectData(counter);
1816 Trigger emergethread (it somehow gets to a non-triggered but
1817 bysy state sometimes)
1820 float &counter = m_emergethread_trigger_timer;
1826 m_emergethread.trigger();
1830 // Save map, players and auth stuff
1832 float &counter = m_savemap_timer;
1834 if(counter >= g_settings->getFloat("server_map_save_interval"))
1838 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1841 if(m_authmanager.isModified())
1842 m_authmanager.save();
1845 if(m_banmanager.isModified())
1846 m_banmanager.save();
1849 JMutexAutoLock lock(m_env_mutex);
1851 /*// Unload unused data (delete from memory)
1852 m_env->getMap().unloadUnusedData(
1853 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1855 /*u32 deleted_count = m_env->getMap().unloadUnusedData(
1856 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1859 // Save only changed parts
1860 m_env->getMap().save(true);
1862 /*if(deleted_count > 0)
1864 infostream<<"Server: Unloaded "<<deleted_count
1865 <<" blocks from memory"<<std::endl;
1869 m_env->serializePlayers(m_mapsavedir);
1871 // Save environment metadata
1872 m_env->saveMeta(m_mapsavedir);
1877 void Server::Receive()
1879 DSTACK(__FUNCTION_NAME);
1880 SharedBuffer<u8> data;
1885 JMutexAutoLock conlock(m_con_mutex);
1886 datasize = m_con.Receive(peer_id, data);
1889 // This has to be called so that the client list gets synced
1890 // with the peer list of the connection
1891 handlePeerChanges();
1893 ProcessData(*data, datasize, peer_id);
1895 catch(con::InvalidIncomingDataException &e)
1897 infostream<<"Server::Receive(): "
1898 "InvalidIncomingDataException: what()="
1899 <<e.what()<<std::endl;
1901 catch(con::PeerNotFoundException &e)
1903 //NOTE: This is not needed anymore
1905 // The peer has been disconnected.
1906 // Find the associated player and remove it.
1908 /*JMutexAutoLock envlock(m_env_mutex);
1910 infostream<<"ServerThread: peer_id="<<peer_id
1911 <<" has apparently closed connection. "
1912 <<"Removing player."<<std::endl;
1914 m_env->removePlayer(peer_id);*/
1918 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1920 DSTACK(__FUNCTION_NAME);
1921 // Environment is locked first.
1922 JMutexAutoLock envlock(m_env_mutex);
1923 JMutexAutoLock conlock(m_con_mutex);
1926 Address address = m_con.GetPeerAddress(peer_id);
1928 // drop player if is ip is banned
1929 if(m_banmanager.isIpBanned(address.serializeString())){
1930 SendAccessDenied(m_con, peer_id,
1931 L"Your ip is banned. Banned name was "
1932 +narrow_to_wide(m_banmanager.getBanName(
1933 address.serializeString())));
1934 m_con.DeletePeer(peer_id);
1938 catch(con::PeerNotFoundException &e)
1940 infostream<<"Server::ProcessData(): Cancelling: peer "
1941 <<peer_id<<" not found"<<std::endl;
1945 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1953 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1955 if(command == TOSERVER_INIT)
1957 // [0] u16 TOSERVER_INIT
1958 // [2] u8 SER_FMT_VER_HIGHEST
1959 // [3] u8[20] player_name
1960 // [23] u8[28] password <--- can be sent without this, from old versions
1962 if(datasize < 2+1+PLAYERNAME_SIZE)
1965 infostream<<"Server: Got TOSERVER_INIT from "
1966 <<peer_id<<std::endl;
1968 // First byte after command is maximum supported
1969 // serialization version
1970 u8 client_max = data[2];
1971 u8 our_max = SER_FMT_VER_HIGHEST;
1972 // Use the highest version supported by both
1973 u8 deployed = core::min_(client_max, our_max);
1974 // If it's lower than the lowest supported, give up.
1975 if(deployed < SER_FMT_VER_LOWEST)
1976 deployed = SER_FMT_VER_INVALID;
1978 //peer->serialization_version = deployed;
1979 getClient(peer_id)->pending_serialization_version = deployed;
1981 if(deployed == SER_FMT_VER_INVALID)
1983 infostream<<"Server: Cannot negotiate "
1984 "serialization version with peer "
1985 <<peer_id<<std::endl;
1986 SendAccessDenied(m_con, peer_id,
1987 L"Your client is too old (map format)");
1992 Read and check network protocol version
1995 u16 net_proto_version = 0;
1996 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1998 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2001 getClient(peer_id)->net_proto_version = net_proto_version;
2003 if(net_proto_version == 0)
2005 SendAccessDenied(m_con, peer_id,
2006 L"Your client is too old. Please upgrade.");
2010 /* Uhh... this should actually be a warning but let's do it like this */
2011 if(g_settings->getBool("strict_protocol_version_checking"))
2013 if(net_proto_version < PROTOCOL_VERSION)
2015 SendAccessDenied(m_con, peer_id,
2016 L"Your client is too old. Please upgrade.");
2026 char playername[PLAYERNAME_SIZE];
2027 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2029 playername[i] = data[3+i];
2031 playername[PLAYERNAME_SIZE-1] = 0;
2033 if(playername[0]=='\0')
2035 infostream<<"Server: Player has empty name"<<std::endl;
2036 SendAccessDenied(m_con, peer_id,
2041 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2043 infostream<<"Server: Player has invalid name"<<std::endl;
2044 SendAccessDenied(m_con, peer_id,
2045 L"Name contains unallowed characters");
2050 char password[PASSWORD_SIZE];
2051 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2053 // old version - assume blank password
2058 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2060 password[i] = data[23+i];
2062 password[PASSWORD_SIZE-1] = 0;
2065 std::string checkpwd;
2066 if(m_authmanager.exists(playername))
2068 checkpwd = m_authmanager.getPassword(playername);
2072 checkpwd = g_settings->get("default_password");
2075 /*infostream<<"Server: Client gave password '"<<password
2076 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2078 if(password != checkpwd && m_authmanager.exists(playername))
2080 infostream<<"Server: peer_id="<<peer_id
2081 <<": supplied invalid password for "
2082 <<playername<<std::endl;
2083 SendAccessDenied(m_con, peer_id, L"Invalid password");
2087 // Add player to auth manager
2088 if(m_authmanager.exists(playername) == false)
2090 infostream<<"Server: adding player "<<playername
2091 <<" to auth manager"<<std::endl;
2092 m_authmanager.add(playername);
2093 m_authmanager.setPassword(playername, checkpwd);
2094 m_authmanager.setPrivs(playername,
2095 stringToPrivs(g_settings->get("default_privs")));
2096 m_authmanager.save();
2099 // Enforce user limit.
2100 // Don't enforce for users that have some admin right
2101 if(m_clients.size() >= g_settings->getU16("max_users") &&
2102 (m_authmanager.getPrivs(playername)
2103 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 &&
2104 playername != g_settings->get("name"))
2106 SendAccessDenied(m_con, peer_id, L"Too many users.");
2111 Player *player = emergePlayer(playername, password, peer_id);
2113 // If failed, cancel
2116 infostream<<"Server: peer_id="<<peer_id
2117 <<": failed to emerge player"<<std::endl;
2122 Answer with a TOCLIENT_INIT
2125 SharedBuffer<u8> reply(2+1+6+8);
2126 writeU16(&reply[0], TOCLIENT_INIT);
2127 writeU8(&reply[2], deployed);
2128 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2129 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2132 m_con.Send(peer_id, 0, reply, true);
2136 Send complete position information
2138 SendMovePlayer(player);
2143 if(command == TOSERVER_INIT2)
2145 infostream<<"Server: Got TOSERVER_INIT2 from "
2146 <<peer_id<<std::endl;
2149 getClient(peer_id)->serialization_version
2150 = getClient(peer_id)->pending_serialization_version;
2153 Send some initialization data
2156 // Send tool definitions
2157 SendToolDef(m_con, peer_id, m_toolmgr);
2159 // Send node definitions
2160 SendNodeDef(m_con, peer_id, m_nodedef);
2163 SendTextures(peer_id);
2165 // Send player info to all players
2168 // Send inventory to player
2169 UpdateCrafting(peer_id);
2170 SendInventory(peer_id);
2172 // Send player items to all players
2175 Player *player = m_env->getPlayer(peer_id);
2178 SendPlayerHP(player);
2182 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2183 m_env->getTimeOfDay());
2184 m_con.Send(peer_id, 0, data, true);
2187 // Send information about server to player in chat
2188 SendChatMessage(peer_id, getStatusString());
2190 // Send information about joining in chat
2192 std::wstring name = L"unknown";
2193 Player *player = m_env->getPlayer(peer_id);
2195 name = narrow_to_wide(player->getName());
2197 std::wstring message;
2200 message += L" joined game";
2201 BroadcastChatMessage(message);
2204 // Warnings about protocol version can be issued here
2205 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2207 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2211 Check HP, respawn if necessary
2213 HandlePlayerHP(player, 0);
2219 std::ostringstream os(std::ios_base::binary);
2220 for(core::map<u16, RemoteClient*>::Iterator
2221 i = m_clients.getIterator();
2222 i.atEnd() == false; i++)
2224 RemoteClient *client = i.getNode()->getValue();
2225 assert(client->peer_id == i.getNode()->getKey());
2226 if(client->serialization_version == SER_FMT_VER_INVALID)
2229 Player *player = m_env->getPlayer(client->peer_id);
2232 // Get name of player
2233 os<<player->getName()<<" ";
2236 actionstream<<player->getName()<<" joins game. List of players: "
2237 <<os.str()<<std::endl;
2243 if(peer_ser_ver == SER_FMT_VER_INVALID)
2245 infostream<<"Server::ProcessData(): Cancelling: Peer"
2246 " serialization format invalid or not initialized."
2247 " Skipping incoming command="<<command<<std::endl;
2251 Player *player = m_env->getPlayer(peer_id);
2254 infostream<<"Server::ProcessData(): Cancelling: "
2255 "No player for peer_id="<<peer_id
2259 if(command == TOSERVER_PLAYERPOS)
2261 if(datasize < 2+12+12+4+4)
2265 v3s32 ps = readV3S32(&data[start+2]);
2266 v3s32 ss = readV3S32(&data[start+2+12]);
2267 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2268 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2269 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2270 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2271 pitch = wrapDegrees(pitch);
2272 yaw = wrapDegrees(yaw);
2274 player->setPosition(position);
2275 player->setSpeed(speed);
2276 player->setPitch(pitch);
2277 player->setYaw(yaw);
2279 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2280 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2281 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2283 else if(command == TOSERVER_GOTBLOCKS)
2296 u16 count = data[2];
2297 for(u16 i=0; i<count; i++)
2299 if((s16)datasize < 2+1+(i+1)*6)
2300 throw con::InvalidIncomingDataException
2301 ("GOTBLOCKS length is too short");
2302 v3s16 p = readV3S16(&data[2+1+i*6]);
2303 /*infostream<<"Server: GOTBLOCKS ("
2304 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2305 RemoteClient *client = getClient(peer_id);
2306 client->GotBlock(p);
2309 else if(command == TOSERVER_DELETEDBLOCKS)
2322 u16 count = data[2];
2323 for(u16 i=0; i<count; i++)
2325 if((s16)datasize < 2+1+(i+1)*6)
2326 throw con::InvalidIncomingDataException
2327 ("DELETEDBLOCKS length is too short");
2328 v3s16 p = readV3S16(&data[2+1+i*6]);
2329 /*infostream<<"Server: DELETEDBLOCKS ("
2330 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2331 RemoteClient *client = getClient(peer_id);
2332 client->SetBlockNotSent(p);
2335 else if(command == TOSERVER_CLICK_OBJECT)
2337 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2340 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2345 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2351 [2] u8 button (0=left, 1=right)
2355 u8 button = readU8(&data[2]);
2356 u16 id = readS16(&data[3]);
2357 u16 item_i = readU16(&data[5]);
2359 ServerActiveObject *obj = m_env->getActiveObject(id);
2363 infostream<<"Server: CLICK_ACTIVEOBJECT: object not found"
2368 // Skip if object has been removed
2372 //TODO: Check that object is reasonably close
2374 // Get ServerRemotePlayer
2375 ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
2377 // Update wielded item
2378 srp->wieldItem(item_i);
2380 // Left click, pick/punch
2383 actionstream<<player->getName()<<" punches object "
2384 <<obj->getId()<<std::endl;
2391 Try creating inventory item
2393 InventoryItem *item = obj->createPickedUpItem();
2397 InventoryList *ilist = player->inventory.getList("main");
2400 actionstream<<player->getName()<<" picked up "
2401 <<item->getName()<<std::endl;
2402 if(g_settings->getBool("creative_mode") == false)
2404 // Skip if inventory has no free space
2405 if(ilist->roomForItem(item) == false)
2407 infostream<<"Player inventory has no free space"<<std::endl;
2411 // Add to inventory and send inventory
2412 ilist->addItem(item);
2413 UpdateCrafting(player->peer_id);
2414 SendInventory(player->peer_id);
2417 // Remove object from environment
2418 obj->m_removed = true;
2424 Item cannot be picked up. Punch it instead.
2427 actionstream<<player->getName()<<" punches object "
2428 <<obj->getId()<<std::endl;
2430 ToolItem *titem = NULL;
2431 std::string toolname = "";
2433 InventoryList *mlist = player->inventory.getList("main");
2436 InventoryItem *item = mlist->getItem(item_i);
2437 if(item && (std::string)item->getName() == "ToolItem")
2439 titem = (ToolItem*)item;
2440 toolname = titem->getToolName();
2444 v3f playerpos = player->getPosition();
2445 v3f objpos = obj->getBasePosition();
2446 v3f dir = (objpos - playerpos).normalize();
2448 u16 wear = obj->punch(toolname, dir, player->getName());
2452 bool weared_out = titem->addWear(wear);
2454 mlist->deleteItem(item_i);
2455 SendInventory(player->peer_id);
2460 // Right click, do something with object
2463 actionstream<<player->getName()<<" right clicks object "
2464 <<obj->getId()<<std::endl;
2467 obj->rightClick(srp);
2471 Update player state to client
2473 SendPlayerHP(player);
2474 UpdateCrafting(player->peer_id);
2475 SendInventory(player->peer_id);
2477 else if(command == TOSERVER_GROUND_ACTION)
2485 [3] v3s16 nodepos_undersurface
2486 [9] v3s16 nodepos_abovesurface
2491 2: stop digging (all parameters ignored)
2492 3: digging completed
2494 u8 action = readU8(&data[2]);
2496 p_under.X = readS16(&data[3]);
2497 p_under.Y = readS16(&data[5]);
2498 p_under.Z = readS16(&data[7]);
2500 p_over.X = readS16(&data[9]);
2501 p_over.Y = readS16(&data[11]);
2502 p_over.Z = readS16(&data[13]);
2503 u16 item_i = readU16(&data[15]);
2505 //TODO: Check that target is reasonably close
2513 NOTE: This can be used in the future to check if
2514 somebody is cheating, by checking the timing.
2516 bool cannot_punch_node = false;
2518 MapNode n(CONTENT_IGNORE);
2522 n = m_env->getMap().getNode(p_under);
2524 catch(InvalidPositionException &e)
2526 infostream<<"Server: Not punching: Node not found."
2527 <<" Adding block to emerge queue."
2529 m_emerge_queue.addBlock(peer_id,
2530 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2531 cannot_punch_node = true;
2534 if(cannot_punch_node)
2540 ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
2541 scriptapi_environment_on_punchnode(m_lua, p_under, n, srp);
2548 else if(action == 2)
2551 RemoteClient *client = getClient(peer_id);
2552 JMutexAutoLock digmutex(client->m_dig_mutex);
2553 client->m_dig_tool_item = -1;
2558 3: Digging completed
2560 else if(action == 3)
2562 // Mandatory parameter; actually used for nothing
2563 core::map<v3s16, MapBlock*> modified_blocks;
2565 content_t material = CONTENT_IGNORE;
2566 u8 mineral = MINERAL_NONE;
2568 bool cannot_remove_node = false;
2570 MapNode n(CONTENT_IGNORE);
2573 n = m_env->getMap().getNode(p_under);
2575 mineral = n.getMineral(m_nodedef);
2576 // Get material at position
2577 material = n.getContent();
2578 // If not yet cancelled
2579 if(cannot_remove_node == false)
2581 // If it's not diggable, do nothing
2582 if(m_nodedef->get(material).diggable == false)
2584 infostream<<"Server: Not finishing digging: "
2585 <<"Node not diggable"
2587 cannot_remove_node = true;
2590 // If not yet cancelled
2591 if(cannot_remove_node == false)
2593 // Get node metadata
2594 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
2595 if(meta && meta->nodeRemovalDisabled() == true)
2597 infostream<<"Server: Not finishing digging: "
2598 <<"Node metadata disables removal"
2600 cannot_remove_node = true;
2604 catch(InvalidPositionException &e)
2606 infostream<<"Server: Not finishing digging: Node not found."
2607 <<" Adding block to emerge queue."
2609 m_emerge_queue.addBlock(peer_id,
2610 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2611 cannot_remove_node = true;
2614 // Make sure the player is allowed to do it
2615 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2617 infostream<<"Player "<<player->getName()<<" cannot remove node"
2618 <<" because privileges are "<<getPlayerPrivs(player)
2620 cannot_remove_node = true;
2624 If node can't be removed, set block to be re-sent to
2627 if(cannot_remove_node)
2629 infostream<<"Server: Not finishing digging."<<std::endl;
2631 // Client probably has wrong data.
2632 // Set block not sent, so that client will get
2634 infostream<<"Client "<<peer_id<<" tried to dig "
2635 <<"node; but node cannot be removed."
2636 <<" setting MapBlock not sent."<<std::endl;
2637 RemoteClient *client = getClient(peer_id);
2638 v3s16 blockpos = getNodeBlockPos(p_under);
2639 client->SetBlockNotSent(blockpos);
2644 actionstream<<player->getName()<<" digs "<<PP(p_under)
2645 <<", gets material "<<(int)material<<", mineral "
2646 <<(int)mineral<<std::endl;
2649 Send the removal to all close-by players.
2650 - If other player is close, send REMOVENODE
2651 - Otherwise set blocks not sent
2653 core::list<u16> far_players;
2654 sendRemoveNode(p_under, peer_id, &far_players, 30);
2657 Update and send inventory
2660 if(g_settings->getBool("creative_mode") == false)
2665 InventoryList *mlist = player->inventory.getList("main");
2668 InventoryItem *item = mlist->getItem(item_i);
2669 if(item && (std::string)item->getName() == "ToolItem")
2671 ToolItem *titem = (ToolItem*)item;
2672 std::string toolname = titem->getToolName();
2674 // Get digging properties for material and tool
2675 ToolDiggingProperties tp =
2676 m_toolmgr->getDiggingProperties(toolname);
2677 DiggingProperties prop =
2678 getDiggingProperties(material, &tp, m_nodedef);
2680 if(prop.diggable == false)
2682 infostream<<"Server: WARNING: Player digged"
2683 <<" with impossible material + tool"
2684 <<" combination"<<std::endl;
2687 bool weared_out = titem->addWear(prop.wear);
2691 mlist->deleteItem(item_i);
2697 Add dug item to inventory
2700 InventoryItem *item = NULL;
2702 if(mineral != MINERAL_NONE)
2703 item = getDiggedMineralItem(mineral, this);
2708 const std::string &dug_s = m_nodedef->get(material).dug_item;
2711 std::istringstream is(dug_s, std::ios::binary);
2712 item = InventoryItem::deSerialize(is, this);
2718 // Add a item to inventory
2719 player->inventory.addItem("main", item);
2722 UpdateCrafting(player->peer_id);
2723 SendInventory(player->peer_id);
2728 if(mineral != MINERAL_NONE)
2729 item = getDiggedMineralItem(mineral, this);
2734 const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item;
2735 s32 extra_rarity = m_nodedef->get(material).extra_dug_item_rarity;
2736 if(extra_dug_s != "" && extra_rarity != 0
2737 && myrand() % extra_rarity == 0)
2739 std::istringstream is(extra_dug_s, std::ios::binary);
2740 item = InventoryItem::deSerialize(is, this);
2746 // Add a item to inventory
2747 player->inventory.addItem("main", item);
2750 UpdateCrafting(player->peer_id);
2751 SendInventory(player->peer_id);
2757 (this takes some time so it is done after the quick stuff)
2760 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2762 m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
2765 Set blocks not sent to far players
2767 for(core::list<u16>::Iterator
2768 i = far_players.begin();
2769 i != far_players.end(); i++)
2772 RemoteClient *client = getClient(peer_id);
2775 client->SetBlocksNotSent(modified_blocks);
2781 ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
2782 scriptapi_environment_on_dignode(m_lua, p_under, n, srp);
2788 else if(action == 1)
2791 InventoryList *ilist = player->inventory.getList("main");
2796 InventoryItem *item = ilist->getItem(item_i);
2798 // If there is no item, it is not possible to add it anywhere
2803 Handle material items
2805 if(std::string("MaterialItem") == item->getName())
2808 // Don't add a node if this is not a free space
2809 MapNode n2 = m_env->getMap().getNode(p_over);
2810 bool no_enough_privs =
2811 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2813 infostream<<"Player "<<player->getName()<<" cannot add node"
2814 <<" because privileges are "<<getPlayerPrivs(player)
2817 if(m_nodedef->get(n2).buildable_to == false
2820 // Client probably has wrong data.
2821 // Set block not sent, so that client will get
2823 infostream<<"Client "<<peer_id<<" tried to place"
2824 <<" node in invalid position; setting"
2825 <<" MapBlock not sent."<<std::endl;
2826 RemoteClient *client = getClient(peer_id);
2827 v3s16 blockpos = getNodeBlockPos(p_over);
2828 client->SetBlockNotSent(blockpos);
2832 catch(InvalidPositionException &e)
2834 infostream<<"Server: Ignoring ADDNODE: Node not found"
2835 <<" Adding block to emerge queue."
2837 m_emerge_queue.addBlock(peer_id,
2838 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2842 // Reset build time counter
2843 getClient(peer_id)->m_time_from_building = 0.0;
2846 MaterialItem *mitem = (MaterialItem*)item;
2848 n.setContent(mitem->getMaterial());
2850 actionstream<<player->getName()<<" places material "
2851 <<(int)mitem->getMaterial()
2852 <<" at "<<PP(p_under)<<std::endl;
2854 // Calculate direction for wall mounted stuff
2855 if(m_nodedef->get(n).wall_mounted)
2856 n.param2 = packDir(p_under - p_over);
2858 // Calculate the direction for furnaces and chests and stuff
2859 if(m_nodedef->get(n).param_type == CPT_FACEDIR_SIMPLE)
2861 v3f playerpos = player->getPosition();
2862 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2863 blockpos = blockpos.normalize();
2865 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2879 Send to all close-by players
2881 core::list<u16> far_players;
2882 sendAddNode(p_over, n, 0, &far_players, 30);
2887 InventoryList *ilist = player->inventory.getList("main");
2888 if(g_settings->getBool("creative_mode") == false && ilist)
2890 // Remove from inventory and send inventory
2891 if(mitem->getCount() == 1)
2892 ilist->deleteItem(item_i);
2896 UpdateCrafting(peer_id);
2897 SendInventory(peer_id);
2903 This takes some time so it is done after the quick stuff
2905 core::map<v3s16, MapBlock*> modified_blocks;
2907 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2909 std::string p_name = std::string(player->getName());
2910 m_env->getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
2913 Set blocks not sent to far players
2915 for(core::list<u16>::Iterator
2916 i = far_players.begin();
2917 i != far_players.end(); i++)
2920 RemoteClient *client = getClient(peer_id);
2923 client->SetBlocksNotSent(modified_blocks);
2929 ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
2930 scriptapi_environment_on_placenode(m_lua, p_over, n, srp);
2933 Calculate special events
2936 /*if(n.d == LEGN(m_nodedef, "CONTENT_MESE"))
2939 for(s16 z=-1; z<=1; z++)
2940 for(s16 y=-1; y<=1; y++)
2941 for(s16 x=-1; x<=1; x++)
2948 Place other item (not a block)
2952 v3s16 blockpos = getNodeBlockPos(p_over);
2955 Check that the block is loaded so that the item
2956 can properly be added to the static list too
2958 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2961 infostream<<"Error while placing object: "
2962 "block not found"<<std::endl;
2967 If in creative mode, item dropping is disabled unless
2968 player has build privileges
2970 if(g_settings->getBool("creative_mode") &&
2971 (getPlayerPrivs(player) & PRIV_BUILD) == 0)
2973 infostream<<"Not allowing player to drop item: "
2974 "creative mode and no build privs"<<std::endl;
2978 // Calculate a position for it
2979 v3f pos = intToFloat(p_over, BS);
2981 /*pos.Y -= BS*0.25; // let it drop a bit
2983 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2984 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;*/
2989 ServerActiveObject *obj = item->createSAO(m_env, 0, pos);
2993 infostream<<"WARNING: item resulted in NULL object, "
2994 <<"not placing onto map"
2999 actionstream<<player->getName()<<" places "<<item->getName()
3000 <<" at "<<PP(p_over)<<std::endl;
3002 // Add the object to the environment
3003 m_env->addActiveObject(obj);
3005 infostream<<"Placed object"<<std::endl;
3007 if(g_settings->getBool("creative_mode") == false)
3009 // Delete the right amount of items from the slot
3010 u16 dropcount = item->getDropCount();
3012 // Delete item if all gone
3013 if(item->getCount() <= dropcount)
3015 if(item->getCount() < dropcount)
3016 infostream<<"WARNING: Server: dropped more items"
3017 <<" than the slot contains"<<std::endl;
3019 InventoryList *ilist = player->inventory.getList("main");
3021 // Remove from inventory and send inventory
3022 ilist->deleteItem(item_i);
3024 // Else decrement it
3026 item->remove(dropcount);
3029 UpdateCrafting(peer_id);
3030 SendInventory(peer_id);
3038 Catch invalid actions
3042 infostream<<"WARNING: Server: Invalid action "
3043 <<action<<std::endl;
3047 else if(command == TOSERVER_RELEASE)
3056 infostream<<"TOSERVER_RELEASE ignored"<<std::endl;
3059 else if(command == TOSERVER_SIGNTEXT)
3061 infostream<<"Server: TOSERVER_SIGNTEXT not supported anymore"
3065 else if(command == TOSERVER_SIGNNODETEXT)
3067 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3075 std::string datastring((char*)&data[2], datasize-2);
3076 std::istringstream is(datastring, std::ios_base::binary);
3079 is.read((char*)buf, 6);
3080 v3s16 p = readV3S16(buf);
3081 is.read((char*)buf, 2);
3082 u16 textlen = readU16(buf);
3084 for(u16 i=0; i<textlen; i++)
3086 is.read((char*)buf, 1);
3087 text += (char)buf[0];
3090 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3093 if(meta->typeId() != LEGN(m_nodedef, "CONTENT_SIGN_WALL"))
3095 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3096 signmeta->setText(text);
3098 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign "
3099 <<" at "<<PP(p)<<std::endl;
3101 v3s16 blockpos = getNodeBlockPos(p);
3102 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3105 block->raiseModified(MOD_STATE_WRITE_NEEDED,
3109 setBlockNotSent(blockpos);
3111 else if(command == TOSERVER_INVENTORY_ACTION)
3113 /*// Ignore inventory changes if in creative mode
3114 if(g_settings->getBool("creative_mode") == true)
3116 infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3120 // Strip command and create a stream
3121 std::string datastring((char*)&data[2], datasize-2);
3122 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3123 std::istringstream is(datastring, std::ios_base::binary);
3125 InventoryAction *a = InventoryAction::deSerialize(is);
3130 c.current_player = player;
3133 Handle craftresult specially if not in creative mode
3135 bool disable_action = false;
3136 if(a->getType() == IACTION_MOVE
3137 && g_settings->getBool("creative_mode") == false)
3139 IMoveAction *ma = (IMoveAction*)a;
3140 if(ma->to_inv == "current_player" &&
3141 ma->from_inv == "current_player")
3143 InventoryList *rlist = player->inventory.getList("craftresult");
3145 InventoryList *clist = player->inventory.getList("craft");
3147 InventoryList *mlist = player->inventory.getList("main");
3150 Craftresult is no longer preview if something
3153 if(ma->to_list == "craftresult"
3154 && ma->from_list != "craftresult")
3156 // If it currently is a preview, remove
3158 if(player->craftresult_is_preview)
3160 rlist->deleteItem(0);
3162 player->craftresult_is_preview = false;
3165 Crafting takes place if this condition is true.
3167 if(player->craftresult_is_preview &&
3168 ma->from_list == "craftresult")
3170 player->craftresult_is_preview = false;
3171 clist->decrementMaterials(1);
3173 /* Print out action */
3174 InventoryList *list =
3175 player->inventory.getList("craftresult");
3177 InventoryItem *item = list->getItem(0);
3178 std::string itemname = "NULL";
3180 itemname = item->getName();
3181 actionstream<<player->getName()<<" crafts "
3182 <<itemname<<std::endl;
3185 If the craftresult is placed on itself, move it to
3186 main inventory instead of doing the action
3188 if(ma->to_list == "craftresult"
3189 && ma->from_list == "craftresult")
3191 disable_action = true;
3193 InventoryItem *item1 = rlist->changeItem(0, NULL);
3194 mlist->addItem(item1);
3197 // Disallow moving items if not allowed to build
3198 else if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3202 // if it's a locking chest, only allow the owner or server admins to move items
3203 else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3205 Strfnd fn(ma->from_inv);
3206 std::string id0 = fn.next(":");
3207 if(id0 == "nodemeta")
3210 p.X = stoi(fn.next(","));
3211 p.Y = stoi(fn.next(","));
3212 p.Z = stoi(fn.next(","));
3213 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3214 if(meta && meta->typeId() == LEGN(m_nodedef, "CONTENT_LOCKABLE_CHEST")) {
3215 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3216 if (lcm->getOwner() != player->getName())
3221 else if (ma->to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3223 Strfnd fn(ma->to_inv);
3224 std::string id0 = fn.next(":");
3225 if(id0 == "nodemeta")
3228 p.X = stoi(fn.next(","));
3229 p.Y = stoi(fn.next(","));
3230 p.Z = stoi(fn.next(","));
3231 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3232 if(meta && meta->typeId() == LEGN(m_nodedef, "CONTENT_LOCKABLE_CHEST")) {
3233 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3234 if (lcm->getOwner() != player->getName())
3241 if(disable_action == false)
3243 // Feed action to player inventory
3251 UpdateCrafting(player->peer_id);
3252 SendInventory(player->peer_id);
3257 infostream<<"TOSERVER_INVENTORY_ACTION: "
3258 <<"InventoryAction::deSerialize() returned NULL"
3262 else if(command == TOSERVER_CHAT_MESSAGE)
3270 std::string datastring((char*)&data[2], datasize-2);
3271 std::istringstream is(datastring, std::ios_base::binary);
3274 is.read((char*)buf, 2);
3275 u16 len = readU16(buf);
3277 std::wstring message;
3278 for(u16 i=0; i<len; i++)
3280 is.read((char*)buf, 2);
3281 message += (wchar_t)readU16(buf);
3284 // Get player name of this client
3285 std::wstring name = narrow_to_wide(player->getName());
3287 // Line to send to players
3289 // Whether to send to the player that sent the line
3290 bool send_to_sender = false;
3291 // Whether to send to other players
3292 bool send_to_others = false;
3294 // Local player gets all privileges regardless of
3295 // what's set on their account.
3296 u64 privs = getPlayerPrivs(player);
3299 if(message[0] == L'/')
3301 size_t strip_size = 1;
3302 if (message[1] == L'#') // support old-style commans
3304 message = message.substr(strip_size);
3306 WStrfnd f1(message);
3307 f1.next(L" "); // Skip over /#whatever
3308 std::wstring paramstring = f1.next(L"");
3310 ServerCommandContext *ctx = new ServerCommandContext(
3311 str_split(message, L' '),
3318 std::wstring reply(processServerCommand(ctx));
3319 send_to_sender = ctx->flags & SEND_TO_SENDER;
3320 send_to_others = ctx->flags & SEND_TO_OTHERS;
3322 if (ctx->flags & SEND_NO_PREFIX)
3325 line += L"Server: " + reply;
3332 if(privs & PRIV_SHOUT)
3338 send_to_others = true;
3342 line += L"Server: You are not allowed to shout";
3343 send_to_sender = true;
3350 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3353 Send the message to clients
3355 for(core::map<u16, RemoteClient*>::Iterator
3356 i = m_clients.getIterator();
3357 i.atEnd() == false; i++)
3359 // Get client and check that it is valid
3360 RemoteClient *client = i.getNode()->getValue();
3361 assert(client->peer_id == i.getNode()->getKey());
3362 if(client->serialization_version == SER_FMT_VER_INVALID)
3366 bool sender_selected = (peer_id == client->peer_id);
3367 if(sender_selected == true && send_to_sender == false)
3369 if(sender_selected == false && send_to_others == false)
3372 SendChatMessage(client->peer_id, line);
3376 else if(command == TOSERVER_DAMAGE)
3378 std::string datastring((char*)&data[2], datasize-2);
3379 std::istringstream is(datastring, std::ios_base::binary);
3380 u8 damage = readU8(is);
3382 if(g_settings->getBool("enable_damage"))
3384 actionstream<<player->getName()<<" damaged by "
3385 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
3388 HandlePlayerHP(player, damage);
3392 SendPlayerHP(player);
3395 else if(command == TOSERVER_PASSWORD)
3398 [0] u16 TOSERVER_PASSWORD
3399 [2] u8[28] old password
3400 [30] u8[28] new password
3403 if(datasize != 2+PASSWORD_SIZE*2)
3405 /*char password[PASSWORD_SIZE];
3406 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3407 password[i] = data[2+i];
3408 password[PASSWORD_SIZE-1] = 0;*/
3410 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3418 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3420 char c = data[2+PASSWORD_SIZE+i];
3426 infostream<<"Server: Client requests a password change from "
3427 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3429 std::string playername = player->getName();
3431 if(m_authmanager.exists(playername) == false)
3433 infostream<<"Server: playername not found in authmanager"<<std::endl;
3434 // Wrong old password supplied!!
3435 SendChatMessage(peer_id, L"playername not found in authmanager");
3439 std::string checkpwd = m_authmanager.getPassword(playername);
3441 if(oldpwd != checkpwd)
3443 infostream<<"Server: invalid old password"<<std::endl;
3444 // Wrong old password supplied!!
3445 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3449 actionstream<<player->getName()<<" changes password"<<std::endl;
3451 m_authmanager.setPassword(playername, newpwd);
3453 infostream<<"Server: password change successful for "<<playername
3455 SendChatMessage(peer_id, L"Password change successful");
3457 else if(command == TOSERVER_PLAYERITEM)
3462 u16 item = readU16(&data[2]);
3463 player->wieldItem(item);
3464 SendWieldedItem(player);
3466 else if(command == TOSERVER_RESPAWN)
3471 RespawnPlayer(player);
3473 actionstream<<player->getName()<<" respawns at "
3474 <<PP(player->getPosition()/BS)<<std::endl;
3478 infostream<<"Server::ProcessData(): Ignoring "
3479 "unknown command "<<command<<std::endl;
3483 catch(SendFailedException &e)
3485 errorstream<<"Server::ProcessData(): SendFailedException: "
3491 void Server::onMapEditEvent(MapEditEvent *event)
3493 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3494 if(m_ignore_map_edit_events)
3496 MapEditEvent *e = event->clone();
3497 m_unsent_map_edit_queue.push_back(e);
3500 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3502 if(id == "current_player")
3504 assert(c->current_player);
3505 return &(c->current_player->inventory);
3509 std::string id0 = fn.next(":");
3511 if(id0 == "nodemeta")
3514 p.X = stoi(fn.next(","));
3515 p.Y = stoi(fn.next(","));
3516 p.Z = stoi(fn.next(","));
3517 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3519 return meta->getInventory();
3520 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3521 <<"no metadata found"<<std::endl;
3525 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3528 void Server::inventoryModified(InventoryContext *c, std::string id)
3530 if(id == "current_player")
3532 assert(c->current_player);
3534 UpdateCrafting(c->current_player->peer_id);
3535 SendInventory(c->current_player->peer_id);
3540 std::string id0 = fn.next(":");
3542 if(id0 == "nodemeta")
3545 p.X = stoi(fn.next(","));
3546 p.Y = stoi(fn.next(","));
3547 p.Z = stoi(fn.next(","));
3548 v3s16 blockpos = getNodeBlockPos(p);
3550 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3552 meta->inventoryModified();
3554 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3556 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3558 setBlockNotSent(blockpos);
3563 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3566 core::list<PlayerInfo> Server::getPlayerInfo()
3568 DSTACK(__FUNCTION_NAME);
3569 JMutexAutoLock envlock(m_env_mutex);
3570 JMutexAutoLock conlock(m_con_mutex);
3572 core::list<PlayerInfo> list;
3574 core::list<Player*> players = m_env->getPlayers();
3576 core::list<Player*>::Iterator i;
3577 for(i = players.begin();
3578 i != players.end(); i++)
3582 Player *player = *i;
3585 // Copy info from connection to info struct
3586 info.id = player->peer_id;
3587 info.address = m_con.GetPeerAddress(player->peer_id);
3588 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3590 catch(con::PeerNotFoundException &e)
3592 // Set dummy peer info
3594 info.address = Address(0,0,0,0,0);
3598 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3599 info.position = player->getPosition();
3601 list.push_back(info);
3608 void Server::peerAdded(con::Peer *peer)
3610 DSTACK(__FUNCTION_NAME);
3611 infostream<<"Server::peerAdded(): peer->id="
3612 <<peer->id<<std::endl;
3615 c.type = PEER_ADDED;
3616 c.peer_id = peer->id;
3618 m_peer_change_queue.push_back(c);
3621 void Server::deletingPeer(con::Peer *peer, bool timeout)
3623 DSTACK(__FUNCTION_NAME);
3624 infostream<<"Server::deletingPeer(): peer->id="
3625 <<peer->id<<", timeout="<<timeout<<std::endl;
3628 c.type = PEER_REMOVED;
3629 c.peer_id = peer->id;
3630 c.timeout = timeout;
3631 m_peer_change_queue.push_back(c);
3638 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3640 DSTACK(__FUNCTION_NAME);
3641 std::ostringstream os(std::ios_base::binary);
3643 writeU16(os, TOCLIENT_HP);
3647 std::string s = os.str();
3648 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3650 con.Send(peer_id, 0, data, true);
3653 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3654 const std::wstring &reason)
3656 DSTACK(__FUNCTION_NAME);
3657 std::ostringstream os(std::ios_base::binary);
3659 writeU16(os, TOCLIENT_ACCESS_DENIED);
3660 os<<serializeWideString(reason);
3663 std::string s = os.str();
3664 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3666 con.Send(peer_id, 0, data, true);
3669 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3670 bool set_camera_point_target, v3f camera_point_target)
3672 DSTACK(__FUNCTION_NAME);
3673 std::ostringstream os(std::ios_base::binary);
3675 writeU16(os, TOCLIENT_DEATHSCREEN);
3676 writeU8(os, set_camera_point_target);
3677 writeV3F1000(os, camera_point_target);
3680 std::string s = os.str();
3681 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3683 con.Send(peer_id, 0, data, true);
3686 void Server::SendToolDef(con::Connection &con, u16 peer_id,
3687 IToolDefManager *tooldef)
3689 DSTACK(__FUNCTION_NAME);
3690 std::ostringstream os(std::ios_base::binary);
3694 u32 length of the next item
3695 serialized ToolDefManager
3697 writeU16(os, TOCLIENT_TOOLDEF);
3698 std::ostringstream tmp_os(std::ios::binary);
3699 tooldef->serialize(tmp_os);
3700 os<<serializeLongString(tmp_os.str());
3703 std::string s = os.str();
3704 infostream<<"Server::SendToolDef(): Sending tool definitions: size="
3705 <<s.size()<<std::endl;
3706 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3708 con.Send(peer_id, 0, data, true);
3711 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3712 INodeDefManager *nodedef)
3714 DSTACK(__FUNCTION_NAME);
3715 std::ostringstream os(std::ios_base::binary);
3719 u32 length of the next item
3720 serialized NodeDefManager
3722 writeU16(os, TOCLIENT_NODEDEF);
3723 std::ostringstream tmp_os(std::ios::binary);
3724 nodedef->serialize(tmp_os);
3725 os<<serializeLongString(tmp_os.str());
3728 std::string s = os.str();
3729 infostream<<"Server::SendNodeDef(): Sending node definitions: size="
3730 <<s.size()<<std::endl;
3731 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3733 con.Send(peer_id, 0, data, true);
3737 Non-static send methods
3740 void Server::SendObjectData(float dtime)
3742 DSTACK(__FUNCTION_NAME);
3744 core::map<v3s16, bool> stepped_blocks;
3746 for(core::map<u16, RemoteClient*>::Iterator
3747 i = m_clients.getIterator();
3748 i.atEnd() == false; i++)
3750 u16 peer_id = i.getNode()->getKey();
3751 RemoteClient *client = i.getNode()->getValue();
3752 assert(client->peer_id == peer_id);
3754 if(client->serialization_version == SER_FMT_VER_INVALID)
3757 client->SendObjectData(this, dtime, stepped_blocks);
3761 void Server::SendPlayerInfos()
3763 DSTACK(__FUNCTION_NAME);
3765 //JMutexAutoLock envlock(m_env_mutex);
3767 // Get connected players
3768 core::list<Player*> players = m_env->getPlayers(true);
3770 u32 player_count = players.getSize();
3771 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3773 SharedBuffer<u8> data(datasize);
3774 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3777 core::list<Player*>::Iterator i;
3778 for(i = players.begin();
3779 i != players.end(); i++)
3781 Player *player = *i;
3783 /*infostream<<"Server sending player info for player with "
3784 "peer_id="<<player->peer_id<<std::endl;*/
3786 writeU16(&data[start], player->peer_id);
3787 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3788 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3789 start += 2+PLAYERNAME_SIZE;
3792 //JMutexAutoLock conlock(m_con_mutex);
3795 m_con.SendToAll(0, data, true);
3798 void Server::SendInventory(u16 peer_id)
3800 DSTACK(__FUNCTION_NAME);
3802 Player* player = m_env->getPlayer(peer_id);
3809 std::ostringstream os;
3810 //os.imbue(std::locale("C"));
3812 player->inventory.serialize(os);
3814 std::string s = os.str();
3816 SharedBuffer<u8> data(s.size()+2);
3817 writeU16(&data[0], TOCLIENT_INVENTORY);
3818 memcpy(&data[2], s.c_str(), s.size());
3821 m_con.Send(peer_id, 0, data, true);
3824 std::string getWieldedItemString(const Player *player)
3826 const InventoryItem *item = player->getWieldItem();
3828 return std::string("");
3829 std::ostringstream os(std::ios_base::binary);
3830 item->serialize(os);
3834 void Server::SendWieldedItem(const Player* player)
3836 DSTACK(__FUNCTION_NAME);
3840 std::ostringstream os(std::ios_base::binary);
3842 writeU16(os, TOCLIENT_PLAYERITEM);
3844 writeU16(os, player->peer_id);
3845 os<<serializeString(getWieldedItemString(player));
3848 std::string s = os.str();
3849 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3851 m_con.SendToAll(0, data, true);
3854 void Server::SendPlayerItems()
3856 DSTACK(__FUNCTION_NAME);
3858 std::ostringstream os(std::ios_base::binary);
3859 core::list<Player *> players = m_env->getPlayers(true);
3861 writeU16(os, TOCLIENT_PLAYERITEM);
3862 writeU16(os, players.size());
3863 core::list<Player *>::Iterator i;
3864 for(i = players.begin(); i != players.end(); ++i)
3867 writeU16(os, p->peer_id);
3868 os<<serializeString(getWieldedItemString(p));
3872 std::string s = os.str();
3873 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3875 m_con.SendToAll(0, data, true);
3878 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3880 DSTACK(__FUNCTION_NAME);
3882 std::ostringstream os(std::ios_base::binary);
3886 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3887 os.write((char*)buf, 2);
3890 writeU16(buf, message.size());
3891 os.write((char*)buf, 2);
3894 for(u32 i=0; i<message.size(); i++)
3898 os.write((char*)buf, 2);
3902 std::string s = os.str();
3903 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3905 m_con.Send(peer_id, 0, data, true);
3908 void Server::BroadcastChatMessage(const std::wstring &message)
3910 for(core::map<u16, RemoteClient*>::Iterator
3911 i = m_clients.getIterator();
3912 i.atEnd() == false; i++)
3914 // Get client and check that it is valid
3915 RemoteClient *client = i.getNode()->getValue();
3916 assert(client->peer_id == i.getNode()->getKey());
3917 if(client->serialization_version == SER_FMT_VER_INVALID)
3920 SendChatMessage(client->peer_id, message);
3924 void Server::SendPlayerHP(Player *player)
3926 SendHP(m_con, player->peer_id, player->hp);
3929 void Server::SendMovePlayer(Player *player)
3931 DSTACK(__FUNCTION_NAME);
3932 std::ostringstream os(std::ios_base::binary);
3934 writeU16(os, TOCLIENT_MOVE_PLAYER);
3935 writeV3F1000(os, player->getPosition());
3936 writeF1000(os, player->getPitch());
3937 writeF1000(os, player->getYaw());
3940 v3f pos = player->getPosition();
3941 f32 pitch = player->getPitch();
3942 f32 yaw = player->getYaw();
3943 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
3944 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3951 std::string s = os.str();
3952 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3954 m_con.Send(player->peer_id, 0, data, true);
3957 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3958 core::list<u16> *far_players, float far_d_nodes)
3960 float maxd = far_d_nodes*BS;
3961 v3f p_f = intToFloat(p, BS);
3965 SharedBuffer<u8> reply(replysize);
3966 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3967 writeS16(&reply[2], p.X);
3968 writeS16(&reply[4], p.Y);
3969 writeS16(&reply[6], p.Z);
3971 for(core::map<u16, RemoteClient*>::Iterator
3972 i = m_clients.getIterator();
3973 i.atEnd() == false; i++)
3975 // Get client and check that it is valid
3976 RemoteClient *client = i.getNode()->getValue();
3977 assert(client->peer_id == i.getNode()->getKey());
3978 if(client->serialization_version == SER_FMT_VER_INVALID)
3981 // Don't send if it's the same one
3982 if(client->peer_id == ignore_id)
3988 Player *player = m_env->getPlayer(client->peer_id);
3991 // If player is far away, only set modified blocks not sent
3992 v3f player_pos = player->getPosition();
3993 if(player_pos.getDistanceFrom(p_f) > maxd)
3995 far_players->push_back(client->peer_id);
4002 m_con.Send(client->peer_id, 0, reply, true);
4006 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4007 core::list<u16> *far_players, float far_d_nodes)
4009 float maxd = far_d_nodes*BS;
4010 v3f p_f = intToFloat(p, BS);
4012 for(core::map<u16, RemoteClient*>::Iterator
4013 i = m_clients.getIterator();
4014 i.atEnd() == false; i++)
4016 // Get client and check that it is valid
4017 RemoteClient *client = i.getNode()->getValue();
4018 assert(client->peer_id == i.getNode()->getKey());
4019 if(client->serialization_version == SER_FMT_VER_INVALID)
4022 // Don't send if it's the same one
4023 if(client->peer_id == ignore_id)
4029 Player *player = m_env->getPlayer(client->peer_id);
4032 // If player is far away, only set modified blocks not sent
4033 v3f player_pos = player->getPosition();
4034 if(player_pos.getDistanceFrom(p_f) > maxd)
4036 far_players->push_back(client->peer_id);
4043 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4044 SharedBuffer<u8> reply(replysize);
4045 writeU16(&reply[0], TOCLIENT_ADDNODE);
4046 writeS16(&reply[2], p.X);
4047 writeS16(&reply[4], p.Y);
4048 writeS16(&reply[6], p.Z);
4049 n.serialize(&reply[8], client->serialization_version);
4052 m_con.Send(client->peer_id, 0, reply, true);
4056 void Server::setBlockNotSent(v3s16 p)
4058 for(core::map<u16, RemoteClient*>::Iterator
4059 i = m_clients.getIterator();
4060 i.atEnd()==false; i++)
4062 RemoteClient *client = i.getNode()->getValue();
4063 client->SetBlockNotSent(p);
4067 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4069 DSTACK(__FUNCTION_NAME);
4071 v3s16 p = block->getPos();
4075 bool completely_air = true;
4076 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4077 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4078 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4080 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4082 completely_air = false;
4083 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4088 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4090 infostream<<"[completely air] ";
4091 infostream<<std::endl;
4095 Create a packet with the block in the right format
4098 std::ostringstream os(std::ios_base::binary);
4099 block->serialize(os, ver);
4100 std::string s = os.str();
4101 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4103 u32 replysize = 8 + blockdata.getSize();
4104 SharedBuffer<u8> reply(replysize);
4105 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4106 writeS16(&reply[2], p.X);
4107 writeS16(&reply[4], p.Y);
4108 writeS16(&reply[6], p.Z);
4109 memcpy(&reply[8], *blockdata, blockdata.getSize());
4111 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4112 <<": \tpacket size: "<<replysize<<std::endl;*/
4117 m_con.Send(peer_id, 1, reply, true);
4120 void Server::SendBlocks(float dtime)
4122 DSTACK(__FUNCTION_NAME);
4124 JMutexAutoLock envlock(m_env_mutex);
4125 JMutexAutoLock conlock(m_con_mutex);
4127 //TimeTaker timer("Server::SendBlocks");
4129 core::array<PrioritySortedBlockTransfer> queue;
4131 s32 total_sending = 0;
4134 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4136 for(core::map<u16, RemoteClient*>::Iterator
4137 i = m_clients.getIterator();
4138 i.atEnd() == false; i++)
4140 RemoteClient *client = i.getNode()->getValue();
4141 assert(client->peer_id == i.getNode()->getKey());
4143 total_sending += client->SendingCount();
4145 if(client->serialization_version == SER_FMT_VER_INVALID)
4148 client->GetNextBlocks(this, dtime, queue);
4153 // Lowest priority number comes first.
4154 // Lowest is most important.
4157 for(u32 i=0; i<queue.size(); i++)
4159 //TODO: Calculate limit dynamically
4160 if(total_sending >= g_settings->getS32
4161 ("max_simultaneous_block_sends_server_total"))
4164 PrioritySortedBlockTransfer q = queue[i];
4166 MapBlock *block = NULL;
4169 block = m_env->getMap().getBlockNoCreate(q.pos);
4171 catch(InvalidPositionException &e)
4176 RemoteClient *client = getClient(q.peer_id);
4178 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4180 client->SentBlock(q.pos);
4186 struct SendableTexture
4192 SendableTexture(const std::string &name_="", const std::string path_="",
4193 const std::string &data_=""):
4200 void Server::SendTextures(u16 peer_id)
4202 DSTACK(__FUNCTION_NAME);
4204 infostream<<"Server::SendTextures(): Sending textures to client"<<std::endl;
4208 // Put 5kB in one bunch (this is not accurate)
4209 u32 bytes_per_bunch = 5000;
4211 core::array< core::list<SendableTexture> > texture_bunches;
4212 texture_bunches.push_back(core::list<SendableTexture>());
4214 u32 texture_size_bunch_total = 0;
4215 core::list<ModSpec> mods = getMods(m_modspaths);
4216 for(core::list<ModSpec>::Iterator i = mods.begin();
4217 i != mods.end(); i++){
4219 std::string texturepath = mod.path + DIR_DELIM + "textures";
4220 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
4221 for(u32 j=0; j<dirlist.size(); j++){
4222 if(dirlist[j].dir) // Ignode dirs
4224 std::string tname = dirlist[j].name;
4225 std::string tpath = texturepath + DIR_DELIM + tname;
4227 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4228 if(fis.good() == false){
4229 errorstream<<"Server::SendTextures(): Could not open \""
4230 <<tname<<"\" for reading"<<std::endl;
4233 std::ostringstream tmp_os(std::ios_base::binary);
4237 fis.read(buf, 1024);
4238 std::streamsize len = fis.gcount();
4239 tmp_os.write(buf, len);
4240 texture_size_bunch_total += len;
4249 errorstream<<"Server::SendTextures(): Failed to read \""
4250 <<tname<<"\""<<std::endl;
4253 /*infostream<<"Server::SendTextures(): Loaded \""
4254 <<tname<<"\""<<std::endl;*/
4256 texture_bunches[texture_bunches.size()-1].push_back(
4257 SendableTexture(tname, tpath, tmp_os.str()));
4259 // Start next bunch if got enough data
4260 if(texture_size_bunch_total >= bytes_per_bunch){
4261 texture_bunches.push_back(core::list<SendableTexture>());
4262 texture_size_bunch_total = 0;
4267 /* Create and send packets */
4269 u32 num_bunches = texture_bunches.size();
4270 for(u32 i=0; i<num_bunches; i++)
4274 u16 total number of texture bunches
4275 u16 index of this bunch
4276 u32 number of textures in this bunch
4284 std::ostringstream os(std::ios_base::binary);
4286 writeU16(os, TOCLIENT_TEXTURES);
4287 writeU16(os, num_bunches);
4289 writeU32(os, texture_bunches[i].size());
4291 for(core::list<SendableTexture>::Iterator
4292 j = texture_bunches[i].begin();
4293 j != texture_bunches[i].end(); j++){
4294 os<<serializeString(j->name);
4295 os<<serializeLongString(j->data);
4299 std::string s = os.str();
4300 infostream<<"Server::SendTextures(): bunch "<<i<<"/"<<num_bunches
4301 <<" textures="<<texture_bunches[i].size()
4302 <<" size=" <<s.size()<<std::endl;
4303 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4305 m_con.Send(peer_id, 0, data, true);
4313 void Server::HandlePlayerHP(Player *player, s16 damage)
4315 if(player->hp > damage)
4317 player->hp -= damage;
4318 SendPlayerHP(player);
4322 infostream<<"Server::HandlePlayerHP(): Player "
4323 <<player->getName()<<" dies"<<std::endl;
4327 //TODO: Throw items around
4329 // Handle players that are not connected
4330 if(player->peer_id == PEER_ID_INEXISTENT){
4331 RespawnPlayer(player);
4335 SendPlayerHP(player);
4337 RemoteClient *client = getClient(player->peer_id);
4338 if(client->net_proto_version >= 3)
4340 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4344 RespawnPlayer(player);
4349 void Server::RespawnPlayer(Player *player)
4352 ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
4353 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4355 v3f pos = findSpawnPos(m_env->getServerMap());
4356 player->setPosition(pos);
4358 SendMovePlayer(player);
4359 SendPlayerHP(player);
4362 void Server::UpdateCrafting(u16 peer_id)
4364 DSTACK(__FUNCTION_NAME);
4366 Player* player = m_env->getPlayer(peer_id);
4370 Calculate crafting stuff
4372 if(g_settings->getBool("creative_mode") == false)
4374 InventoryList *clist = player->inventory.getList("craft");
4375 InventoryList *rlist = player->inventory.getList("craftresult");
4377 if(rlist && rlist->getUsedSlots() == 0)
4378 player->craftresult_is_preview = true;
4380 if(rlist && player->craftresult_is_preview)
4382 rlist->clearItems();
4384 if(clist && rlist && player->craftresult_is_preview)
4386 // Get result of crafting grid
4388 std::vector<InventoryItem*> items;
4389 for(u16 i=0; i<9; i++){
4390 if(clist->getItem(i) == NULL)
4391 items.push_back(NULL);
4393 items.push_back(clist->getItem(i)->clone());
4395 CraftPointerInput cpi(3, items);
4397 InventoryItem *result = m_craftdef->getCraftResult(cpi, this);
4398 //InventoryItem *result = craft_get_result(items, this);
4400 rlist->addItem(result);
4403 } // if creative_mode == false
4406 RemoteClient* Server::getClient(u16 peer_id)
4408 DSTACK(__FUNCTION_NAME);
4409 //JMutexAutoLock lock(m_con_mutex);
4410 core::map<u16, RemoteClient*>::Node *n;
4411 n = m_clients.find(peer_id);
4412 // A client should exist for all peers
4414 return n->getValue();
4417 std::wstring Server::getStatusString()
4419 std::wostringstream os(std::ios_base::binary);
4422 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4424 os<<L", uptime="<<m_uptime.get();
4425 // Information about clients
4427 for(core::map<u16, RemoteClient*>::Iterator
4428 i = m_clients.getIterator();
4429 i.atEnd() == false; i++)
4431 // Get client and check that it is valid
4432 RemoteClient *client = i.getNode()->getValue();
4433 assert(client->peer_id == i.getNode()->getKey());
4434 if(client->serialization_version == SER_FMT_VER_INVALID)
4437 Player *player = m_env->getPlayer(client->peer_id);
4438 // Get name of player
4439 std::wstring name = L"unknown";
4441 name = narrow_to_wide(player->getName());
4442 // Add name to information string
4446 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4447 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4448 if(g_settings->get("motd") != "")
4449 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4453 // Saves g_settings to configpath given at initialization
4454 void Server::saveConfig()
4456 if(m_configpath != "")
4457 g_settings->updateConfigFile(m_configpath.c_str());
4460 void Server::notifyPlayer(const char *name, const std::wstring msg)
4462 Player *player = m_env->getPlayer(name);
4465 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4468 void Server::notifyPlayers(const std::wstring msg)
4470 BroadcastChatMessage(msg);
4473 // IGameDef interface
4475 IToolDefManager* Server::getToolDefManager()
4479 INodeDefManager* Server::getNodeDefManager()
4483 ICraftDefManager* Server::getCraftDefManager()
4487 ITextureSource* Server::getTextureSource()
4491 u16 Server::allocateUnknownNodeId(const std::string &name)
4493 return m_nodedef->allocateDummy(name);
4496 IWritableToolDefManager* Server::getWritableToolDefManager()
4500 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4504 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4509 v3f findSpawnPos(ServerMap &map)
4511 //return v3f(50,50,50)*BS;
4516 nodepos = v2s16(0,0);
4521 // Try to find a good place a few times
4522 for(s32 i=0; i<1000; i++)
4525 // We're going to try to throw the player to this position
4526 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4527 -range + (myrand()%(range*2)));
4528 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4529 // Get ground height at point (fallbacks to heightmap function)
4530 s16 groundheight = map.findGroundLevel(nodepos2d);
4531 // Don't go underwater
4532 if(groundheight < WATER_LEVEL)
4534 //infostream<<"-> Underwater"<<std::endl;
4537 // Don't go to high places
4538 if(groundheight > WATER_LEVEL + 4)
4540 //infostream<<"-> Underwater"<<std::endl;
4544 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4545 bool is_good = false;
4547 for(s32 i=0; i<10; i++){
4548 v3s16 blockpos = getNodeBlockPos(nodepos);
4549 map.emergeBlock(blockpos, true);
4550 MapNode n = map.getNodeNoEx(nodepos);
4551 if(n.getContent() == CONTENT_AIR){
4562 // Found a good place
4563 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4569 return intToFloat(nodepos, BS);
4572 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4575 Try to get an existing player
4577 Player *player = m_env->getPlayer(name);
4580 // If player is already connected, cancel
4581 if(player->peer_id != 0)
4583 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4588 player->peer_id = peer_id;
4590 // Reset inventory to creative if in creative mode
4591 if(g_settings->getBool("creative_mode"))
4593 // Warning: double code below
4594 // Backup actual inventory
4595 player->inventory_backup = new Inventory();
4596 *(player->inventory_backup) = player->inventory;
4597 // Set creative inventory
4598 craft_set_creative_inventory(player, this);
4605 If player with the wanted peer_id already exists, cancel.
4607 if(m_env->getPlayer(peer_id) != NULL)
4609 infostream<<"emergePlayer(): Player with wrong name but same"
4610 " peer_id already exists"<<std::endl;
4618 // Add authentication stuff
4619 m_authmanager.add(name);
4620 m_authmanager.setPassword(name, password);
4621 m_authmanager.setPrivs(name,
4622 stringToPrivs(g_settings->get("default_privs")));
4624 /* Set player position */
4626 infostream<<"Server: Finding spawn place for player \""
4627 <<name<<"\""<<std::endl;
4629 v3f pos = findSpawnPos(m_env->getServerMap());
4631 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4633 /* Add player to environment */
4634 m_env->addPlayer(player);
4637 ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
4638 scriptapi_on_newplayer(m_lua, srp);
4640 /* Add stuff to inventory */
4641 if(g_settings->getBool("creative_mode"))
4643 // Warning: double code above
4644 // Backup actual inventory
4645 player->inventory_backup = new Inventory();
4646 *(player->inventory_backup) = player->inventory;
4647 // Set creative inventory
4648 craft_set_creative_inventory(player, this);
4653 } // create new player
4656 void Server::handlePeerChange(PeerChange &c)
4658 JMutexAutoLock envlock(m_env_mutex);
4659 JMutexAutoLock conlock(m_con_mutex);
4661 if(c.type == PEER_ADDED)
4668 core::map<u16, RemoteClient*>::Node *n;
4669 n = m_clients.find(c.peer_id);
4670 // The client shouldn't already exist
4674 RemoteClient *client = new RemoteClient();
4675 client->peer_id = c.peer_id;
4676 m_clients.insert(client->peer_id, client);
4679 else if(c.type == PEER_REMOVED)
4686 core::map<u16, RemoteClient*>::Node *n;
4687 n = m_clients.find(c.peer_id);
4688 // The client should exist
4692 Mark objects to be not known by the client
4694 RemoteClient *client = n->getValue();
4696 for(core::map<u16, bool>::Iterator
4697 i = client->m_known_objects.getIterator();
4698 i.atEnd()==false; i++)
4701 u16 id = i.getNode()->getKey();
4702 ServerActiveObject* obj = m_env->getActiveObject(id);
4704 if(obj && obj->m_known_by_count > 0)
4705 obj->m_known_by_count--;
4708 // Collect information about leaving in chat
4709 std::wstring message;
4711 Player *player = m_env->getPlayer(c.peer_id);
4714 std::wstring name = narrow_to_wide(player->getName());
4717 message += L" left game";
4719 message += L" (timed out)";
4725 m_env->removePlayer(c.peer_id);
4728 // Set player client disconnected
4730 Player *player = m_env->getPlayer(c.peer_id);
4732 player->peer_id = 0;
4739 std::ostringstream os(std::ios_base::binary);
4740 for(core::map<u16, RemoteClient*>::Iterator
4741 i = m_clients.getIterator();
4742 i.atEnd() == false; i++)
4744 RemoteClient *client = i.getNode()->getValue();
4745 assert(client->peer_id == i.getNode()->getKey());
4746 if(client->serialization_version == SER_FMT_VER_INVALID)
4749 Player *player = m_env->getPlayer(client->peer_id);
4752 // Get name of player
4753 os<<player->getName()<<" ";
4756 actionstream<<player->getName()<<" "
4757 <<(c.timeout?"times out.":"leaves game.")
4758 <<" List of players: "
4759 <<os.str()<<std::endl;
4764 delete m_clients[c.peer_id];
4765 m_clients.remove(c.peer_id);
4767 // Send player info to all remaining clients
4770 // Send leave chat message to all remaining clients
4771 BroadcastChatMessage(message);
4780 void Server::handlePeerChanges()
4782 while(m_peer_change_queue.size() > 0)
4784 PeerChange c = m_peer_change_queue.pop_front();
4786 infostream<<"Server: Handling peer change: "
4787 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4790 handlePeerChange(c);
4794 u64 Server::getPlayerPrivs(Player *player)
4798 std::string playername = player->getName();
4799 // Local player gets all privileges regardless of
4800 // what's set on their account.
4801 if(g_settings->get("name") == playername)
4807 return getPlayerAuthPrivs(playername);
4811 void dedicated_server_loop(Server &server, bool &kill)
4813 DSTACK(__FUNCTION_NAME);
4815 infostream<<DTIME<<std::endl;
4816 infostream<<"========================"<<std::endl;
4817 infostream<<"Running dedicated server"<<std::endl;
4818 infostream<<"========================"<<std::endl;
4819 infostream<<std::endl;
4821 IntervalLimiter m_profiler_interval;
4825 // This is kind of a hack but can be done like this
4826 // because server.step() is very light
4828 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4833 if(server.getShutdownRequested() || kill)
4835 infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4842 float profiler_print_interval =
4843 g_settings->getFloat("profiler_print_interval");
4844 if(profiler_print_interval != 0)
4846 if(m_profiler_interval.step(0.030, profiler_print_interval))
4848 infostream<<"Profiler:"<<std::endl;
4849 g_profiler->print(infostream);
4850 g_profiler->clear();
4857 static int counter = 0;
4863 core::list<PlayerInfo> list = server.getPlayerInfo();
4864 core::list<PlayerInfo>::Iterator i;
4865 static u32 sum_old = 0;
4866 u32 sum = PIChecksum(list);
4869 infostream<<DTIME<<"Player info:"<<std::endl;
4870 for(i=list.begin(); i!=list.end(); i++)
4872 i->PrintLine(&infostream);