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 player movement settings
2348 SendMovement(m_con, peer_id);
2350 // Send item definitions
2351 SendItemDef(m_con, peer_id, m_itemdef);
2353 // Send node definitions
2354 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2356 // Send media announcement
2357 sendMediaAnnouncement(peer_id);
2360 SendPlayerPrivileges(peer_id);
2362 // Send inventory formspec
2363 SendPlayerInventoryFormspec(peer_id);
2366 UpdateCrafting(peer_id);
2367 SendInventory(peer_id);
2370 if(g_settings->getBool("enable_damage"))
2371 SendPlayerHP(peer_id);
2373 // Send detached inventories
2374 sendDetachedInventories(peer_id);
2376 // Show death screen if necessary
2378 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2382 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2383 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2384 m_con.Send(peer_id, 0, data, true);
2387 // Note things in chat if not in simple singleplayer mode
2388 if(!m_simple_singleplayer_mode)
2390 // Send information about server to player in chat
2391 SendChatMessage(peer_id, getStatusString());
2393 // Send information about joining in chat
2395 std::wstring name = L"unknown";
2396 Player *player = m_env->getPlayer(peer_id);
2398 name = narrow_to_wide(player->getName());
2400 std::wstring message;
2403 message += L" joined the game.";
2404 BroadcastChatMessage(message);
2408 // Warnings about protocol version can be issued here
2409 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2411 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2412 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2419 std::ostringstream os(std::ios_base::binary);
2420 for(core::map<u16, RemoteClient*>::Iterator
2421 i = m_clients.getIterator();
2422 i.atEnd() == false; i++)
2424 RemoteClient *client = i.getNode()->getValue();
2425 assert(client->peer_id == i.getNode()->getKey());
2426 if(client->serialization_version == SER_FMT_VER_INVALID)
2429 Player *player = m_env->getPlayer(client->peer_id);
2432 // Get name of player
2433 os<<player->getName()<<" ";
2436 actionstream<<player->getName()<<" joins game. List of players: "
2437 <<os.str()<<std::endl;
2443 if(peer_ser_ver == SER_FMT_VER_INVALID)
2445 infostream<<"Server::ProcessData(): Cancelling: Peer"
2446 " serialization format invalid or not initialized."
2447 " Skipping incoming command="<<command<<std::endl;
2451 Player *player = m_env->getPlayer(peer_id);
2453 infostream<<"Server::ProcessData(): Cancelling: "
2454 "No player for peer_id="<<peer_id
2459 PlayerSAO *playersao = player->getPlayerSAO();
2460 if(playersao == NULL){
2461 infostream<<"Server::ProcessData(): Cancelling: "
2462 "No player object for peer_id="<<peer_id
2467 if(command == TOSERVER_PLAYERPOS)
2469 if(datasize < 2+12+12+4+4)
2473 v3s32 ps = readV3S32(&data[start+2]);
2474 v3s32 ss = readV3S32(&data[start+2+12]);
2475 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2476 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2478 if(datasize >= 2+12+12+4+4+4)
2479 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2480 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2481 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2482 pitch = wrapDegrees(pitch);
2483 yaw = wrapDegrees(yaw);
2485 player->setPosition(position);
2486 player->setSpeed(speed);
2487 player->setPitch(pitch);
2488 player->setYaw(yaw);
2489 player->keyPressed=keyPressed;
2490 player->control.up = (bool)(keyPressed&1);
2491 player->control.down = (bool)(keyPressed&2);
2492 player->control.left = (bool)(keyPressed&4);
2493 player->control.right = (bool)(keyPressed&8);
2494 player->control.jump = (bool)(keyPressed&16);
2495 player->control.aux1 = (bool)(keyPressed&32);
2496 player->control.sneak = (bool)(keyPressed&64);
2497 player->control.LMB = (bool)(keyPressed&128);
2498 player->control.RMB = (bool)(keyPressed&256);
2500 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2501 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2502 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2504 else if(command == TOSERVER_GOTBLOCKS)
2517 u16 count = data[2];
2518 for(u16 i=0; i<count; i++)
2520 if((s16)datasize < 2+1+(i+1)*6)
2521 throw con::InvalidIncomingDataException
2522 ("GOTBLOCKS length is too short");
2523 v3s16 p = readV3S16(&data[2+1+i*6]);
2524 /*infostream<<"Server: GOTBLOCKS ("
2525 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2526 RemoteClient *client = getClient(peer_id);
2527 client->GotBlock(p);
2530 else if(command == TOSERVER_DELETEDBLOCKS)
2543 u16 count = data[2];
2544 for(u16 i=0; i<count; i++)
2546 if((s16)datasize < 2+1+(i+1)*6)
2547 throw con::InvalidIncomingDataException
2548 ("DELETEDBLOCKS length is too short");
2549 v3s16 p = readV3S16(&data[2+1+i*6]);
2550 /*infostream<<"Server: DELETEDBLOCKS ("
2551 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2552 RemoteClient *client = getClient(peer_id);
2553 client->SetBlockNotSent(p);
2556 else if(command == TOSERVER_CLICK_OBJECT)
2558 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2561 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2563 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2566 else if(command == TOSERVER_GROUND_ACTION)
2568 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2572 else if(command == TOSERVER_RELEASE)
2574 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2577 else if(command == TOSERVER_SIGNTEXT)
2579 infostream<<"Server: SIGNTEXT not supported anymore"
2583 else if(command == TOSERVER_SIGNNODETEXT)
2585 infostream<<"Server: SIGNNODETEXT not supported anymore"
2589 else if(command == TOSERVER_INVENTORY_ACTION)
2591 // Strip command and create a stream
2592 std::string datastring((char*)&data[2], datasize-2);
2593 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2594 std::istringstream is(datastring, std::ios_base::binary);
2596 InventoryAction *a = InventoryAction::deSerialize(is);
2599 infostream<<"TOSERVER_INVENTORY_ACTION: "
2600 <<"InventoryAction::deSerialize() returned NULL"
2605 // If something goes wrong, this player is to blame
2606 RollbackScopeActor rollback_scope(m_rollback,
2607 std::string("player:")+player->getName());
2610 Note: Always set inventory not sent, to repair cases
2611 where the client made a bad prediction.
2615 Handle restrictions and special cases of the move action
2617 if(a->getType() == IACTION_MOVE)
2619 IMoveAction *ma = (IMoveAction*)a;
2621 ma->from_inv.applyCurrentPlayer(player->getName());
2622 ma->to_inv.applyCurrentPlayer(player->getName());
2624 setInventoryModified(ma->from_inv);
2625 setInventoryModified(ma->to_inv);
2627 bool from_inv_is_current_player =
2628 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2629 (ma->from_inv.name == player->getName());
2631 bool to_inv_is_current_player =
2632 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2633 (ma->to_inv.name == player->getName());
2636 Disable moving items out of craftpreview
2638 if(ma->from_list == "craftpreview")
2640 infostream<<"Ignoring IMoveAction from "
2641 <<(ma->from_inv.dump())<<":"<<ma->from_list
2642 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2643 <<" because src is "<<ma->from_list<<std::endl;
2649 Disable moving items into craftresult and craftpreview
2651 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2653 infostream<<"Ignoring IMoveAction from "
2654 <<(ma->from_inv.dump())<<":"<<ma->from_list
2655 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2656 <<" because dst is "<<ma->to_list<<std::endl;
2661 // Disallow moving items in elsewhere than player's inventory
2662 // if not allowed to interact
2663 if(!checkPriv(player->getName(), "interact") &&
2664 (!from_inv_is_current_player ||
2665 !to_inv_is_current_player))
2667 infostream<<"Cannot move outside of player's inventory: "
2668 <<"No interact privilege"<<std::endl;
2674 Handle restrictions and special cases of the drop action
2676 else if(a->getType() == IACTION_DROP)
2678 IDropAction *da = (IDropAction*)a;
2680 da->from_inv.applyCurrentPlayer(player->getName());
2682 setInventoryModified(da->from_inv);
2684 // Disallow dropping items if not allowed to interact
2685 if(!checkPriv(player->getName(), "interact"))
2692 Handle restrictions and special cases of the craft action
2694 else if(a->getType() == IACTION_CRAFT)
2696 ICraftAction *ca = (ICraftAction*)a;
2698 ca->craft_inv.applyCurrentPlayer(player->getName());
2700 setInventoryModified(ca->craft_inv);
2702 //bool craft_inv_is_current_player =
2703 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2704 // (ca->craft_inv.name == player->getName());
2706 // Disallow crafting if not allowed to interact
2707 if(!checkPriv(player->getName(), "interact"))
2709 infostream<<"Cannot craft: "
2710 <<"No interact privilege"<<std::endl;
2717 a->apply(this, playersao, this);
2721 else if(command == TOSERVER_CHAT_MESSAGE)
2729 std::string datastring((char*)&data[2], datasize-2);
2730 std::istringstream is(datastring, std::ios_base::binary);
2733 is.read((char*)buf, 2);
2734 u16 len = readU16(buf);
2736 std::wstring message;
2737 for(u16 i=0; i<len; i++)
2739 is.read((char*)buf, 2);
2740 message += (wchar_t)readU16(buf);
2743 // If something goes wrong, this player is to blame
2744 RollbackScopeActor rollback_scope(m_rollback,
2745 std::string("player:")+player->getName());
2747 // Get player name of this client
2748 std::wstring name = narrow_to_wide(player->getName());
2751 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2752 wide_to_narrow(message));
2753 // If script ate the message, don't proceed
2757 // Line to send to players
2759 // Whether to send to the player that sent the line
2760 bool send_to_sender = false;
2761 // Whether to send to other players
2762 bool send_to_others = false;
2764 // Commands are implemented in Lua, so only catch invalid
2765 // commands that were not "eaten" and send an error back
2766 if(message[0] == L'/')
2768 message = message.substr(1);
2769 send_to_sender = true;
2770 if(message.length() == 0)
2771 line += L"-!- Empty command";
2773 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2777 if(checkPriv(player->getName(), "shout")){
2782 send_to_others = true;
2784 line += L"-!- You don't have permission to shout.";
2785 send_to_sender = true;
2792 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2795 Send the message to clients
2797 for(core::map<u16, RemoteClient*>::Iterator
2798 i = m_clients.getIterator();
2799 i.atEnd() == false; i++)
2801 // Get client and check that it is valid
2802 RemoteClient *client = i.getNode()->getValue();
2803 assert(client->peer_id == i.getNode()->getKey());
2804 if(client->serialization_version == SER_FMT_VER_INVALID)
2808 bool sender_selected = (peer_id == client->peer_id);
2809 if(sender_selected == true && send_to_sender == false)
2811 if(sender_selected == false && send_to_others == false)
2814 SendChatMessage(client->peer_id, line);
2818 else if(command == TOSERVER_DAMAGE)
2820 std::string datastring((char*)&data[2], datasize-2);
2821 std::istringstream is(datastring, std::ios_base::binary);
2822 u8 damage = readU8(is);
2824 if(g_settings->getBool("enable_damage"))
2826 actionstream<<player->getName()<<" damaged by "
2827 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2830 playersao->setHP(playersao->getHP() - damage);
2832 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2835 if(playersao->m_hp_not_sent)
2836 SendPlayerHP(peer_id);
2839 else if(command == TOSERVER_PASSWORD)
2842 [0] u16 TOSERVER_PASSWORD
2843 [2] u8[28] old password
2844 [30] u8[28] new password
2847 if(datasize != 2+PASSWORD_SIZE*2)
2849 /*char password[PASSWORD_SIZE];
2850 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2851 password[i] = data[2+i];
2852 password[PASSWORD_SIZE-1] = 0;*/
2854 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2862 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2864 char c = data[2+PASSWORD_SIZE+i];
2870 if(!base64_is_valid(newpwd)){
2871 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2872 // Wrong old password supplied!!
2873 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2877 infostream<<"Server: Client requests a password change from "
2878 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2880 std::string playername = player->getName();
2882 std::string checkpwd;
2883 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2885 if(oldpwd != checkpwd)
2887 infostream<<"Server: invalid old password"<<std::endl;
2888 // Wrong old password supplied!!
2889 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2893 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2895 actionstream<<player->getName()<<" changes password"<<std::endl;
2896 SendChatMessage(peer_id, L"Password change successful.");
2898 actionstream<<player->getName()<<" tries to change password but "
2899 <<"it fails"<<std::endl;
2900 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2903 else if(command == TOSERVER_PLAYERITEM)
2908 u16 item = readU16(&data[2]);
2909 playersao->setWieldIndex(item);
2911 else if(command == TOSERVER_RESPAWN)
2913 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2916 RespawnPlayer(peer_id);
2918 actionstream<<player->getName()<<" respawns at "
2919 <<PP(player->getPosition()/BS)<<std::endl;
2921 // ActiveObject is added to environment in AsyncRunStep after
2922 // the previous addition has been succesfully removed
2924 else if(command == TOSERVER_REQUEST_MEDIA) {
2925 std::string datastring((char*)&data[2], datasize-2);
2926 std::istringstream is(datastring, std::ios_base::binary);
2928 core::list<MediaRequest> tosend;
2929 u16 numfiles = readU16(is);
2931 infostream<<"Sending "<<numfiles<<" files to "
2932 <<getPlayerName(peer_id)<<std::endl;
2933 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2935 for(int i = 0; i < numfiles; i++) {
2936 std::string name = deSerializeString(is);
2937 tosend.push_back(MediaRequest(name));
2938 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2942 sendRequestedMedia(peer_id, tosend);
2944 // Now the client should know about everything
2945 // (definitions and files)
2946 getClient(peer_id)->definitions_sent = true;
2948 else if(command == TOSERVER_RECEIVED_MEDIA) {
2949 getClient(peer_id)->definitions_sent = true;
2951 else if(command == TOSERVER_INTERACT)
2953 std::string datastring((char*)&data[2], datasize-2);
2954 std::istringstream is(datastring, std::ios_base::binary);
2960 [5] u32 length of the next item
2961 [9] serialized PointedThing
2963 0: start digging (from undersurface) or use
2964 1: stop digging (all parameters ignored)
2965 2: digging completed
2966 3: place block or item (to abovesurface)
2969 u8 action = readU8(is);
2970 u16 item_i = readU16(is);
2971 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2972 PointedThing pointed;
2973 pointed.deSerialize(tmp_is);
2975 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2976 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2980 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2981 <<" tried to interact, but is dead!"<<std::endl;
2985 v3f player_pos = playersao->getLastGoodPosition();
2987 // Update wielded item
2988 playersao->setWieldIndex(item_i);
2990 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2991 v3s16 p_under = pointed.node_undersurface;
2992 v3s16 p_above = pointed.node_abovesurface;
2994 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2995 ServerActiveObject *pointed_object = NULL;
2996 if(pointed.type == POINTEDTHING_OBJECT)
2998 pointed_object = m_env->getActiveObject(pointed.object_id);
2999 if(pointed_object == NULL)
3001 verbosestream<<"TOSERVER_INTERACT: "
3002 "pointed object is NULL"<<std::endl;
3008 v3f pointed_pos_under = player_pos;
3009 v3f pointed_pos_above = player_pos;
3010 if(pointed.type == POINTEDTHING_NODE)
3012 pointed_pos_under = intToFloat(p_under, BS);
3013 pointed_pos_above = intToFloat(p_above, BS);
3015 else if(pointed.type == POINTEDTHING_OBJECT)
3017 pointed_pos_under = pointed_object->getBasePosition();
3018 pointed_pos_above = pointed_pos_under;
3022 Check that target is reasonably close
3023 (only when digging or placing things)
3025 if(action == 0 || action == 2 || action == 3)
3027 float d = player_pos.getDistanceFrom(pointed_pos_under);
3028 float max_d = BS * 14; // Just some large enough value
3030 actionstream<<"Player "<<player->getName()
3031 <<" tried to access "<<pointed.dump()
3033 <<"d="<<d<<", max_d="<<max_d
3034 <<". ignoring."<<std::endl;
3035 // Re-send block to revert change on client-side
3036 RemoteClient *client = getClient(peer_id);
3037 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3038 client->SetBlockNotSent(blockpos);
3045 Make sure the player is allowed to do it
3047 if(!checkPriv(player->getName(), "interact"))
3049 actionstream<<player->getName()<<" attempted to interact with "
3050 <<pointed.dump()<<" without 'interact' privilege"
3052 // Re-send block to revert change on client-side
3053 RemoteClient *client = getClient(peer_id);
3054 // Digging completed -> under
3056 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3057 client->SetBlockNotSent(blockpos);
3059 // Placement -> above
3061 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3062 client->SetBlockNotSent(blockpos);
3068 If something goes wrong, this player is to blame
3070 RollbackScopeActor rollback_scope(m_rollback,
3071 std::string("player:")+player->getName());
3074 0: start digging or punch object
3078 if(pointed.type == POINTEDTHING_NODE)
3081 NOTE: This can be used in the future to check if
3082 somebody is cheating, by checking the timing.
3084 MapNode n(CONTENT_IGNORE);
3087 n = m_env->getMap().getNode(p_under);
3089 catch(InvalidPositionException &e)
3091 infostream<<"Server: Not punching: Node not found."
3092 <<" Adding block to emerge queue."
3094 m_emerge_queue.addBlock(peer_id,
3095 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3097 if(n.getContent() != CONTENT_IGNORE)
3098 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3100 playersao->noCheatDigStart(p_under);
3102 else if(pointed.type == POINTEDTHING_OBJECT)
3104 // Skip if object has been removed
3105 if(pointed_object->m_removed)
3108 actionstream<<player->getName()<<" punches object "
3109 <<pointed.object_id<<": "
3110 <<pointed_object->getDescription()<<std::endl;
3112 ItemStack punchitem = playersao->getWieldedItem();
3113 ToolCapabilities toolcap =
3114 punchitem.getToolCapabilities(m_itemdef);
3115 v3f dir = (pointed_object->getBasePosition() -
3116 (player->getPosition() + player->getEyeOffset())
3118 float time_from_last_punch =
3119 playersao->resetTimeFromLastPunch();
3120 pointed_object->punch(dir, &toolcap, playersao,
3121 time_from_last_punch);
3129 else if(action == 1)
3134 2: Digging completed
3136 else if(action == 2)
3138 // Only digging of nodes
3139 if(pointed.type == POINTEDTHING_NODE)
3141 MapNode n(CONTENT_IGNORE);
3144 n = m_env->getMap().getNode(p_under);
3146 catch(InvalidPositionException &e)
3148 infostream<<"Server: Not finishing digging: Node not found."
3149 <<" Adding block to emerge queue."
3151 m_emerge_queue.addBlock(peer_id,
3152 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3155 /* Cheat prevention */
3156 bool is_valid_dig = true;
3157 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3159 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3160 float nocheat_t = playersao->getNoCheatDigTime();
3161 playersao->noCheatDigEnd();
3162 // If player didn't start digging this, ignore dig
3163 if(nocheat_p != p_under){
3164 infostream<<"Server: NoCheat: "<<player->getName()
3165 <<" started digging "
3166 <<PP(nocheat_p)<<" and completed digging "
3167 <<PP(p_under)<<"; not digging."<<std::endl;
3168 is_valid_dig = false;
3170 // Get player's wielded item
3171 ItemStack playeritem;
3172 InventoryList *mlist = playersao->getInventory()->getList("main");
3174 playeritem = mlist->getItem(playersao->getWieldIndex());
3175 ToolCapabilities playeritem_toolcap =
3176 playeritem.getToolCapabilities(m_itemdef);
3177 // Get diggability and expected digging time
3178 DigParams params = getDigParams(m_nodedef->get(n).groups,
3179 &playeritem_toolcap);
3180 // If can't dig, try hand
3181 if(!params.diggable){
3182 const ItemDefinition &hand = m_itemdef->get("");
3183 const ToolCapabilities *tp = hand.tool_capabilities;
3185 params = getDigParams(m_nodedef->get(n).groups, tp);
3187 // If can't dig, ignore dig
3188 if(!params.diggable){
3189 infostream<<"Server: NoCheat: "<<player->getName()
3190 <<" completed digging "<<PP(p_under)
3191 <<", which is not diggable with tool. not digging."
3193 is_valid_dig = false;
3195 // If time is considerably too short, ignore dig
3196 // Check time only for medium and slow timed digs
3197 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3198 infostream<<"Server: NoCheat: "<<player->getName()
3199 <<" completed digging "
3200 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3201 <<params.time<<"s; not digging."<<std::endl;
3202 is_valid_dig = false;
3206 /* Actually dig node */
3208 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3209 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3211 // Send unusual result (that is, node not being removed)
3212 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3214 // Re-send block to revert change on client-side
3215 RemoteClient *client = getClient(peer_id);
3216 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3217 client->SetBlockNotSent(blockpos);
3223 3: place block or right-click object
3225 else if(action == 3)
3227 ItemStack item = playersao->getWieldedItem();
3229 // Reset build time counter
3230 if(pointed.type == POINTEDTHING_NODE &&
3231 item.getDefinition(m_itemdef).type == ITEM_NODE)
3232 getClient(peer_id)->m_time_from_building = 0.0;
3234 if(pointed.type == POINTEDTHING_OBJECT)
3236 // Right click object
3238 // Skip if object has been removed
3239 if(pointed_object->m_removed)
3242 actionstream<<player->getName()<<" right-clicks object "
3243 <<pointed.object_id<<": "
3244 <<pointed_object->getDescription()<<std::endl;
3247 pointed_object->rightClick(playersao);
3249 else if(scriptapi_item_on_place(m_lua,
3250 item, playersao, pointed))
3252 // Placement was handled in lua
3254 // Apply returned ItemStack
3255 playersao->setWieldedItem(item);
3258 // If item has node placement prediction, always send the above
3259 // node to make sure the client knows what exactly happened
3260 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3261 RemoteClient *client = getClient(peer_id);
3262 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3263 client->SetBlockNotSent(blockpos);
3270 else if(action == 4)
3272 ItemStack item = playersao->getWieldedItem();
3274 actionstream<<player->getName()<<" uses "<<item.name
3275 <<", pointing at "<<pointed.dump()<<std::endl;
3277 if(scriptapi_item_on_use(m_lua,
3278 item, playersao, pointed))
3280 // Apply returned ItemStack
3281 playersao->setWieldedItem(item);
3288 Catch invalid actions
3292 infostream<<"WARNING: Server: Invalid action "
3293 <<action<<std::endl;
3296 else if(command == TOSERVER_REMOVED_SOUNDS)
3298 std::string datastring((char*)&data[2], datasize-2);
3299 std::istringstream is(datastring, std::ios_base::binary);
3301 int num = readU16(is);
3302 for(int k=0; k<num; k++){
3303 s32 id = readS32(is);
3304 std::map<s32, ServerPlayingSound>::iterator i =
3305 m_playing_sounds.find(id);
3306 if(i == m_playing_sounds.end())
3308 ServerPlayingSound &psound = i->second;
3309 psound.clients.erase(peer_id);
3310 if(psound.clients.size() == 0)
3311 m_playing_sounds.erase(i++);
3314 else if(command == TOSERVER_NODEMETA_FIELDS)
3316 std::string datastring((char*)&data[2], datasize-2);
3317 std::istringstream is(datastring, std::ios_base::binary);
3319 v3s16 p = readV3S16(is);
3320 std::string formname = deSerializeString(is);
3321 int num = readU16(is);
3322 std::map<std::string, std::string> fields;
3323 for(int k=0; k<num; k++){
3324 std::string fieldname = deSerializeString(is);
3325 std::string fieldvalue = deSerializeLongString(is);
3326 fields[fieldname] = fieldvalue;
3329 // If something goes wrong, this player is to blame
3330 RollbackScopeActor rollback_scope(m_rollback,
3331 std::string("player:")+player->getName());
3333 // Check the target node for rollback data; leave others unnoticed
3334 RollbackNode rn_old(&m_env->getMap(), p, this);
3336 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3339 // Report rollback data
3340 RollbackNode rn_new(&m_env->getMap(), p, this);
3341 if(rollback() && rn_new != rn_old){
3342 RollbackAction action;
3343 action.setSetNode(p, rn_old, rn_new);
3344 rollback()->reportAction(action);
3347 else if(command == TOSERVER_INVENTORY_FIELDS)
3349 std::string datastring((char*)&data[2], datasize-2);
3350 std::istringstream is(datastring, std::ios_base::binary);
3352 std::string formname = deSerializeString(is);
3353 int num = readU16(is);
3354 std::map<std::string, std::string> fields;
3355 for(int k=0; k<num; k++){
3356 std::string fieldname = deSerializeString(is);
3357 std::string fieldvalue = deSerializeLongString(is);
3358 fields[fieldname] = fieldvalue;
3361 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3365 infostream<<"Server::ProcessData(): Ignoring "
3366 "unknown command "<<command<<std::endl;
3370 catch(SendFailedException &e)
3372 errorstream<<"Server::ProcessData(): SendFailedException: "
3378 void Server::onMapEditEvent(MapEditEvent *event)
3380 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3381 if(m_ignore_map_edit_events)
3383 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3385 MapEditEvent *e = event->clone();
3386 m_unsent_map_edit_queue.push_back(e);
3389 Inventory* Server::getInventory(const InventoryLocation &loc)
3392 case InventoryLocation::UNDEFINED:
3395 case InventoryLocation::CURRENT_PLAYER:
3398 case InventoryLocation::PLAYER:
3400 Player *player = m_env->getPlayer(loc.name.c_str());
3403 PlayerSAO *playersao = player->getPlayerSAO();
3406 return playersao->getInventory();
3409 case InventoryLocation::NODEMETA:
3411 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3414 return meta->getInventory();
3417 case InventoryLocation::DETACHED:
3419 if(m_detached_inventories.count(loc.name) == 0)
3421 return m_detached_inventories[loc.name];
3429 void Server::setInventoryModified(const InventoryLocation &loc)
3432 case InventoryLocation::UNDEFINED:
3435 case InventoryLocation::PLAYER:
3437 Player *player = m_env->getPlayer(loc.name.c_str());
3440 PlayerSAO *playersao = player->getPlayerSAO();
3443 playersao->m_inventory_not_sent = true;
3444 playersao->m_wielded_item_not_sent = true;
3447 case InventoryLocation::NODEMETA:
3449 v3s16 blockpos = getNodeBlockPos(loc.p);
3451 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3453 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3455 setBlockNotSent(blockpos);
3458 case InventoryLocation::DETACHED:
3460 sendDetachedInventoryToAll(loc.name);
3468 core::list<PlayerInfo> Server::getPlayerInfo()
3470 DSTACK(__FUNCTION_NAME);
3471 JMutexAutoLock envlock(m_env_mutex);
3472 JMutexAutoLock conlock(m_con_mutex);
3474 core::list<PlayerInfo> list;
3476 core::list<Player*> players = m_env->getPlayers();
3478 core::list<Player*>::Iterator i;
3479 for(i = players.begin();
3480 i != players.end(); i++)
3484 Player *player = *i;
3487 // Copy info from connection to info struct
3488 info.id = player->peer_id;
3489 info.address = m_con.GetPeerAddress(player->peer_id);
3490 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3492 catch(con::PeerNotFoundException &e)
3494 // Set dummy peer info
3496 info.address = Address(0,0,0,0,0);
3500 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3501 info.position = player->getPosition();
3503 list.push_back(info);
3510 void Server::peerAdded(con::Peer *peer)
3512 DSTACK(__FUNCTION_NAME);
3513 verbosestream<<"Server::peerAdded(): peer->id="
3514 <<peer->id<<std::endl;
3517 c.type = PEER_ADDED;
3518 c.peer_id = peer->id;
3520 m_peer_change_queue.push_back(c);
3523 void Server::deletingPeer(con::Peer *peer, bool timeout)
3525 DSTACK(__FUNCTION_NAME);
3526 verbosestream<<"Server::deletingPeer(): peer->id="
3527 <<peer->id<<", timeout="<<timeout<<std::endl;
3530 c.type = PEER_REMOVED;
3531 c.peer_id = peer->id;
3532 c.timeout = timeout;
3533 m_peer_change_queue.push_back(c);
3540 void Server::SendMovement(con::Connection &con, u16 peer_id)
3542 DSTACK(__FUNCTION_NAME);
3543 std::ostringstream os(std::ios_base::binary);
3545 writeU16(os, TOCLIENT_MOVEMENT);
3546 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3547 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3548 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3549 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3550 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3551 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3552 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3553 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3554 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3555 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3556 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3557 writeF1000(os, g_settings->getFloat("movement_gravity"));
3560 std::string s = os.str();
3561 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3563 con.Send(peer_id, 0, data, true);
3566 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3568 DSTACK(__FUNCTION_NAME);
3569 std::ostringstream os(std::ios_base::binary);
3571 writeU16(os, TOCLIENT_HP);
3575 std::string s = os.str();
3576 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3578 con.Send(peer_id, 0, data, true);
3581 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3582 const std::wstring &reason)
3584 DSTACK(__FUNCTION_NAME);
3585 std::ostringstream os(std::ios_base::binary);
3587 writeU16(os, TOCLIENT_ACCESS_DENIED);
3588 os<<serializeWideString(reason);
3591 std::string s = os.str();
3592 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3594 con.Send(peer_id, 0, data, true);
3597 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3598 bool set_camera_point_target, v3f camera_point_target)
3600 DSTACK(__FUNCTION_NAME);
3601 std::ostringstream os(std::ios_base::binary);
3603 writeU16(os, TOCLIENT_DEATHSCREEN);
3604 writeU8(os, set_camera_point_target);
3605 writeV3F1000(os, camera_point_target);
3608 std::string s = os.str();
3609 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3611 con.Send(peer_id, 0, data, true);
3614 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3615 IItemDefManager *itemdef)
3617 DSTACK(__FUNCTION_NAME);
3618 std::ostringstream os(std::ios_base::binary);
3622 u32 length of the next item
3623 zlib-compressed serialized ItemDefManager
3625 writeU16(os, TOCLIENT_ITEMDEF);
3626 std::ostringstream tmp_os(std::ios::binary);
3627 itemdef->serialize(tmp_os);
3628 std::ostringstream tmp_os2(std::ios::binary);
3629 compressZlib(tmp_os.str(), tmp_os2);
3630 os<<serializeLongString(tmp_os2.str());
3633 std::string s = os.str();
3634 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3635 <<"): size="<<s.size()<<std::endl;
3636 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3638 con.Send(peer_id, 0, data, true);
3641 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3642 INodeDefManager *nodedef, u16 protocol_version)
3644 DSTACK(__FUNCTION_NAME);
3645 std::ostringstream os(std::ios_base::binary);
3649 u32 length of the next item
3650 zlib-compressed serialized NodeDefManager
3652 writeU16(os, TOCLIENT_NODEDEF);
3653 std::ostringstream tmp_os(std::ios::binary);
3654 nodedef->serialize(tmp_os, protocol_version);
3655 std::ostringstream tmp_os2(std::ios::binary);
3656 compressZlib(tmp_os.str(), tmp_os2);
3657 os<<serializeLongString(tmp_os2.str());
3660 std::string s = os.str();
3661 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3662 <<"): size="<<s.size()<<std::endl;
3663 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3665 con.Send(peer_id, 0, data, true);
3669 Non-static send methods
3672 void Server::SendInventory(u16 peer_id)
3674 DSTACK(__FUNCTION_NAME);
3676 PlayerSAO *playersao = getPlayerSAO(peer_id);
3679 playersao->m_inventory_not_sent = false;
3685 std::ostringstream os;
3686 playersao->getInventory()->serialize(os);
3688 std::string s = os.str();
3690 SharedBuffer<u8> data(s.size()+2);
3691 writeU16(&data[0], TOCLIENT_INVENTORY);
3692 memcpy(&data[2], s.c_str(), s.size());
3695 m_con.Send(peer_id, 0, data, true);
3698 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3700 DSTACK(__FUNCTION_NAME);
3702 std::ostringstream os(std::ios_base::binary);
3706 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3707 os.write((char*)buf, 2);
3710 writeU16(buf, message.size());
3711 os.write((char*)buf, 2);
3714 for(u32 i=0; i<message.size(); i++)
3718 os.write((char*)buf, 2);
3722 std::string s = os.str();
3723 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3725 m_con.Send(peer_id, 0, data, true);
3727 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3729 DSTACK(__FUNCTION_NAME);
3731 std::ostringstream os(std::ios_base::binary);
3735 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3736 os.write((char*)buf, 2);
3737 os<<serializeLongString(formspec);
3738 os<<serializeString(formname);
3741 std::string s = os.str();
3742 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3744 m_con.Send(peer_id, 0, data, true);
3747 void Server::BroadcastChatMessage(const std::wstring &message)
3749 for(core::map<u16, RemoteClient*>::Iterator
3750 i = m_clients.getIterator();
3751 i.atEnd() == false; i++)
3753 // Get client and check that it is valid
3754 RemoteClient *client = i.getNode()->getValue();
3755 assert(client->peer_id == i.getNode()->getKey());
3756 if(client->serialization_version == SER_FMT_VER_INVALID)
3759 SendChatMessage(client->peer_id, message);
3763 void Server::SendPlayerHP(u16 peer_id)
3765 DSTACK(__FUNCTION_NAME);
3766 PlayerSAO *playersao = getPlayerSAO(peer_id);
3768 playersao->m_hp_not_sent = false;
3769 SendHP(m_con, peer_id, playersao->getHP());
3772 void Server::SendMovePlayer(u16 peer_id)
3774 DSTACK(__FUNCTION_NAME);
3775 Player *player = m_env->getPlayer(peer_id);
3778 std::ostringstream os(std::ios_base::binary);
3779 writeU16(os, TOCLIENT_MOVE_PLAYER);
3780 writeV3F1000(os, player->getPosition());
3781 writeF1000(os, player->getPitch());
3782 writeF1000(os, player->getYaw());
3785 v3f pos = player->getPosition();
3786 f32 pitch = player->getPitch();
3787 f32 yaw = player->getYaw();
3788 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3789 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3796 std::string s = os.str();
3797 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3799 m_con.Send(peer_id, 0, data, true);
3802 void Server::SendPlayerPrivileges(u16 peer_id)
3804 Player *player = m_env->getPlayer(peer_id);
3806 if(player->peer_id == PEER_ID_INEXISTENT)
3809 std::set<std::string> privs;
3810 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3812 std::ostringstream os(std::ios_base::binary);
3813 writeU16(os, TOCLIENT_PRIVILEGES);
3814 writeU16(os, privs.size());
3815 for(std::set<std::string>::const_iterator i = privs.begin();
3816 i != privs.end(); i++){
3817 os<<serializeString(*i);
3821 std::string s = os.str();
3822 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3824 m_con.Send(peer_id, 0, data, true);
3827 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3829 Player *player = m_env->getPlayer(peer_id);
3831 if(player->peer_id == PEER_ID_INEXISTENT)
3834 std::ostringstream os(std::ios_base::binary);
3835 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3836 os<<serializeLongString(player->inventory_formspec);
3839 std::string s = os.str();
3840 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3842 m_con.Send(peer_id, 0, data, true);
3845 s32 Server::playSound(const SimpleSoundSpec &spec,
3846 const ServerSoundParams ¶ms)
3848 // Find out initial position of sound
3849 bool pos_exists = false;
3850 v3f pos = params.getPos(m_env, &pos_exists);
3851 // If position is not found while it should be, cancel sound
3852 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3854 // Filter destination clients
3855 std::set<RemoteClient*> dst_clients;
3856 if(params.to_player != "")
3858 Player *player = m_env->getPlayer(params.to_player.c_str());
3860 infostream<<"Server::playSound: Player \""<<params.to_player
3861 <<"\" not found"<<std::endl;
3864 if(player->peer_id == PEER_ID_INEXISTENT){
3865 infostream<<"Server::playSound: Player \""<<params.to_player
3866 <<"\" not connected"<<std::endl;
3869 RemoteClient *client = getClient(player->peer_id);
3870 dst_clients.insert(client);
3874 for(core::map<u16, RemoteClient*>::Iterator
3875 i = m_clients.getIterator(); i.atEnd() == false; i++)
3877 RemoteClient *client = i.getNode()->getValue();
3878 Player *player = m_env->getPlayer(client->peer_id);
3882 if(player->getPosition().getDistanceFrom(pos) >
3883 params.max_hear_distance)
3886 dst_clients.insert(client);
3889 if(dst_clients.size() == 0)
3892 s32 id = m_next_sound_id++;
3893 // The sound will exist as a reference in m_playing_sounds
3894 m_playing_sounds[id] = ServerPlayingSound();
3895 ServerPlayingSound &psound = m_playing_sounds[id];
3896 psound.params = params;
3897 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3898 i != dst_clients.end(); i++)
3899 psound.clients.insert((*i)->peer_id);
3901 std::ostringstream os(std::ios_base::binary);
3902 writeU16(os, TOCLIENT_PLAY_SOUND);
3904 os<<serializeString(spec.name);
3905 writeF1000(os, spec.gain * params.gain);
3906 writeU8(os, params.type);
3907 writeV3F1000(os, pos);
3908 writeU16(os, params.object);
3909 writeU8(os, params.loop);
3911 std::string s = os.str();
3912 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3914 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3915 i != dst_clients.end(); i++){
3917 m_con.Send((*i)->peer_id, 0, data, true);
3921 void Server::stopSound(s32 handle)
3923 // Get sound reference
3924 std::map<s32, ServerPlayingSound>::iterator i =
3925 m_playing_sounds.find(handle);
3926 if(i == m_playing_sounds.end())
3928 ServerPlayingSound &psound = i->second;
3930 std::ostringstream os(std::ios_base::binary);
3931 writeU16(os, TOCLIENT_STOP_SOUND);
3932 writeS32(os, handle);
3934 std::string s = os.str();
3935 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3937 for(std::set<u16>::iterator i = psound.clients.begin();
3938 i != psound.clients.end(); i++){
3940 m_con.Send(*i, 0, data, true);
3942 // Remove sound reference
3943 m_playing_sounds.erase(i);
3946 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3947 core::list<u16> *far_players, float far_d_nodes)
3949 float maxd = far_d_nodes*BS;
3950 v3f p_f = intToFloat(p, BS);
3954 SharedBuffer<u8> reply(replysize);
3955 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3956 writeS16(&reply[2], p.X);
3957 writeS16(&reply[4], p.Y);
3958 writeS16(&reply[6], p.Z);
3960 for(core::map<u16, RemoteClient*>::Iterator
3961 i = m_clients.getIterator();
3962 i.atEnd() == false; i++)
3964 // Get client and check that it is valid
3965 RemoteClient *client = i.getNode()->getValue();
3966 assert(client->peer_id == i.getNode()->getKey());
3967 if(client->serialization_version == SER_FMT_VER_INVALID)
3970 // Don't send if it's the same one
3971 if(client->peer_id == ignore_id)
3977 Player *player = m_env->getPlayer(client->peer_id);
3980 // If player is far away, only set modified blocks not sent
3981 v3f player_pos = player->getPosition();
3982 if(player_pos.getDistanceFrom(p_f) > maxd)
3984 far_players->push_back(client->peer_id);
3991 m_con.Send(client->peer_id, 0, reply, true);
3995 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3996 core::list<u16> *far_players, float far_d_nodes)
3998 float maxd = far_d_nodes*BS;
3999 v3f p_f = intToFloat(p, BS);
4001 for(core::map<u16, RemoteClient*>::Iterator
4002 i = m_clients.getIterator();
4003 i.atEnd() == false; i++)
4005 // Get client and check that it is valid
4006 RemoteClient *client = i.getNode()->getValue();
4007 assert(client->peer_id == i.getNode()->getKey());
4008 if(client->serialization_version == SER_FMT_VER_INVALID)
4011 // Don't send if it's the same one
4012 if(client->peer_id == ignore_id)
4018 Player *player = m_env->getPlayer(client->peer_id);
4021 // If player is far away, only set modified blocks not sent
4022 v3f player_pos = player->getPosition();
4023 if(player_pos.getDistanceFrom(p_f) > maxd)
4025 far_players->push_back(client->peer_id);
4032 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4033 SharedBuffer<u8> reply(replysize);
4034 writeU16(&reply[0], TOCLIENT_ADDNODE);
4035 writeS16(&reply[2], p.X);
4036 writeS16(&reply[4], p.Y);
4037 writeS16(&reply[6], p.Z);
4038 n.serialize(&reply[8], client->serialization_version);
4041 m_con.Send(client->peer_id, 0, reply, true);
4045 void Server::setBlockNotSent(v3s16 p)
4047 for(core::map<u16, RemoteClient*>::Iterator
4048 i = m_clients.getIterator();
4049 i.atEnd()==false; i++)
4051 RemoteClient *client = i.getNode()->getValue();
4052 client->SetBlockNotSent(p);
4056 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4058 DSTACK(__FUNCTION_NAME);
4060 v3s16 p = block->getPos();
4064 bool completely_air = true;
4065 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4066 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4067 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4069 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4071 completely_air = false;
4072 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4077 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4079 infostream<<"[completely air] ";
4080 infostream<<std::endl;
4084 Create a packet with the block in the right format
4087 std::ostringstream os(std::ios_base::binary);
4088 block->serialize(os, ver, false);
4089 std::string s = os.str();
4090 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4092 u32 replysize = 8 + blockdata.getSize();
4093 SharedBuffer<u8> reply(replysize);
4094 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4095 writeS16(&reply[2], p.X);
4096 writeS16(&reply[4], p.Y);
4097 writeS16(&reply[6], p.Z);
4098 memcpy(&reply[8], *blockdata, blockdata.getSize());
4100 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4101 <<": \tpacket size: "<<replysize<<std::endl;*/
4106 m_con.Send(peer_id, 1, reply, true);
4109 void Server::SendBlocks(float dtime)
4111 DSTACK(__FUNCTION_NAME);
4113 JMutexAutoLock envlock(m_env_mutex);
4114 JMutexAutoLock conlock(m_con_mutex);
4116 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4118 core::array<PrioritySortedBlockTransfer> queue;
4120 s32 total_sending = 0;
4123 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4125 for(core::map<u16, RemoteClient*>::Iterator
4126 i = m_clients.getIterator();
4127 i.atEnd() == false; i++)
4129 RemoteClient *client = i.getNode()->getValue();
4130 assert(client->peer_id == i.getNode()->getKey());
4132 // If definitions and textures have not been sent, don't
4133 // send MapBlocks either
4134 if(!client->definitions_sent)
4137 total_sending += client->SendingCount();
4139 if(client->serialization_version == SER_FMT_VER_INVALID)
4142 client->GetNextBlocks(this, dtime, queue);
4147 // Lowest priority number comes first.
4148 // Lowest is most important.
4151 for(u32 i=0; i<queue.size(); i++)
4153 //TODO: Calculate limit dynamically
4154 if(total_sending >= g_settings->getS32
4155 ("max_simultaneous_block_sends_server_total"))
4158 PrioritySortedBlockTransfer q = queue[i];
4160 MapBlock *block = NULL;
4163 block = m_env->getMap().getBlockNoCreate(q.pos);
4165 catch(InvalidPositionException &e)
4170 RemoteClient *client = getClient(q.peer_id);
4172 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4174 client->SentBlock(q.pos);
4180 void Server::fillMediaCache()
4182 DSTACK(__FUNCTION_NAME);
4184 infostream<<"Server: Calculating media file checksums"<<std::endl;
4186 // Collect all media file paths
4187 std::list<std::string> paths;
4188 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4189 i != m_mods.end(); i++){
4190 const ModSpec &mod = *i;
4191 paths.push_back(mod.path + DIR_DELIM + "textures");
4192 paths.push_back(mod.path + DIR_DELIM + "sounds");
4193 paths.push_back(mod.path + DIR_DELIM + "media");
4194 paths.push_back(mod.path + DIR_DELIM + "models");
4196 std::string path_all = "textures";
4197 paths.push_back(path_all + DIR_DELIM + "all");
4199 // Collect media file information from paths into cache
4200 for(std::list<std::string>::iterator i = paths.begin();
4201 i != paths.end(); i++)
4203 std::string mediapath = *i;
4204 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4205 for(u32 j=0; j<dirlist.size(); j++){
4206 if(dirlist[j].dir) // Ignode dirs
4208 std::string filename = dirlist[j].name;
4209 // If name contains illegal characters, ignore the file
4210 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4211 infostream<<"Server: ignoring illegal file name: \""
4212 <<filename<<"\""<<std::endl;
4215 // If name is not in a supported format, ignore it
4216 const char *supported_ext[] = {
4217 ".png", ".jpg", ".bmp", ".tga",
4218 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4220 ".x", ".b3d", ".md2", ".obj",
4223 if(removeStringEnd(filename, supported_ext) == ""){
4224 infostream<<"Server: ignoring unsupported file extension: \""
4225 <<filename<<"\""<<std::endl;
4228 // Ok, attempt to load the file and add to cache
4229 std::string filepath = mediapath + DIR_DELIM + filename;
4231 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4232 if(fis.good() == false){
4233 errorstream<<"Server::fillMediaCache(): Could not open \""
4234 <<filename<<"\" for reading"<<std::endl;
4237 std::ostringstream tmp_os(std::ios_base::binary);
4241 fis.read(buf, 1024);
4242 std::streamsize len = fis.gcount();
4243 tmp_os.write(buf, len);
4252 errorstream<<"Server::fillMediaCache(): Failed to read \""
4253 <<filename<<"\""<<std::endl;
4256 if(tmp_os.str().length() == 0){
4257 errorstream<<"Server::fillMediaCache(): Empty file \""
4258 <<filepath<<"\""<<std::endl;
4263 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4265 unsigned char *digest = sha1.getDigest();
4266 std::string sha1_base64 = base64_encode(digest, 20);
4267 std::string sha1_hex = hex_encode((char*)digest, 20);
4271 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4272 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4277 struct SendableMediaAnnouncement
4280 std::string sha1_digest;
4282 SendableMediaAnnouncement(const std::string name_="",
4283 const std::string sha1_digest_=""):
4285 sha1_digest(sha1_digest_)
4289 void Server::sendMediaAnnouncement(u16 peer_id)
4291 DSTACK(__FUNCTION_NAME);
4293 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4296 core::list<SendableMediaAnnouncement> file_announcements;
4298 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4299 i != m_media.end(); i++){
4301 file_announcements.push_back(
4302 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4306 std::ostringstream os(std::ios_base::binary);
4314 u16 length of sha1_digest
4319 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4320 writeU16(os, file_announcements.size());
4322 for(core::list<SendableMediaAnnouncement>::Iterator
4323 j = file_announcements.begin();
4324 j != file_announcements.end(); j++){
4325 os<<serializeString(j->name);
4326 os<<serializeString(j->sha1_digest);
4328 os<<serializeString(g_settings->get("remote_media"));
4331 std::string s = os.str();
4332 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4335 m_con.Send(peer_id, 0, data, true);
4338 struct SendableMedia
4344 SendableMedia(const std::string &name_="", const std::string path_="",
4345 const std::string &data_=""):
4352 void Server::sendRequestedMedia(u16 peer_id,
4353 const core::list<MediaRequest> &tosend)
4355 DSTACK(__FUNCTION_NAME);
4357 verbosestream<<"Server::sendRequestedMedia(): "
4358 <<"Sending files to client"<<std::endl;
4362 // Put 5kB in one bunch (this is not accurate)
4363 u32 bytes_per_bunch = 5000;
4365 core::array< core::list<SendableMedia> > file_bunches;
4366 file_bunches.push_back(core::list<SendableMedia>());
4368 u32 file_size_bunch_total = 0;
4370 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4371 i != tosend.end(); i++)
4373 if(m_media.find(i->name) == m_media.end()){
4374 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4375 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4379 //TODO get path + name
4380 std::string tpath = m_media[(*i).name].path;
4383 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4384 if(fis.good() == false){
4385 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4386 <<tpath<<"\" for reading"<<std::endl;
4389 std::ostringstream tmp_os(std::ios_base::binary);
4393 fis.read(buf, 1024);
4394 std::streamsize len = fis.gcount();
4395 tmp_os.write(buf, len);
4396 file_size_bunch_total += len;
4405 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4406 <<(*i).name<<"\""<<std::endl;
4409 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4410 <<tname<<"\""<<std::endl;*/
4412 file_bunches[file_bunches.size()-1].push_back(
4413 SendableMedia((*i).name, tpath, tmp_os.str()));
4415 // Start next bunch if got enough data
4416 if(file_size_bunch_total >= bytes_per_bunch){
4417 file_bunches.push_back(core::list<SendableMedia>());
4418 file_size_bunch_total = 0;
4423 /* Create and send packets */
4425 u32 num_bunches = file_bunches.size();
4426 for(u32 i=0; i<num_bunches; i++)
4428 std::ostringstream os(std::ios_base::binary);
4432 u16 total number of texture bunches
4433 u16 index of this bunch
4434 u32 number of files in this bunch
4443 writeU16(os, TOCLIENT_MEDIA);
4444 writeU16(os, num_bunches);
4446 writeU32(os, file_bunches[i].size());
4448 for(core::list<SendableMedia>::Iterator
4449 j = file_bunches[i].begin();
4450 j != file_bunches[i].end(); j++){
4451 os<<serializeString(j->name);
4452 os<<serializeLongString(j->data);
4456 std::string s = os.str();
4457 verbosestream<<"Server::sendRequestedMedia(): bunch "
4458 <<i<<"/"<<num_bunches
4459 <<" files="<<file_bunches[i].size()
4460 <<" size=" <<s.size()<<std::endl;
4461 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4463 m_con.Send(peer_id, 0, data, true);
4467 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4469 if(m_detached_inventories.count(name) == 0){
4470 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4473 Inventory *inv = m_detached_inventories[name];
4475 std::ostringstream os(std::ios_base::binary);
4476 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4477 os<<serializeString(name);
4481 std::string s = os.str();
4482 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4484 m_con.Send(peer_id, 0, data, true);
4487 void Server::sendDetachedInventoryToAll(const std::string &name)
4489 DSTACK(__FUNCTION_NAME);
4491 for(core::map<u16, RemoteClient*>::Iterator
4492 i = m_clients.getIterator();
4493 i.atEnd() == false; i++){
4494 RemoteClient *client = i.getNode()->getValue();
4495 sendDetachedInventory(name, client->peer_id);
4499 void Server::sendDetachedInventories(u16 peer_id)
4501 DSTACK(__FUNCTION_NAME);
4503 for(std::map<std::string, Inventory*>::iterator
4504 i = m_detached_inventories.begin();
4505 i != m_detached_inventories.end(); i++){
4506 const std::string &name = i->first;
4507 //Inventory *inv = i->second;
4508 sendDetachedInventory(name, peer_id);
4516 void Server::DiePlayer(u16 peer_id)
4518 DSTACK(__FUNCTION_NAME);
4520 PlayerSAO *playersao = getPlayerSAO(peer_id);
4523 infostream<<"Server::DiePlayer(): Player "
4524 <<playersao->getPlayer()->getName()
4525 <<" dies"<<std::endl;
4527 playersao->setHP(0);
4529 // Trigger scripted stuff
4530 scriptapi_on_dieplayer(m_lua, playersao);
4532 SendPlayerHP(peer_id);
4533 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4536 void Server::RespawnPlayer(u16 peer_id)
4538 DSTACK(__FUNCTION_NAME);
4540 PlayerSAO *playersao = getPlayerSAO(peer_id);
4543 infostream<<"Server::RespawnPlayer(): Player "
4544 <<playersao->getPlayer()->getName()
4545 <<" respawns"<<std::endl;
4547 playersao->setHP(PLAYER_MAX_HP);
4549 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4551 v3f pos = findSpawnPos(m_env->getServerMap());
4552 playersao->setPos(pos);
4556 void Server::UpdateCrafting(u16 peer_id)
4558 DSTACK(__FUNCTION_NAME);
4560 Player* player = m_env->getPlayer(peer_id);
4563 // Get a preview for crafting
4565 getCraftingResult(&player->inventory, preview, false, this);
4567 // Put the new preview in
4568 InventoryList *plist = player->inventory.getList("craftpreview");
4570 assert(plist->getSize() >= 1);
4571 plist->changeItem(0, preview);
4574 RemoteClient* Server::getClient(u16 peer_id)
4576 DSTACK(__FUNCTION_NAME);
4577 //JMutexAutoLock lock(m_con_mutex);
4578 core::map<u16, RemoteClient*>::Node *n;
4579 n = m_clients.find(peer_id);
4580 // A client should exist for all peers
4582 return n->getValue();
4585 std::wstring Server::getStatusString()
4587 std::wostringstream os(std::ios_base::binary);
4590 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4592 os<<L", uptime="<<m_uptime.get();
4593 // Information about clients
4594 core::map<u16, RemoteClient*>::Iterator i;
4597 for(i = m_clients.getIterator(), first = true;
4598 i.atEnd() == false; i++)
4600 // Get client and check that it is valid
4601 RemoteClient *client = i.getNode()->getValue();
4602 assert(client->peer_id == i.getNode()->getKey());
4603 if(client->serialization_version == SER_FMT_VER_INVALID)
4606 Player *player = m_env->getPlayer(client->peer_id);
4607 // Get name of player
4608 std::wstring name = L"unknown";
4610 name = narrow_to_wide(player->getName());
4611 // Add name to information string
4619 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4620 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4621 if(g_settings->get("motd") != "")
4622 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4626 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4628 std::set<std::string> privs;
4629 scriptapi_get_auth(m_lua, name, NULL, &privs);
4633 bool Server::checkPriv(const std::string &name, const std::string &priv)
4635 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4636 return (privs.count(priv) != 0);
4639 void Server::reportPrivsModified(const std::string &name)
4642 for(core::map<u16, RemoteClient*>::Iterator
4643 i = m_clients.getIterator();
4644 i.atEnd() == false; i++){
4645 RemoteClient *client = i.getNode()->getValue();
4646 Player *player = m_env->getPlayer(client->peer_id);
4647 reportPrivsModified(player->getName());
4650 Player *player = m_env->getPlayer(name.c_str());
4653 SendPlayerPrivileges(player->peer_id);
4654 PlayerSAO *sao = player->getPlayerSAO();
4657 sao->updatePrivileges(
4658 getPlayerEffectivePrivs(name),
4663 void Server::reportInventoryFormspecModified(const std::string &name)
4665 Player *player = m_env->getPlayer(name.c_str());
4668 SendPlayerInventoryFormspec(player->peer_id);
4671 // Saves g_settings to configpath given at initialization
4672 void Server::saveConfig()
4674 if(m_path_config != "")
4675 g_settings->updateConfigFile(m_path_config.c_str());
4678 void Server::notifyPlayer(const char *name, const std::wstring msg)
4680 Player *player = m_env->getPlayer(name);
4683 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4686 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4688 Player *player = m_env->getPlayer(playername);
4692 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4696 SendShowFormspecMessage(player->peer_id, formspec, formname);
4700 void Server::notifyPlayers(const std::wstring msg)
4702 BroadcastChatMessage(msg);
4705 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4709 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4710 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4713 Inventory* Server::createDetachedInventory(const std::string &name)
4715 if(m_detached_inventories.count(name) > 0){
4716 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4717 delete m_detached_inventories[name];
4719 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4721 Inventory *inv = new Inventory(m_itemdef);
4723 m_detached_inventories[name] = inv;
4724 sendDetachedInventoryToAll(name);
4731 BoolScopeSet(bool *dst, bool val):
4734 m_orig_state = *m_dst;
4739 *m_dst = m_orig_state;
4746 // actions: time-reversed list
4747 // Return value: success/failure
4748 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4749 std::list<std::string> *log)
4751 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4752 ServerMap *map = (ServerMap*)(&m_env->getMap());
4753 // Disable rollback report sink while reverting
4754 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4756 // Fail if no actions to handle
4757 if(actions.empty()){
4758 log->push_back("Nothing to do.");
4765 for(std::list<RollbackAction>::const_iterator
4766 i = actions.begin();
4767 i != actions.end(); i++)
4769 const RollbackAction &action = *i;
4771 bool success = action.applyRevert(map, this, this);
4774 std::ostringstream os;
4775 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4776 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4778 log->push_back(os.str());
4780 std::ostringstream os;
4781 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4782 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4784 log->push_back(os.str());
4788 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4789 <<" failed"<<std::endl;
4791 // Call it done if less than half failed
4792 return num_failed <= num_tried/2;
4795 // IGameDef interface
4797 IItemDefManager* Server::getItemDefManager()
4801 INodeDefManager* Server::getNodeDefManager()
4805 ICraftDefManager* Server::getCraftDefManager()
4809 ITextureSource* Server::getTextureSource()
4813 IShaderSource* Server::getShaderSource()
4817 u16 Server::allocateUnknownNodeId(const std::string &name)
4819 return m_nodedef->allocateDummy(name);
4821 ISoundManager* Server::getSoundManager()
4823 return &dummySoundManager;
4825 MtEventManager* Server::getEventManager()
4829 IRollbackReportSink* Server::getRollbackReportSink()
4831 if(!m_enable_rollback_recording)
4833 if(!m_rollback_sink_enabled)
4838 IWritableItemDefManager* Server::getWritableItemDefManager()
4842 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4846 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4851 const ModSpec* Server::getModSpec(const std::string &modname)
4853 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4854 i != m_mods.end(); i++){
4855 const ModSpec &mod = *i;
4856 if(mod.name == modname)
4861 void Server::getModNames(core::list<std::string> &modlist)
4863 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4865 modlist.push_back((*i).name);
4868 std::string Server::getBuiltinLuaPath()
4870 return porting::path_share + DIR_DELIM + "builtin";
4873 v3f findSpawnPos(ServerMap &map)
4875 //return v3f(50,50,50)*BS;
4880 nodepos = v2s16(0,0);
4885 s16 water_level = map.m_mgparams->water_level;
4887 // Try to find a good place a few times
4888 for(s32 i=0; i<1000; i++)
4891 // We're going to try to throw the player to this position
4892 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4893 -range + (myrand()%(range*2)));
4894 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4895 // Get ground height at point (fallbacks to heightmap function)
4896 s16 groundheight = map.findGroundLevel(nodepos2d);
4897 // Don't go underwater
4898 if(groundheight <= water_level)
4900 //infostream<<"-> Underwater"<<std::endl;
4903 // Don't go to high places
4904 if(groundheight > water_level + 6)
4906 //infostream<<"-> Underwater"<<std::endl;
4910 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4911 bool is_good = false;
4913 for(s32 i=0; i<10; i++){
4914 v3s16 blockpos = getNodeBlockPos(nodepos);
4915 map.emergeBlock(blockpos, true);
4916 MapNode n = map.getNodeNoEx(nodepos);
4917 if(n.getContent() == CONTENT_AIR){
4928 // Found a good place
4929 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4935 return intToFloat(nodepos, BS);
4938 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4940 RemotePlayer *player = NULL;
4941 bool newplayer = false;
4944 Try to get an existing player
4946 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4948 // If player is already connected, cancel
4949 if(player != NULL && player->peer_id != 0)
4951 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4956 If player with the wanted peer_id already exists, cancel.
4958 if(m_env->getPlayer(peer_id) != NULL)
4960 infostream<<"emergePlayer(): Player with wrong name but same"
4961 " peer_id already exists"<<std::endl;
4966 Create a new player if it doesn't exist yet
4971 player = new RemotePlayer(this);
4972 player->updateName(name);
4974 /* Set player position */
4975 infostream<<"Server: Finding spawn place for player \""
4976 <<name<<"\""<<std::endl;
4977 v3f pos = findSpawnPos(m_env->getServerMap());
4978 player->setPosition(pos);
4980 /* Add player to environment */
4981 m_env->addPlayer(player);
4985 Create a new player active object
4987 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4988 getPlayerEffectivePrivs(player->getName()),
4991 /* Add object to environment */
4992 m_env->addActiveObject(playersao);
4996 scriptapi_on_newplayer(m_lua, playersao);
4998 scriptapi_on_joinplayer(m_lua, playersao);
5003 void Server::handlePeerChange(PeerChange &c)
5005 JMutexAutoLock envlock(m_env_mutex);
5006 JMutexAutoLock conlock(m_con_mutex);
5008 if(c.type == PEER_ADDED)
5015 core::map<u16, RemoteClient*>::Node *n;
5016 n = m_clients.find(c.peer_id);
5017 // The client shouldn't already exist
5021 RemoteClient *client = new RemoteClient();
5022 client->peer_id = c.peer_id;
5023 m_clients.insert(client->peer_id, client);
5026 else if(c.type == PEER_REMOVED)
5033 core::map<u16, RemoteClient*>::Node *n;
5034 n = m_clients.find(c.peer_id);
5035 // The client should exist
5039 Mark objects to be not known by the client
5041 RemoteClient *client = n->getValue();
5043 for(core::map<u16, bool>::Iterator
5044 i = client->m_known_objects.getIterator();
5045 i.atEnd()==false; i++)
5048 u16 id = i.getNode()->getKey();
5049 ServerActiveObject* obj = m_env->getActiveObject(id);
5051 if(obj && obj->m_known_by_count > 0)
5052 obj->m_known_by_count--;
5056 Clear references to playing sounds
5058 for(std::map<s32, ServerPlayingSound>::iterator
5059 i = m_playing_sounds.begin();
5060 i != m_playing_sounds.end();)
5062 ServerPlayingSound &psound = i->second;
5063 psound.clients.erase(c.peer_id);
5064 if(psound.clients.size() == 0)
5065 m_playing_sounds.erase(i++);
5070 Player *player = m_env->getPlayer(c.peer_id);
5072 // Collect information about leaving in chat
5073 std::wstring message;
5077 std::wstring name = narrow_to_wide(player->getName());
5080 message += L" left the game.";
5082 message += L" (timed out)";
5086 /* Run scripts and remove from environment */
5090 PlayerSAO *playersao = player->getPlayerSAO();
5093 scriptapi_on_leaveplayer(m_lua, playersao);
5095 playersao->disconnected();
5105 std::ostringstream os(std::ios_base::binary);
5106 for(core::map<u16, RemoteClient*>::Iterator
5107 i = m_clients.getIterator();
5108 i.atEnd() == false; i++)
5110 RemoteClient *client = i.getNode()->getValue();
5111 assert(client->peer_id == i.getNode()->getKey());
5112 if(client->serialization_version == SER_FMT_VER_INVALID)
5115 Player *player = m_env->getPlayer(client->peer_id);
5118 // Get name of player
5119 os<<player->getName()<<" ";
5122 actionstream<<player->getName()<<" "
5123 <<(c.timeout?"times out.":"leaves game.")
5124 <<" List of players: "
5125 <<os.str()<<std::endl;
5130 delete m_clients[c.peer_id];
5131 m_clients.remove(c.peer_id);
5133 // Send player info to all remaining clients
5134 //SendPlayerInfos();
5136 // Send leave chat message to all remaining clients
5137 if(message.length() != 0)
5138 BroadcastChatMessage(message);
5147 void Server::handlePeerChanges()
5149 while(m_peer_change_queue.size() > 0)
5151 PeerChange c = m_peer_change_queue.pop_front();
5153 verbosestream<<"Server: Handling peer change: "
5154 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5157 handlePeerChange(c);
5161 void dedicated_server_loop(Server &server, bool &kill)
5163 DSTACK(__FUNCTION_NAME);
5165 verbosestream<<"dedicated_server_loop()"<<std::endl;
5167 IntervalLimiter m_profiler_interval;
5171 float steplen = g_settings->getFloat("dedicated_server_step");
5172 // This is kind of a hack but can be done like this
5173 // because server.step() is very light
5175 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5176 sleep_ms((int)(steplen*1000.0));
5178 server.step(steplen);
5180 if(server.getShutdownRequested() || kill)
5182 infostream<<"Dedicated server quitting"<<std::endl;
5189 float profiler_print_interval =
5190 g_settings->getFloat("profiler_print_interval");
5191 if(profiler_print_interval != 0)
5193 if(m_profiler_interval.step(steplen, profiler_print_interval))
5195 infostream<<"Profiler:"<<std::endl;
5196 g_profiler->print(infostream);
5197 g_profiler->clear();