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 // Initialize Environment
1101 ServerMap *servermap = new ServerMap(path_world, this);
1102 m_env = new ServerEnvironment(servermap, m_lua, this, this);
1104 // Create emerge manager
1105 m_emerge = new EmergeManager(this, m_biomedef, servermap->getMapgenParams());
1107 // Give map pointer to the emerge manager
1108 servermap->setEmerge(m_emerge);
1110 // Give environment reference to scripting api
1111 scriptapi_add_environment(m_lua, m_env);
1113 // Register us to receive map edit events
1114 servermap->addEventReceiver(this);
1116 // If file exists, load environment metadata
1117 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1119 infostream<<"Server: Loading environment metadata"<<std::endl;
1120 m_env->loadMeta(m_path_world);
1124 infostream<<"Server: Loading players"<<std::endl;
1125 m_env->deSerializePlayers(m_path_world);
1128 Add some test ActiveBlockModifiers to environment
1130 add_legacy_abms(m_env, m_nodedef);
1135 infostream<<"Server destructing"<<std::endl;
1138 Send shutdown message
1141 JMutexAutoLock conlock(m_con_mutex);
1143 std::wstring line = L"*** Server shutting down";
1146 Send the message to clients
1148 for(core::map<u16, RemoteClient*>::Iterator
1149 i = m_clients.getIterator();
1150 i.atEnd() == false; i++)
1152 // Get client and check that it is valid
1153 RemoteClient *client = i.getNode()->getValue();
1154 assert(client->peer_id == i.getNode()->getKey());
1155 if(client->serialization_version == SER_FMT_VER_INVALID)
1159 SendChatMessage(client->peer_id, line);
1161 catch(con::PeerNotFoundException &e)
1167 JMutexAutoLock envlock(m_env_mutex);
1168 JMutexAutoLock conlock(m_con_mutex);
1171 Execute script shutdown hooks
1173 scriptapi_on_shutdown(m_lua);
1177 JMutexAutoLock envlock(m_env_mutex);
1182 infostream<<"Server: Saving players"<<std::endl;
1183 m_env->serializePlayers(m_path_world);
1186 Save environment metadata
1188 infostream<<"Server: Saving environment metadata"<<std::endl;
1189 m_env->saveMeta(m_path_world);
1201 JMutexAutoLock clientslock(m_con_mutex);
1203 for(core::map<u16, RemoteClient*>::Iterator
1204 i = m_clients.getIterator();
1205 i.atEnd() == false; i++)
1209 delete i.getNode()->getValue();
1213 // Delete things in the reverse order of creation
1222 // Deinitialize scripting
1223 infostream<<"Server: Deinitializing scripting"<<std::endl;
1224 script_deinit(m_lua);
1226 // Delete detached inventories
1228 for(std::map<std::string, Inventory*>::iterator
1229 i = m_detached_inventories.begin();
1230 i != m_detached_inventories.end(); i++){
1236 void Server::start(unsigned short port)
1238 DSTACK(__FUNCTION_NAME);
1239 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1241 // Stop thread if already running
1244 // Initialize connection
1245 m_con.SetTimeoutMs(30);
1249 m_thread.setRun(true);
1252 // ASCII art for the win!
1254 <<" .__ __ __ "<<std::endl
1255 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1256 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1257 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1258 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1259 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1260 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1261 actionstream<<"Server for gameid=\""<<m_gamespec.id
1262 <<"\" listening on port "<<port<<"."<<std::endl;
1267 DSTACK(__FUNCTION_NAME);
1269 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1271 // Stop threads (set run=false first so both start stopping)
1272 m_thread.setRun(false);
1273 m_emergethread.setRun(false);
1275 m_emergethread.stop();
1277 infostream<<"Server: Threads stopped"<<std::endl;
1280 void Server::step(float dtime)
1282 DSTACK(__FUNCTION_NAME);
1287 JMutexAutoLock lock(m_step_dtime_mutex);
1288 m_step_dtime += dtime;
1290 // Throw if fatal error occurred in thread
1291 std::string async_err = m_async_fatal_error.get();
1292 if(async_err != ""){
1293 throw ServerError(async_err);
1297 void Server::AsyncRunStep()
1299 DSTACK(__FUNCTION_NAME);
1301 g_profiler->add("Server::AsyncRunStep (num)", 1);
1305 JMutexAutoLock lock1(m_step_dtime_mutex);
1306 dtime = m_step_dtime;
1310 // Send blocks to clients
1317 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1319 //infostream<<"Server steps "<<dtime<<std::endl;
1320 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1323 JMutexAutoLock lock1(m_step_dtime_mutex);
1324 m_step_dtime -= dtime;
1331 m_uptime.set(m_uptime.get() + dtime);
1335 // Process connection's timeouts
1336 JMutexAutoLock lock2(m_con_mutex);
1337 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1338 m_con.RunTimeouts(dtime);
1342 // This has to be called so that the client list gets synced
1343 // with the peer list of the connection
1344 handlePeerChanges();
1348 Update time of day and overall game time
1351 JMutexAutoLock envlock(m_env_mutex);
1353 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1356 Send to clients at constant intervals
1359 m_time_of_day_send_timer -= dtime;
1360 if(m_time_of_day_send_timer < 0.0)
1362 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1364 //JMutexAutoLock envlock(m_env_mutex);
1365 JMutexAutoLock conlock(m_con_mutex);
1367 for(core::map<u16, RemoteClient*>::Iterator
1368 i = m_clients.getIterator();
1369 i.atEnd() == false; i++)
1371 RemoteClient *client = i.getNode()->getValue();
1372 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1373 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1375 m_con.Send(client->peer_id, 0, data, true);
1381 JMutexAutoLock lock(m_env_mutex);
1383 ScopeProfiler sp(g_profiler, "SEnv step");
1384 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1388 const float map_timer_and_unload_dtime = 2.92;
1389 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1391 JMutexAutoLock lock(m_env_mutex);
1392 // Run Map's timers and unload unused data
1393 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1394 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1395 g_settings->getFloat("server_unload_unused_data_timeout"));
1406 JMutexAutoLock lock(m_env_mutex);
1407 JMutexAutoLock lock2(m_con_mutex);
1409 ScopeProfiler sp(g_profiler, "Server: handle players");
1411 for(core::map<u16, RemoteClient*>::Iterator
1412 i = m_clients.getIterator();
1413 i.atEnd() == false; i++)
1415 RemoteClient *client = i.getNode()->getValue();
1416 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1417 if(playersao == NULL)
1421 Handle player HPs (die if hp=0)
1423 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1425 if(playersao->getHP() == 0)
1426 DiePlayer(client->peer_id);
1428 SendPlayerHP(client->peer_id);
1432 Send player inventories if necessary
1434 if(playersao->m_moved){
1435 SendMovePlayer(client->peer_id);
1436 playersao->m_moved = false;
1438 if(playersao->m_inventory_not_sent){
1439 UpdateCrafting(client->peer_id);
1440 SendInventory(client->peer_id);
1445 /* Transform liquids */
1446 m_liquid_transform_timer += dtime;
1447 if(m_liquid_transform_timer >= 1.00)
1449 m_liquid_transform_timer -= 1.00;
1451 JMutexAutoLock lock(m_env_mutex);
1453 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1455 core::map<v3s16, MapBlock*> modified_blocks;
1456 m_env->getMap().transformLiquids(modified_blocks);
1461 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1462 ServerMap &map = ((ServerMap&)m_env->getMap());
1463 map.updateLighting(modified_blocks, lighting_modified_blocks);
1465 // Add blocks modified by lighting to modified_blocks
1466 for(core::map<v3s16, MapBlock*>::Iterator
1467 i = lighting_modified_blocks.getIterator();
1468 i.atEnd() == false; i++)
1470 MapBlock *block = i.getNode()->getValue();
1471 modified_blocks.insert(block->getPos(), block);
1475 Set the modified blocks unsent for all the clients
1478 JMutexAutoLock lock2(m_con_mutex);
1480 for(core::map<u16, RemoteClient*>::Iterator
1481 i = m_clients.getIterator();
1482 i.atEnd() == false; i++)
1484 RemoteClient *client = i.getNode()->getValue();
1486 if(modified_blocks.size() > 0)
1488 // Remove block from sent history
1489 client->SetBlocksNotSent(modified_blocks);
1494 // Periodically print some info
1496 float &counter = m_print_info_timer;
1502 JMutexAutoLock lock2(m_con_mutex);
1504 if(m_clients.size() != 0)
1505 infostream<<"Players:"<<std::endl;
1506 for(core::map<u16, RemoteClient*>::Iterator
1507 i = m_clients.getIterator();
1508 i.atEnd() == false; i++)
1510 //u16 peer_id = i.getNode()->getKey();
1511 RemoteClient *client = i.getNode()->getValue();
1512 Player *player = m_env->getPlayer(client->peer_id);
1515 infostream<<"* "<<player->getName()<<"\t";
1516 client->PrintInfo(infostream);
1521 //if(g_settings->getBool("enable_experimental"))
1525 Check added and deleted active objects
1528 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1529 JMutexAutoLock envlock(m_env_mutex);
1530 JMutexAutoLock conlock(m_con_mutex);
1532 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1534 // Radius inside which objects are active
1535 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1536 radius *= MAP_BLOCKSIZE;
1538 for(core::map<u16, RemoteClient*>::Iterator
1539 i = m_clients.getIterator();
1540 i.atEnd() == false; i++)
1542 RemoteClient *client = i.getNode()->getValue();
1544 // If definitions and textures have not been sent, don't
1545 // send objects either
1546 if(!client->definitions_sent)
1549 Player *player = m_env->getPlayer(client->peer_id);
1552 // This can happen if the client timeouts somehow
1553 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1555 <<" has no associated player"<<std::endl;*/
1558 v3s16 pos = floatToInt(player->getPosition(), BS);
1560 core::map<u16, bool> removed_objects;
1561 core::map<u16, bool> added_objects;
1562 m_env->getRemovedActiveObjects(pos, radius,
1563 client->m_known_objects, removed_objects);
1564 m_env->getAddedActiveObjects(pos, radius,
1565 client->m_known_objects, added_objects);
1567 // Ignore if nothing happened
1568 if(removed_objects.size() == 0 && added_objects.size() == 0)
1570 //infostream<<"active objects: none changed"<<std::endl;
1574 std::string data_buffer;
1578 // Handle removed objects
1579 writeU16((u8*)buf, removed_objects.size());
1580 data_buffer.append(buf, 2);
1581 for(core::map<u16, bool>::Iterator
1582 i = removed_objects.getIterator();
1583 i.atEnd()==false; i++)
1586 u16 id = i.getNode()->getKey();
1587 ServerActiveObject* obj = m_env->getActiveObject(id);
1589 // Add to data buffer for sending
1590 writeU16((u8*)buf, i.getNode()->getKey());
1591 data_buffer.append(buf, 2);
1593 // Remove from known objects
1594 client->m_known_objects.remove(i.getNode()->getKey());
1596 if(obj && obj->m_known_by_count > 0)
1597 obj->m_known_by_count--;
1600 // Handle added objects
1601 writeU16((u8*)buf, added_objects.size());
1602 data_buffer.append(buf, 2);
1603 for(core::map<u16, bool>::Iterator
1604 i = added_objects.getIterator();
1605 i.atEnd()==false; i++)
1608 u16 id = i.getNode()->getKey();
1609 ServerActiveObject* obj = m_env->getActiveObject(id);
1612 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1614 infostream<<"WARNING: "<<__FUNCTION_NAME
1615 <<": NULL object"<<std::endl;
1617 type = obj->getSendType();
1619 // Add to data buffer for sending
1620 writeU16((u8*)buf, id);
1621 data_buffer.append(buf, 2);
1622 writeU8((u8*)buf, type);
1623 data_buffer.append(buf, 1);
1626 data_buffer.append(serializeLongString(
1627 obj->getClientInitializationData(client->net_proto_version)));
1629 data_buffer.append(serializeLongString(""));
1631 // Add to known objects
1632 client->m_known_objects.insert(i.getNode()->getKey(), false);
1635 obj->m_known_by_count++;
1639 SharedBuffer<u8> reply(2 + data_buffer.size());
1640 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1641 memcpy((char*)&reply[2], data_buffer.c_str(),
1642 data_buffer.size());
1644 m_con.Send(client->peer_id, 0, reply, true);
1646 verbosestream<<"Server: Sent object remove/add: "
1647 <<removed_objects.size()<<" removed, "
1648 <<added_objects.size()<<" added, "
1649 <<"packet size is "<<reply.getSize()<<std::endl;
1654 Collect a list of all the objects known by the clients
1655 and report it back to the environment.
1658 core::map<u16, bool> all_known_objects;
1660 for(core::map<u16, RemoteClient*>::Iterator
1661 i = m_clients.getIterator();
1662 i.atEnd() == false; i++)
1664 RemoteClient *client = i.getNode()->getValue();
1665 // Go through all known objects of client
1666 for(core::map<u16, bool>::Iterator
1667 i = client->m_known_objects.getIterator();
1668 i.atEnd()==false; i++)
1670 u16 id = i.getNode()->getKey();
1671 all_known_objects[id] = true;
1675 m_env->setKnownActiveObjects(whatever);
1681 Send object messages
1684 JMutexAutoLock envlock(m_env_mutex);
1685 JMutexAutoLock conlock(m_con_mutex);
1687 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1690 // Value = data sent by object
1691 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1693 // Get active object messages from environment
1696 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1700 core::list<ActiveObjectMessage>* message_list = NULL;
1701 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1702 n = buffered_messages.find(aom.id);
1705 message_list = new core::list<ActiveObjectMessage>;
1706 buffered_messages.insert(aom.id, message_list);
1710 message_list = n->getValue();
1712 message_list->push_back(aom);
1715 // Route data to every client
1716 for(core::map<u16, RemoteClient*>::Iterator
1717 i = m_clients.getIterator();
1718 i.atEnd()==false; i++)
1720 RemoteClient *client = i.getNode()->getValue();
1721 std::string reliable_data;
1722 std::string unreliable_data;
1723 // Go through all objects in message buffer
1724 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1725 j = buffered_messages.getIterator();
1726 j.atEnd()==false; j++)
1728 // If object is not known by client, skip it
1729 u16 id = j.getNode()->getKey();
1730 if(client->m_known_objects.find(id) == NULL)
1732 // Get message list of object
1733 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1734 // Go through every message
1735 for(core::list<ActiveObjectMessage>::Iterator
1736 k = list->begin(); k != list->end(); k++)
1738 // Compose the full new data with header
1739 ActiveObjectMessage aom = *k;
1740 std::string new_data;
1743 writeU16((u8*)&buf[0], aom.id);
1744 new_data.append(buf, 2);
1746 new_data += serializeString(aom.datastring);
1747 // Add data to buffer
1749 reliable_data += new_data;
1751 unreliable_data += new_data;
1755 reliable_data and unreliable_data are now ready.
1758 if(reliable_data.size() > 0)
1760 SharedBuffer<u8> reply(2 + reliable_data.size());
1761 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1762 memcpy((char*)&reply[2], reliable_data.c_str(),
1763 reliable_data.size());
1765 m_con.Send(client->peer_id, 0, reply, true);
1767 if(unreliable_data.size() > 0)
1769 SharedBuffer<u8> reply(2 + unreliable_data.size());
1770 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1771 memcpy((char*)&reply[2], unreliable_data.c_str(),
1772 unreliable_data.size());
1773 // Send as unreliable
1774 m_con.Send(client->peer_id, 0, reply, false);
1777 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1779 infostream<<"Server: Size of object message data: "
1780 <<"reliable: "<<reliable_data.size()
1781 <<", unreliable: "<<unreliable_data.size()
1786 // Clear buffered_messages
1787 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1788 i = buffered_messages.getIterator();
1789 i.atEnd()==false; i++)
1791 delete i.getNode()->getValue();
1795 } // enable_experimental
1798 Send queued-for-sending map edit events.
1801 // We will be accessing the environment and the connection
1802 JMutexAutoLock lock(m_env_mutex);
1803 JMutexAutoLock conlock(m_con_mutex);
1805 // Don't send too many at a time
1808 // Single change sending is disabled if queue size is not small
1809 bool disable_single_change_sending = false;
1810 if(m_unsent_map_edit_queue.size() >= 4)
1811 disable_single_change_sending = true;
1813 int event_count = m_unsent_map_edit_queue.size();
1815 // We'll log the amount of each
1818 while(m_unsent_map_edit_queue.size() != 0)
1820 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1822 // Players far away from the change are stored here.
1823 // Instead of sending the changes, MapBlocks are set not sent
1825 core::list<u16> far_players;
1827 if(event->type == MEET_ADDNODE)
1829 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1830 prof.add("MEET_ADDNODE", 1);
1831 if(disable_single_change_sending)
1832 sendAddNode(event->p, event->n, event->already_known_by_peer,
1835 sendAddNode(event->p, event->n, event->already_known_by_peer,
1838 else if(event->type == MEET_REMOVENODE)
1840 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1841 prof.add("MEET_REMOVENODE", 1);
1842 if(disable_single_change_sending)
1843 sendRemoveNode(event->p, event->already_known_by_peer,
1846 sendRemoveNode(event->p, event->already_known_by_peer,
1849 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1851 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1852 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1853 setBlockNotSent(event->p);
1855 else if(event->type == MEET_OTHER)
1857 infostream<<"Server: MEET_OTHER"<<std::endl;
1858 prof.add("MEET_OTHER", 1);
1859 for(core::map<v3s16, bool>::Iterator
1860 i = event->modified_blocks.getIterator();
1861 i.atEnd()==false; i++)
1863 v3s16 p = i.getNode()->getKey();
1869 prof.add("unknown", 1);
1870 infostream<<"WARNING: Server: Unknown MapEditEvent "
1871 <<((u32)event->type)<<std::endl;
1875 Set blocks not sent to far players
1877 if(far_players.size() > 0)
1879 // Convert list format to that wanted by SetBlocksNotSent
1880 core::map<v3s16, MapBlock*> modified_blocks2;
1881 for(core::map<v3s16, bool>::Iterator
1882 i = event->modified_blocks.getIterator();
1883 i.atEnd()==false; i++)
1885 v3s16 p = i.getNode()->getKey();
1886 modified_blocks2.insert(p,
1887 m_env->getMap().getBlockNoCreateNoEx(p));
1889 // Set blocks not sent
1890 for(core::list<u16>::Iterator
1891 i = far_players.begin();
1892 i != far_players.end(); i++)
1895 RemoteClient *client = getClient(peer_id);
1898 client->SetBlocksNotSent(modified_blocks2);
1904 /*// Don't send too many at a time
1906 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1910 if(event_count >= 5){
1911 infostream<<"Server: MapEditEvents:"<<std::endl;
1912 prof.print(infostream);
1913 } else if(event_count != 0){
1914 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1915 prof.print(verbosestream);
1921 Trigger emergethread (it somehow gets to a non-triggered but
1922 bysy state sometimes)
1925 float &counter = m_emergethread_trigger_timer;
1931 m_emergethread.trigger();
1933 // Update m_enable_rollback_recording here too
1934 m_enable_rollback_recording =
1935 g_settings->getBool("enable_rollback_recording");
1939 // Save map, players and auth stuff
1941 float &counter = m_savemap_timer;
1943 if(counter >= g_settings->getFloat("server_map_save_interval"))
1946 JMutexAutoLock lock(m_env_mutex);
1948 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1951 if(m_banmanager.isModified())
1952 m_banmanager.save();
1954 // Save changed parts of map
1955 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1958 m_env->serializePlayers(m_path_world);
1960 // Save environment metadata
1961 m_env->saveMeta(m_path_world);
1966 void Server::Receive()
1968 DSTACK(__FUNCTION_NAME);
1969 SharedBuffer<u8> data;
1974 JMutexAutoLock conlock(m_con_mutex);
1975 datasize = m_con.Receive(peer_id, data);
1978 // This has to be called so that the client list gets synced
1979 // with the peer list of the connection
1980 handlePeerChanges();
1982 ProcessData(*data, datasize, peer_id);
1984 catch(con::InvalidIncomingDataException &e)
1986 infostream<<"Server::Receive(): "
1987 "InvalidIncomingDataException: what()="
1988 <<e.what()<<std::endl;
1990 catch(con::PeerNotFoundException &e)
1992 //NOTE: This is not needed anymore
1994 // The peer has been disconnected.
1995 // Find the associated player and remove it.
1997 /*JMutexAutoLock envlock(m_env_mutex);
1999 infostream<<"ServerThread: peer_id="<<peer_id
2000 <<" has apparently closed connection. "
2001 <<"Removing player."<<std::endl;
2003 m_env->removePlayer(peer_id);*/
2007 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
2009 DSTACK(__FUNCTION_NAME);
2010 // Environment is locked first.
2011 JMutexAutoLock envlock(m_env_mutex);
2012 JMutexAutoLock conlock(m_con_mutex);
2014 ScopeProfiler sp(g_profiler, "Server::ProcessData");
2017 Address address = m_con.GetPeerAddress(peer_id);
2018 std::string addr_s = address.serializeString();
2020 // drop player if is ip is banned
2021 if(m_banmanager.isIpBanned(addr_s)){
2022 infostream<<"Server: A banned client tried to connect from "
2023 <<addr_s<<"; banned name was "
2024 <<m_banmanager.getBanName(addr_s)<<std::endl;
2025 // This actually doesn't seem to transfer to the client
2026 SendAccessDenied(m_con, peer_id,
2027 L"Your ip is banned. Banned name was "
2028 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
2029 m_con.DeletePeer(peer_id);
2033 catch(con::PeerNotFoundException &e)
2035 infostream<<"Server::ProcessData(): Cancelling: peer "
2036 <<peer_id<<" not found"<<std::endl;
2040 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
2042 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
2050 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
2052 if(command == TOSERVER_INIT)
2054 // [0] u16 TOSERVER_INIT
2055 // [2] u8 SER_FMT_VER_HIGHEST
2056 // [3] u8[20] player_name
2057 // [23] u8[28] password <--- can be sent without this, from old versions
2059 if(datasize < 2+1+PLAYERNAME_SIZE)
2062 verbosestream<<"Server: Got TOSERVER_INIT from "
2063 <<peer_id<<std::endl;
2065 // First byte after command is maximum supported
2066 // serialization version
2067 u8 client_max = data[2];
2068 u8 our_max = SER_FMT_VER_HIGHEST;
2069 // Use the highest version supported by both
2070 u8 deployed = core::min_(client_max, our_max);
2071 // If it's lower than the lowest supported, give up.
2072 if(deployed < SER_FMT_VER_LOWEST)
2073 deployed = SER_FMT_VER_INVALID;
2075 //peer->serialization_version = deployed;
2076 getClient(peer_id)->pending_serialization_version = deployed;
2078 if(deployed == SER_FMT_VER_INVALID)
2080 actionstream<<"Server: A mismatched client tried to connect from "
2081 <<addr_s<<std::endl;
2082 infostream<<"Server: Cannot negotiate "
2083 "serialization version with peer "
2084 <<peer_id<<std::endl;
2085 SendAccessDenied(m_con, peer_id, std::wstring(
2086 L"Your client's version is not supported.\n"
2087 L"Server version is ")
2088 + narrow_to_wide(VERSION_STRING) + L"."
2094 Read and check network protocol version
2097 u16 min_net_proto_version = 0;
2098 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2099 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2101 // Use same version as minimum and maximum if maximum version field
2102 // doesn't exist (backwards compatibility)
2103 u16 max_net_proto_version = min_net_proto_version;
2104 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
2105 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
2107 // Start with client's maximum version
2108 u16 net_proto_version = max_net_proto_version;
2110 // Figure out a working version if it is possible at all
2111 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
2112 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
2114 // If maximum is larger than our maximum, go with our maximum
2115 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2116 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
2117 // Else go with client's maximum
2119 net_proto_version = max_net_proto_version;
2122 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
2123 <<min_net_proto_version<<", max: "<<max_net_proto_version
2124 <<", chosen: "<<net_proto_version<<std::endl;
2126 getClient(peer_id)->net_proto_version = net_proto_version;
2128 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
2129 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2131 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
2133 SendAccessDenied(m_con, peer_id, std::wstring(
2134 L"Your client's version is not supported.\n"
2135 L"Server version is ")
2136 + narrow_to_wide(VERSION_STRING) + L",\n"
2137 + L"server's PROTOCOL_VERSION is "
2138 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
2140 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
2141 + L", client's PROTOCOL_VERSION is "
2142 + narrow_to_wide(itos(min_net_proto_version))
2144 + narrow_to_wide(itos(max_net_proto_version))
2149 if(g_settings->getBool("strict_protocol_version_checking"))
2151 if(net_proto_version != LATEST_PROTOCOL_VERSION)
2153 actionstream<<"Server: A mismatched (strict) client tried to "
2154 <<"connect from "<<addr_s<<std::endl;
2155 SendAccessDenied(m_con, peer_id, std::wstring(
2156 L"Your client's version is not supported.\n"
2157 L"Server version is ")
2158 + narrow_to_wide(VERSION_STRING) + L",\n"
2159 + L"server's PROTOCOL_VERSION (strict) is "
2160 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
2161 + L", client's PROTOCOL_VERSION is "
2162 + narrow_to_wide(itos(min_net_proto_version))
2164 + narrow_to_wide(itos(max_net_proto_version))
2175 char playername[PLAYERNAME_SIZE];
2176 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2178 playername[i] = data[3+i];
2180 playername[PLAYERNAME_SIZE-1] = 0;
2182 if(playername[0]=='\0')
2184 actionstream<<"Server: Player with an empty name "
2185 <<"tried to connect from "<<addr_s<<std::endl;
2186 SendAccessDenied(m_con, peer_id,
2191 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2193 actionstream<<"Server: Player with an invalid name "
2194 <<"tried to connect from "<<addr_s<<std::endl;
2195 SendAccessDenied(m_con, peer_id,
2196 L"Name contains unallowed characters");
2200 infostream<<"Server: New connection: \""<<playername<<"\" from "
2201 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2204 char given_password[PASSWORD_SIZE];
2205 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2207 // old version - assume blank password
2208 given_password[0] = 0;
2212 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2214 given_password[i] = data[23+i];
2216 given_password[PASSWORD_SIZE-1] = 0;
2219 if(!base64_is_valid(given_password)){
2220 infostream<<"Server: "<<playername
2221 <<" supplied invalid password hash"<<std::endl;
2222 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2226 std::string checkpwd; // Password hash to check against
2227 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2229 // If no authentication info exists for user, create it
2231 if(!isSingleplayer() &&
2232 g_settings->getBool("disallow_empty_password") &&
2233 std::string(given_password) == ""){
2234 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2235 L"disallowed. Set a password and try again.");
2238 std::wstring raw_default_password =
2239 narrow_to_wide(g_settings->get("default_password"));
2240 std::string initial_password =
2241 translatePassword(playername, raw_default_password);
2243 // If default_password is empty, allow any initial password
2244 if (raw_default_password.length() == 0)
2245 initial_password = given_password;
2247 scriptapi_create_auth(m_lua, playername, initial_password);
2250 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2253 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2257 if(given_password != checkpwd){
2258 infostream<<"Server: peer_id="<<peer_id
2259 <<": supplied invalid password for "
2260 <<playername<<std::endl;
2261 SendAccessDenied(m_con, peer_id, L"Invalid password");
2265 // Do not allow multiple players in simple singleplayer mode.
2266 // This isn't a perfect way to do it, but will suffice for now.
2267 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2268 infostream<<"Server: Not allowing another client to connect in"
2269 <<" simple singleplayer mode"<<std::endl;
2270 SendAccessDenied(m_con, peer_id,
2271 L"Running in simple singleplayer mode.");
2275 // Enforce user limit.
2276 // Don't enforce for users that have some admin right
2277 if(m_clients.size() >= g_settings->getU16("max_users") &&
2278 !checkPriv(playername, "server") &&
2279 !checkPriv(playername, "ban") &&
2280 !checkPriv(playername, "privs") &&
2281 !checkPriv(playername, "password") &&
2282 playername != g_settings->get("name"))
2284 actionstream<<"Server: "<<playername<<" tried to join, but there"
2285 <<" are already max_users="
2286 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2287 SendAccessDenied(m_con, peer_id, L"Too many users.");
2292 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2294 // If failed, cancel
2295 if(playersao == NULL)
2297 errorstream<<"Server: peer_id="<<peer_id
2298 <<": failed to emerge player"<<std::endl;
2303 Answer with a TOCLIENT_INIT
2306 SharedBuffer<u8> reply(2+1+6+8+4);
2307 writeU16(&reply[0], TOCLIENT_INIT);
2308 writeU8(&reply[2], deployed);
2309 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2310 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2311 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2314 m_con.Send(peer_id, 0, reply, true);
2318 Send complete position information
2320 SendMovePlayer(peer_id);
2325 if(command == TOSERVER_INIT2)
2327 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2328 <<peer_id<<std::endl;
2330 Player *player = m_env->getPlayer(peer_id);
2332 verbosestream<<"Server: TOSERVER_INIT2: "
2333 <<"Player not found; ignoring."<<std::endl;
2337 RemoteClient *client = getClient(peer_id);
2338 client->serialization_version =
2339 getClient(peer_id)->pending_serialization_version;
2342 Send some initialization data
2345 infostream<<"Server: Sending content to "
2346 <<getPlayerName(peer_id)<<std::endl;
2348 // Send item definitions
2349 SendItemDef(m_con, peer_id, m_itemdef);
2351 // Send node definitions
2352 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2354 // Send media announcement
2355 sendMediaAnnouncement(peer_id);
2358 SendPlayerPrivileges(peer_id);
2360 // Send inventory formspec
2361 SendPlayerInventoryFormspec(peer_id);
2364 UpdateCrafting(peer_id);
2365 SendInventory(peer_id);
2368 if(g_settings->getBool("enable_damage"))
2369 SendPlayerHP(peer_id);
2371 // Send detached inventories
2372 sendDetachedInventories(peer_id);
2374 // Show death screen if necessary
2376 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2380 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2381 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2382 m_con.Send(peer_id, 0, data, true);
2385 // Note things in chat if not in simple singleplayer mode
2386 if(!m_simple_singleplayer_mode)
2388 // Send information about server to player in chat
2389 SendChatMessage(peer_id, getStatusString());
2391 // Send information about joining in chat
2393 std::wstring name = L"unknown";
2394 Player *player = m_env->getPlayer(peer_id);
2396 name = narrow_to_wide(player->getName());
2398 std::wstring message;
2401 message += L" joined the game.";
2402 BroadcastChatMessage(message);
2406 // Warnings about protocol version can be issued here
2407 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2409 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2410 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2417 std::ostringstream os(std::ios_base::binary);
2418 for(core::map<u16, RemoteClient*>::Iterator
2419 i = m_clients.getIterator();
2420 i.atEnd() == false; i++)
2422 RemoteClient *client = i.getNode()->getValue();
2423 assert(client->peer_id == i.getNode()->getKey());
2424 if(client->serialization_version == SER_FMT_VER_INVALID)
2427 Player *player = m_env->getPlayer(client->peer_id);
2430 // Get name of player
2431 os<<player->getName()<<" ";
2434 actionstream<<player->getName()<<" joins game. List of players: "
2435 <<os.str()<<std::endl;
2441 if(peer_ser_ver == SER_FMT_VER_INVALID)
2443 infostream<<"Server::ProcessData(): Cancelling: Peer"
2444 " serialization format invalid or not initialized."
2445 " Skipping incoming command="<<command<<std::endl;
2449 Player *player = m_env->getPlayer(peer_id);
2451 infostream<<"Server::ProcessData(): Cancelling: "
2452 "No player for peer_id="<<peer_id
2457 PlayerSAO *playersao = player->getPlayerSAO();
2458 if(playersao == NULL){
2459 infostream<<"Server::ProcessData(): Cancelling: "
2460 "No player object for peer_id="<<peer_id
2465 if(command == TOSERVER_PLAYERPOS)
2467 if(datasize < 2+12+12+4+4)
2471 v3s32 ps = readV3S32(&data[start+2]);
2472 v3s32 ss = readV3S32(&data[start+2+12]);
2473 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2474 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2476 if(datasize >= 2+12+12+4+4+4)
2477 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2478 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2479 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2480 pitch = wrapDegrees(pitch);
2481 yaw = wrapDegrees(yaw);
2483 player->setPosition(position);
2484 player->setSpeed(speed);
2485 player->setPitch(pitch);
2486 player->setYaw(yaw);
2487 player->keyPressed=keyPressed;
2488 player->control.up = (bool)(keyPressed&1);
2489 player->control.down = (bool)(keyPressed&2);
2490 player->control.left = (bool)(keyPressed&4);
2491 player->control.right = (bool)(keyPressed&8);
2492 player->control.jump = (bool)(keyPressed&16);
2493 player->control.aux1 = (bool)(keyPressed&32);
2494 player->control.sneak = (bool)(keyPressed&64);
2495 player->control.LMB = (bool)(keyPressed&128);
2496 player->control.RMB = (bool)(keyPressed&256);
2498 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2499 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2500 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2502 else if(command == TOSERVER_GOTBLOCKS)
2515 u16 count = data[2];
2516 for(u16 i=0; i<count; i++)
2518 if((s16)datasize < 2+1+(i+1)*6)
2519 throw con::InvalidIncomingDataException
2520 ("GOTBLOCKS length is too short");
2521 v3s16 p = readV3S16(&data[2+1+i*6]);
2522 /*infostream<<"Server: GOTBLOCKS ("
2523 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2524 RemoteClient *client = getClient(peer_id);
2525 client->GotBlock(p);
2528 else if(command == TOSERVER_DELETEDBLOCKS)
2541 u16 count = data[2];
2542 for(u16 i=0; i<count; i++)
2544 if((s16)datasize < 2+1+(i+1)*6)
2545 throw con::InvalidIncomingDataException
2546 ("DELETEDBLOCKS length is too short");
2547 v3s16 p = readV3S16(&data[2+1+i*6]);
2548 /*infostream<<"Server: DELETEDBLOCKS ("
2549 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2550 RemoteClient *client = getClient(peer_id);
2551 client->SetBlockNotSent(p);
2554 else if(command == TOSERVER_CLICK_OBJECT)
2556 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2559 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2561 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2564 else if(command == TOSERVER_GROUND_ACTION)
2566 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2570 else if(command == TOSERVER_RELEASE)
2572 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2575 else if(command == TOSERVER_SIGNTEXT)
2577 infostream<<"Server: SIGNTEXT not supported anymore"
2581 else if(command == TOSERVER_SIGNNODETEXT)
2583 infostream<<"Server: SIGNNODETEXT not supported anymore"
2587 else if(command == TOSERVER_INVENTORY_ACTION)
2589 // Strip command and create a stream
2590 std::string datastring((char*)&data[2], datasize-2);
2591 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2592 std::istringstream is(datastring, std::ios_base::binary);
2594 InventoryAction *a = InventoryAction::deSerialize(is);
2597 infostream<<"TOSERVER_INVENTORY_ACTION: "
2598 <<"InventoryAction::deSerialize() returned NULL"
2603 // If something goes wrong, this player is to blame
2604 RollbackScopeActor rollback_scope(m_rollback,
2605 std::string("player:")+player->getName());
2608 Note: Always set inventory not sent, to repair cases
2609 where the client made a bad prediction.
2613 Handle restrictions and special cases of the move action
2615 if(a->getType() == IACTION_MOVE)
2617 IMoveAction *ma = (IMoveAction*)a;
2619 ma->from_inv.applyCurrentPlayer(player->getName());
2620 ma->to_inv.applyCurrentPlayer(player->getName());
2622 setInventoryModified(ma->from_inv);
2623 setInventoryModified(ma->to_inv);
2625 bool from_inv_is_current_player =
2626 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2627 (ma->from_inv.name == player->getName());
2629 bool to_inv_is_current_player =
2630 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2631 (ma->to_inv.name == player->getName());
2634 Disable moving items out of craftpreview
2636 if(ma->from_list == "craftpreview")
2638 infostream<<"Ignoring IMoveAction from "
2639 <<(ma->from_inv.dump())<<":"<<ma->from_list
2640 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2641 <<" because src is "<<ma->from_list<<std::endl;
2647 Disable moving items into craftresult and craftpreview
2649 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2651 infostream<<"Ignoring IMoveAction from "
2652 <<(ma->from_inv.dump())<<":"<<ma->from_list
2653 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2654 <<" because dst is "<<ma->to_list<<std::endl;
2659 // Disallow moving items in elsewhere than player's inventory
2660 // if not allowed to interact
2661 if(!checkPriv(player->getName(), "interact") &&
2662 (!from_inv_is_current_player ||
2663 !to_inv_is_current_player))
2665 infostream<<"Cannot move outside of player's inventory: "
2666 <<"No interact privilege"<<std::endl;
2672 Handle restrictions and special cases of the drop action
2674 else if(a->getType() == IACTION_DROP)
2676 IDropAction *da = (IDropAction*)a;
2678 da->from_inv.applyCurrentPlayer(player->getName());
2680 setInventoryModified(da->from_inv);
2682 // Disallow dropping items if not allowed to interact
2683 if(!checkPriv(player->getName(), "interact"))
2690 Handle restrictions and special cases of the craft action
2692 else if(a->getType() == IACTION_CRAFT)
2694 ICraftAction *ca = (ICraftAction*)a;
2696 ca->craft_inv.applyCurrentPlayer(player->getName());
2698 setInventoryModified(ca->craft_inv);
2700 //bool craft_inv_is_current_player =
2701 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2702 // (ca->craft_inv.name == player->getName());
2704 // Disallow crafting if not allowed to interact
2705 if(!checkPriv(player->getName(), "interact"))
2707 infostream<<"Cannot craft: "
2708 <<"No interact privilege"<<std::endl;
2715 a->apply(this, playersao, this);
2719 else if(command == TOSERVER_CHAT_MESSAGE)
2727 std::string datastring((char*)&data[2], datasize-2);
2728 std::istringstream is(datastring, std::ios_base::binary);
2731 is.read((char*)buf, 2);
2732 u16 len = readU16(buf);
2734 std::wstring message;
2735 for(u16 i=0; i<len; i++)
2737 is.read((char*)buf, 2);
2738 message += (wchar_t)readU16(buf);
2741 // If something goes wrong, this player is to blame
2742 RollbackScopeActor rollback_scope(m_rollback,
2743 std::string("player:")+player->getName());
2745 // Get player name of this client
2746 std::wstring name = narrow_to_wide(player->getName());
2749 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2750 wide_to_narrow(message));
2751 // If script ate the message, don't proceed
2755 // Line to send to players
2757 // Whether to send to the player that sent the line
2758 bool send_to_sender = false;
2759 // Whether to send to other players
2760 bool send_to_others = false;
2762 // Commands are implemented in Lua, so only catch invalid
2763 // commands that were not "eaten" and send an error back
2764 if(message[0] == L'/')
2766 message = message.substr(1);
2767 send_to_sender = true;
2768 if(message.length() == 0)
2769 line += L"-!- Empty command";
2771 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2775 if(checkPriv(player->getName(), "shout")){
2780 send_to_others = true;
2782 line += L"-!- You don't have permission to shout.";
2783 send_to_sender = true;
2790 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2793 Send the message to clients
2795 for(core::map<u16, RemoteClient*>::Iterator
2796 i = m_clients.getIterator();
2797 i.atEnd() == false; i++)
2799 // Get client and check that it is valid
2800 RemoteClient *client = i.getNode()->getValue();
2801 assert(client->peer_id == i.getNode()->getKey());
2802 if(client->serialization_version == SER_FMT_VER_INVALID)
2806 bool sender_selected = (peer_id == client->peer_id);
2807 if(sender_selected == true && send_to_sender == false)
2809 if(sender_selected == false && send_to_others == false)
2812 SendChatMessage(client->peer_id, line);
2816 else if(command == TOSERVER_DAMAGE)
2818 std::string datastring((char*)&data[2], datasize-2);
2819 std::istringstream is(datastring, std::ios_base::binary);
2820 u8 damage = readU8(is);
2822 if(g_settings->getBool("enable_damage"))
2824 actionstream<<player->getName()<<" damaged by "
2825 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2828 playersao->setHP(playersao->getHP() - damage);
2830 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2833 if(playersao->m_hp_not_sent)
2834 SendPlayerHP(peer_id);
2837 else if(command == TOSERVER_PASSWORD)
2840 [0] u16 TOSERVER_PASSWORD
2841 [2] u8[28] old password
2842 [30] u8[28] new password
2845 if(datasize != 2+PASSWORD_SIZE*2)
2847 /*char password[PASSWORD_SIZE];
2848 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2849 password[i] = data[2+i];
2850 password[PASSWORD_SIZE-1] = 0;*/
2852 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2860 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2862 char c = data[2+PASSWORD_SIZE+i];
2868 if(!base64_is_valid(newpwd)){
2869 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2870 // Wrong old password supplied!!
2871 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2875 infostream<<"Server: Client requests a password change from "
2876 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2878 std::string playername = player->getName();
2880 std::string checkpwd;
2881 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2883 if(oldpwd != checkpwd)
2885 infostream<<"Server: invalid old password"<<std::endl;
2886 // Wrong old password supplied!!
2887 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2891 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2893 actionstream<<player->getName()<<" changes password"<<std::endl;
2894 SendChatMessage(peer_id, L"Password change successful.");
2896 actionstream<<player->getName()<<" tries to change password but "
2897 <<"it fails"<<std::endl;
2898 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2901 else if(command == TOSERVER_PLAYERITEM)
2906 u16 item = readU16(&data[2]);
2907 playersao->setWieldIndex(item);
2909 else if(command == TOSERVER_RESPAWN)
2911 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2914 RespawnPlayer(peer_id);
2916 actionstream<<player->getName()<<" respawns at "
2917 <<PP(player->getPosition()/BS)<<std::endl;
2919 // ActiveObject is added to environment in AsyncRunStep after
2920 // the previous addition has been succesfully removed
2922 else if(command == TOSERVER_REQUEST_MEDIA) {
2923 std::string datastring((char*)&data[2], datasize-2);
2924 std::istringstream is(datastring, std::ios_base::binary);
2926 core::list<MediaRequest> tosend;
2927 u16 numfiles = readU16(is);
2929 infostream<<"Sending "<<numfiles<<" files to "
2930 <<getPlayerName(peer_id)<<std::endl;
2931 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2933 for(int i = 0; i < numfiles; i++) {
2934 std::string name = deSerializeString(is);
2935 tosend.push_back(MediaRequest(name));
2936 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2940 sendRequestedMedia(peer_id, tosend);
2942 // Now the client should know about everything
2943 // (definitions and files)
2944 getClient(peer_id)->definitions_sent = true;
2946 else if(command == TOSERVER_RECEIVED_MEDIA) {
2947 getClient(peer_id)->definitions_sent = true;
2949 else if(command == TOSERVER_INTERACT)
2951 std::string datastring((char*)&data[2], datasize-2);
2952 std::istringstream is(datastring, std::ios_base::binary);
2958 [5] u32 length of the next item
2959 [9] serialized PointedThing
2961 0: start digging (from undersurface) or use
2962 1: stop digging (all parameters ignored)
2963 2: digging completed
2964 3: place block or item (to abovesurface)
2967 u8 action = readU8(is);
2968 u16 item_i = readU16(is);
2969 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2970 PointedThing pointed;
2971 pointed.deSerialize(tmp_is);
2973 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2974 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2978 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2979 <<" tried to interact, but is dead!"<<std::endl;
2983 v3f player_pos = playersao->getLastGoodPosition();
2985 // Update wielded item
2986 playersao->setWieldIndex(item_i);
2988 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2989 v3s16 p_under = pointed.node_undersurface;
2990 v3s16 p_above = pointed.node_abovesurface;
2992 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2993 ServerActiveObject *pointed_object = NULL;
2994 if(pointed.type == POINTEDTHING_OBJECT)
2996 pointed_object = m_env->getActiveObject(pointed.object_id);
2997 if(pointed_object == NULL)
2999 verbosestream<<"TOSERVER_INTERACT: "
3000 "pointed object is NULL"<<std::endl;
3006 v3f pointed_pos_under = player_pos;
3007 v3f pointed_pos_above = player_pos;
3008 if(pointed.type == POINTEDTHING_NODE)
3010 pointed_pos_under = intToFloat(p_under, BS);
3011 pointed_pos_above = intToFloat(p_above, BS);
3013 else if(pointed.type == POINTEDTHING_OBJECT)
3015 pointed_pos_under = pointed_object->getBasePosition();
3016 pointed_pos_above = pointed_pos_under;
3020 Check that target is reasonably close
3021 (only when digging or placing things)
3023 if(action == 0 || action == 2 || action == 3)
3025 float d = player_pos.getDistanceFrom(pointed_pos_under);
3026 float max_d = BS * 14; // Just some large enough value
3028 actionstream<<"Player "<<player->getName()
3029 <<" tried to access "<<pointed.dump()
3031 <<"d="<<d<<", max_d="<<max_d
3032 <<". ignoring."<<std::endl;
3033 // Re-send block to revert change on client-side
3034 RemoteClient *client = getClient(peer_id);
3035 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3036 client->SetBlockNotSent(blockpos);
3043 Make sure the player is allowed to do it
3045 if(!checkPriv(player->getName(), "interact"))
3047 actionstream<<player->getName()<<" attempted to interact with "
3048 <<pointed.dump()<<" without 'interact' privilege"
3050 // Re-send block to revert change on client-side
3051 RemoteClient *client = getClient(peer_id);
3052 // Digging completed -> under
3054 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3055 client->SetBlockNotSent(blockpos);
3057 // Placement -> above
3059 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3060 client->SetBlockNotSent(blockpos);
3066 If something goes wrong, this player is to blame
3068 RollbackScopeActor rollback_scope(m_rollback,
3069 std::string("player:")+player->getName());
3072 0: start digging or punch object
3076 if(pointed.type == POINTEDTHING_NODE)
3079 NOTE: This can be used in the future to check if
3080 somebody is cheating, by checking the timing.
3082 MapNode n(CONTENT_IGNORE);
3085 n = m_env->getMap().getNode(p_under);
3087 catch(InvalidPositionException &e)
3089 infostream<<"Server: Not punching: Node not found."
3090 <<" Adding block to emerge queue."
3092 m_emerge_queue.addBlock(peer_id,
3093 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3095 if(n.getContent() != CONTENT_IGNORE)
3096 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3098 playersao->noCheatDigStart(p_under);
3100 else if(pointed.type == POINTEDTHING_OBJECT)
3102 // Skip if object has been removed
3103 if(pointed_object->m_removed)
3106 actionstream<<player->getName()<<" punches object "
3107 <<pointed.object_id<<": "
3108 <<pointed_object->getDescription()<<std::endl;
3110 ItemStack punchitem = playersao->getWieldedItem();
3111 ToolCapabilities toolcap =
3112 punchitem.getToolCapabilities(m_itemdef);
3113 v3f dir = (pointed_object->getBasePosition() -
3114 (player->getPosition() + player->getEyeOffset())
3116 float time_from_last_punch =
3117 playersao->resetTimeFromLastPunch();
3118 pointed_object->punch(dir, &toolcap, playersao,
3119 time_from_last_punch);
3127 else if(action == 1)
3132 2: Digging completed
3134 else if(action == 2)
3136 // Only digging of nodes
3137 if(pointed.type == POINTEDTHING_NODE)
3139 MapNode n(CONTENT_IGNORE);
3142 n = m_env->getMap().getNode(p_under);
3144 catch(InvalidPositionException &e)
3146 infostream<<"Server: Not finishing digging: Node not found."
3147 <<" Adding block to emerge queue."
3149 m_emerge_queue.addBlock(peer_id,
3150 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3153 /* Cheat prevention */
3154 bool is_valid_dig = true;
3155 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3157 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3158 float nocheat_t = playersao->getNoCheatDigTime();
3159 playersao->noCheatDigEnd();
3160 // If player didn't start digging this, ignore dig
3161 if(nocheat_p != p_under){
3162 infostream<<"Server: NoCheat: "<<player->getName()
3163 <<" started digging "
3164 <<PP(nocheat_p)<<" and completed digging "
3165 <<PP(p_under)<<"; not digging."<<std::endl;
3166 is_valid_dig = false;
3168 // Get player's wielded item
3169 ItemStack playeritem;
3170 InventoryList *mlist = playersao->getInventory()->getList("main");
3172 playeritem = mlist->getItem(playersao->getWieldIndex());
3173 ToolCapabilities playeritem_toolcap =
3174 playeritem.getToolCapabilities(m_itemdef);
3175 // Get diggability and expected digging time
3176 DigParams params = getDigParams(m_nodedef->get(n).groups,
3177 &playeritem_toolcap);
3178 // If can't dig, try hand
3179 if(!params.diggable){
3180 const ItemDefinition &hand = m_itemdef->get("");
3181 const ToolCapabilities *tp = hand.tool_capabilities;
3183 params = getDigParams(m_nodedef->get(n).groups, tp);
3185 // If can't dig, ignore dig
3186 if(!params.diggable){
3187 infostream<<"Server: NoCheat: "<<player->getName()
3188 <<" completed digging "<<PP(p_under)
3189 <<", which is not diggable with tool. not digging."
3191 is_valid_dig = false;
3193 // If time is considerably too short, ignore dig
3194 // Check time only for medium and slow timed digs
3195 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3196 infostream<<"Server: NoCheat: "<<player->getName()
3197 <<" completed digging "
3198 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3199 <<params.time<<"s; not digging."<<std::endl;
3200 is_valid_dig = false;
3204 /* Actually dig node */
3206 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3207 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3209 // Send unusual result (that is, node not being removed)
3210 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3212 // Re-send block to revert change on client-side
3213 RemoteClient *client = getClient(peer_id);
3214 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3215 client->SetBlockNotSent(blockpos);
3221 3: place block or right-click object
3223 else if(action == 3)
3225 ItemStack item = playersao->getWieldedItem();
3227 // Reset build time counter
3228 if(pointed.type == POINTEDTHING_NODE &&
3229 item.getDefinition(m_itemdef).type == ITEM_NODE)
3230 getClient(peer_id)->m_time_from_building = 0.0;
3232 if(pointed.type == POINTEDTHING_OBJECT)
3234 // Right click object
3236 // Skip if object has been removed
3237 if(pointed_object->m_removed)
3240 actionstream<<player->getName()<<" right-clicks object "
3241 <<pointed.object_id<<": "
3242 <<pointed_object->getDescription()<<std::endl;
3245 pointed_object->rightClick(playersao);
3247 else if(scriptapi_item_on_place(m_lua,
3248 item, playersao, pointed))
3250 // Placement was handled in lua
3252 // Apply returned ItemStack
3253 playersao->setWieldedItem(item);
3256 // If item has node placement prediction, always send the above
3257 // node to make sure the client knows what exactly happened
3258 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3259 RemoteClient *client = getClient(peer_id);
3260 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3261 client->SetBlockNotSent(blockpos);
3268 else if(action == 4)
3270 ItemStack item = playersao->getWieldedItem();
3272 actionstream<<player->getName()<<" uses "<<item.name
3273 <<", pointing at "<<pointed.dump()<<std::endl;
3275 if(scriptapi_item_on_use(m_lua,
3276 item, playersao, pointed))
3278 // Apply returned ItemStack
3279 playersao->setWieldedItem(item);
3286 Catch invalid actions
3290 infostream<<"WARNING: Server: Invalid action "
3291 <<action<<std::endl;
3294 else if(command == TOSERVER_REMOVED_SOUNDS)
3296 std::string datastring((char*)&data[2], datasize-2);
3297 std::istringstream is(datastring, std::ios_base::binary);
3299 int num = readU16(is);
3300 for(int k=0; k<num; k++){
3301 s32 id = readS32(is);
3302 std::map<s32, ServerPlayingSound>::iterator i =
3303 m_playing_sounds.find(id);
3304 if(i == m_playing_sounds.end())
3306 ServerPlayingSound &psound = i->second;
3307 psound.clients.erase(peer_id);
3308 if(psound.clients.size() == 0)
3309 m_playing_sounds.erase(i++);
3312 else if(command == TOSERVER_NODEMETA_FIELDS)
3314 std::string datastring((char*)&data[2], datasize-2);
3315 std::istringstream is(datastring, std::ios_base::binary);
3317 v3s16 p = readV3S16(is);
3318 std::string formname = deSerializeString(is);
3319 int num = readU16(is);
3320 std::map<std::string, std::string> fields;
3321 for(int k=0; k<num; k++){
3322 std::string fieldname = deSerializeString(is);
3323 std::string fieldvalue = deSerializeLongString(is);
3324 fields[fieldname] = fieldvalue;
3327 // If something goes wrong, this player is to blame
3328 RollbackScopeActor rollback_scope(m_rollback,
3329 std::string("player:")+player->getName());
3331 // Check the target node for rollback data; leave others unnoticed
3332 RollbackNode rn_old(&m_env->getMap(), p, this);
3334 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3337 // Report rollback data
3338 RollbackNode rn_new(&m_env->getMap(), p, this);
3339 if(rollback() && rn_new != rn_old){
3340 RollbackAction action;
3341 action.setSetNode(p, rn_old, rn_new);
3342 rollback()->reportAction(action);
3345 else if(command == TOSERVER_INVENTORY_FIELDS)
3347 std::string datastring((char*)&data[2], datasize-2);
3348 std::istringstream is(datastring, std::ios_base::binary);
3350 std::string formname = deSerializeString(is);
3351 int num = readU16(is);
3352 std::map<std::string, std::string> fields;
3353 for(int k=0; k<num; k++){
3354 std::string fieldname = deSerializeString(is);
3355 std::string fieldvalue = deSerializeLongString(is);
3356 fields[fieldname] = fieldvalue;
3359 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3363 infostream<<"Server::ProcessData(): Ignoring "
3364 "unknown command "<<command<<std::endl;
3368 catch(SendFailedException &e)
3370 errorstream<<"Server::ProcessData(): SendFailedException: "
3376 void Server::onMapEditEvent(MapEditEvent *event)
3378 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3379 if(m_ignore_map_edit_events)
3381 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3383 MapEditEvent *e = event->clone();
3384 m_unsent_map_edit_queue.push_back(e);
3387 Inventory* Server::getInventory(const InventoryLocation &loc)
3390 case InventoryLocation::UNDEFINED:
3393 case InventoryLocation::CURRENT_PLAYER:
3396 case InventoryLocation::PLAYER:
3398 Player *player = m_env->getPlayer(loc.name.c_str());
3401 PlayerSAO *playersao = player->getPlayerSAO();
3404 return playersao->getInventory();
3407 case InventoryLocation::NODEMETA:
3409 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3412 return meta->getInventory();
3415 case InventoryLocation::DETACHED:
3417 if(m_detached_inventories.count(loc.name) == 0)
3419 return m_detached_inventories[loc.name];
3427 void Server::setInventoryModified(const InventoryLocation &loc)
3430 case InventoryLocation::UNDEFINED:
3433 case InventoryLocation::PLAYER:
3435 Player *player = m_env->getPlayer(loc.name.c_str());
3438 PlayerSAO *playersao = player->getPlayerSAO();
3441 playersao->m_inventory_not_sent = true;
3442 playersao->m_wielded_item_not_sent = true;
3445 case InventoryLocation::NODEMETA:
3447 v3s16 blockpos = getNodeBlockPos(loc.p);
3449 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3451 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3453 setBlockNotSent(blockpos);
3456 case InventoryLocation::DETACHED:
3458 sendDetachedInventoryToAll(loc.name);
3466 core::list<PlayerInfo> Server::getPlayerInfo()
3468 DSTACK(__FUNCTION_NAME);
3469 JMutexAutoLock envlock(m_env_mutex);
3470 JMutexAutoLock conlock(m_con_mutex);
3472 core::list<PlayerInfo> list;
3474 core::list<Player*> players = m_env->getPlayers();
3476 core::list<Player*>::Iterator i;
3477 for(i = players.begin();
3478 i != players.end(); i++)
3482 Player *player = *i;
3485 // Copy info from connection to info struct
3486 info.id = player->peer_id;
3487 info.address = m_con.GetPeerAddress(player->peer_id);
3488 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3490 catch(con::PeerNotFoundException &e)
3492 // Set dummy peer info
3494 info.address = Address(0,0,0,0,0);
3498 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3499 info.position = player->getPosition();
3501 list.push_back(info);
3508 void Server::peerAdded(con::Peer *peer)
3510 DSTACK(__FUNCTION_NAME);
3511 verbosestream<<"Server::peerAdded(): peer->id="
3512 <<peer->id<<std::endl;
3515 c.type = PEER_ADDED;
3516 c.peer_id = peer->id;
3518 m_peer_change_queue.push_back(c);
3521 void Server::deletingPeer(con::Peer *peer, bool timeout)
3523 DSTACK(__FUNCTION_NAME);
3524 verbosestream<<"Server::deletingPeer(): peer->id="
3525 <<peer->id<<", timeout="<<timeout<<std::endl;
3528 c.type = PEER_REMOVED;
3529 c.peer_id = peer->id;
3530 c.timeout = timeout;
3531 m_peer_change_queue.push_back(c);
3538 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3540 DSTACK(__FUNCTION_NAME);
3541 std::ostringstream os(std::ios_base::binary);
3543 writeU16(os, TOCLIENT_HP);
3547 std::string s = os.str();
3548 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3550 con.Send(peer_id, 0, data, true);
3553 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3554 const std::wstring &reason)
3556 DSTACK(__FUNCTION_NAME);
3557 std::ostringstream os(std::ios_base::binary);
3559 writeU16(os, TOCLIENT_ACCESS_DENIED);
3560 os<<serializeWideString(reason);
3563 std::string s = os.str();
3564 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3566 con.Send(peer_id, 0, data, true);
3569 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3570 bool set_camera_point_target, v3f camera_point_target)
3572 DSTACK(__FUNCTION_NAME);
3573 std::ostringstream os(std::ios_base::binary);
3575 writeU16(os, TOCLIENT_DEATHSCREEN);
3576 writeU8(os, set_camera_point_target);
3577 writeV3F1000(os, camera_point_target);
3580 std::string s = os.str();
3581 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3583 con.Send(peer_id, 0, data, true);
3586 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3587 IItemDefManager *itemdef)
3589 DSTACK(__FUNCTION_NAME);
3590 std::ostringstream os(std::ios_base::binary);
3594 u32 length of the next item
3595 zlib-compressed serialized ItemDefManager
3597 writeU16(os, TOCLIENT_ITEMDEF);
3598 std::ostringstream tmp_os(std::ios::binary);
3599 itemdef->serialize(tmp_os);
3600 std::ostringstream tmp_os2(std::ios::binary);
3601 compressZlib(tmp_os.str(), tmp_os2);
3602 os<<serializeLongString(tmp_os2.str());
3605 std::string s = os.str();
3606 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3607 <<"): size="<<s.size()<<std::endl;
3608 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3610 con.Send(peer_id, 0, data, true);
3613 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3614 INodeDefManager *nodedef, u16 protocol_version)
3616 DSTACK(__FUNCTION_NAME);
3617 std::ostringstream os(std::ios_base::binary);
3621 u32 length of the next item
3622 zlib-compressed serialized NodeDefManager
3624 writeU16(os, TOCLIENT_NODEDEF);
3625 std::ostringstream tmp_os(std::ios::binary);
3626 nodedef->serialize(tmp_os, protocol_version);
3627 std::ostringstream tmp_os2(std::ios::binary);
3628 compressZlib(tmp_os.str(), tmp_os2);
3629 os<<serializeLongString(tmp_os2.str());
3632 std::string s = os.str();
3633 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3634 <<"): size="<<s.size()<<std::endl;
3635 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3637 con.Send(peer_id, 0, data, true);
3641 Non-static send methods
3644 void Server::SendInventory(u16 peer_id)
3646 DSTACK(__FUNCTION_NAME);
3648 PlayerSAO *playersao = getPlayerSAO(peer_id);
3651 playersao->m_inventory_not_sent = false;
3657 std::ostringstream os;
3658 playersao->getInventory()->serialize(os);
3660 std::string s = os.str();
3662 SharedBuffer<u8> data(s.size()+2);
3663 writeU16(&data[0], TOCLIENT_INVENTORY);
3664 memcpy(&data[2], s.c_str(), s.size());
3667 m_con.Send(peer_id, 0, data, true);
3670 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3672 DSTACK(__FUNCTION_NAME);
3674 std::ostringstream os(std::ios_base::binary);
3678 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3679 os.write((char*)buf, 2);
3682 writeU16(buf, message.size());
3683 os.write((char*)buf, 2);
3686 for(u32 i=0; i<message.size(); i++)
3690 os.write((char*)buf, 2);
3694 std::string s = os.str();
3695 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3697 m_con.Send(peer_id, 0, data, true);
3699 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3701 DSTACK(__FUNCTION_NAME);
3703 std::ostringstream os(std::ios_base::binary);
3707 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3708 os.write((char*)buf, 2);
3709 os<<serializeLongString(formspec);
3710 os<<serializeString(formname);
3713 std::string s = os.str();
3714 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3716 m_con.Send(peer_id, 0, data, true);
3719 void Server::BroadcastChatMessage(const std::wstring &message)
3721 for(core::map<u16, RemoteClient*>::Iterator
3722 i = m_clients.getIterator();
3723 i.atEnd() == false; i++)
3725 // Get client and check that it is valid
3726 RemoteClient *client = i.getNode()->getValue();
3727 assert(client->peer_id == i.getNode()->getKey());
3728 if(client->serialization_version == SER_FMT_VER_INVALID)
3731 SendChatMessage(client->peer_id, message);
3735 void Server::SendPlayerHP(u16 peer_id)
3737 DSTACK(__FUNCTION_NAME);
3738 PlayerSAO *playersao = getPlayerSAO(peer_id);
3740 playersao->m_hp_not_sent = false;
3741 SendHP(m_con, peer_id, playersao->getHP());
3744 void Server::SendMovePlayer(u16 peer_id)
3746 DSTACK(__FUNCTION_NAME);
3747 Player *player = m_env->getPlayer(peer_id);
3750 std::ostringstream os(std::ios_base::binary);
3751 writeU16(os, TOCLIENT_MOVE_PLAYER);
3752 writeV3F1000(os, player->getPosition());
3753 writeF1000(os, player->getPitch());
3754 writeF1000(os, player->getYaw());
3757 v3f pos = player->getPosition();
3758 f32 pitch = player->getPitch();
3759 f32 yaw = player->getYaw();
3760 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3761 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3768 std::string s = os.str();
3769 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3771 m_con.Send(peer_id, 0, data, true);
3774 void Server::SendPlayerPrivileges(u16 peer_id)
3776 Player *player = m_env->getPlayer(peer_id);
3778 if(player->peer_id == PEER_ID_INEXISTENT)
3781 std::set<std::string> privs;
3782 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3784 std::ostringstream os(std::ios_base::binary);
3785 writeU16(os, TOCLIENT_PRIVILEGES);
3786 writeU16(os, privs.size());
3787 for(std::set<std::string>::const_iterator i = privs.begin();
3788 i != privs.end(); i++){
3789 os<<serializeString(*i);
3793 std::string s = os.str();
3794 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3796 m_con.Send(peer_id, 0, data, true);
3799 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3801 Player *player = m_env->getPlayer(peer_id);
3803 if(player->peer_id == PEER_ID_INEXISTENT)
3806 std::ostringstream os(std::ios_base::binary);
3807 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3808 os<<serializeLongString(player->inventory_formspec);
3811 std::string s = os.str();
3812 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3814 m_con.Send(peer_id, 0, data, true);
3817 s32 Server::playSound(const SimpleSoundSpec &spec,
3818 const ServerSoundParams ¶ms)
3820 // Find out initial position of sound
3821 bool pos_exists = false;
3822 v3f pos = params.getPos(m_env, &pos_exists);
3823 // If position is not found while it should be, cancel sound
3824 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3826 // Filter destination clients
3827 std::set<RemoteClient*> dst_clients;
3828 if(params.to_player != "")
3830 Player *player = m_env->getPlayer(params.to_player.c_str());
3832 infostream<<"Server::playSound: Player \""<<params.to_player
3833 <<"\" not found"<<std::endl;
3836 if(player->peer_id == PEER_ID_INEXISTENT){
3837 infostream<<"Server::playSound: Player \""<<params.to_player
3838 <<"\" not connected"<<std::endl;
3841 RemoteClient *client = getClient(player->peer_id);
3842 dst_clients.insert(client);
3846 for(core::map<u16, RemoteClient*>::Iterator
3847 i = m_clients.getIterator(); i.atEnd() == false; i++)
3849 RemoteClient *client = i.getNode()->getValue();
3850 Player *player = m_env->getPlayer(client->peer_id);
3854 if(player->getPosition().getDistanceFrom(pos) >
3855 params.max_hear_distance)
3858 dst_clients.insert(client);
3861 if(dst_clients.size() == 0)
3864 s32 id = m_next_sound_id++;
3865 // The sound will exist as a reference in m_playing_sounds
3866 m_playing_sounds[id] = ServerPlayingSound();
3867 ServerPlayingSound &psound = m_playing_sounds[id];
3868 psound.params = params;
3869 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3870 i != dst_clients.end(); i++)
3871 psound.clients.insert((*i)->peer_id);
3873 std::ostringstream os(std::ios_base::binary);
3874 writeU16(os, TOCLIENT_PLAY_SOUND);
3876 os<<serializeString(spec.name);
3877 writeF1000(os, spec.gain * params.gain);
3878 writeU8(os, params.type);
3879 writeV3F1000(os, pos);
3880 writeU16(os, params.object);
3881 writeU8(os, params.loop);
3883 std::string s = os.str();
3884 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3886 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3887 i != dst_clients.end(); i++){
3889 m_con.Send((*i)->peer_id, 0, data, true);
3893 void Server::stopSound(s32 handle)
3895 // Get sound reference
3896 std::map<s32, ServerPlayingSound>::iterator i =
3897 m_playing_sounds.find(handle);
3898 if(i == m_playing_sounds.end())
3900 ServerPlayingSound &psound = i->second;
3902 std::ostringstream os(std::ios_base::binary);
3903 writeU16(os, TOCLIENT_STOP_SOUND);
3904 writeS32(os, handle);
3906 std::string s = os.str();
3907 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3909 for(std::set<u16>::iterator i = psound.clients.begin();
3910 i != psound.clients.end(); i++){
3912 m_con.Send(*i, 0, data, true);
3914 // Remove sound reference
3915 m_playing_sounds.erase(i);
3918 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3919 core::list<u16> *far_players, float far_d_nodes)
3921 float maxd = far_d_nodes*BS;
3922 v3f p_f = intToFloat(p, BS);
3926 SharedBuffer<u8> reply(replysize);
3927 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3928 writeS16(&reply[2], p.X);
3929 writeS16(&reply[4], p.Y);
3930 writeS16(&reply[6], p.Z);
3932 for(core::map<u16, RemoteClient*>::Iterator
3933 i = m_clients.getIterator();
3934 i.atEnd() == false; i++)
3936 // Get client and check that it is valid
3937 RemoteClient *client = i.getNode()->getValue();
3938 assert(client->peer_id == i.getNode()->getKey());
3939 if(client->serialization_version == SER_FMT_VER_INVALID)
3942 // Don't send if it's the same one
3943 if(client->peer_id == ignore_id)
3949 Player *player = m_env->getPlayer(client->peer_id);
3952 // If player is far away, only set modified blocks not sent
3953 v3f player_pos = player->getPosition();
3954 if(player_pos.getDistanceFrom(p_f) > maxd)
3956 far_players->push_back(client->peer_id);
3963 m_con.Send(client->peer_id, 0, reply, true);
3967 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3968 core::list<u16> *far_players, float far_d_nodes)
3970 float maxd = far_d_nodes*BS;
3971 v3f p_f = intToFloat(p, BS);
3973 for(core::map<u16, RemoteClient*>::Iterator
3974 i = m_clients.getIterator();
3975 i.atEnd() == false; i++)
3977 // Get client and check that it is valid
3978 RemoteClient *client = i.getNode()->getValue();
3979 assert(client->peer_id == i.getNode()->getKey());
3980 if(client->serialization_version == SER_FMT_VER_INVALID)
3983 // Don't send if it's the same one
3984 if(client->peer_id == ignore_id)
3990 Player *player = m_env->getPlayer(client->peer_id);
3993 // If player is far away, only set modified blocks not sent
3994 v3f player_pos = player->getPosition();
3995 if(player_pos.getDistanceFrom(p_f) > maxd)
3997 far_players->push_back(client->peer_id);
4004 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4005 SharedBuffer<u8> reply(replysize);
4006 writeU16(&reply[0], TOCLIENT_ADDNODE);
4007 writeS16(&reply[2], p.X);
4008 writeS16(&reply[4], p.Y);
4009 writeS16(&reply[6], p.Z);
4010 n.serialize(&reply[8], client->serialization_version);
4013 m_con.Send(client->peer_id, 0, reply, true);
4017 void Server::setBlockNotSent(v3s16 p)
4019 for(core::map<u16, RemoteClient*>::Iterator
4020 i = m_clients.getIterator();
4021 i.atEnd()==false; i++)
4023 RemoteClient *client = i.getNode()->getValue();
4024 client->SetBlockNotSent(p);
4028 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4030 DSTACK(__FUNCTION_NAME);
4032 v3s16 p = block->getPos();
4036 bool completely_air = true;
4037 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4038 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4039 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4041 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4043 completely_air = false;
4044 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4049 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4051 infostream<<"[completely air] ";
4052 infostream<<std::endl;
4056 Create a packet with the block in the right format
4059 std::ostringstream os(std::ios_base::binary);
4060 block->serialize(os, ver, false);
4061 std::string s = os.str();
4062 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4064 u32 replysize = 8 + blockdata.getSize();
4065 SharedBuffer<u8> reply(replysize);
4066 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4067 writeS16(&reply[2], p.X);
4068 writeS16(&reply[4], p.Y);
4069 writeS16(&reply[6], p.Z);
4070 memcpy(&reply[8], *blockdata, blockdata.getSize());
4072 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4073 <<": \tpacket size: "<<replysize<<std::endl;*/
4078 m_con.Send(peer_id, 1, reply, true);
4081 void Server::SendBlocks(float dtime)
4083 DSTACK(__FUNCTION_NAME);
4085 JMutexAutoLock envlock(m_env_mutex);
4086 JMutexAutoLock conlock(m_con_mutex);
4088 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4090 core::array<PrioritySortedBlockTransfer> queue;
4092 s32 total_sending = 0;
4095 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4097 for(core::map<u16, RemoteClient*>::Iterator
4098 i = m_clients.getIterator();
4099 i.atEnd() == false; i++)
4101 RemoteClient *client = i.getNode()->getValue();
4102 assert(client->peer_id == i.getNode()->getKey());
4104 // If definitions and textures have not been sent, don't
4105 // send MapBlocks either
4106 if(!client->definitions_sent)
4109 total_sending += client->SendingCount();
4111 if(client->serialization_version == SER_FMT_VER_INVALID)
4114 client->GetNextBlocks(this, dtime, queue);
4119 // Lowest priority number comes first.
4120 // Lowest is most important.
4123 for(u32 i=0; i<queue.size(); i++)
4125 //TODO: Calculate limit dynamically
4126 if(total_sending >= g_settings->getS32
4127 ("max_simultaneous_block_sends_server_total"))
4130 PrioritySortedBlockTransfer q = queue[i];
4132 MapBlock *block = NULL;
4135 block = m_env->getMap().getBlockNoCreate(q.pos);
4137 catch(InvalidPositionException &e)
4142 RemoteClient *client = getClient(q.peer_id);
4144 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4146 client->SentBlock(q.pos);
4152 void Server::fillMediaCache()
4154 DSTACK(__FUNCTION_NAME);
4156 infostream<<"Server: Calculating media file checksums"<<std::endl;
4158 // Collect all media file paths
4159 std::list<std::string> paths;
4160 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4161 i != m_mods.end(); i++){
4162 const ModSpec &mod = *i;
4163 paths.push_back(mod.path + DIR_DELIM + "textures");
4164 paths.push_back(mod.path + DIR_DELIM + "sounds");
4165 paths.push_back(mod.path + DIR_DELIM + "media");
4166 paths.push_back(mod.path + DIR_DELIM + "models");
4168 std::string path_all = "textures";
4169 paths.push_back(path_all + DIR_DELIM + "all");
4171 // Collect media file information from paths into cache
4172 for(std::list<std::string>::iterator i = paths.begin();
4173 i != paths.end(); i++)
4175 std::string mediapath = *i;
4176 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4177 for(u32 j=0; j<dirlist.size(); j++){
4178 if(dirlist[j].dir) // Ignode dirs
4180 std::string filename = dirlist[j].name;
4181 // If name contains illegal characters, ignore the file
4182 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4183 infostream<<"Server: ignoring illegal file name: \""
4184 <<filename<<"\""<<std::endl;
4187 // If name is not in a supported format, ignore it
4188 const char *supported_ext[] = {
4189 ".png", ".jpg", ".bmp", ".tga",
4190 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4192 ".x", ".b3d", ".md2", ".obj",
4195 if(removeStringEnd(filename, supported_ext) == ""){
4196 infostream<<"Server: ignoring unsupported file extension: \""
4197 <<filename<<"\""<<std::endl;
4200 // Ok, attempt to load the file and add to cache
4201 std::string filepath = mediapath + DIR_DELIM + filename;
4203 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4204 if(fis.good() == false){
4205 errorstream<<"Server::fillMediaCache(): Could not open \""
4206 <<filename<<"\" for reading"<<std::endl;
4209 std::ostringstream tmp_os(std::ios_base::binary);
4213 fis.read(buf, 1024);
4214 std::streamsize len = fis.gcount();
4215 tmp_os.write(buf, len);
4224 errorstream<<"Server::fillMediaCache(): Failed to read \""
4225 <<filename<<"\""<<std::endl;
4228 if(tmp_os.str().length() == 0){
4229 errorstream<<"Server::fillMediaCache(): Empty file \""
4230 <<filepath<<"\""<<std::endl;
4235 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4237 unsigned char *digest = sha1.getDigest();
4238 std::string sha1_base64 = base64_encode(digest, 20);
4239 std::string sha1_hex = hex_encode((char*)digest, 20);
4243 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4244 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4249 struct SendableMediaAnnouncement
4252 std::string sha1_digest;
4254 SendableMediaAnnouncement(const std::string name_="",
4255 const std::string sha1_digest_=""):
4257 sha1_digest(sha1_digest_)
4261 void Server::sendMediaAnnouncement(u16 peer_id)
4263 DSTACK(__FUNCTION_NAME);
4265 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4268 core::list<SendableMediaAnnouncement> file_announcements;
4270 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4271 i != m_media.end(); i++){
4273 file_announcements.push_back(
4274 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4278 std::ostringstream os(std::ios_base::binary);
4286 u16 length of sha1_digest
4291 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4292 writeU16(os, file_announcements.size());
4294 for(core::list<SendableMediaAnnouncement>::Iterator
4295 j = file_announcements.begin();
4296 j != file_announcements.end(); j++){
4297 os<<serializeString(j->name);
4298 os<<serializeString(j->sha1_digest);
4300 os<<serializeString(g_settings->get("remote_media"));
4303 std::string s = os.str();
4304 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4307 m_con.Send(peer_id, 0, data, true);
4310 struct SendableMedia
4316 SendableMedia(const std::string &name_="", const std::string path_="",
4317 const std::string &data_=""):
4324 void Server::sendRequestedMedia(u16 peer_id,
4325 const core::list<MediaRequest> &tosend)
4327 DSTACK(__FUNCTION_NAME);
4329 verbosestream<<"Server::sendRequestedMedia(): "
4330 <<"Sending files to client"<<std::endl;
4334 // Put 5kB in one bunch (this is not accurate)
4335 u32 bytes_per_bunch = 5000;
4337 core::array< core::list<SendableMedia> > file_bunches;
4338 file_bunches.push_back(core::list<SendableMedia>());
4340 u32 file_size_bunch_total = 0;
4342 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4343 i != tosend.end(); i++)
4345 if(m_media.find(i->name) == m_media.end()){
4346 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4347 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4351 //TODO get path + name
4352 std::string tpath = m_media[(*i).name].path;
4355 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4356 if(fis.good() == false){
4357 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4358 <<tpath<<"\" for reading"<<std::endl;
4361 std::ostringstream tmp_os(std::ios_base::binary);
4365 fis.read(buf, 1024);
4366 std::streamsize len = fis.gcount();
4367 tmp_os.write(buf, len);
4368 file_size_bunch_total += len;
4377 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4378 <<(*i).name<<"\""<<std::endl;
4381 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4382 <<tname<<"\""<<std::endl;*/
4384 file_bunches[file_bunches.size()-1].push_back(
4385 SendableMedia((*i).name, tpath, tmp_os.str()));
4387 // Start next bunch if got enough data
4388 if(file_size_bunch_total >= bytes_per_bunch){
4389 file_bunches.push_back(core::list<SendableMedia>());
4390 file_size_bunch_total = 0;
4395 /* Create and send packets */
4397 u32 num_bunches = file_bunches.size();
4398 for(u32 i=0; i<num_bunches; i++)
4400 std::ostringstream os(std::ios_base::binary);
4404 u16 total number of texture bunches
4405 u16 index of this bunch
4406 u32 number of files in this bunch
4415 writeU16(os, TOCLIENT_MEDIA);
4416 writeU16(os, num_bunches);
4418 writeU32(os, file_bunches[i].size());
4420 for(core::list<SendableMedia>::Iterator
4421 j = file_bunches[i].begin();
4422 j != file_bunches[i].end(); j++){
4423 os<<serializeString(j->name);
4424 os<<serializeLongString(j->data);
4428 std::string s = os.str();
4429 verbosestream<<"Server::sendRequestedMedia(): bunch "
4430 <<i<<"/"<<num_bunches
4431 <<" files="<<file_bunches[i].size()
4432 <<" size=" <<s.size()<<std::endl;
4433 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4435 m_con.Send(peer_id, 0, data, true);
4439 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4441 if(m_detached_inventories.count(name) == 0){
4442 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4445 Inventory *inv = m_detached_inventories[name];
4447 std::ostringstream os(std::ios_base::binary);
4448 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4449 os<<serializeString(name);
4453 std::string s = os.str();
4454 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4456 m_con.Send(peer_id, 0, data, true);
4459 void Server::sendDetachedInventoryToAll(const std::string &name)
4461 DSTACK(__FUNCTION_NAME);
4463 for(core::map<u16, RemoteClient*>::Iterator
4464 i = m_clients.getIterator();
4465 i.atEnd() == false; i++){
4466 RemoteClient *client = i.getNode()->getValue();
4467 sendDetachedInventory(name, client->peer_id);
4471 void Server::sendDetachedInventories(u16 peer_id)
4473 DSTACK(__FUNCTION_NAME);
4475 for(std::map<std::string, Inventory*>::iterator
4476 i = m_detached_inventories.begin();
4477 i != m_detached_inventories.end(); i++){
4478 const std::string &name = i->first;
4479 //Inventory *inv = i->second;
4480 sendDetachedInventory(name, peer_id);
4488 void Server::DiePlayer(u16 peer_id)
4490 DSTACK(__FUNCTION_NAME);
4492 PlayerSAO *playersao = getPlayerSAO(peer_id);
4495 infostream<<"Server::DiePlayer(): Player "
4496 <<playersao->getPlayer()->getName()
4497 <<" dies"<<std::endl;
4499 playersao->setHP(0);
4501 // Trigger scripted stuff
4502 scriptapi_on_dieplayer(m_lua, playersao);
4504 SendPlayerHP(peer_id);
4505 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4508 void Server::RespawnPlayer(u16 peer_id)
4510 DSTACK(__FUNCTION_NAME);
4512 PlayerSAO *playersao = getPlayerSAO(peer_id);
4515 infostream<<"Server::RespawnPlayer(): Player "
4516 <<playersao->getPlayer()->getName()
4517 <<" respawns"<<std::endl;
4519 playersao->setHP(PLAYER_MAX_HP);
4521 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4523 v3f pos = findSpawnPos(m_env->getServerMap());
4524 playersao->setPos(pos);
4528 void Server::UpdateCrafting(u16 peer_id)
4530 DSTACK(__FUNCTION_NAME);
4532 Player* player = m_env->getPlayer(peer_id);
4535 // Get a preview for crafting
4537 getCraftingResult(&player->inventory, preview, false, this);
4539 // Put the new preview in
4540 InventoryList *plist = player->inventory.getList("craftpreview");
4542 assert(plist->getSize() >= 1);
4543 plist->changeItem(0, preview);
4546 RemoteClient* Server::getClient(u16 peer_id)
4548 DSTACK(__FUNCTION_NAME);
4549 //JMutexAutoLock lock(m_con_mutex);
4550 core::map<u16, RemoteClient*>::Node *n;
4551 n = m_clients.find(peer_id);
4552 // A client should exist for all peers
4554 return n->getValue();
4557 std::wstring Server::getStatusString()
4559 std::wostringstream os(std::ios_base::binary);
4562 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4564 os<<L", uptime="<<m_uptime.get();
4565 // Information about clients
4566 core::map<u16, RemoteClient*>::Iterator i;
4569 for(i = m_clients.getIterator(), first = true;
4570 i.atEnd() == false; i++)
4572 // Get client and check that it is valid
4573 RemoteClient *client = i.getNode()->getValue();
4574 assert(client->peer_id == i.getNode()->getKey());
4575 if(client->serialization_version == SER_FMT_VER_INVALID)
4578 Player *player = m_env->getPlayer(client->peer_id);
4579 // Get name of player
4580 std::wstring name = L"unknown";
4582 name = narrow_to_wide(player->getName());
4583 // Add name to information string
4591 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4592 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4593 if(g_settings->get("motd") != "")
4594 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4598 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4600 std::set<std::string> privs;
4601 scriptapi_get_auth(m_lua, name, NULL, &privs);
4605 bool Server::checkPriv(const std::string &name, const std::string &priv)
4607 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4608 return (privs.count(priv) != 0);
4611 void Server::reportPrivsModified(const std::string &name)
4614 for(core::map<u16, RemoteClient*>::Iterator
4615 i = m_clients.getIterator();
4616 i.atEnd() == false; i++){
4617 RemoteClient *client = i.getNode()->getValue();
4618 Player *player = m_env->getPlayer(client->peer_id);
4619 reportPrivsModified(player->getName());
4622 Player *player = m_env->getPlayer(name.c_str());
4625 SendPlayerPrivileges(player->peer_id);
4626 PlayerSAO *sao = player->getPlayerSAO();
4629 sao->updatePrivileges(
4630 getPlayerEffectivePrivs(name),
4635 void Server::reportInventoryFormspecModified(const std::string &name)
4637 Player *player = m_env->getPlayer(name.c_str());
4640 SendPlayerInventoryFormspec(player->peer_id);
4643 // Saves g_settings to configpath given at initialization
4644 void Server::saveConfig()
4646 if(m_path_config != "")
4647 g_settings->updateConfigFile(m_path_config.c_str());
4650 void Server::notifyPlayer(const char *name, const std::wstring msg)
4652 Player *player = m_env->getPlayer(name);
4655 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4658 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4660 Player *player = m_env->getPlayer(playername);
4664 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4668 SendShowFormspecMessage(player->peer_id, formspec, formname);
4672 void Server::notifyPlayers(const std::wstring msg)
4674 BroadcastChatMessage(msg);
4677 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4681 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4682 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4685 Inventory* Server::createDetachedInventory(const std::string &name)
4687 if(m_detached_inventories.count(name) > 0){
4688 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4689 delete m_detached_inventories[name];
4691 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4693 Inventory *inv = new Inventory(m_itemdef);
4695 m_detached_inventories[name] = inv;
4696 sendDetachedInventoryToAll(name);
4703 BoolScopeSet(bool *dst, bool val):
4706 m_orig_state = *m_dst;
4711 *m_dst = m_orig_state;
4718 // actions: time-reversed list
4719 // Return value: success/failure
4720 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4721 std::list<std::string> *log)
4723 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4724 ServerMap *map = (ServerMap*)(&m_env->getMap());
4725 // Disable rollback report sink while reverting
4726 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4728 // Fail if no actions to handle
4729 if(actions.empty()){
4730 log->push_back("Nothing to do.");
4737 for(std::list<RollbackAction>::const_iterator
4738 i = actions.begin();
4739 i != actions.end(); i++)
4741 const RollbackAction &action = *i;
4743 bool success = action.applyRevert(map, this, this);
4746 std::ostringstream os;
4747 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4748 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4750 log->push_back(os.str());
4752 std::ostringstream os;
4753 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4754 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4756 log->push_back(os.str());
4760 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4761 <<" failed"<<std::endl;
4763 // Call it done if less than half failed
4764 return num_failed <= num_tried/2;
4767 // IGameDef interface
4769 IItemDefManager* Server::getItemDefManager()
4773 INodeDefManager* Server::getNodeDefManager()
4777 ICraftDefManager* Server::getCraftDefManager()
4781 ITextureSource* Server::getTextureSource()
4785 IShaderSource* Server::getShaderSource()
4789 u16 Server::allocateUnknownNodeId(const std::string &name)
4791 return m_nodedef->allocateDummy(name);
4793 ISoundManager* Server::getSoundManager()
4795 return &dummySoundManager;
4797 MtEventManager* Server::getEventManager()
4801 IRollbackReportSink* Server::getRollbackReportSink()
4803 if(!m_enable_rollback_recording)
4805 if(!m_rollback_sink_enabled)
4810 IWritableItemDefManager* Server::getWritableItemDefManager()
4814 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4818 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4823 const ModSpec* Server::getModSpec(const std::string &modname)
4825 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4826 i != m_mods.end(); i++){
4827 const ModSpec &mod = *i;
4828 if(mod.name == modname)
4833 void Server::getModNames(core::list<std::string> &modlist)
4835 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4837 modlist.push_back((*i).name);
4840 std::string Server::getBuiltinLuaPath()
4842 return porting::path_share + DIR_DELIM + "builtin";
4845 v3f findSpawnPos(ServerMap &map)
4847 //return v3f(50,50,50)*BS;
4852 nodepos = v2s16(0,0);
4857 s16 water_level = map.m_mgparams->water_level;
4859 // Try to find a good place a few times
4860 for(s32 i=0; i<1000; i++)
4863 // We're going to try to throw the player to this position
4864 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4865 -range + (myrand()%(range*2)));
4866 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4867 // Get ground height at point (fallbacks to heightmap function)
4868 s16 groundheight = map.findGroundLevel(nodepos2d);
4869 // Don't go underwater
4870 if(groundheight <= water_level)
4872 //infostream<<"-> Underwater"<<std::endl;
4875 // Don't go to high places
4876 if(groundheight > water_level + 6)
4878 //infostream<<"-> Underwater"<<std::endl;
4882 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4883 bool is_good = false;
4885 for(s32 i=0; i<10; i++){
4886 v3s16 blockpos = getNodeBlockPos(nodepos);
4887 map.emergeBlock(blockpos, true);
4888 MapNode n = map.getNodeNoEx(nodepos);
4889 if(n.getContent() == CONTENT_AIR){
4900 // Found a good place
4901 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4907 return intToFloat(nodepos, BS);
4910 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4912 RemotePlayer *player = NULL;
4913 bool newplayer = false;
4916 Try to get an existing player
4918 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4920 // If player is already connected, cancel
4921 if(player != NULL && player->peer_id != 0)
4923 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4928 If player with the wanted peer_id already exists, cancel.
4930 if(m_env->getPlayer(peer_id) != NULL)
4932 infostream<<"emergePlayer(): Player with wrong name but same"
4933 " peer_id already exists"<<std::endl;
4938 Create a new player if it doesn't exist yet
4943 player = new RemotePlayer(this);
4944 player->updateName(name);
4946 /* Set player position */
4947 infostream<<"Server: Finding spawn place for player \""
4948 <<name<<"\""<<std::endl;
4949 v3f pos = findSpawnPos(m_env->getServerMap());
4950 player->setPosition(pos);
4952 /* Add player to environment */
4953 m_env->addPlayer(player);
4957 Create a new player active object
4959 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4960 getPlayerEffectivePrivs(player->getName()),
4963 /* Add object to environment */
4964 m_env->addActiveObject(playersao);
4968 scriptapi_on_newplayer(m_lua, playersao);
4970 scriptapi_on_joinplayer(m_lua, playersao);
4975 void Server::handlePeerChange(PeerChange &c)
4977 JMutexAutoLock envlock(m_env_mutex);
4978 JMutexAutoLock conlock(m_con_mutex);
4980 if(c.type == PEER_ADDED)
4987 core::map<u16, RemoteClient*>::Node *n;
4988 n = m_clients.find(c.peer_id);
4989 // The client shouldn't already exist
4993 RemoteClient *client = new RemoteClient();
4994 client->peer_id = c.peer_id;
4995 m_clients.insert(client->peer_id, client);
4998 else if(c.type == PEER_REMOVED)
5005 core::map<u16, RemoteClient*>::Node *n;
5006 n = m_clients.find(c.peer_id);
5007 // The client should exist
5011 Mark objects to be not known by the client
5013 RemoteClient *client = n->getValue();
5015 for(core::map<u16, bool>::Iterator
5016 i = client->m_known_objects.getIterator();
5017 i.atEnd()==false; i++)
5020 u16 id = i.getNode()->getKey();
5021 ServerActiveObject* obj = m_env->getActiveObject(id);
5023 if(obj && obj->m_known_by_count > 0)
5024 obj->m_known_by_count--;
5028 Clear references to playing sounds
5030 for(std::map<s32, ServerPlayingSound>::iterator
5031 i = m_playing_sounds.begin();
5032 i != m_playing_sounds.end();)
5034 ServerPlayingSound &psound = i->second;
5035 psound.clients.erase(c.peer_id);
5036 if(psound.clients.size() == 0)
5037 m_playing_sounds.erase(i++);
5042 Player *player = m_env->getPlayer(c.peer_id);
5044 // Collect information about leaving in chat
5045 std::wstring message;
5049 std::wstring name = narrow_to_wide(player->getName());
5052 message += L" left the game.";
5054 message += L" (timed out)";
5058 /* Run scripts and remove from environment */
5062 PlayerSAO *playersao = player->getPlayerSAO();
5065 scriptapi_on_leaveplayer(m_lua, playersao);
5067 playersao->disconnected();
5077 std::ostringstream os(std::ios_base::binary);
5078 for(core::map<u16, RemoteClient*>::Iterator
5079 i = m_clients.getIterator();
5080 i.atEnd() == false; i++)
5082 RemoteClient *client = i.getNode()->getValue();
5083 assert(client->peer_id == i.getNode()->getKey());
5084 if(client->serialization_version == SER_FMT_VER_INVALID)
5087 Player *player = m_env->getPlayer(client->peer_id);
5090 // Get name of player
5091 os<<player->getName()<<" ";
5094 actionstream<<player->getName()<<" "
5095 <<(c.timeout?"times out.":"leaves game.")
5096 <<" List of players: "
5097 <<os.str()<<std::endl;
5102 delete m_clients[c.peer_id];
5103 m_clients.remove(c.peer_id);
5105 // Send player info to all remaining clients
5106 //SendPlayerInfos();
5108 // Send leave chat message to all remaining clients
5109 if(message.length() != 0)
5110 BroadcastChatMessage(message);
5119 void Server::handlePeerChanges()
5121 while(m_peer_change_queue.size() > 0)
5123 PeerChange c = m_peer_change_queue.pop_front();
5125 verbosestream<<"Server: Handling peer change: "
5126 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5129 handlePeerChange(c);
5133 void dedicated_server_loop(Server &server, bool &kill)
5135 DSTACK(__FUNCTION_NAME);
5137 verbosestream<<"dedicated_server_loop()"<<std::endl;
5139 IntervalLimiter m_profiler_interval;
5143 float steplen = g_settings->getFloat("dedicated_server_step");
5144 // This is kind of a hack but can be done like this
5145 // because server.step() is very light
5147 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5148 sleep_ms((int)(steplen*1000.0));
5150 server.step(steplen);
5152 if(server.getShutdownRequested() || kill)
5154 infostream<<"Dedicated server quitting"<<std::endl;
5161 float profiler_print_interval =
5162 g_settings->getFloat("profiler_print_interval");
5163 if(profiler_print_interval != 0)
5165 if(m_profiler_interval.step(steplen, profiler_print_interval))
5167 infostream<<"Profiler:"<<std::endl;
5168 g_profiler->print(infostream);
5169 g_profiler->clear();