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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser 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"
32 #include "serverobject.h"
37 #include "scriptapi.h"
43 #include "content_mapnode.h"
44 #include "content_nodemeta.h"
45 #include "content_abm.h"
46 #include "content_sao.h"
51 #include "sound.h" // dummySoundManager
52 #include "event_manager.h"
54 #include "util/string.h"
55 #include "util/pointedthing.h"
56 #include "util/mathconstants.h"
58 #include "util/serialize.h"
60 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
62 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
64 class MapEditEventIgnorer
67 MapEditEventIgnorer(bool *flag):
76 ~MapEditEventIgnorer()
89 class MapEditEventAreaIgnorer
92 MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
93 m_ignorevariable(ignorevariable)
95 if(m_ignorevariable->getVolume() == 0)
96 *m_ignorevariable = a;
98 m_ignorevariable = NULL;
101 ~MapEditEventAreaIgnorer()
105 assert(m_ignorevariable->getVolume() != 0);
106 *m_ignorevariable = VoxelArea();
111 VoxelArea *m_ignorevariable;
114 void * ServerThread::Thread()
118 log_register_thread("ServerThread");
120 DSTACK(__FUNCTION_NAME);
122 BEGIN_DEBUG_EXCEPTION_HANDLER
127 //TimeTaker timer("AsyncRunStep() + Receive()");
130 //TimeTaker timer("AsyncRunStep()");
131 m_server->AsyncRunStep();
134 //infostream<<"Running m_server->Receive()"<<std::endl;
137 catch(con::NoIncomingDataException &e)
140 catch(con::PeerNotFoundException &e)
142 infostream<<"Server: PeerNotFoundException"<<std::endl;
144 catch(con::ConnectionBindFailed &e)
146 m_server->setAsyncFatalError(e.what());
150 m_server->setAsyncFatalError(e.what());
154 END_DEBUG_EXCEPTION_HANDLER(errorstream)
159 void * EmergeThread::Thread()
163 log_register_thread("EmergeThread");
165 DSTACK(__FUNCTION_NAME);
167 BEGIN_DEBUG_EXCEPTION_HANDLER
169 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
171 v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
173 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
174 EmergeManager *emerge = m_server->m_emerge;
175 Mapgen *mapgen = emerge->getMapgen();
178 Get block info from queue, emerge them and send them
181 After queue is empty, exit.
185 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
189 SharedPtr<QueuedBlockEmerge> q(qptr);
197 Do not generate over-limit
199 if(blockpos_over_limit(p))
202 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
204 //TimeTaker timer("block emerge");
207 Try to emerge it from somewhere.
209 If it is only wanted as optional, only loading from disk
214 Check if any peer wants it as non-optional. In that case it
217 Also decrement the emerge queue count in clients.
220 bool only_from_disk = true;
223 core::map<u16, u8>::Iterator i;
224 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
226 //u16 peer_id = i.getNode()->getKey();
229 u8 flags = i.getNode()->getValue();
230 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
231 only_from_disk = false;
236 if(enable_mapgen_debug_info)
237 infostream<<"EmergeThread: p="
238 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
239 <<"only_from_disk="<<only_from_disk<<std::endl;
243 MapBlock *block = NULL;
244 bool got_block = true;
245 core::map<v3s16, MapBlock*> modified_blocks;
248 Try to fetch block from memory or disk.
249 If not found and asked to generate, initialize generator.
252 bool started_generate = false;
256 JMutexAutoLock envlock(m_server->m_env_mutex);
258 // Load sector if it isn't loaded
259 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
260 map.loadSectorMeta(p2d);
262 // Attempt to load block
263 block = map.getBlockNoCreateNoEx(p);
264 if(!block || block->isDummy() || !block->isGenerated())
266 if(enable_mapgen_debug_info)
267 infostream<<"EmergeThread: not in memory, "
268 <<"attempting to load from disk"<<std::endl;
270 block = map.loadBlock(p);
273 // If could not load and allowed to generate, start generation
274 // inside this same envlock
275 if(only_from_disk == false &&
276 (block == NULL || block->isGenerated() == false)){
277 if(enable_mapgen_debug_info)
278 infostream<<"EmergeThread: generating"<<std::endl;
279 started_generate = true;
281 map.initBlockMake(&data, p);
286 If generator was initialized, generate now when envlock is free.
291 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
293 TimeTaker t("mapgen::make_block()");
295 mapgen->makeChunk(&data);
296 //mapgen::make_block(&data);
298 if(enable_mapgen_debug_info == false)
299 t.stop(true); // Hide output
303 // Lock environment again to access the map
304 JMutexAutoLock envlock(m_server->m_env_mutex);
306 ScopeProfiler sp(g_profiler, "EmergeThread: after "
307 "mapgen::make_block (envlock)", SPT_AVG);
309 // Blit data back on map, update lighting, add mobs and
310 // whatever this does
311 map.finishBlockMake(&data, modified_blocks);
314 block = map.getBlockNoCreateNoEx(p);
316 // If block doesn't exist, don't try doing anything with it
317 // This happens if the block is not in generation boundaries
322 Do some post-generate stuff
325 v3s16 minp = data.blockpos_min*MAP_BLOCKSIZE;
326 v3s16 maxp = data.blockpos_max*MAP_BLOCKSIZE +
327 v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
330 Ignore map edit events, they will not need to be
331 sent to anybody because the block hasn't been sent
334 //MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
335 MapEditEventAreaIgnorer ign(
336 &m_server->m_ignore_map_edit_events_area,
337 VoxelArea(minp, maxp));
339 TimeTaker timer("on_generated");
340 scriptapi_environment_on_generated(m_server->m_lua,
341 minp, maxp, emerge->getBlockSeed(minp));
342 /*int t = timer.stop(true);
343 dstream<<"on_generated took "<<t<<"ms"<<std::endl;*/
346 if(enable_mapgen_debug_info)
347 infostream<<"EmergeThread: ended up with: "
348 <<analyze_block(block)<<std::endl;
350 // Activate objects and stuff
351 m_server->m_env->activateBlock(block, 0);
359 Set sent status of modified blocks on clients
362 // NOTE: Server's clients are also behind the connection mutex
363 JMutexAutoLock lock(m_server->m_con_mutex);
366 Add the originally fetched block to the modified list
370 modified_blocks.insert(p, block);
374 Set the modified blocks unsent for all the clients
377 for(core::map<u16, RemoteClient*>::Iterator
378 i = m_server->m_clients.getIterator();
379 i.atEnd() == false; i++)
381 RemoteClient *client = i.getNode()->getValue();
383 if(modified_blocks.size() > 0)
385 // Remove block from sent history
386 client->SetBlocksNotSent(modified_blocks);
390 catch(VersionMismatchException &e)
392 std::ostringstream err;
393 err<<"World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl;
394 err<<"----"<<std::endl;
395 err<<"\""<<e.what()<<"\""<<std::endl;
396 err<<"See debug.txt."<<std::endl;
397 err<<"World probably saved by a newer version of Minetest."<<std::endl;
398 m_server->setAsyncFatalError(err.str());
400 catch(SerializationError &e)
402 std::ostringstream err;
403 err<<"Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl;
404 err<<"----"<<std::endl;
405 err<<"\""<<e.what()<<"\""<<std::endl;
406 err<<"See debug.txt."<<std::endl;
407 err<<"You can ignore this using [ignore_world_load_errors = true]."<<std::endl;
408 m_server->setAsyncFatalError(err.str());
411 END_DEBUG_EXCEPTION_HANDLER(errorstream)
413 log_deregister_thread();
418 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
420 if(pos_exists) *pos_exists = false;
425 if(pos_exists) *pos_exists = true;
430 ServerActiveObject *sao = env->getActiveObject(object);
433 if(pos_exists) *pos_exists = true;
434 return sao->getBasePosition(); }
439 void RemoteClient::GetNextBlocks(Server *server, float dtime,
440 core::array<PrioritySortedBlockTransfer> &dest)
442 DSTACK(__FUNCTION_NAME);
445 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
448 m_nothing_to_send_pause_timer -= dtime;
449 m_nearest_unsent_reset_timer += dtime;
451 if(m_nothing_to_send_pause_timer >= 0)
454 Player *player = server->m_env->getPlayer(peer_id);
455 // This can happen sometimes; clients and players are not in perfect sync.
459 // Won't send anything if already sending
460 if(m_blocks_sending.size() >= g_settings->getU16
461 ("max_simultaneous_block_sends_per_client"))
463 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
467 //TimeTaker timer("RemoteClient::GetNextBlocks");
469 v3f playerpos = player->getPosition();
470 v3f playerspeed = player->getSpeed();
471 v3f playerspeeddir(0,0,0);
472 if(playerspeed.getLength() > 1.0*BS)
473 playerspeeddir = playerspeed / playerspeed.getLength();
474 // Predict to next block
475 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
477 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
479 v3s16 center = getNodeBlockPos(center_nodepos);
481 // Camera position and direction
482 v3f camera_pos = player->getEyePosition();
483 v3f camera_dir = v3f(0,0,1);
484 camera_dir.rotateYZBy(player->getPitch());
485 camera_dir.rotateXZBy(player->getYaw());
487 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
488 <<camera_dir.Z<<")"<<std::endl;*/
491 Get the starting value of the block finder radius.
494 if(m_last_center != center)
496 m_nearest_unsent_d = 0;
497 m_last_center = center;
500 /*infostream<<"m_nearest_unsent_reset_timer="
501 <<m_nearest_unsent_reset_timer<<std::endl;*/
503 // Reset periodically to workaround for some bugs or stuff
504 if(m_nearest_unsent_reset_timer > 20.0)
506 m_nearest_unsent_reset_timer = 0;
507 m_nearest_unsent_d = 0;
508 //infostream<<"Resetting m_nearest_unsent_d for "
509 // <<server->getPlayerName(peer_id)<<std::endl;
512 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
513 s16 d_start = m_nearest_unsent_d;
515 //infostream<<"d_start="<<d_start<<std::endl;
517 u16 max_simul_sends_setting = g_settings->getU16
518 ("max_simultaneous_block_sends_per_client");
519 u16 max_simul_sends_usually = max_simul_sends_setting;
522 Check the time from last addNode/removeNode.
524 Decrease send rate if player is building stuff.
526 m_time_from_building += dtime;
527 if(m_time_from_building < g_settings->getFloat(
528 "full_block_send_enable_min_time_from_building"))
530 max_simul_sends_usually
531 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
535 Number of blocks sending + number of blocks selected for sending
537 u32 num_blocks_selected = m_blocks_sending.size();
540 next time d will be continued from the d from which the nearest
541 unsent block was found this time.
543 This is because not necessarily any of the blocks found this
544 time are actually sent.
546 s32 new_nearest_unsent_d = -1;
548 s16 d_max = g_settings->getS16("max_block_send_distance");
549 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
551 // Don't loop very much at a time
552 s16 max_d_increment_at_time = 2;
553 if(d_max > d_start + max_d_increment_at_time)
554 d_max = d_start + max_d_increment_at_time;
555 /*if(d_max_gen > d_start+2)
556 d_max_gen = d_start+2;*/
558 //infostream<<"Starting from "<<d_start<<std::endl;
560 s32 nearest_emerged_d = -1;
561 s32 nearest_emergefull_d = -1;
562 s32 nearest_sent_d = -1;
563 bool queue_is_full = false;
566 for(d = d_start; d <= d_max; d++)
568 /*errorstream<<"checking d="<<d<<" for "
569 <<server->getPlayerName(peer_id)<<std::endl;*/
570 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
573 If m_nearest_unsent_d was changed by the EmergeThread
574 (it can change it to 0 through SetBlockNotSent),
576 Else update m_nearest_unsent_d
578 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
580 d = m_nearest_unsent_d;
581 last_nearest_unsent_d = m_nearest_unsent_d;
585 Get the border/face dot coordinates of a "d-radiused"
588 core::list<v3s16> list;
589 getFacePositions(list, d);
591 core::list<v3s16>::Iterator li;
592 for(li=list.begin(); li!=list.end(); li++)
594 v3s16 p = *li + center;
598 - Don't allow too many simultaneous transfers
599 - EXCEPT when the blocks are very close
601 Also, don't send blocks that are already flying.
604 // Start with the usual maximum
605 u16 max_simul_dynamic = max_simul_sends_usually;
607 // If block is very close, allow full maximum
608 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
609 max_simul_dynamic = max_simul_sends_setting;
611 // Don't select too many blocks for sending
612 if(num_blocks_selected >= max_simul_dynamic)
614 queue_is_full = true;
615 goto queue_full_break;
618 // Don't send blocks that are currently being transferred
619 if(m_blocks_sending.find(p) != NULL)
625 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
626 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
627 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
628 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
629 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
630 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
633 // If this is true, inexistent block will be made from scratch
634 bool generate = d <= d_max_gen;
637 /*// Limit the generating area vertically to 2/3
638 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
641 // Limit the send area vertically to 1/2
642 if(abs(p.Y - center.Y) > d_max / 2)
648 If block is far away, don't generate it unless it is
654 // Block center y in nodes
655 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
656 // Don't generate if it's very high or very low
657 if(y < -64 || y > 64)
661 v2s16 p2d_nodes_center(
665 // Get ground height in nodes
666 s16 gh = server->m_env->getServerMap().findGroundLevel(
669 // If differs a lot, don't generate
670 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
672 // Actually, don't even send it
678 //infostream<<"d="<<d<<std::endl;
681 Don't generate or send if not in sight
682 FIXME This only works if the client uses a small enough
683 FOV setting. The default of 72 degrees is fine.
686 float camera_fov = (72.0*M_PI/180) * 4./3.;
687 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
693 Don't send already sent blocks
696 if(m_blocks_sent.find(p) != NULL)
703 Check if map has this block
705 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
707 bool surely_not_found_on_disk = false;
708 bool block_is_invalid = false;
711 // Reset usage timer, this block will be of use in the future.
712 block->resetUsageTimer();
714 // Block is dummy if data doesn't exist.
715 // It means it has been not found from disk and not generated
718 surely_not_found_on_disk = true;
721 // Block is valid if lighting is up-to-date and data exists
722 if(block->isValid() == false)
724 block_is_invalid = true;
727 /*if(block->isFullyGenerated() == false)
729 block_is_invalid = true;
734 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
735 v2s16 chunkpos = map->sector_to_chunk(p2d);
736 if(map->chunkNonVolatile(chunkpos) == false)
737 block_is_invalid = true;
739 if(block->isGenerated() == false)
740 block_is_invalid = true;
743 If block is not close, don't send it unless it is near
746 Block is near ground level if night-time mesh
747 differs from day-time mesh.
751 if(block->getDayNightDiff() == false)
758 If block has been marked to not exist on disk (dummy)
759 and generating new ones is not wanted, skip block.
761 if(generate == false && surely_not_found_on_disk == true)
768 Add inexistent block to emerge queue.
770 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
772 //TODO: Get value from somewhere
773 // Allow only one block in emerge queue
774 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
775 // Allow two blocks in queue per client
776 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
778 // Make it more responsive when needing to generate stuff
779 if(surely_not_found_on_disk)
781 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
783 //infostream<<"Adding block to emerge queue"<<std::endl;
785 // Add it to the emerge queue and trigger the thread
788 if(generate == false)
789 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
791 server->m_emerge_queue.addBlock(peer_id, p, flags);
792 server->m_emergethread.trigger();
794 if(nearest_emerged_d == -1)
795 nearest_emerged_d = d;
797 if(nearest_emergefull_d == -1)
798 nearest_emergefull_d = d;
799 goto queue_full_break;
806 if(nearest_sent_d == -1)
810 Add block to send queue
813 /*errorstream<<"sending from d="<<d<<" to "
814 <<server->getPlayerName(peer_id)<<std::endl;*/
816 PrioritySortedBlockTransfer q((float)d, p, peer_id);
820 num_blocks_selected += 1;
825 //infostream<<"Stopped at "<<d<<std::endl;
827 // If nothing was found for sending and nothing was queued for
828 // emerging, continue next time browsing from here
829 if(nearest_emerged_d != -1){
830 new_nearest_unsent_d = nearest_emerged_d;
831 } else if(nearest_emergefull_d != -1){
832 new_nearest_unsent_d = nearest_emergefull_d;
834 if(d > g_settings->getS16("max_block_send_distance")){
835 new_nearest_unsent_d = 0;
836 m_nothing_to_send_pause_timer = 2.0;
837 /*infostream<<"GetNextBlocks(): d wrapped around for "
838 <<server->getPlayerName(peer_id)
839 <<"; setting to 0 and pausing"<<std::endl;*/
841 if(nearest_sent_d != -1)
842 new_nearest_unsent_d = nearest_sent_d;
844 new_nearest_unsent_d = d;
848 if(new_nearest_unsent_d != -1)
849 m_nearest_unsent_d = new_nearest_unsent_d;
851 /*timer_result = timer.stop(true);
852 if(timer_result != 0)
853 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
856 void RemoteClient::GotBlock(v3s16 p)
858 if(m_blocks_sending.find(p) != NULL)
859 m_blocks_sending.remove(p);
862 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
863 " m_blocks_sending"<<std::endl;*/
864 m_excess_gotblocks++;
866 m_blocks_sent.insert(p, true);
869 void RemoteClient::SentBlock(v3s16 p)
871 if(m_blocks_sending.find(p) == NULL)
872 m_blocks_sending.insert(p, 0.0);
874 infostream<<"RemoteClient::SentBlock(): Sent block"
875 " already in m_blocks_sending"<<std::endl;
878 void RemoteClient::SetBlockNotSent(v3s16 p)
880 m_nearest_unsent_d = 0;
882 if(m_blocks_sending.find(p) != NULL)
883 m_blocks_sending.remove(p);
884 if(m_blocks_sent.find(p) != NULL)
885 m_blocks_sent.remove(p);
888 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
890 m_nearest_unsent_d = 0;
892 for(core::map<v3s16, MapBlock*>::Iterator
893 i = blocks.getIterator();
894 i.atEnd()==false; i++)
896 v3s16 p = i.getNode()->getKey();
898 if(m_blocks_sending.find(p) != NULL)
899 m_blocks_sending.remove(p);
900 if(m_blocks_sent.find(p) != NULL)
901 m_blocks_sent.remove(p);
909 PlayerInfo::PlayerInfo()
915 void PlayerInfo::PrintLine(std::ostream *s)
918 (*s)<<"\""<<name<<"\" ("
919 <<(position.X/10)<<","<<(position.Y/10)
920 <<","<<(position.Z/10)<<") ";
922 (*s)<<" avg_rtt="<<avg_rtt;
931 const std::string &path_world,
932 const std::string &path_config,
933 const SubgameSpec &gamespec,
934 bool simple_singleplayer_mode
936 m_path_world(path_world),
937 m_path_config(path_config),
938 m_gamespec(gamespec),
939 m_simple_singleplayer_mode(simple_singleplayer_mode),
940 m_async_fatal_error(""),
942 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
943 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
945 m_rollback_sink_enabled(true),
946 m_enable_rollback_recording(false),
950 m_itemdef(createItemDefManager()),
951 m_nodedef(createNodeDefManager()),
952 m_craftdef(createCraftDefManager()),
953 m_event(new EventManager()),
955 m_emergethread(this),
956 m_time_of_day_send_timer(0),
958 m_shutdown_requested(false),
959 m_ignore_map_edit_events(false),
960 m_ignore_map_edit_events_peer_id(0)
962 m_liquid_transform_timer = 0.0;
963 m_print_info_timer = 0.0;
964 m_objectdata_timer = 0.0;
965 m_emergethread_trigger_timer = 0.0;
966 m_savemap_timer = 0.0;
970 m_step_dtime_mutex.Init();
974 throw ServerError("Supplied empty world path");
976 if(!gamespec.isValid())
977 throw ServerError("Supplied invalid gamespec");
979 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
980 if(m_simple_singleplayer_mode)
981 infostream<<" in simple singleplayer mode"<<std::endl;
983 infostream<<std::endl;
984 infostream<<"- world: "<<m_path_world<<std::endl;
985 infostream<<"- config: "<<m_path_config<<std::endl;
986 infostream<<"- game: "<<m_gamespec.path<<std::endl;
988 // Create biome definition manager
989 m_biomedef = new BiomeDefManager(this);
991 // Create rollback manager
992 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
993 m_rollback = createRollbackManager(rollback_path, this);
995 // Create world if it doesn't exist
996 if(!initializeWorld(m_path_world, m_gamespec.id))
997 throw ServerError("Failed to initialize world");
999 ModConfiguration modconf(m_path_world);
1000 m_mods = modconf.getMods();
1001 // complain about mods with unsatisfied dependencies
1002 if(!modconf.isConsistent())
1004 errorstream << "The following mods have unsatisfied dependencies: ";
1005 std::list<ModSpec> modlist = modconf.getUnsatisfiedMods();
1006 for(std::list<ModSpec>::iterator it = modlist.begin();
1007 it != modlist.end(); ++it)
1009 errorstream << (*it).name << " ";
1011 errorstream << std::endl;
1014 Settings worldmt_settings;
1015 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
1016 worldmt_settings.readConfigFile(worldmt.c_str());
1017 std::vector<std::string> names = worldmt_settings.getNames();
1018 std::set<std::string> exclude_mod_names;
1019 std::set<std::string> load_mod_names;
1020 for(std::vector<std::string>::iterator it = names.begin();
1021 it != names.end(); ++it)
1023 std::string name = *it;
1024 if (name.compare(0,9,"load_mod_")==0)
1026 if(worldmt_settings.getBool(name))
1027 load_mod_names.insert(name.substr(9));
1029 exclude_mod_names.insert(name.substr(9));
1032 // complain about mods declared to be loaded, but not found
1033 for(std::vector<ModSpec>::iterator it = m_mods.begin();
1034 it != m_mods.end(); ++it)
1035 load_mod_names.erase((*it).name);
1036 if(!load_mod_names.empty())
1038 errorstream << "The following mods could not be found: ";
1039 for(std::set<std::string>::iterator it = load_mod_names.begin();
1040 it != load_mod_names.end(); ++it)
1041 errorstream << (*it) << " ";
1042 errorstream << std::endl;
1045 // Path to builtin.lua
1046 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
1049 JMutexAutoLock envlock(m_env_mutex);
1050 JMutexAutoLock conlock(m_con_mutex);
1052 // Initialize scripting
1054 infostream<<"Server: Initializing Lua"<<std::endl;
1055 m_lua = script_init();
1058 scriptapi_export(m_lua, this);
1059 // Load and run builtin.lua
1060 infostream<<"Server: Loading builtin.lua [\""
1061 <<builtinpath<<"\"]"<<std::endl;
1062 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1064 errorstream<<"Server: Failed to load and run "
1065 <<builtinpath<<std::endl;
1066 throw ModError("Failed to load and run "+builtinpath);
1069 infostream<<"Server: Loading mods: ";
1070 for(std::vector<ModSpec>::iterator i = m_mods.begin();
1071 i != m_mods.end(); i++){
1072 const ModSpec &mod = *i;
1073 infostream<<mod.name<<" ";
1075 infostream<<std::endl;
1076 // Load and run "mod" scripts
1077 for(std::vector<ModSpec>::iterator i = m_mods.begin();
1078 i != m_mods.end(); i++){
1079 const ModSpec &mod = *i;
1080 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1081 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1082 <<scriptpath<<"\"]"<<std::endl;
1083 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1085 errorstream<<"Server: Failed to load and run "
1086 <<scriptpath<<std::endl;
1087 throw ModError("Failed to load and run "+scriptpath);
1091 // Read Textures and calculate sha1 sums
1094 // Apply item aliases in the node definition manager
1095 m_nodedef->updateAliases(m_itemdef);
1097 // Add default biomes after nodedef had its aliases added
1098 m_biomedef->addDefaultBiomes();
1100 // Create emerge manager
1101 m_emerge = new EmergeManager(this, m_biomedef);
1103 // Initialize Environment
1104 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
1105 m_env = new ServerEnvironment(servermap, m_lua, this, this);
1107 m_emerge->initMapgens(servermap->getMapgenParams());
1109 // Give environment reference to scripting api
1110 scriptapi_add_environment(m_lua, m_env);
1112 // Register us to receive map edit events
1113 servermap->addEventReceiver(this);
1115 // If file exists, load environment metadata
1116 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1118 infostream<<"Server: Loading environment metadata"<<std::endl;
1119 m_env->loadMeta(m_path_world);
1123 infostream<<"Server: Loading players"<<std::endl;
1124 m_env->deSerializePlayers(m_path_world);
1127 Add some test ActiveBlockModifiers to environment
1129 add_legacy_abms(m_env, m_nodedef);
1134 infostream<<"Server destructing"<<std::endl;
1137 Send shutdown message
1140 JMutexAutoLock conlock(m_con_mutex);
1142 std::wstring line = L"*** Server shutting down";
1145 Send the message to clients
1147 for(core::map<u16, RemoteClient*>::Iterator
1148 i = m_clients.getIterator();
1149 i.atEnd() == false; i++)
1151 // Get client and check that it is valid
1152 RemoteClient *client = i.getNode()->getValue();
1153 assert(client->peer_id == i.getNode()->getKey());
1154 if(client->serialization_version == SER_FMT_VER_INVALID)
1158 SendChatMessage(client->peer_id, line);
1160 catch(con::PeerNotFoundException &e)
1166 JMutexAutoLock envlock(m_env_mutex);
1167 JMutexAutoLock conlock(m_con_mutex);
1170 Execute script shutdown hooks
1172 scriptapi_on_shutdown(m_lua);
1176 JMutexAutoLock envlock(m_env_mutex);
1181 infostream<<"Server: Saving players"<<std::endl;
1182 m_env->serializePlayers(m_path_world);
1185 Save environment metadata
1187 infostream<<"Server: Saving environment metadata"<<std::endl;
1188 m_env->saveMeta(m_path_world);
1200 JMutexAutoLock clientslock(m_con_mutex);
1202 for(core::map<u16, RemoteClient*>::Iterator
1203 i = m_clients.getIterator();
1204 i.atEnd() == false; i++)
1208 delete i.getNode()->getValue();
1212 // Delete things in the reverse order of creation
1221 // Deinitialize scripting
1222 infostream<<"Server: Deinitializing scripting"<<std::endl;
1223 script_deinit(m_lua);
1225 // Delete detached inventories
1227 for(std::map<std::string, Inventory*>::iterator
1228 i = m_detached_inventories.begin();
1229 i != m_detached_inventories.end(); i++){
1235 void Server::start(unsigned short port)
1237 DSTACK(__FUNCTION_NAME);
1238 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1240 // Stop thread if already running
1243 // Initialize connection
1244 m_con.SetTimeoutMs(30);
1248 m_thread.setRun(true);
1251 // ASCII art for the win!
1253 <<" .__ __ __ "<<std::endl
1254 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1255 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1256 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1257 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1258 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1259 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1260 actionstream<<"Server for gameid=\""<<m_gamespec.id
1261 <<"\" listening on port "<<port<<"."<<std::endl;
1266 DSTACK(__FUNCTION_NAME);
1268 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1270 // Stop threads (set run=false first so both start stopping)
1271 m_thread.setRun(false);
1272 m_emergethread.setRun(false);
1274 m_emergethread.stop();
1276 infostream<<"Server: Threads stopped"<<std::endl;
1279 void Server::step(float dtime)
1281 DSTACK(__FUNCTION_NAME);
1286 JMutexAutoLock lock(m_step_dtime_mutex);
1287 m_step_dtime += dtime;
1289 // Throw if fatal error occurred in thread
1290 std::string async_err = m_async_fatal_error.get();
1291 if(async_err != ""){
1292 throw ServerError(async_err);
1296 void Server::AsyncRunStep()
1298 DSTACK(__FUNCTION_NAME);
1300 g_profiler->add("Server::AsyncRunStep (num)", 1);
1304 JMutexAutoLock lock1(m_step_dtime_mutex);
1305 dtime = m_step_dtime;
1309 // Send blocks to clients
1316 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1318 //infostream<<"Server steps "<<dtime<<std::endl;
1319 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1322 JMutexAutoLock lock1(m_step_dtime_mutex);
1323 m_step_dtime -= dtime;
1330 m_uptime.set(m_uptime.get() + dtime);
1334 // Process connection's timeouts
1335 JMutexAutoLock lock2(m_con_mutex);
1336 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1337 m_con.RunTimeouts(dtime);
1341 // This has to be called so that the client list gets synced
1342 // with the peer list of the connection
1343 handlePeerChanges();
1347 Update time of day and overall game time
1350 JMutexAutoLock envlock(m_env_mutex);
1352 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1355 Send to clients at constant intervals
1358 m_time_of_day_send_timer -= dtime;
1359 if(m_time_of_day_send_timer < 0.0)
1361 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1363 //JMutexAutoLock envlock(m_env_mutex);
1364 JMutexAutoLock conlock(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();
1371 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1372 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1374 m_con.Send(client->peer_id, 0, data, true);
1380 JMutexAutoLock lock(m_env_mutex);
1382 ScopeProfiler sp(g_profiler, "SEnv step");
1383 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1387 const float map_timer_and_unload_dtime = 2.92;
1388 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1390 JMutexAutoLock lock(m_env_mutex);
1391 // Run Map's timers and unload unused data
1392 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1393 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1394 g_settings->getFloat("server_unload_unused_data_timeout"));
1405 JMutexAutoLock lock(m_env_mutex);
1406 JMutexAutoLock lock2(m_con_mutex);
1408 ScopeProfiler sp(g_profiler, "Server: handle players");
1410 for(core::map<u16, RemoteClient*>::Iterator
1411 i = m_clients.getIterator();
1412 i.atEnd() == false; i++)
1414 RemoteClient *client = i.getNode()->getValue();
1415 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1416 if(playersao == NULL)
1420 Handle player HPs (die if hp=0)
1422 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1424 if(playersao->getHP() == 0)
1425 DiePlayer(client->peer_id);
1427 SendPlayerHP(client->peer_id);
1431 Send player inventories if necessary
1433 if(playersao->m_moved){
1434 SendMovePlayer(client->peer_id);
1435 playersao->m_moved = false;
1437 if(playersao->m_inventory_not_sent){
1438 UpdateCrafting(client->peer_id);
1439 SendInventory(client->peer_id);
1444 /* Transform liquids */
1445 m_liquid_transform_timer += dtime;
1446 if(m_liquid_transform_timer >= 1.00)
1448 m_liquid_transform_timer -= 1.00;
1450 JMutexAutoLock lock(m_env_mutex);
1452 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1454 core::map<v3s16, MapBlock*> modified_blocks;
1455 m_env->getMap().transformLiquids(modified_blocks);
1460 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1461 ServerMap &map = ((ServerMap&)m_env->getMap());
1462 map.updateLighting(modified_blocks, lighting_modified_blocks);
1464 // Add blocks modified by lighting to modified_blocks
1465 for(core::map<v3s16, MapBlock*>::Iterator
1466 i = lighting_modified_blocks.getIterator();
1467 i.atEnd() == false; i++)
1469 MapBlock *block = i.getNode()->getValue();
1470 modified_blocks.insert(block->getPos(), block);
1474 Set the modified blocks unsent for all the clients
1477 JMutexAutoLock lock2(m_con_mutex);
1479 for(core::map<u16, RemoteClient*>::Iterator
1480 i = m_clients.getIterator();
1481 i.atEnd() == false; i++)
1483 RemoteClient *client = i.getNode()->getValue();
1485 if(modified_blocks.size() > 0)
1487 // Remove block from sent history
1488 client->SetBlocksNotSent(modified_blocks);
1493 // Periodically print some info
1495 float &counter = m_print_info_timer;
1501 JMutexAutoLock lock2(m_con_mutex);
1503 if(m_clients.size() != 0)
1504 infostream<<"Players:"<<std::endl;
1505 for(core::map<u16, RemoteClient*>::Iterator
1506 i = m_clients.getIterator();
1507 i.atEnd() == false; i++)
1509 //u16 peer_id = i.getNode()->getKey();
1510 RemoteClient *client = i.getNode()->getValue();
1511 Player *player = m_env->getPlayer(client->peer_id);
1514 infostream<<"* "<<player->getName()<<"\t";
1515 client->PrintInfo(infostream);
1520 //if(g_settings->getBool("enable_experimental"))
1524 Check added and deleted active objects
1527 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1528 JMutexAutoLock envlock(m_env_mutex);
1529 JMutexAutoLock conlock(m_con_mutex);
1531 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1533 // Radius inside which objects are active
1534 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1535 radius *= MAP_BLOCKSIZE;
1537 for(core::map<u16, RemoteClient*>::Iterator
1538 i = m_clients.getIterator();
1539 i.atEnd() == false; i++)
1541 RemoteClient *client = i.getNode()->getValue();
1543 // If definitions and textures have not been sent, don't
1544 // send objects either
1545 if(!client->definitions_sent)
1548 Player *player = m_env->getPlayer(client->peer_id);
1551 // This can happen if the client timeouts somehow
1552 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1554 <<" has no associated player"<<std::endl;*/
1557 v3s16 pos = floatToInt(player->getPosition(), BS);
1559 core::map<u16, bool> removed_objects;
1560 core::map<u16, bool> added_objects;
1561 m_env->getRemovedActiveObjects(pos, radius,
1562 client->m_known_objects, removed_objects);
1563 m_env->getAddedActiveObjects(pos, radius,
1564 client->m_known_objects, added_objects);
1566 // Ignore if nothing happened
1567 if(removed_objects.size() == 0 && added_objects.size() == 0)
1569 //infostream<<"active objects: none changed"<<std::endl;
1573 std::string data_buffer;
1577 // Handle removed objects
1578 writeU16((u8*)buf, removed_objects.size());
1579 data_buffer.append(buf, 2);
1580 for(core::map<u16, bool>::Iterator
1581 i = removed_objects.getIterator();
1582 i.atEnd()==false; i++)
1585 u16 id = i.getNode()->getKey();
1586 ServerActiveObject* obj = m_env->getActiveObject(id);
1588 // Add to data buffer for sending
1589 writeU16((u8*)buf, i.getNode()->getKey());
1590 data_buffer.append(buf, 2);
1592 // Remove from known objects
1593 client->m_known_objects.remove(i.getNode()->getKey());
1595 if(obj && obj->m_known_by_count > 0)
1596 obj->m_known_by_count--;
1599 // Handle added objects
1600 writeU16((u8*)buf, added_objects.size());
1601 data_buffer.append(buf, 2);
1602 for(core::map<u16, bool>::Iterator
1603 i = added_objects.getIterator();
1604 i.atEnd()==false; i++)
1607 u16 id = i.getNode()->getKey();
1608 ServerActiveObject* obj = m_env->getActiveObject(id);
1611 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1613 infostream<<"WARNING: "<<__FUNCTION_NAME
1614 <<": NULL object"<<std::endl;
1616 type = obj->getSendType();
1618 // Add to data buffer for sending
1619 writeU16((u8*)buf, id);
1620 data_buffer.append(buf, 2);
1621 writeU8((u8*)buf, type);
1622 data_buffer.append(buf, 1);
1625 data_buffer.append(serializeLongString(
1626 obj->getClientInitializationData(client->net_proto_version)));
1628 data_buffer.append(serializeLongString(""));
1630 // Add to known objects
1631 client->m_known_objects.insert(i.getNode()->getKey(), false);
1634 obj->m_known_by_count++;
1638 SharedBuffer<u8> reply(2 + data_buffer.size());
1639 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1640 memcpy((char*)&reply[2], data_buffer.c_str(),
1641 data_buffer.size());
1643 m_con.Send(client->peer_id, 0, reply, true);
1645 verbosestream<<"Server: Sent object remove/add: "
1646 <<removed_objects.size()<<" removed, "
1647 <<added_objects.size()<<" added, "
1648 <<"packet size is "<<reply.getSize()<<std::endl;
1653 Collect a list of all the objects known by the clients
1654 and report it back to the environment.
1657 core::map<u16, bool> all_known_objects;
1659 for(core::map<u16, RemoteClient*>::Iterator
1660 i = m_clients.getIterator();
1661 i.atEnd() == false; i++)
1663 RemoteClient *client = i.getNode()->getValue();
1664 // Go through all known objects of client
1665 for(core::map<u16, bool>::Iterator
1666 i = client->m_known_objects.getIterator();
1667 i.atEnd()==false; i++)
1669 u16 id = i.getNode()->getKey();
1670 all_known_objects[id] = true;
1674 m_env->setKnownActiveObjects(whatever);
1680 Send object messages
1683 JMutexAutoLock envlock(m_env_mutex);
1684 JMutexAutoLock conlock(m_con_mutex);
1686 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1689 // Value = data sent by object
1690 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1692 // Get active object messages from environment
1695 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1699 core::list<ActiveObjectMessage>* message_list = NULL;
1700 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1701 n = buffered_messages.find(aom.id);
1704 message_list = new core::list<ActiveObjectMessage>;
1705 buffered_messages.insert(aom.id, message_list);
1709 message_list = n->getValue();
1711 message_list->push_back(aom);
1714 // Route data to every client
1715 for(core::map<u16, RemoteClient*>::Iterator
1716 i = m_clients.getIterator();
1717 i.atEnd()==false; i++)
1719 RemoteClient *client = i.getNode()->getValue();
1720 std::string reliable_data;
1721 std::string unreliable_data;
1722 // Go through all objects in message buffer
1723 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1724 j = buffered_messages.getIterator();
1725 j.atEnd()==false; j++)
1727 // If object is not known by client, skip it
1728 u16 id = j.getNode()->getKey();
1729 if(client->m_known_objects.find(id) == NULL)
1731 // Get message list of object
1732 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1733 // Go through every message
1734 for(core::list<ActiveObjectMessage>::Iterator
1735 k = list->begin(); k != list->end(); k++)
1737 // Compose the full new data with header
1738 ActiveObjectMessage aom = *k;
1739 std::string new_data;
1742 writeU16((u8*)&buf[0], aom.id);
1743 new_data.append(buf, 2);
1745 new_data += serializeString(aom.datastring);
1746 // Add data to buffer
1748 reliable_data += new_data;
1750 unreliable_data += new_data;
1754 reliable_data and unreliable_data are now ready.
1757 if(reliable_data.size() > 0)
1759 SharedBuffer<u8> reply(2 + reliable_data.size());
1760 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1761 memcpy((char*)&reply[2], reliable_data.c_str(),
1762 reliable_data.size());
1764 m_con.Send(client->peer_id, 0, reply, true);
1766 if(unreliable_data.size() > 0)
1768 SharedBuffer<u8> reply(2 + unreliable_data.size());
1769 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1770 memcpy((char*)&reply[2], unreliable_data.c_str(),
1771 unreliable_data.size());
1772 // Send as unreliable
1773 m_con.Send(client->peer_id, 0, reply, false);
1776 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1778 infostream<<"Server: Size of object message data: "
1779 <<"reliable: "<<reliable_data.size()
1780 <<", unreliable: "<<unreliable_data.size()
1785 // Clear buffered_messages
1786 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1787 i = buffered_messages.getIterator();
1788 i.atEnd()==false; i++)
1790 delete i.getNode()->getValue();
1794 } // enable_experimental
1797 Send queued-for-sending map edit events.
1800 // We will be accessing the environment and the connection
1801 JMutexAutoLock lock(m_env_mutex);
1802 JMutexAutoLock conlock(m_con_mutex);
1804 // Don't send too many at a time
1807 // Single change sending is disabled if queue size is not small
1808 bool disable_single_change_sending = false;
1809 if(m_unsent_map_edit_queue.size() >= 4)
1810 disable_single_change_sending = true;
1812 int event_count = m_unsent_map_edit_queue.size();
1814 // We'll log the amount of each
1817 while(m_unsent_map_edit_queue.size() != 0)
1819 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1821 // Players far away from the change are stored here.
1822 // Instead of sending the changes, MapBlocks are set not sent
1824 core::list<u16> far_players;
1826 if(event->type == MEET_ADDNODE)
1828 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1829 prof.add("MEET_ADDNODE", 1);
1830 if(disable_single_change_sending)
1831 sendAddNode(event->p, event->n, event->already_known_by_peer,
1834 sendAddNode(event->p, event->n, event->already_known_by_peer,
1837 else if(event->type == MEET_REMOVENODE)
1839 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1840 prof.add("MEET_REMOVENODE", 1);
1841 if(disable_single_change_sending)
1842 sendRemoveNode(event->p, event->already_known_by_peer,
1845 sendRemoveNode(event->p, event->already_known_by_peer,
1848 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1850 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1851 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1852 setBlockNotSent(event->p);
1854 else if(event->type == MEET_OTHER)
1856 infostream<<"Server: MEET_OTHER"<<std::endl;
1857 prof.add("MEET_OTHER", 1);
1858 for(core::map<v3s16, bool>::Iterator
1859 i = event->modified_blocks.getIterator();
1860 i.atEnd()==false; i++)
1862 v3s16 p = i.getNode()->getKey();
1868 prof.add("unknown", 1);
1869 infostream<<"WARNING: Server: Unknown MapEditEvent "
1870 <<((u32)event->type)<<std::endl;
1874 Set blocks not sent to far players
1876 if(far_players.size() > 0)
1878 // Convert list format to that wanted by SetBlocksNotSent
1879 core::map<v3s16, MapBlock*> modified_blocks2;
1880 for(core::map<v3s16, bool>::Iterator
1881 i = event->modified_blocks.getIterator();
1882 i.atEnd()==false; i++)
1884 v3s16 p = i.getNode()->getKey();
1885 modified_blocks2.insert(p,
1886 m_env->getMap().getBlockNoCreateNoEx(p));
1888 // Set blocks not sent
1889 for(core::list<u16>::Iterator
1890 i = far_players.begin();
1891 i != far_players.end(); i++)
1894 RemoteClient *client = getClient(peer_id);
1897 client->SetBlocksNotSent(modified_blocks2);
1903 /*// Don't send too many at a time
1905 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1909 if(event_count >= 5){
1910 infostream<<"Server: MapEditEvents:"<<std::endl;
1911 prof.print(infostream);
1912 } else if(event_count != 0){
1913 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1914 prof.print(verbosestream);
1920 Trigger emergethread (it somehow gets to a non-triggered but
1921 bysy state sometimes)
1924 float &counter = m_emergethread_trigger_timer;
1930 m_emergethread.trigger();
1932 // Update m_enable_rollback_recording here too
1933 m_enable_rollback_recording =
1934 g_settings->getBool("enable_rollback_recording");
1938 // Save map, players and auth stuff
1940 float &counter = m_savemap_timer;
1942 if(counter >= g_settings->getFloat("server_map_save_interval"))
1945 JMutexAutoLock lock(m_env_mutex);
1947 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1950 if(m_banmanager.isModified())
1951 m_banmanager.save();
1953 // Save changed parts of map
1954 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1957 m_env->serializePlayers(m_path_world);
1959 // Save environment metadata
1960 m_env->saveMeta(m_path_world);
1965 void Server::Receive()
1967 DSTACK(__FUNCTION_NAME);
1968 SharedBuffer<u8> data;
1973 JMutexAutoLock conlock(m_con_mutex);
1974 datasize = m_con.Receive(peer_id, data);
1977 // This has to be called so that the client list gets synced
1978 // with the peer list of the connection
1979 handlePeerChanges();
1981 ProcessData(*data, datasize, peer_id);
1983 catch(con::InvalidIncomingDataException &e)
1985 infostream<<"Server::Receive(): "
1986 "InvalidIncomingDataException: what()="
1987 <<e.what()<<std::endl;
1989 catch(con::PeerNotFoundException &e)
1991 //NOTE: This is not needed anymore
1993 // The peer has been disconnected.
1994 // Find the associated player and remove it.
1996 /*JMutexAutoLock envlock(m_env_mutex);
1998 infostream<<"ServerThread: peer_id="<<peer_id
1999 <<" has apparently closed connection. "
2000 <<"Removing player."<<std::endl;
2002 m_env->removePlayer(peer_id);*/
2006 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
2008 DSTACK(__FUNCTION_NAME);
2009 // Environment is locked first.
2010 JMutexAutoLock envlock(m_env_mutex);
2011 JMutexAutoLock conlock(m_con_mutex);
2013 ScopeProfiler sp(g_profiler, "Server::ProcessData");
2016 Address address = m_con.GetPeerAddress(peer_id);
2017 std::string addr_s = address.serializeString();
2019 // drop player if is ip is banned
2020 if(m_banmanager.isIpBanned(addr_s)){
2021 infostream<<"Server: A banned client tried to connect from "
2022 <<addr_s<<"; banned name was "
2023 <<m_banmanager.getBanName(addr_s)<<std::endl;
2024 // This actually doesn't seem to transfer to the client
2025 SendAccessDenied(m_con, peer_id,
2026 L"Your ip is banned. Banned name was "
2027 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
2028 m_con.DeletePeer(peer_id);
2032 catch(con::PeerNotFoundException &e)
2034 infostream<<"Server::ProcessData(): Cancelling: peer "
2035 <<peer_id<<" not found"<<std::endl;
2039 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
2041 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
2049 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
2051 if(command == TOSERVER_INIT)
2053 // [0] u16 TOSERVER_INIT
2054 // [2] u8 SER_FMT_VER_HIGHEST
2055 // [3] u8[20] player_name
2056 // [23] u8[28] password <--- can be sent without this, from old versions
2058 if(datasize < 2+1+PLAYERNAME_SIZE)
2061 verbosestream<<"Server: Got TOSERVER_INIT from "
2062 <<peer_id<<std::endl;
2064 // First byte after command is maximum supported
2065 // serialization version
2066 u8 client_max = data[2];
2067 u8 our_max = SER_FMT_VER_HIGHEST;
2068 // Use the highest version supported by both
2069 u8 deployed = core::min_(client_max, our_max);
2070 // If it's lower than the lowest supported, give up.
2071 if(deployed < SER_FMT_VER_LOWEST)
2072 deployed = SER_FMT_VER_INVALID;
2074 //peer->serialization_version = deployed;
2075 getClient(peer_id)->pending_serialization_version = deployed;
2077 if(deployed == SER_FMT_VER_INVALID)
2079 actionstream<<"Server: A mismatched client tried to connect from "
2080 <<addr_s<<std::endl;
2081 infostream<<"Server: Cannot negotiate "
2082 "serialization version with peer "
2083 <<peer_id<<std::endl;
2084 SendAccessDenied(m_con, peer_id, std::wstring(
2085 L"Your client's version is not supported.\n"
2086 L"Server version is ")
2087 + narrow_to_wide(VERSION_STRING) + L"."
2093 Read and check network protocol version
2096 u16 min_net_proto_version = 0;
2097 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2098 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2100 // Use same version as minimum and maximum if maximum version field
2101 // doesn't exist (backwards compatibility)
2102 u16 max_net_proto_version = min_net_proto_version;
2103 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
2104 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
2106 // Start with client's maximum version
2107 u16 net_proto_version = max_net_proto_version;
2109 // Figure out a working version if it is possible at all
2110 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
2111 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
2113 // If maximum is larger than our maximum, go with our maximum
2114 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2115 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
2116 // Else go with client's maximum
2118 net_proto_version = max_net_proto_version;
2121 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
2122 <<min_net_proto_version<<", max: "<<max_net_proto_version
2123 <<", chosen: "<<net_proto_version<<std::endl;
2125 getClient(peer_id)->net_proto_version = net_proto_version;
2127 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
2128 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2130 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
2132 SendAccessDenied(m_con, peer_id, std::wstring(
2133 L"Your client's version is not supported.\n"
2134 L"Server version is ")
2135 + narrow_to_wide(VERSION_STRING) + L",\n"
2136 + L"server's PROTOCOL_VERSION is "
2137 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
2139 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
2140 + L", client's PROTOCOL_VERSION is "
2141 + narrow_to_wide(itos(min_net_proto_version))
2143 + narrow_to_wide(itos(max_net_proto_version))
2148 if(g_settings->getBool("strict_protocol_version_checking"))
2150 if(net_proto_version != LATEST_PROTOCOL_VERSION)
2152 actionstream<<"Server: A mismatched (strict) client tried to "
2153 <<"connect from "<<addr_s<<std::endl;
2154 SendAccessDenied(m_con, peer_id, std::wstring(
2155 L"Your client's version is not supported.\n"
2156 L"Server version is ")
2157 + narrow_to_wide(VERSION_STRING) + L",\n"
2158 + L"server's PROTOCOL_VERSION (strict) is "
2159 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
2160 + L", client's PROTOCOL_VERSION is "
2161 + narrow_to_wide(itos(min_net_proto_version))
2163 + narrow_to_wide(itos(max_net_proto_version))
2174 char playername[PLAYERNAME_SIZE];
2175 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2177 playername[i] = data[3+i];
2179 playername[PLAYERNAME_SIZE-1] = 0;
2181 if(playername[0]=='\0')
2183 actionstream<<"Server: Player with an empty name "
2184 <<"tried to connect from "<<addr_s<<std::endl;
2185 SendAccessDenied(m_con, peer_id,
2190 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2192 actionstream<<"Server: Player with an invalid name "
2193 <<"tried to connect from "<<addr_s<<std::endl;
2194 SendAccessDenied(m_con, peer_id,
2195 L"Name contains unallowed characters");
2199 infostream<<"Server: New connection: \""<<playername<<"\" from "
2200 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2203 char given_password[PASSWORD_SIZE];
2204 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2206 // old version - assume blank password
2207 given_password[0] = 0;
2211 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2213 given_password[i] = data[23+i];
2215 given_password[PASSWORD_SIZE-1] = 0;
2218 if(!base64_is_valid(given_password)){
2219 infostream<<"Server: "<<playername
2220 <<" supplied invalid password hash"<<std::endl;
2221 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2225 std::string checkpwd; // Password hash to check against
2226 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2228 // If no authentication info exists for user, create it
2230 if(!isSingleplayer() &&
2231 g_settings->getBool("disallow_empty_password") &&
2232 std::string(given_password) == ""){
2233 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2234 L"disallowed. Set a password and try again.");
2237 std::wstring raw_default_password =
2238 narrow_to_wide(g_settings->get("default_password"));
2239 std::string initial_password =
2240 translatePassword(playername, raw_default_password);
2242 // If default_password is empty, allow any initial password
2243 if (raw_default_password.length() == 0)
2244 initial_password = given_password;
2246 scriptapi_create_auth(m_lua, playername, initial_password);
2249 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2252 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2256 if(given_password != checkpwd){
2257 infostream<<"Server: peer_id="<<peer_id
2258 <<": supplied invalid password for "
2259 <<playername<<std::endl;
2260 SendAccessDenied(m_con, peer_id, L"Invalid password");
2264 // Do not allow multiple players in simple singleplayer mode.
2265 // This isn't a perfect way to do it, but will suffice for now.
2266 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2267 infostream<<"Server: Not allowing another client to connect in"
2268 <<" simple singleplayer mode"<<std::endl;
2269 SendAccessDenied(m_con, peer_id,
2270 L"Running in simple singleplayer mode.");
2274 // Enforce user limit.
2275 // Don't enforce for users that have some admin right
2276 if(m_clients.size() >= g_settings->getU16("max_users") &&
2277 !checkPriv(playername, "server") &&
2278 !checkPriv(playername, "ban") &&
2279 !checkPriv(playername, "privs") &&
2280 !checkPriv(playername, "password") &&
2281 playername != g_settings->get("name"))
2283 actionstream<<"Server: "<<playername<<" tried to join, but there"
2284 <<" are already max_users="
2285 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2286 SendAccessDenied(m_con, peer_id, L"Too many users.");
2291 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2293 // If failed, cancel
2294 if(playersao == NULL)
2296 errorstream<<"Server: peer_id="<<peer_id
2297 <<": failed to emerge player"<<std::endl;
2302 Answer with a TOCLIENT_INIT
2305 SharedBuffer<u8> reply(2+1+6+8+4);
2306 writeU16(&reply[0], TOCLIENT_INIT);
2307 writeU8(&reply[2], deployed);
2308 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2309 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2310 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2313 m_con.Send(peer_id, 0, reply, true);
2317 Send complete position information
2319 SendMovePlayer(peer_id);
2324 if(command == TOSERVER_INIT2)
2326 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2327 <<peer_id<<std::endl;
2329 Player *player = m_env->getPlayer(peer_id);
2331 verbosestream<<"Server: TOSERVER_INIT2: "
2332 <<"Player not found; ignoring."<<std::endl;
2336 RemoteClient *client = getClient(peer_id);
2337 client->serialization_version =
2338 getClient(peer_id)->pending_serialization_version;
2341 Send some initialization data
2344 infostream<<"Server: Sending content to "
2345 <<getPlayerName(peer_id)<<std::endl;
2347 // Send item definitions
2348 SendItemDef(m_con, peer_id, m_itemdef);
2350 // Send node definitions
2351 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2353 // Send media announcement
2354 sendMediaAnnouncement(peer_id);
2357 SendPlayerPrivileges(peer_id);
2359 // Send inventory formspec
2360 SendPlayerInventoryFormspec(peer_id);
2363 UpdateCrafting(peer_id);
2364 SendInventory(peer_id);
2367 if(g_settings->getBool("enable_damage"))
2368 SendPlayerHP(peer_id);
2370 // Send detached inventories
2371 sendDetachedInventories(peer_id);
2373 // Show death screen if necessary
2375 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2379 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2380 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2381 m_con.Send(peer_id, 0, data, true);
2384 // Note things in chat if not in simple singleplayer mode
2385 if(!m_simple_singleplayer_mode)
2387 // Send information about server to player in chat
2388 SendChatMessage(peer_id, getStatusString());
2390 // Send information about joining in chat
2392 std::wstring name = L"unknown";
2393 Player *player = m_env->getPlayer(peer_id);
2395 name = narrow_to_wide(player->getName());
2397 std::wstring message;
2400 message += L" joined the game.";
2401 BroadcastChatMessage(message);
2405 // Warnings about protocol version can be issued here
2406 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2408 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2409 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2416 std::ostringstream os(std::ios_base::binary);
2417 for(core::map<u16, RemoteClient*>::Iterator
2418 i = m_clients.getIterator();
2419 i.atEnd() == false; i++)
2421 RemoteClient *client = i.getNode()->getValue();
2422 assert(client->peer_id == i.getNode()->getKey());
2423 if(client->serialization_version == SER_FMT_VER_INVALID)
2426 Player *player = m_env->getPlayer(client->peer_id);
2429 // Get name of player
2430 os<<player->getName()<<" ";
2433 actionstream<<player->getName()<<" joins game. List of players: "
2434 <<os.str()<<std::endl;
2440 if(peer_ser_ver == SER_FMT_VER_INVALID)
2442 infostream<<"Server::ProcessData(): Cancelling: Peer"
2443 " serialization format invalid or not initialized."
2444 " Skipping incoming command="<<command<<std::endl;
2448 Player *player = m_env->getPlayer(peer_id);
2450 infostream<<"Server::ProcessData(): Cancelling: "
2451 "No player for peer_id="<<peer_id
2456 PlayerSAO *playersao = player->getPlayerSAO();
2457 if(playersao == NULL){
2458 infostream<<"Server::ProcessData(): Cancelling: "
2459 "No player object for peer_id="<<peer_id
2464 if(command == TOSERVER_PLAYERPOS)
2466 if(datasize < 2+12+12+4+4)
2470 v3s32 ps = readV3S32(&data[start+2]);
2471 v3s32 ss = readV3S32(&data[start+2+12]);
2472 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2473 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2475 if(datasize >= 2+12+12+4+4+4)
2476 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2477 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2478 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2479 pitch = wrapDegrees(pitch);
2480 yaw = wrapDegrees(yaw);
2482 player->setPosition(position);
2483 player->setSpeed(speed);
2484 player->setPitch(pitch);
2485 player->setYaw(yaw);
2486 player->keyPressed=keyPressed;
2487 player->control.up = (bool)(keyPressed&1);
2488 player->control.down = (bool)(keyPressed&2);
2489 player->control.left = (bool)(keyPressed&4);
2490 player->control.right = (bool)(keyPressed&8);
2491 player->control.jump = (bool)(keyPressed&16);
2492 player->control.aux1 = (bool)(keyPressed&32);
2493 player->control.sneak = (bool)(keyPressed&64);
2494 player->control.LMB = (bool)(keyPressed&128);
2495 player->control.RMB = (bool)(keyPressed&256);
2497 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2498 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2499 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2501 else if(command == TOSERVER_GOTBLOCKS)
2514 u16 count = data[2];
2515 for(u16 i=0; i<count; i++)
2517 if((s16)datasize < 2+1+(i+1)*6)
2518 throw con::InvalidIncomingDataException
2519 ("GOTBLOCKS length is too short");
2520 v3s16 p = readV3S16(&data[2+1+i*6]);
2521 /*infostream<<"Server: GOTBLOCKS ("
2522 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2523 RemoteClient *client = getClient(peer_id);
2524 client->GotBlock(p);
2527 else if(command == TOSERVER_DELETEDBLOCKS)
2540 u16 count = data[2];
2541 for(u16 i=0; i<count; i++)
2543 if((s16)datasize < 2+1+(i+1)*6)
2544 throw con::InvalidIncomingDataException
2545 ("DELETEDBLOCKS length is too short");
2546 v3s16 p = readV3S16(&data[2+1+i*6]);
2547 /*infostream<<"Server: DELETEDBLOCKS ("
2548 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2549 RemoteClient *client = getClient(peer_id);
2550 client->SetBlockNotSent(p);
2553 else if(command == TOSERVER_CLICK_OBJECT)
2555 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2558 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2560 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2563 else if(command == TOSERVER_GROUND_ACTION)
2565 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2569 else if(command == TOSERVER_RELEASE)
2571 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2574 else if(command == TOSERVER_SIGNTEXT)
2576 infostream<<"Server: SIGNTEXT not supported anymore"
2580 else if(command == TOSERVER_SIGNNODETEXT)
2582 infostream<<"Server: SIGNNODETEXT not supported anymore"
2586 else if(command == TOSERVER_INVENTORY_ACTION)
2588 // Strip command and create a stream
2589 std::string datastring((char*)&data[2], datasize-2);
2590 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2591 std::istringstream is(datastring, std::ios_base::binary);
2593 InventoryAction *a = InventoryAction::deSerialize(is);
2596 infostream<<"TOSERVER_INVENTORY_ACTION: "
2597 <<"InventoryAction::deSerialize() returned NULL"
2602 // If something goes wrong, this player is to blame
2603 RollbackScopeActor rollback_scope(m_rollback,
2604 std::string("player:")+player->getName());
2607 Note: Always set inventory not sent, to repair cases
2608 where the client made a bad prediction.
2612 Handle restrictions and special cases of the move action
2614 if(a->getType() == IACTION_MOVE)
2616 IMoveAction *ma = (IMoveAction*)a;
2618 ma->from_inv.applyCurrentPlayer(player->getName());
2619 ma->to_inv.applyCurrentPlayer(player->getName());
2621 setInventoryModified(ma->from_inv);
2622 setInventoryModified(ma->to_inv);
2624 bool from_inv_is_current_player =
2625 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2626 (ma->from_inv.name == player->getName());
2628 bool to_inv_is_current_player =
2629 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2630 (ma->to_inv.name == player->getName());
2633 Disable moving items out of craftpreview
2635 if(ma->from_list == "craftpreview")
2637 infostream<<"Ignoring IMoveAction from "
2638 <<(ma->from_inv.dump())<<":"<<ma->from_list
2639 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2640 <<" because src is "<<ma->from_list<<std::endl;
2646 Disable moving items into craftresult and craftpreview
2648 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2650 infostream<<"Ignoring IMoveAction from "
2651 <<(ma->from_inv.dump())<<":"<<ma->from_list
2652 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2653 <<" because dst is "<<ma->to_list<<std::endl;
2658 // Disallow moving items in elsewhere than player's inventory
2659 // if not allowed to interact
2660 if(!checkPriv(player->getName(), "interact") &&
2661 (!from_inv_is_current_player ||
2662 !to_inv_is_current_player))
2664 infostream<<"Cannot move outside of player's inventory: "
2665 <<"No interact privilege"<<std::endl;
2671 Handle restrictions and special cases of the drop action
2673 else if(a->getType() == IACTION_DROP)
2675 IDropAction *da = (IDropAction*)a;
2677 da->from_inv.applyCurrentPlayer(player->getName());
2679 setInventoryModified(da->from_inv);
2681 // Disallow dropping items if not allowed to interact
2682 if(!checkPriv(player->getName(), "interact"))
2689 Handle restrictions and special cases of the craft action
2691 else if(a->getType() == IACTION_CRAFT)
2693 ICraftAction *ca = (ICraftAction*)a;
2695 ca->craft_inv.applyCurrentPlayer(player->getName());
2697 setInventoryModified(ca->craft_inv);
2699 //bool craft_inv_is_current_player =
2700 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2701 // (ca->craft_inv.name == player->getName());
2703 // Disallow crafting if not allowed to interact
2704 if(!checkPriv(player->getName(), "interact"))
2706 infostream<<"Cannot craft: "
2707 <<"No interact privilege"<<std::endl;
2714 a->apply(this, playersao, this);
2718 else if(command == TOSERVER_CHAT_MESSAGE)
2726 std::string datastring((char*)&data[2], datasize-2);
2727 std::istringstream is(datastring, std::ios_base::binary);
2730 is.read((char*)buf, 2);
2731 u16 len = readU16(buf);
2733 std::wstring message;
2734 for(u16 i=0; i<len; i++)
2736 is.read((char*)buf, 2);
2737 message += (wchar_t)readU16(buf);
2740 // If something goes wrong, this player is to blame
2741 RollbackScopeActor rollback_scope(m_rollback,
2742 std::string("player:")+player->getName());
2744 // Get player name of this client
2745 std::wstring name = narrow_to_wide(player->getName());
2748 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2749 wide_to_narrow(message));
2750 // If script ate the message, don't proceed
2754 // Line to send to players
2756 // Whether to send to the player that sent the line
2757 bool send_to_sender = false;
2758 // Whether to send to other players
2759 bool send_to_others = false;
2761 // Commands are implemented in Lua, so only catch invalid
2762 // commands that were not "eaten" and send an error back
2763 if(message[0] == L'/')
2765 message = message.substr(1);
2766 send_to_sender = true;
2767 if(message.length() == 0)
2768 line += L"-!- Empty command";
2770 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2774 if(checkPriv(player->getName(), "shout")){
2779 send_to_others = true;
2781 line += L"-!- You don't have permission to shout.";
2782 send_to_sender = true;
2789 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2792 Send the message to clients
2794 for(core::map<u16, RemoteClient*>::Iterator
2795 i = m_clients.getIterator();
2796 i.atEnd() == false; i++)
2798 // Get client and check that it is valid
2799 RemoteClient *client = i.getNode()->getValue();
2800 assert(client->peer_id == i.getNode()->getKey());
2801 if(client->serialization_version == SER_FMT_VER_INVALID)
2805 bool sender_selected = (peer_id == client->peer_id);
2806 if(sender_selected == true && send_to_sender == false)
2808 if(sender_selected == false && send_to_others == false)
2811 SendChatMessage(client->peer_id, line);
2815 else if(command == TOSERVER_DAMAGE)
2817 std::string datastring((char*)&data[2], datasize-2);
2818 std::istringstream is(datastring, std::ios_base::binary);
2819 u8 damage = readU8(is);
2821 if(g_settings->getBool("enable_damage"))
2823 actionstream<<player->getName()<<" damaged by "
2824 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2827 playersao->setHP(playersao->getHP() - damage);
2829 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2832 if(playersao->m_hp_not_sent)
2833 SendPlayerHP(peer_id);
2836 else if(command == TOSERVER_PASSWORD)
2839 [0] u16 TOSERVER_PASSWORD
2840 [2] u8[28] old password
2841 [30] u8[28] new password
2844 if(datasize != 2+PASSWORD_SIZE*2)
2846 /*char password[PASSWORD_SIZE];
2847 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2848 password[i] = data[2+i];
2849 password[PASSWORD_SIZE-1] = 0;*/
2851 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2859 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2861 char c = data[2+PASSWORD_SIZE+i];
2867 if(!base64_is_valid(newpwd)){
2868 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2869 // Wrong old password supplied!!
2870 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2874 infostream<<"Server: Client requests a password change from "
2875 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2877 std::string playername = player->getName();
2879 std::string checkpwd;
2880 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2882 if(oldpwd != checkpwd)
2884 infostream<<"Server: invalid old password"<<std::endl;
2885 // Wrong old password supplied!!
2886 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2890 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2892 actionstream<<player->getName()<<" changes password"<<std::endl;
2893 SendChatMessage(peer_id, L"Password change successful.");
2895 actionstream<<player->getName()<<" tries to change password but "
2896 <<"it fails"<<std::endl;
2897 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2900 else if(command == TOSERVER_PLAYERITEM)
2905 u16 item = readU16(&data[2]);
2906 playersao->setWieldIndex(item);
2908 else if(command == TOSERVER_RESPAWN)
2910 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2913 RespawnPlayer(peer_id);
2915 actionstream<<player->getName()<<" respawns at "
2916 <<PP(player->getPosition()/BS)<<std::endl;
2918 // ActiveObject is added to environment in AsyncRunStep after
2919 // the previous addition has been succesfully removed
2921 else if(command == TOSERVER_REQUEST_MEDIA) {
2922 std::string datastring((char*)&data[2], datasize-2);
2923 std::istringstream is(datastring, std::ios_base::binary);
2925 core::list<MediaRequest> tosend;
2926 u16 numfiles = readU16(is);
2928 infostream<<"Sending "<<numfiles<<" files to "
2929 <<getPlayerName(peer_id)<<std::endl;
2930 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2932 for(int i = 0; i < numfiles; i++) {
2933 std::string name = deSerializeString(is);
2934 tosend.push_back(MediaRequest(name));
2935 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2939 sendRequestedMedia(peer_id, tosend);
2941 // Now the client should know about everything
2942 // (definitions and files)
2943 getClient(peer_id)->definitions_sent = true;
2945 else if(command == TOSERVER_RECEIVED_MEDIA) {
2946 getClient(peer_id)->definitions_sent = true;
2948 else if(command == TOSERVER_INTERACT)
2950 std::string datastring((char*)&data[2], datasize-2);
2951 std::istringstream is(datastring, std::ios_base::binary);
2957 [5] u32 length of the next item
2958 [9] serialized PointedThing
2960 0: start digging (from undersurface) or use
2961 1: stop digging (all parameters ignored)
2962 2: digging completed
2963 3: place block or item (to abovesurface)
2966 u8 action = readU8(is);
2967 u16 item_i = readU16(is);
2968 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2969 PointedThing pointed;
2970 pointed.deSerialize(tmp_is);
2972 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2973 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2977 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2978 <<" tried to interact, but is dead!"<<std::endl;
2982 v3f player_pos = playersao->getLastGoodPosition();
2984 // Update wielded item
2985 playersao->setWieldIndex(item_i);
2987 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2988 v3s16 p_under = pointed.node_undersurface;
2989 v3s16 p_above = pointed.node_abovesurface;
2991 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2992 ServerActiveObject *pointed_object = NULL;
2993 if(pointed.type == POINTEDTHING_OBJECT)
2995 pointed_object = m_env->getActiveObject(pointed.object_id);
2996 if(pointed_object == NULL)
2998 verbosestream<<"TOSERVER_INTERACT: "
2999 "pointed object is NULL"<<std::endl;
3005 v3f pointed_pos_under = player_pos;
3006 v3f pointed_pos_above = player_pos;
3007 if(pointed.type == POINTEDTHING_NODE)
3009 pointed_pos_under = intToFloat(p_under, BS);
3010 pointed_pos_above = intToFloat(p_above, BS);
3012 else if(pointed.type == POINTEDTHING_OBJECT)
3014 pointed_pos_under = pointed_object->getBasePosition();
3015 pointed_pos_above = pointed_pos_under;
3019 Check that target is reasonably close
3020 (only when digging or placing things)
3022 if(action == 0 || action == 2 || action == 3)
3024 float d = player_pos.getDistanceFrom(pointed_pos_under);
3025 float max_d = BS * 14; // Just some large enough value
3027 actionstream<<"Player "<<player->getName()
3028 <<" tried to access "<<pointed.dump()
3030 <<"d="<<d<<", max_d="<<max_d
3031 <<". ignoring."<<std::endl;
3032 // Re-send block to revert change on client-side
3033 RemoteClient *client = getClient(peer_id);
3034 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3035 client->SetBlockNotSent(blockpos);
3042 Make sure the player is allowed to do it
3044 if(!checkPriv(player->getName(), "interact"))
3046 actionstream<<player->getName()<<" attempted to interact with "
3047 <<pointed.dump()<<" without 'interact' privilege"
3049 // Re-send block to revert change on client-side
3050 RemoteClient *client = getClient(peer_id);
3051 // Digging completed -> under
3053 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3054 client->SetBlockNotSent(blockpos);
3056 // Placement -> above
3058 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3059 client->SetBlockNotSent(blockpos);
3065 If something goes wrong, this player is to blame
3067 RollbackScopeActor rollback_scope(m_rollback,
3068 std::string("player:")+player->getName());
3071 0: start digging or punch object
3075 if(pointed.type == POINTEDTHING_NODE)
3078 NOTE: This can be used in the future to check if
3079 somebody is cheating, by checking the timing.
3081 MapNode n(CONTENT_IGNORE);
3084 n = m_env->getMap().getNode(p_under);
3086 catch(InvalidPositionException &e)
3088 infostream<<"Server: Not punching: Node not found."
3089 <<" Adding block to emerge queue."
3091 m_emerge_queue.addBlock(peer_id,
3092 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3094 if(n.getContent() != CONTENT_IGNORE)
3095 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3097 playersao->noCheatDigStart(p_under);
3099 else if(pointed.type == POINTEDTHING_OBJECT)
3101 // Skip if object has been removed
3102 if(pointed_object->m_removed)
3105 actionstream<<player->getName()<<" punches object "
3106 <<pointed.object_id<<": "
3107 <<pointed_object->getDescription()<<std::endl;
3109 ItemStack punchitem = playersao->getWieldedItem();
3110 ToolCapabilities toolcap =
3111 punchitem.getToolCapabilities(m_itemdef);
3112 v3f dir = (pointed_object->getBasePosition() -
3113 (player->getPosition() + player->getEyeOffset())
3115 float time_from_last_punch =
3116 playersao->resetTimeFromLastPunch();
3117 pointed_object->punch(dir, &toolcap, playersao,
3118 time_from_last_punch);
3126 else if(action == 1)
3131 2: Digging completed
3133 else if(action == 2)
3135 // Only digging of nodes
3136 if(pointed.type == POINTEDTHING_NODE)
3138 MapNode n(CONTENT_IGNORE);
3141 n = m_env->getMap().getNode(p_under);
3143 catch(InvalidPositionException &e)
3145 infostream<<"Server: Not finishing digging: Node not found."
3146 <<" Adding block to emerge queue."
3148 m_emerge_queue.addBlock(peer_id,
3149 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3152 /* Cheat prevention */
3153 bool is_valid_dig = true;
3154 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3156 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3157 float nocheat_t = playersao->getNoCheatDigTime();
3158 playersao->noCheatDigEnd();
3159 // If player didn't start digging this, ignore dig
3160 if(nocheat_p != p_under){
3161 infostream<<"Server: NoCheat: "<<player->getName()
3162 <<" started digging "
3163 <<PP(nocheat_p)<<" and completed digging "
3164 <<PP(p_under)<<"; not digging."<<std::endl;
3165 is_valid_dig = false;
3167 // Get player's wielded item
3168 ItemStack playeritem;
3169 InventoryList *mlist = playersao->getInventory()->getList("main");
3171 playeritem = mlist->getItem(playersao->getWieldIndex());
3172 ToolCapabilities playeritem_toolcap =
3173 playeritem.getToolCapabilities(m_itemdef);
3174 // Get diggability and expected digging time
3175 DigParams params = getDigParams(m_nodedef->get(n).groups,
3176 &playeritem_toolcap);
3177 // If can't dig, try hand
3178 if(!params.diggable){
3179 const ItemDefinition &hand = m_itemdef->get("");
3180 const ToolCapabilities *tp = hand.tool_capabilities;
3182 params = getDigParams(m_nodedef->get(n).groups, tp);
3184 // If can't dig, ignore dig
3185 if(!params.diggable){
3186 infostream<<"Server: NoCheat: "<<player->getName()
3187 <<" completed digging "<<PP(p_under)
3188 <<", which is not diggable with tool. not digging."
3190 is_valid_dig = false;
3192 // If time is considerably too short, ignore dig
3193 // Check time only for medium and slow timed digs
3194 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3195 infostream<<"Server: NoCheat: "<<player->getName()
3196 <<" completed digging "
3197 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3198 <<params.time<<"s; not digging."<<std::endl;
3199 is_valid_dig = false;
3203 /* Actually dig node */
3205 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3206 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3208 // Send unusual result (that is, node not being removed)
3209 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3211 // Re-send block to revert change on client-side
3212 RemoteClient *client = getClient(peer_id);
3213 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3214 client->SetBlockNotSent(blockpos);
3220 3: place block or right-click object
3222 else if(action == 3)
3224 ItemStack item = playersao->getWieldedItem();
3226 // Reset build time counter
3227 if(pointed.type == POINTEDTHING_NODE &&
3228 item.getDefinition(m_itemdef).type == ITEM_NODE)
3229 getClient(peer_id)->m_time_from_building = 0.0;
3231 if(pointed.type == POINTEDTHING_OBJECT)
3233 // Right click object
3235 // Skip if object has been removed
3236 if(pointed_object->m_removed)
3239 actionstream<<player->getName()<<" right-clicks object "
3240 <<pointed.object_id<<": "
3241 <<pointed_object->getDescription()<<std::endl;
3244 pointed_object->rightClick(playersao);
3246 else if(scriptapi_item_on_place(m_lua,
3247 item, playersao, pointed))
3249 // Placement was handled in lua
3251 // Apply returned ItemStack
3252 playersao->setWieldedItem(item);
3255 // If item has node placement prediction, always send the above
3256 // node to make sure the client knows what exactly happened
3257 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3258 RemoteClient *client = getClient(peer_id);
3259 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3260 client->SetBlockNotSent(blockpos);
3267 else if(action == 4)
3269 ItemStack item = playersao->getWieldedItem();
3271 actionstream<<player->getName()<<" uses "<<item.name
3272 <<", pointing at "<<pointed.dump()<<std::endl;
3274 if(scriptapi_item_on_use(m_lua,
3275 item, playersao, pointed))
3277 // Apply returned ItemStack
3278 playersao->setWieldedItem(item);
3285 Catch invalid actions
3289 infostream<<"WARNING: Server: Invalid action "
3290 <<action<<std::endl;
3293 else if(command == TOSERVER_REMOVED_SOUNDS)
3295 std::string datastring((char*)&data[2], datasize-2);
3296 std::istringstream is(datastring, std::ios_base::binary);
3298 int num = readU16(is);
3299 for(int k=0; k<num; k++){
3300 s32 id = readS32(is);
3301 std::map<s32, ServerPlayingSound>::iterator i =
3302 m_playing_sounds.find(id);
3303 if(i == m_playing_sounds.end())
3305 ServerPlayingSound &psound = i->second;
3306 psound.clients.erase(peer_id);
3307 if(psound.clients.size() == 0)
3308 m_playing_sounds.erase(i++);
3311 else if(command == TOSERVER_NODEMETA_FIELDS)
3313 std::string datastring((char*)&data[2], datasize-2);
3314 std::istringstream is(datastring, std::ios_base::binary);
3316 v3s16 p = readV3S16(is);
3317 std::string formname = deSerializeString(is);
3318 int num = readU16(is);
3319 std::map<std::string, std::string> fields;
3320 for(int k=0; k<num; k++){
3321 std::string fieldname = deSerializeString(is);
3322 std::string fieldvalue = deSerializeLongString(is);
3323 fields[fieldname] = fieldvalue;
3326 // If something goes wrong, this player is to blame
3327 RollbackScopeActor rollback_scope(m_rollback,
3328 std::string("player:")+player->getName());
3330 // Check the target node for rollback data; leave others unnoticed
3331 RollbackNode rn_old(&m_env->getMap(), p, this);
3333 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3336 // Report rollback data
3337 RollbackNode rn_new(&m_env->getMap(), p, this);
3338 if(rollback() && rn_new != rn_old){
3339 RollbackAction action;
3340 action.setSetNode(p, rn_old, rn_new);
3341 rollback()->reportAction(action);
3344 else if(command == TOSERVER_INVENTORY_FIELDS)
3346 std::string datastring((char*)&data[2], datasize-2);
3347 std::istringstream is(datastring, std::ios_base::binary);
3349 std::string formname = deSerializeString(is);
3350 int num = readU16(is);
3351 std::map<std::string, std::string> fields;
3352 for(int k=0; k<num; k++){
3353 std::string fieldname = deSerializeString(is);
3354 std::string fieldvalue = deSerializeLongString(is);
3355 fields[fieldname] = fieldvalue;
3358 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3362 infostream<<"Server::ProcessData(): Ignoring "
3363 "unknown command "<<command<<std::endl;
3367 catch(SendFailedException &e)
3369 errorstream<<"Server::ProcessData(): SendFailedException: "
3375 void Server::onMapEditEvent(MapEditEvent *event)
3377 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3378 if(m_ignore_map_edit_events)
3380 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3382 MapEditEvent *e = event->clone();
3383 m_unsent_map_edit_queue.push_back(e);
3386 Inventory* Server::getInventory(const InventoryLocation &loc)
3389 case InventoryLocation::UNDEFINED:
3392 case InventoryLocation::CURRENT_PLAYER:
3395 case InventoryLocation::PLAYER:
3397 Player *player = m_env->getPlayer(loc.name.c_str());
3400 PlayerSAO *playersao = player->getPlayerSAO();
3403 return playersao->getInventory();
3406 case InventoryLocation::NODEMETA:
3408 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3411 return meta->getInventory();
3414 case InventoryLocation::DETACHED:
3416 if(m_detached_inventories.count(loc.name) == 0)
3418 return m_detached_inventories[loc.name];
3426 void Server::setInventoryModified(const InventoryLocation &loc)
3429 case InventoryLocation::UNDEFINED:
3432 case InventoryLocation::PLAYER:
3434 Player *player = m_env->getPlayer(loc.name.c_str());
3437 PlayerSAO *playersao = player->getPlayerSAO();
3440 playersao->m_inventory_not_sent = true;
3441 playersao->m_wielded_item_not_sent = true;
3444 case InventoryLocation::NODEMETA:
3446 v3s16 blockpos = getNodeBlockPos(loc.p);
3448 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3450 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3452 setBlockNotSent(blockpos);
3455 case InventoryLocation::DETACHED:
3457 sendDetachedInventoryToAll(loc.name);
3465 core::list<PlayerInfo> Server::getPlayerInfo()
3467 DSTACK(__FUNCTION_NAME);
3468 JMutexAutoLock envlock(m_env_mutex);
3469 JMutexAutoLock conlock(m_con_mutex);
3471 core::list<PlayerInfo> list;
3473 core::list<Player*> players = m_env->getPlayers();
3475 core::list<Player*>::Iterator i;
3476 for(i = players.begin();
3477 i != players.end(); i++)
3481 Player *player = *i;
3484 // Copy info from connection to info struct
3485 info.id = player->peer_id;
3486 info.address = m_con.GetPeerAddress(player->peer_id);
3487 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3489 catch(con::PeerNotFoundException &e)
3491 // Set dummy peer info
3493 info.address = Address(0,0,0,0,0);
3497 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3498 info.position = player->getPosition();
3500 list.push_back(info);
3507 void Server::peerAdded(con::Peer *peer)
3509 DSTACK(__FUNCTION_NAME);
3510 verbosestream<<"Server::peerAdded(): peer->id="
3511 <<peer->id<<std::endl;
3514 c.type = PEER_ADDED;
3515 c.peer_id = peer->id;
3517 m_peer_change_queue.push_back(c);
3520 void Server::deletingPeer(con::Peer *peer, bool timeout)
3522 DSTACK(__FUNCTION_NAME);
3523 verbosestream<<"Server::deletingPeer(): peer->id="
3524 <<peer->id<<", timeout="<<timeout<<std::endl;
3527 c.type = PEER_REMOVED;
3528 c.peer_id = peer->id;
3529 c.timeout = timeout;
3530 m_peer_change_queue.push_back(c);
3537 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3539 DSTACK(__FUNCTION_NAME);
3540 std::ostringstream os(std::ios_base::binary);
3542 writeU16(os, TOCLIENT_HP);
3546 std::string s = os.str();
3547 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3549 con.Send(peer_id, 0, data, true);
3552 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3553 const std::wstring &reason)
3555 DSTACK(__FUNCTION_NAME);
3556 std::ostringstream os(std::ios_base::binary);
3558 writeU16(os, TOCLIENT_ACCESS_DENIED);
3559 os<<serializeWideString(reason);
3562 std::string s = os.str();
3563 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3565 con.Send(peer_id, 0, data, true);
3568 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3569 bool set_camera_point_target, v3f camera_point_target)
3571 DSTACK(__FUNCTION_NAME);
3572 std::ostringstream os(std::ios_base::binary);
3574 writeU16(os, TOCLIENT_DEATHSCREEN);
3575 writeU8(os, set_camera_point_target);
3576 writeV3F1000(os, camera_point_target);
3579 std::string s = os.str();
3580 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3582 con.Send(peer_id, 0, data, true);
3585 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3586 IItemDefManager *itemdef)
3588 DSTACK(__FUNCTION_NAME);
3589 std::ostringstream os(std::ios_base::binary);
3593 u32 length of the next item
3594 zlib-compressed serialized ItemDefManager
3596 writeU16(os, TOCLIENT_ITEMDEF);
3597 std::ostringstream tmp_os(std::ios::binary);
3598 itemdef->serialize(tmp_os);
3599 std::ostringstream tmp_os2(std::ios::binary);
3600 compressZlib(tmp_os.str(), tmp_os2);
3601 os<<serializeLongString(tmp_os2.str());
3604 std::string s = os.str();
3605 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3606 <<"): size="<<s.size()<<std::endl;
3607 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3609 con.Send(peer_id, 0, data, true);
3612 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3613 INodeDefManager *nodedef, u16 protocol_version)
3615 DSTACK(__FUNCTION_NAME);
3616 std::ostringstream os(std::ios_base::binary);
3620 u32 length of the next item
3621 zlib-compressed serialized NodeDefManager
3623 writeU16(os, TOCLIENT_NODEDEF);
3624 std::ostringstream tmp_os(std::ios::binary);
3625 nodedef->serialize(tmp_os, protocol_version);
3626 std::ostringstream tmp_os2(std::ios::binary);
3627 compressZlib(tmp_os.str(), tmp_os2);
3628 os<<serializeLongString(tmp_os2.str());
3631 std::string s = os.str();
3632 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3633 <<"): size="<<s.size()<<std::endl;
3634 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3636 con.Send(peer_id, 0, data, true);
3640 Non-static send methods
3643 void Server::SendInventory(u16 peer_id)
3645 DSTACK(__FUNCTION_NAME);
3647 PlayerSAO *playersao = getPlayerSAO(peer_id);
3650 playersao->m_inventory_not_sent = false;
3656 std::ostringstream os;
3657 playersao->getInventory()->serialize(os);
3659 std::string s = os.str();
3661 SharedBuffer<u8> data(s.size()+2);
3662 writeU16(&data[0], TOCLIENT_INVENTORY);
3663 memcpy(&data[2], s.c_str(), s.size());
3666 m_con.Send(peer_id, 0, data, true);
3669 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3671 DSTACK(__FUNCTION_NAME);
3673 std::ostringstream os(std::ios_base::binary);
3677 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3678 os.write((char*)buf, 2);
3681 writeU16(buf, message.size());
3682 os.write((char*)buf, 2);
3685 for(u32 i=0; i<message.size(); i++)
3689 os.write((char*)buf, 2);
3693 std::string s = os.str();
3694 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3696 m_con.Send(peer_id, 0, data, true);
3698 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3700 DSTACK(__FUNCTION_NAME);
3702 std::ostringstream os(std::ios_base::binary);
3706 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3707 os.write((char*)buf, 2);
3708 os<<serializeLongString(formspec);
3709 os<<serializeString(formname);
3712 std::string s = os.str();
3713 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3715 m_con.Send(peer_id, 0, data, true);
3718 void Server::BroadcastChatMessage(const std::wstring &message)
3720 for(core::map<u16, RemoteClient*>::Iterator
3721 i = m_clients.getIterator();
3722 i.atEnd() == false; i++)
3724 // Get client and check that it is valid
3725 RemoteClient *client = i.getNode()->getValue();
3726 assert(client->peer_id == i.getNode()->getKey());
3727 if(client->serialization_version == SER_FMT_VER_INVALID)
3730 SendChatMessage(client->peer_id, message);
3734 void Server::SendPlayerHP(u16 peer_id)
3736 DSTACK(__FUNCTION_NAME);
3737 PlayerSAO *playersao = getPlayerSAO(peer_id);
3739 playersao->m_hp_not_sent = false;
3740 SendHP(m_con, peer_id, playersao->getHP());
3743 void Server::SendMovePlayer(u16 peer_id)
3745 DSTACK(__FUNCTION_NAME);
3746 Player *player = m_env->getPlayer(peer_id);
3749 std::ostringstream os(std::ios_base::binary);
3750 writeU16(os, TOCLIENT_MOVE_PLAYER);
3751 writeV3F1000(os, player->getPosition());
3752 writeF1000(os, player->getPitch());
3753 writeF1000(os, player->getYaw());
3756 v3f pos = player->getPosition();
3757 f32 pitch = player->getPitch();
3758 f32 yaw = player->getYaw();
3759 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3760 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3767 std::string s = os.str();
3768 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3770 m_con.Send(peer_id, 0, data, true);
3773 void Server::SendPlayerPrivileges(u16 peer_id)
3775 Player *player = m_env->getPlayer(peer_id);
3777 if(player->peer_id == PEER_ID_INEXISTENT)
3780 std::set<std::string> privs;
3781 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3783 std::ostringstream os(std::ios_base::binary);
3784 writeU16(os, TOCLIENT_PRIVILEGES);
3785 writeU16(os, privs.size());
3786 for(std::set<std::string>::const_iterator i = privs.begin();
3787 i != privs.end(); i++){
3788 os<<serializeString(*i);
3792 std::string s = os.str();
3793 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3795 m_con.Send(peer_id, 0, data, true);
3798 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3800 Player *player = m_env->getPlayer(peer_id);
3802 if(player->peer_id == PEER_ID_INEXISTENT)
3805 std::ostringstream os(std::ios_base::binary);
3806 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3807 os<<serializeLongString(player->inventory_formspec);
3810 std::string s = os.str();
3811 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3813 m_con.Send(peer_id, 0, data, true);
3816 s32 Server::playSound(const SimpleSoundSpec &spec,
3817 const ServerSoundParams ¶ms)
3819 // Find out initial position of sound
3820 bool pos_exists = false;
3821 v3f pos = params.getPos(m_env, &pos_exists);
3822 // If position is not found while it should be, cancel sound
3823 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3825 // Filter destination clients
3826 std::set<RemoteClient*> dst_clients;
3827 if(params.to_player != "")
3829 Player *player = m_env->getPlayer(params.to_player.c_str());
3831 infostream<<"Server::playSound: Player \""<<params.to_player
3832 <<"\" not found"<<std::endl;
3835 if(player->peer_id == PEER_ID_INEXISTENT){
3836 infostream<<"Server::playSound: Player \""<<params.to_player
3837 <<"\" not connected"<<std::endl;
3840 RemoteClient *client = getClient(player->peer_id);
3841 dst_clients.insert(client);
3845 for(core::map<u16, RemoteClient*>::Iterator
3846 i = m_clients.getIterator(); i.atEnd() == false; i++)
3848 RemoteClient *client = i.getNode()->getValue();
3849 Player *player = m_env->getPlayer(client->peer_id);
3853 if(player->getPosition().getDistanceFrom(pos) >
3854 params.max_hear_distance)
3857 dst_clients.insert(client);
3860 if(dst_clients.size() == 0)
3863 s32 id = m_next_sound_id++;
3864 // The sound will exist as a reference in m_playing_sounds
3865 m_playing_sounds[id] = ServerPlayingSound();
3866 ServerPlayingSound &psound = m_playing_sounds[id];
3867 psound.params = params;
3868 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3869 i != dst_clients.end(); i++)
3870 psound.clients.insert((*i)->peer_id);
3872 std::ostringstream os(std::ios_base::binary);
3873 writeU16(os, TOCLIENT_PLAY_SOUND);
3875 os<<serializeString(spec.name);
3876 writeF1000(os, spec.gain * params.gain);
3877 writeU8(os, params.type);
3878 writeV3F1000(os, pos);
3879 writeU16(os, params.object);
3880 writeU8(os, params.loop);
3882 std::string s = os.str();
3883 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3885 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3886 i != dst_clients.end(); i++){
3888 m_con.Send((*i)->peer_id, 0, data, true);
3892 void Server::stopSound(s32 handle)
3894 // Get sound reference
3895 std::map<s32, ServerPlayingSound>::iterator i =
3896 m_playing_sounds.find(handle);
3897 if(i == m_playing_sounds.end())
3899 ServerPlayingSound &psound = i->second;
3901 std::ostringstream os(std::ios_base::binary);
3902 writeU16(os, TOCLIENT_STOP_SOUND);
3903 writeS32(os, handle);
3905 std::string s = os.str();
3906 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3908 for(std::set<u16>::iterator i = psound.clients.begin();
3909 i != psound.clients.end(); i++){
3911 m_con.Send(*i, 0, data, true);
3913 // Remove sound reference
3914 m_playing_sounds.erase(i);
3917 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3918 core::list<u16> *far_players, float far_d_nodes)
3920 float maxd = far_d_nodes*BS;
3921 v3f p_f = intToFloat(p, BS);
3925 SharedBuffer<u8> reply(replysize);
3926 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3927 writeS16(&reply[2], p.X);
3928 writeS16(&reply[4], p.Y);
3929 writeS16(&reply[6], p.Z);
3931 for(core::map<u16, RemoteClient*>::Iterator
3932 i = m_clients.getIterator();
3933 i.atEnd() == false; i++)
3935 // Get client and check that it is valid
3936 RemoteClient *client = i.getNode()->getValue();
3937 assert(client->peer_id == i.getNode()->getKey());
3938 if(client->serialization_version == SER_FMT_VER_INVALID)
3941 // Don't send if it's the same one
3942 if(client->peer_id == ignore_id)
3948 Player *player = m_env->getPlayer(client->peer_id);
3951 // If player is far away, only set modified blocks not sent
3952 v3f player_pos = player->getPosition();
3953 if(player_pos.getDistanceFrom(p_f) > maxd)
3955 far_players->push_back(client->peer_id);
3962 m_con.Send(client->peer_id, 0, reply, true);
3966 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3967 core::list<u16> *far_players, float far_d_nodes)
3969 float maxd = far_d_nodes*BS;
3970 v3f p_f = intToFloat(p, BS);
3972 for(core::map<u16, RemoteClient*>::Iterator
3973 i = m_clients.getIterator();
3974 i.atEnd() == false; i++)
3976 // Get client and check that it is valid
3977 RemoteClient *client = i.getNode()->getValue();
3978 assert(client->peer_id == i.getNode()->getKey());
3979 if(client->serialization_version == SER_FMT_VER_INVALID)
3982 // Don't send if it's the same one
3983 if(client->peer_id == ignore_id)
3989 Player *player = m_env->getPlayer(client->peer_id);
3992 // If player is far away, only set modified blocks not sent
3993 v3f player_pos = player->getPosition();
3994 if(player_pos.getDistanceFrom(p_f) > maxd)
3996 far_players->push_back(client->peer_id);
4003 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4004 SharedBuffer<u8> reply(replysize);
4005 writeU16(&reply[0], TOCLIENT_ADDNODE);
4006 writeS16(&reply[2], p.X);
4007 writeS16(&reply[4], p.Y);
4008 writeS16(&reply[6], p.Z);
4009 n.serialize(&reply[8], client->serialization_version);
4012 m_con.Send(client->peer_id, 0, reply, true);
4016 void Server::setBlockNotSent(v3s16 p)
4018 for(core::map<u16, RemoteClient*>::Iterator
4019 i = m_clients.getIterator();
4020 i.atEnd()==false; i++)
4022 RemoteClient *client = i.getNode()->getValue();
4023 client->SetBlockNotSent(p);
4027 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4029 DSTACK(__FUNCTION_NAME);
4031 v3s16 p = block->getPos();
4035 bool completely_air = true;
4036 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4037 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4038 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4040 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4042 completely_air = false;
4043 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4048 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4050 infostream<<"[completely air] ";
4051 infostream<<std::endl;
4055 Create a packet with the block in the right format
4058 std::ostringstream os(std::ios_base::binary);
4059 block->serialize(os, ver, false);
4060 std::string s = os.str();
4061 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4063 u32 replysize = 8 + blockdata.getSize();
4064 SharedBuffer<u8> reply(replysize);
4065 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4066 writeS16(&reply[2], p.X);
4067 writeS16(&reply[4], p.Y);
4068 writeS16(&reply[6], p.Z);
4069 memcpy(&reply[8], *blockdata, blockdata.getSize());
4071 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4072 <<": \tpacket size: "<<replysize<<std::endl;*/
4077 m_con.Send(peer_id, 1, reply, true);
4080 void Server::SendBlocks(float dtime)
4082 DSTACK(__FUNCTION_NAME);
4084 JMutexAutoLock envlock(m_env_mutex);
4085 JMutexAutoLock conlock(m_con_mutex);
4087 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4089 core::array<PrioritySortedBlockTransfer> queue;
4091 s32 total_sending = 0;
4094 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4096 for(core::map<u16, RemoteClient*>::Iterator
4097 i = m_clients.getIterator();
4098 i.atEnd() == false; i++)
4100 RemoteClient *client = i.getNode()->getValue();
4101 assert(client->peer_id == i.getNode()->getKey());
4103 // If definitions and textures have not been sent, don't
4104 // send MapBlocks either
4105 if(!client->definitions_sent)
4108 total_sending += client->SendingCount();
4110 if(client->serialization_version == SER_FMT_VER_INVALID)
4113 client->GetNextBlocks(this, dtime, queue);
4118 // Lowest priority number comes first.
4119 // Lowest is most important.
4122 for(u32 i=0; i<queue.size(); i++)
4124 //TODO: Calculate limit dynamically
4125 if(total_sending >= g_settings->getS32
4126 ("max_simultaneous_block_sends_server_total"))
4129 PrioritySortedBlockTransfer q = queue[i];
4131 MapBlock *block = NULL;
4134 block = m_env->getMap().getBlockNoCreate(q.pos);
4136 catch(InvalidPositionException &e)
4141 RemoteClient *client = getClient(q.peer_id);
4143 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4145 client->SentBlock(q.pos);
4151 void Server::fillMediaCache()
4153 DSTACK(__FUNCTION_NAME);
4155 infostream<<"Server: Calculating media file checksums"<<std::endl;
4157 // Collect all media file paths
4158 std::list<std::string> paths;
4159 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4160 i != m_mods.end(); i++){
4161 const ModSpec &mod = *i;
4162 paths.push_back(mod.path + DIR_DELIM + "textures");
4163 paths.push_back(mod.path + DIR_DELIM + "sounds");
4164 paths.push_back(mod.path + DIR_DELIM + "media");
4165 paths.push_back(mod.path + DIR_DELIM + "models");
4167 std::string path_all = "textures";
4168 paths.push_back(path_all + DIR_DELIM + "all");
4170 // Collect media file information from paths into cache
4171 for(std::list<std::string>::iterator i = paths.begin();
4172 i != paths.end(); i++)
4174 std::string mediapath = *i;
4175 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4176 for(u32 j=0; j<dirlist.size(); j++){
4177 if(dirlist[j].dir) // Ignode dirs
4179 std::string filename = dirlist[j].name;
4180 // If name contains illegal characters, ignore the file
4181 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4182 infostream<<"Server: ignoring illegal file name: \""
4183 <<filename<<"\""<<std::endl;
4186 // If name is not in a supported format, ignore it
4187 const char *supported_ext[] = {
4188 ".png", ".jpg", ".bmp", ".tga",
4189 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4191 ".x", ".b3d", ".md2", ".obj",
4194 if(removeStringEnd(filename, supported_ext) == ""){
4195 infostream<<"Server: ignoring unsupported file extension: \""
4196 <<filename<<"\""<<std::endl;
4199 // Ok, attempt to load the file and add to cache
4200 std::string filepath = mediapath + DIR_DELIM + filename;
4202 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4203 if(fis.good() == false){
4204 errorstream<<"Server::fillMediaCache(): Could not open \""
4205 <<filename<<"\" for reading"<<std::endl;
4208 std::ostringstream tmp_os(std::ios_base::binary);
4212 fis.read(buf, 1024);
4213 std::streamsize len = fis.gcount();
4214 tmp_os.write(buf, len);
4223 errorstream<<"Server::fillMediaCache(): Failed to read \""
4224 <<filename<<"\""<<std::endl;
4227 if(tmp_os.str().length() == 0){
4228 errorstream<<"Server::fillMediaCache(): Empty file \""
4229 <<filepath<<"\""<<std::endl;
4234 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4236 unsigned char *digest = sha1.getDigest();
4237 std::string sha1_base64 = base64_encode(digest, 20);
4238 std::string sha1_hex = hex_encode((char*)digest, 20);
4242 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4243 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4248 struct SendableMediaAnnouncement
4251 std::string sha1_digest;
4253 SendableMediaAnnouncement(const std::string name_="",
4254 const std::string sha1_digest_=""):
4256 sha1_digest(sha1_digest_)
4260 void Server::sendMediaAnnouncement(u16 peer_id)
4262 DSTACK(__FUNCTION_NAME);
4264 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4267 core::list<SendableMediaAnnouncement> file_announcements;
4269 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4270 i != m_media.end(); i++){
4272 file_announcements.push_back(
4273 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4277 std::ostringstream os(std::ios_base::binary);
4285 u16 length of sha1_digest
4290 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4291 writeU16(os, file_announcements.size());
4293 for(core::list<SendableMediaAnnouncement>::Iterator
4294 j = file_announcements.begin();
4295 j != file_announcements.end(); j++){
4296 os<<serializeString(j->name);
4297 os<<serializeString(j->sha1_digest);
4299 os<<serializeString(g_settings->get("remote_media"));
4302 std::string s = os.str();
4303 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4306 m_con.Send(peer_id, 0, data, true);
4309 struct SendableMedia
4315 SendableMedia(const std::string &name_="", const std::string path_="",
4316 const std::string &data_=""):
4323 void Server::sendRequestedMedia(u16 peer_id,
4324 const core::list<MediaRequest> &tosend)
4326 DSTACK(__FUNCTION_NAME);
4328 verbosestream<<"Server::sendRequestedMedia(): "
4329 <<"Sending files to client"<<std::endl;
4333 // Put 5kB in one bunch (this is not accurate)
4334 u32 bytes_per_bunch = 5000;
4336 core::array< core::list<SendableMedia> > file_bunches;
4337 file_bunches.push_back(core::list<SendableMedia>());
4339 u32 file_size_bunch_total = 0;
4341 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4342 i != tosend.end(); i++)
4344 if(m_media.find(i->name) == m_media.end()){
4345 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4346 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4350 //TODO get path + name
4351 std::string tpath = m_media[(*i).name].path;
4354 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4355 if(fis.good() == false){
4356 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4357 <<tpath<<"\" for reading"<<std::endl;
4360 std::ostringstream tmp_os(std::ios_base::binary);
4364 fis.read(buf, 1024);
4365 std::streamsize len = fis.gcount();
4366 tmp_os.write(buf, len);
4367 file_size_bunch_total += len;
4376 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4377 <<(*i).name<<"\""<<std::endl;
4380 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4381 <<tname<<"\""<<std::endl;*/
4383 file_bunches[file_bunches.size()-1].push_back(
4384 SendableMedia((*i).name, tpath, tmp_os.str()));
4386 // Start next bunch if got enough data
4387 if(file_size_bunch_total >= bytes_per_bunch){
4388 file_bunches.push_back(core::list<SendableMedia>());
4389 file_size_bunch_total = 0;
4394 /* Create and send packets */
4396 u32 num_bunches = file_bunches.size();
4397 for(u32 i=0; i<num_bunches; i++)
4399 std::ostringstream os(std::ios_base::binary);
4403 u16 total number of texture bunches
4404 u16 index of this bunch
4405 u32 number of files in this bunch
4414 writeU16(os, TOCLIENT_MEDIA);
4415 writeU16(os, num_bunches);
4417 writeU32(os, file_bunches[i].size());
4419 for(core::list<SendableMedia>::Iterator
4420 j = file_bunches[i].begin();
4421 j != file_bunches[i].end(); j++){
4422 os<<serializeString(j->name);
4423 os<<serializeLongString(j->data);
4427 std::string s = os.str();
4428 verbosestream<<"Server::sendRequestedMedia(): bunch "
4429 <<i<<"/"<<num_bunches
4430 <<" files="<<file_bunches[i].size()
4431 <<" size=" <<s.size()<<std::endl;
4432 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4434 m_con.Send(peer_id, 0, data, true);
4438 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4440 if(m_detached_inventories.count(name) == 0){
4441 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4444 Inventory *inv = m_detached_inventories[name];
4446 std::ostringstream os(std::ios_base::binary);
4447 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4448 os<<serializeString(name);
4452 std::string s = os.str();
4453 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4455 m_con.Send(peer_id, 0, data, true);
4458 void Server::sendDetachedInventoryToAll(const std::string &name)
4460 DSTACK(__FUNCTION_NAME);
4462 for(core::map<u16, RemoteClient*>::Iterator
4463 i = m_clients.getIterator();
4464 i.atEnd() == false; i++){
4465 RemoteClient *client = i.getNode()->getValue();
4466 sendDetachedInventory(name, client->peer_id);
4470 void Server::sendDetachedInventories(u16 peer_id)
4472 DSTACK(__FUNCTION_NAME);
4474 for(std::map<std::string, Inventory*>::iterator
4475 i = m_detached_inventories.begin();
4476 i != m_detached_inventories.end(); i++){
4477 const std::string &name = i->first;
4478 //Inventory *inv = i->second;
4479 sendDetachedInventory(name, peer_id);
4487 void Server::DiePlayer(u16 peer_id)
4489 DSTACK(__FUNCTION_NAME);
4491 PlayerSAO *playersao = getPlayerSAO(peer_id);
4494 infostream<<"Server::DiePlayer(): Player "
4495 <<playersao->getPlayer()->getName()
4496 <<" dies"<<std::endl;
4498 playersao->setHP(0);
4500 // Trigger scripted stuff
4501 scriptapi_on_dieplayer(m_lua, playersao);
4503 SendPlayerHP(peer_id);
4504 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4507 void Server::RespawnPlayer(u16 peer_id)
4509 DSTACK(__FUNCTION_NAME);
4511 PlayerSAO *playersao = getPlayerSAO(peer_id);
4514 infostream<<"Server::RespawnPlayer(): Player "
4515 <<playersao->getPlayer()->getName()
4516 <<" respawns"<<std::endl;
4518 playersao->setHP(PLAYER_MAX_HP);
4520 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4522 v3f pos = findSpawnPos(m_env->getServerMap());
4523 playersao->setPos(pos);
4527 void Server::UpdateCrafting(u16 peer_id)
4529 DSTACK(__FUNCTION_NAME);
4531 Player* player = m_env->getPlayer(peer_id);
4534 // Get a preview for crafting
4536 getCraftingResult(&player->inventory, preview, false, this);
4538 // Put the new preview in
4539 InventoryList *plist = player->inventory.getList("craftpreview");
4541 assert(plist->getSize() >= 1);
4542 plist->changeItem(0, preview);
4545 RemoteClient* Server::getClient(u16 peer_id)
4547 DSTACK(__FUNCTION_NAME);
4548 //JMutexAutoLock lock(m_con_mutex);
4549 core::map<u16, RemoteClient*>::Node *n;
4550 n = m_clients.find(peer_id);
4551 // A client should exist for all peers
4553 return n->getValue();
4556 std::wstring Server::getStatusString()
4558 std::wostringstream os(std::ios_base::binary);
4561 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4563 os<<L", uptime="<<m_uptime.get();
4564 // Information about clients
4565 core::map<u16, RemoteClient*>::Iterator i;
4568 for(i = m_clients.getIterator(), first = true;
4569 i.atEnd() == false; i++)
4571 // Get client and check that it is valid
4572 RemoteClient *client = i.getNode()->getValue();
4573 assert(client->peer_id == i.getNode()->getKey());
4574 if(client->serialization_version == SER_FMT_VER_INVALID)
4577 Player *player = m_env->getPlayer(client->peer_id);
4578 // Get name of player
4579 std::wstring name = L"unknown";
4581 name = narrow_to_wide(player->getName());
4582 // Add name to information string
4590 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4591 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4592 if(g_settings->get("motd") != "")
4593 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4597 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4599 std::set<std::string> privs;
4600 scriptapi_get_auth(m_lua, name, NULL, &privs);
4604 bool Server::checkPriv(const std::string &name, const std::string &priv)
4606 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4607 return (privs.count(priv) != 0);
4610 void Server::reportPrivsModified(const std::string &name)
4613 for(core::map<u16, RemoteClient*>::Iterator
4614 i = m_clients.getIterator();
4615 i.atEnd() == false; i++){
4616 RemoteClient *client = i.getNode()->getValue();
4617 Player *player = m_env->getPlayer(client->peer_id);
4618 reportPrivsModified(player->getName());
4621 Player *player = m_env->getPlayer(name.c_str());
4624 SendPlayerPrivileges(player->peer_id);
4625 PlayerSAO *sao = player->getPlayerSAO();
4628 sao->updatePrivileges(
4629 getPlayerEffectivePrivs(name),
4634 void Server::reportInventoryFormspecModified(const std::string &name)
4636 Player *player = m_env->getPlayer(name.c_str());
4639 SendPlayerInventoryFormspec(player->peer_id);
4642 // Saves g_settings to configpath given at initialization
4643 void Server::saveConfig()
4645 if(m_path_config != "")
4646 g_settings->updateConfigFile(m_path_config.c_str());
4649 void Server::notifyPlayer(const char *name, const std::wstring msg)
4651 Player *player = m_env->getPlayer(name);
4654 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4657 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4659 Player *player = m_env->getPlayer(playername);
4663 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4667 SendShowFormspecMessage(player->peer_id, formspec, formname);
4671 void Server::notifyPlayers(const std::wstring msg)
4673 BroadcastChatMessage(msg);
4676 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4680 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4681 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4684 Inventory* Server::createDetachedInventory(const std::string &name)
4686 if(m_detached_inventories.count(name) > 0){
4687 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4688 delete m_detached_inventories[name];
4690 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4692 Inventory *inv = new Inventory(m_itemdef);
4694 m_detached_inventories[name] = inv;
4695 sendDetachedInventoryToAll(name);
4702 BoolScopeSet(bool *dst, bool val):
4705 m_orig_state = *m_dst;
4710 *m_dst = m_orig_state;
4717 // actions: time-reversed list
4718 // Return value: success/failure
4719 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4720 std::list<std::string> *log)
4722 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4723 ServerMap *map = (ServerMap*)(&m_env->getMap());
4724 // Disable rollback report sink while reverting
4725 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4727 // Fail if no actions to handle
4728 if(actions.empty()){
4729 log->push_back("Nothing to do.");
4736 for(std::list<RollbackAction>::const_iterator
4737 i = actions.begin();
4738 i != actions.end(); i++)
4740 const RollbackAction &action = *i;
4742 bool success = action.applyRevert(map, this, this);
4745 std::ostringstream os;
4746 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4747 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4749 log->push_back(os.str());
4751 std::ostringstream os;
4752 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4753 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4755 log->push_back(os.str());
4759 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4760 <<" failed"<<std::endl;
4762 // Call it done if less than half failed
4763 return num_failed <= num_tried/2;
4766 // IGameDef interface
4768 IItemDefManager* Server::getItemDefManager()
4772 INodeDefManager* Server::getNodeDefManager()
4776 ICraftDefManager* Server::getCraftDefManager()
4780 ITextureSource* Server::getTextureSource()
4784 IShaderSource* Server::getShaderSource()
4788 u16 Server::allocateUnknownNodeId(const std::string &name)
4790 return m_nodedef->allocateDummy(name);
4792 ISoundManager* Server::getSoundManager()
4794 return &dummySoundManager;
4796 MtEventManager* Server::getEventManager()
4800 IRollbackReportSink* Server::getRollbackReportSink()
4802 if(!m_enable_rollback_recording)
4804 if(!m_rollback_sink_enabled)
4809 IWritableItemDefManager* Server::getWritableItemDefManager()
4813 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4817 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4822 const ModSpec* Server::getModSpec(const std::string &modname)
4824 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4825 i != m_mods.end(); i++){
4826 const ModSpec &mod = *i;
4827 if(mod.name == modname)
4832 void Server::getModNames(core::list<std::string> &modlist)
4834 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4836 modlist.push_back((*i).name);
4839 std::string Server::getBuiltinLuaPath()
4841 return porting::path_share + DIR_DELIM + "builtin";
4844 v3f findSpawnPos(ServerMap &map)
4846 //return v3f(50,50,50)*BS;
4851 nodepos = v2s16(0,0);
4856 s16 water_level = map.m_mgparams->water_level;
4858 // Try to find a good place a few times
4859 for(s32 i=0; i<1000; i++)
4862 // We're going to try to throw the player to this position
4863 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4864 -range + (myrand()%(range*2)));
4865 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4866 // Get ground height at point (fallbacks to heightmap function)
4867 s16 groundheight = map.findGroundLevel(nodepos2d);
4868 // Don't go underwater
4869 if(groundheight <= water_level)
4871 //infostream<<"-> Underwater"<<std::endl;
4874 // Don't go to high places
4875 if(groundheight > water_level + 6)
4877 //infostream<<"-> Underwater"<<std::endl;
4881 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4882 bool is_good = false;
4884 for(s32 i=0; i<10; i++){
4885 v3s16 blockpos = getNodeBlockPos(nodepos);
4886 map.emergeBlock(blockpos, true);
4887 MapNode n = map.getNodeNoEx(nodepos);
4888 if(n.getContent() == CONTENT_AIR){
4899 // Found a good place
4900 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4906 return intToFloat(nodepos, BS);
4909 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4911 RemotePlayer *player = NULL;
4912 bool newplayer = false;
4915 Try to get an existing player
4917 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4919 // If player is already connected, cancel
4920 if(player != NULL && player->peer_id != 0)
4922 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4927 If player with the wanted peer_id already exists, cancel.
4929 if(m_env->getPlayer(peer_id) != NULL)
4931 infostream<<"emergePlayer(): Player with wrong name but same"
4932 " peer_id already exists"<<std::endl;
4937 Create a new player if it doesn't exist yet
4942 player = new RemotePlayer(this);
4943 player->updateName(name);
4945 /* Set player position */
4946 infostream<<"Server: Finding spawn place for player \""
4947 <<name<<"\""<<std::endl;
4948 v3f pos = findSpawnPos(m_env->getServerMap());
4949 player->setPosition(pos);
4951 /* Add player to environment */
4952 m_env->addPlayer(player);
4956 Create a new player active object
4958 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4959 getPlayerEffectivePrivs(player->getName()),
4962 /* Add object to environment */
4963 m_env->addActiveObject(playersao);
4967 scriptapi_on_newplayer(m_lua, playersao);
4969 scriptapi_on_joinplayer(m_lua, playersao);
4974 void Server::handlePeerChange(PeerChange &c)
4976 JMutexAutoLock envlock(m_env_mutex);
4977 JMutexAutoLock conlock(m_con_mutex);
4979 if(c.type == PEER_ADDED)
4986 core::map<u16, RemoteClient*>::Node *n;
4987 n = m_clients.find(c.peer_id);
4988 // The client shouldn't already exist
4992 RemoteClient *client = new RemoteClient();
4993 client->peer_id = c.peer_id;
4994 m_clients.insert(client->peer_id, client);
4997 else if(c.type == PEER_REMOVED)
5004 core::map<u16, RemoteClient*>::Node *n;
5005 n = m_clients.find(c.peer_id);
5006 // The client should exist
5010 Mark objects to be not known by the client
5012 RemoteClient *client = n->getValue();
5014 for(core::map<u16, bool>::Iterator
5015 i = client->m_known_objects.getIterator();
5016 i.atEnd()==false; i++)
5019 u16 id = i.getNode()->getKey();
5020 ServerActiveObject* obj = m_env->getActiveObject(id);
5022 if(obj && obj->m_known_by_count > 0)
5023 obj->m_known_by_count--;
5027 Clear references to playing sounds
5029 for(std::map<s32, ServerPlayingSound>::iterator
5030 i = m_playing_sounds.begin();
5031 i != m_playing_sounds.end();)
5033 ServerPlayingSound &psound = i->second;
5034 psound.clients.erase(c.peer_id);
5035 if(psound.clients.size() == 0)
5036 m_playing_sounds.erase(i++);
5041 Player *player = m_env->getPlayer(c.peer_id);
5043 // Collect information about leaving in chat
5044 std::wstring message;
5048 std::wstring name = narrow_to_wide(player->getName());
5051 message += L" left the game.";
5053 message += L" (timed out)";
5057 /* Run scripts and remove from environment */
5061 PlayerSAO *playersao = player->getPlayerSAO();
5064 scriptapi_on_leaveplayer(m_lua, playersao);
5066 playersao->disconnected();
5076 std::ostringstream os(std::ios_base::binary);
5077 for(core::map<u16, RemoteClient*>::Iterator
5078 i = m_clients.getIterator();
5079 i.atEnd() == false; i++)
5081 RemoteClient *client = i.getNode()->getValue();
5082 assert(client->peer_id == i.getNode()->getKey());
5083 if(client->serialization_version == SER_FMT_VER_INVALID)
5086 Player *player = m_env->getPlayer(client->peer_id);
5089 // Get name of player
5090 os<<player->getName()<<" ";
5093 actionstream<<player->getName()<<" "
5094 <<(c.timeout?"times out.":"leaves game.")
5095 <<" List of players: "
5096 <<os.str()<<std::endl;
5101 delete m_clients[c.peer_id];
5102 m_clients.remove(c.peer_id);
5104 // Send player info to all remaining clients
5105 //SendPlayerInfos();
5107 // Send leave chat message to all remaining clients
5108 if(message.length() != 0)
5109 BroadcastChatMessage(message);
5118 void Server::handlePeerChanges()
5120 while(m_peer_change_queue.size() > 0)
5122 PeerChange c = m_peer_change_queue.pop_front();
5124 verbosestream<<"Server: Handling peer change: "
5125 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5128 handlePeerChange(c);
5132 void dedicated_server_loop(Server &server, bool &kill)
5134 DSTACK(__FUNCTION_NAME);
5136 verbosestream<<"dedicated_server_loop()"<<std::endl;
5138 IntervalLimiter m_profiler_interval;
5142 float steplen = g_settings->getFloat("dedicated_server_step");
5143 // This is kind of a hack but can be done like this
5144 // because server.step() is very light
5146 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5147 sleep_ms((int)(steplen*1000.0));
5149 server.step(steplen);
5151 if(server.getShutdownRequested() || kill)
5153 infostream<<"Dedicated server quitting"<<std::endl;
5160 float profiler_print_interval =
5161 g_settings->getFloat("profiler_print_interval");
5162 if(profiler_print_interval != 0)
5164 if(m_profiler_interval.step(steplen, profiler_print_interval))
5166 infostream<<"Profiler:"<<std::endl;
5167 g_profiler->print(infostream);
5168 g_profiler->clear();