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),
949 m_itemdef(createItemDefManager()),
950 m_nodedef(createNodeDefManager()),
951 m_craftdef(createCraftDefManager()),
952 m_event(new EventManager()),
954 m_emergethread(this),
955 m_time_of_day_send_timer(0),
957 m_shutdown_requested(false),
958 m_ignore_map_edit_events(false),
959 m_ignore_map_edit_events_peer_id(0)
961 m_liquid_transform_timer = 0.0;
962 m_print_info_timer = 0.0;
963 m_objectdata_timer = 0.0;
964 m_emergethread_trigger_timer = 0.0;
965 m_savemap_timer = 0.0;
969 m_step_dtime_mutex.Init();
973 throw ServerError("Supplied empty world path");
975 if(!gamespec.isValid())
976 throw ServerError("Supplied invalid gamespec");
978 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
979 if(m_simple_singleplayer_mode)
980 infostream<<" in simple singleplayer mode"<<std::endl;
982 infostream<<std::endl;
983 infostream<<"- world: "<<m_path_world<<std::endl;
984 infostream<<"- config: "<<m_path_config<<std::endl;
985 infostream<<"- game: "<<m_gamespec.path<<std::endl;
987 // Create emerge manager
988 m_emerge = new EmergeManager(this, g_settings->getS16("use_mapgen_version"));
990 // Create rollback manager
991 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
992 m_rollback = createRollbackManager(rollback_path, this);
994 // Create world if it doesn't exist
995 if(!initializeWorld(m_path_world, m_gamespec.id))
996 throw ServerError("Failed to initialize world");
998 ModConfiguration modconf(m_path_world);
999 m_mods = modconf.getMods();
1000 // complain about mods with unsatisfied dependencies
1001 if(!modconf.isConsistent())
1003 errorstream << "The following mods have unsatisfied dependencies: ";
1004 std::list<ModSpec> modlist = modconf.getUnsatisfiedMods();
1005 for(std::list<ModSpec>::iterator it = modlist.begin();
1006 it != modlist.end(); ++it)
1008 errorstream << (*it).name << " ";
1010 errorstream << std::endl;
1013 Settings worldmt_settings;
1014 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
1015 worldmt_settings.readConfigFile(worldmt.c_str());
1016 std::vector<std::string> names = worldmt_settings.getNames();
1017 std::set<std::string> exclude_mod_names;
1018 std::set<std::string> load_mod_names;
1019 for(std::vector<std::string>::iterator it = names.begin();
1020 it != names.end(); ++it)
1022 std::string name = *it;
1023 if (name.compare(0,9,"load_mod_")==0)
1025 if(worldmt_settings.getBool(name))
1026 load_mod_names.insert(name.substr(9));
1028 exclude_mod_names.insert(name.substr(9));
1031 // complain about mods declared to be loaded, but not found
1032 for(std::vector<ModSpec>::iterator it = m_mods.begin();
1033 it != m_mods.end(); ++it)
1034 load_mod_names.erase((*it).name);
1035 if(!load_mod_names.empty())
1037 errorstream << "The following mods could not be found: ";
1038 for(std::set<std::string>::iterator it = load_mod_names.begin();
1039 it != load_mod_names.end(); ++it)
1040 errorstream << (*it) << " ";
1041 errorstream << std::endl;
1044 // Path to builtin.lua
1045 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
1048 JMutexAutoLock envlock(m_env_mutex);
1049 JMutexAutoLock conlock(m_con_mutex);
1051 // Initialize scripting
1053 infostream<<"Server: Initializing Lua"<<std::endl;
1054 m_lua = script_init();
1057 scriptapi_export(m_lua, this);
1058 // Load and run builtin.lua
1059 infostream<<"Server: Loading builtin.lua [\""
1060 <<builtinpath<<"\"]"<<std::endl;
1061 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1063 errorstream<<"Server: Failed to load and run "
1064 <<builtinpath<<std::endl;
1065 throw ModError("Failed to load and run "+builtinpath);
1068 infostream<<"Server: Loading mods: ";
1069 for(std::vector<ModSpec>::iterator i = m_mods.begin();
1070 i != m_mods.end(); i++){
1071 const ModSpec &mod = *i;
1072 infostream<<mod.name<<" ";
1074 infostream<<std::endl;
1075 // Load and run "mod" scripts
1076 for(std::vector<ModSpec>::iterator i = m_mods.begin();
1077 i != m_mods.end(); i++){
1078 const ModSpec &mod = *i;
1079 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1080 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1081 <<scriptpath<<"\"]"<<std::endl;
1082 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1084 errorstream<<"Server: Failed to load and run "
1085 <<scriptpath<<std::endl;
1086 throw ModError("Failed to load and run "+scriptpath);
1090 // Read Textures and calculate sha1 sums
1093 // Apply item aliases in the node definition manager
1094 m_nodedef->updateAliases(m_itemdef);
1096 // Add default biomes after nodedef had its aliases added
1097 if (m_emerge->biomedef)
1098 m_emerge->biomedef->addDefaultBiomes();
1100 // Initialize Environment
1102 m_env = new ServerEnvironment(new ServerMap(path_world, this, m_emerge), m_lua,
1105 // Give environment reference to scripting api
1106 scriptapi_add_environment(m_lua, m_env);
1108 // Register us to receive map edit events
1109 m_env->getMap().addEventReceiver(this);
1111 // If file exists, load environment metadata
1112 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1114 infostream<<"Server: Loading environment metadata"<<std::endl;
1115 m_env->loadMeta(m_path_world);
1119 infostream<<"Server: Loading players"<<std::endl;
1120 m_env->deSerializePlayers(m_path_world);
1123 Add some test ActiveBlockModifiers to environment
1125 add_legacy_abms(m_env, m_nodedef);
1130 infostream<<"Server destructing"<<std::endl;
1133 Send shutdown message
1136 JMutexAutoLock conlock(m_con_mutex);
1138 std::wstring line = L"*** Server shutting down";
1141 Send the message to clients
1143 for(core::map<u16, RemoteClient*>::Iterator
1144 i = m_clients.getIterator();
1145 i.atEnd() == false; i++)
1147 // Get client and check that it is valid
1148 RemoteClient *client = i.getNode()->getValue();
1149 assert(client->peer_id == i.getNode()->getKey());
1150 if(client->serialization_version == SER_FMT_VER_INVALID)
1154 SendChatMessage(client->peer_id, line);
1156 catch(con::PeerNotFoundException &e)
1162 JMutexAutoLock envlock(m_env_mutex);
1163 JMutexAutoLock conlock(m_con_mutex);
1166 Execute script shutdown hooks
1168 scriptapi_on_shutdown(m_lua);
1172 JMutexAutoLock envlock(m_env_mutex);
1177 infostream<<"Server: Saving players"<<std::endl;
1178 m_env->serializePlayers(m_path_world);
1181 Save environment metadata
1183 infostream<<"Server: Saving environment metadata"<<std::endl;
1184 m_env->saveMeta(m_path_world);
1196 JMutexAutoLock clientslock(m_con_mutex);
1198 for(core::map<u16, RemoteClient*>::Iterator
1199 i = m_clients.getIterator();
1200 i.atEnd() == false; i++)
1204 delete i.getNode()->getValue();
1208 // Delete things in the reverse order of creation
1217 // Deinitialize scripting
1218 infostream<<"Server: Deinitializing scripting"<<std::endl;
1219 script_deinit(m_lua);
1221 // Delete detached inventories
1223 for(std::map<std::string, Inventory*>::iterator
1224 i = m_detached_inventories.begin();
1225 i != m_detached_inventories.end(); i++){
1231 void Server::start(unsigned short port)
1233 DSTACK(__FUNCTION_NAME);
1234 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1236 // Stop thread if already running
1239 // Initialize connection
1240 m_con.SetTimeoutMs(30);
1244 m_thread.setRun(true);
1247 // ASCII art for the win!
1249 <<" .__ __ __ "<<std::endl
1250 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1251 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1252 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1253 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1254 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1255 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1256 actionstream<<"Server for gameid=\""<<m_gamespec.id
1257 <<"\" listening on port "<<port<<"."<<std::endl;
1262 DSTACK(__FUNCTION_NAME);
1264 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1266 // Stop threads (set run=false first so both start stopping)
1267 m_thread.setRun(false);
1268 m_emergethread.setRun(false);
1270 m_emergethread.stop();
1272 infostream<<"Server: Threads stopped"<<std::endl;
1275 void Server::step(float dtime)
1277 DSTACK(__FUNCTION_NAME);
1282 JMutexAutoLock lock(m_step_dtime_mutex);
1283 m_step_dtime += dtime;
1285 // Throw if fatal error occurred in thread
1286 std::string async_err = m_async_fatal_error.get();
1287 if(async_err != ""){
1288 throw ServerError(async_err);
1292 void Server::AsyncRunStep()
1294 DSTACK(__FUNCTION_NAME);
1296 g_profiler->add("Server::AsyncRunStep (num)", 1);
1300 JMutexAutoLock lock1(m_step_dtime_mutex);
1301 dtime = m_step_dtime;
1305 // Send blocks to clients
1312 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1314 //infostream<<"Server steps "<<dtime<<std::endl;
1315 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1318 JMutexAutoLock lock1(m_step_dtime_mutex);
1319 m_step_dtime -= dtime;
1326 m_uptime.set(m_uptime.get() + dtime);
1330 // Process connection's timeouts
1331 JMutexAutoLock lock2(m_con_mutex);
1332 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1333 m_con.RunTimeouts(dtime);
1337 // This has to be called so that the client list gets synced
1338 // with the peer list of the connection
1339 handlePeerChanges();
1343 Update time of day and overall game time
1346 JMutexAutoLock envlock(m_env_mutex);
1348 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1351 Send to clients at constant intervals
1354 m_time_of_day_send_timer -= dtime;
1355 if(m_time_of_day_send_timer < 0.0)
1357 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1359 //JMutexAutoLock envlock(m_env_mutex);
1360 JMutexAutoLock conlock(m_con_mutex);
1362 for(core::map<u16, RemoteClient*>::Iterator
1363 i = m_clients.getIterator();
1364 i.atEnd() == false; i++)
1366 RemoteClient *client = i.getNode()->getValue();
1367 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1368 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1370 m_con.Send(client->peer_id, 0, data, true);
1376 JMutexAutoLock lock(m_env_mutex);
1378 ScopeProfiler sp(g_profiler, "SEnv step");
1379 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1383 const float map_timer_and_unload_dtime = 2.92;
1384 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1386 JMutexAutoLock lock(m_env_mutex);
1387 // Run Map's timers and unload unused data
1388 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1389 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1390 g_settings->getFloat("server_unload_unused_data_timeout"));
1401 JMutexAutoLock lock(m_env_mutex);
1402 JMutexAutoLock lock2(m_con_mutex);
1404 ScopeProfiler sp(g_profiler, "Server: handle players");
1406 for(core::map<u16, RemoteClient*>::Iterator
1407 i = m_clients.getIterator();
1408 i.atEnd() == false; i++)
1410 RemoteClient *client = i.getNode()->getValue();
1411 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1412 if(playersao == NULL)
1416 Handle player HPs (die if hp=0)
1418 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1420 if(playersao->getHP() == 0)
1421 DiePlayer(client->peer_id);
1423 SendPlayerHP(client->peer_id);
1427 Send player inventories if necessary
1429 if(playersao->m_moved){
1430 SendMovePlayer(client->peer_id);
1431 playersao->m_moved = false;
1433 if(playersao->m_inventory_not_sent){
1434 UpdateCrafting(client->peer_id);
1435 SendInventory(client->peer_id);
1440 /* Transform liquids */
1441 m_liquid_transform_timer += dtime;
1442 if(m_liquid_transform_timer >= 1.00)
1444 m_liquid_transform_timer -= 1.00;
1446 JMutexAutoLock lock(m_env_mutex);
1448 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1450 core::map<v3s16, MapBlock*> modified_blocks;
1451 m_env->getMap().transformLiquids(modified_blocks);
1456 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1457 ServerMap &map = ((ServerMap&)m_env->getMap());
1458 map.updateLighting(modified_blocks, lighting_modified_blocks);
1460 // Add blocks modified by lighting to modified_blocks
1461 for(core::map<v3s16, MapBlock*>::Iterator
1462 i = lighting_modified_blocks.getIterator();
1463 i.atEnd() == false; i++)
1465 MapBlock *block = i.getNode()->getValue();
1466 modified_blocks.insert(block->getPos(), block);
1470 Set the modified blocks unsent for all the clients
1473 JMutexAutoLock lock2(m_con_mutex);
1475 for(core::map<u16, RemoteClient*>::Iterator
1476 i = m_clients.getIterator();
1477 i.atEnd() == false; i++)
1479 RemoteClient *client = i.getNode()->getValue();
1481 if(modified_blocks.size() > 0)
1483 // Remove block from sent history
1484 client->SetBlocksNotSent(modified_blocks);
1489 // Periodically print some info
1491 float &counter = m_print_info_timer;
1497 JMutexAutoLock lock2(m_con_mutex);
1499 if(m_clients.size() != 0)
1500 infostream<<"Players:"<<std::endl;
1501 for(core::map<u16, RemoteClient*>::Iterator
1502 i = m_clients.getIterator();
1503 i.atEnd() == false; i++)
1505 //u16 peer_id = i.getNode()->getKey();
1506 RemoteClient *client = i.getNode()->getValue();
1507 Player *player = m_env->getPlayer(client->peer_id);
1510 infostream<<"* "<<player->getName()<<"\t";
1511 client->PrintInfo(infostream);
1516 //if(g_settings->getBool("enable_experimental"))
1520 Check added and deleted active objects
1523 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1524 JMutexAutoLock envlock(m_env_mutex);
1525 JMutexAutoLock conlock(m_con_mutex);
1527 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1529 // Radius inside which objects are active
1530 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1531 radius *= MAP_BLOCKSIZE;
1533 for(core::map<u16, RemoteClient*>::Iterator
1534 i = m_clients.getIterator();
1535 i.atEnd() == false; i++)
1537 RemoteClient *client = i.getNode()->getValue();
1539 // If definitions and textures have not been sent, don't
1540 // send objects either
1541 if(!client->definitions_sent)
1544 Player *player = m_env->getPlayer(client->peer_id);
1547 // This can happen if the client timeouts somehow
1548 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1550 <<" has no associated player"<<std::endl;*/
1553 v3s16 pos = floatToInt(player->getPosition(), BS);
1555 core::map<u16, bool> removed_objects;
1556 core::map<u16, bool> added_objects;
1557 m_env->getRemovedActiveObjects(pos, radius,
1558 client->m_known_objects, removed_objects);
1559 m_env->getAddedActiveObjects(pos, radius,
1560 client->m_known_objects, added_objects);
1562 // Ignore if nothing happened
1563 if(removed_objects.size() == 0 && added_objects.size() == 0)
1565 //infostream<<"active objects: none changed"<<std::endl;
1569 std::string data_buffer;
1573 // Handle removed objects
1574 writeU16((u8*)buf, removed_objects.size());
1575 data_buffer.append(buf, 2);
1576 for(core::map<u16, bool>::Iterator
1577 i = removed_objects.getIterator();
1578 i.atEnd()==false; i++)
1581 u16 id = i.getNode()->getKey();
1582 ServerActiveObject* obj = m_env->getActiveObject(id);
1584 // Add to data buffer for sending
1585 writeU16((u8*)buf, i.getNode()->getKey());
1586 data_buffer.append(buf, 2);
1588 // Remove from known objects
1589 client->m_known_objects.remove(i.getNode()->getKey());
1591 if(obj && obj->m_known_by_count > 0)
1592 obj->m_known_by_count--;
1595 // Handle added objects
1596 writeU16((u8*)buf, added_objects.size());
1597 data_buffer.append(buf, 2);
1598 for(core::map<u16, bool>::Iterator
1599 i = added_objects.getIterator();
1600 i.atEnd()==false; i++)
1603 u16 id = i.getNode()->getKey();
1604 ServerActiveObject* obj = m_env->getActiveObject(id);
1607 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1609 infostream<<"WARNING: "<<__FUNCTION_NAME
1610 <<": NULL object"<<std::endl;
1612 type = obj->getSendType();
1614 // Add to data buffer for sending
1615 writeU16((u8*)buf, id);
1616 data_buffer.append(buf, 2);
1617 writeU8((u8*)buf, type);
1618 data_buffer.append(buf, 1);
1621 data_buffer.append(serializeLongString(
1622 obj->getClientInitializationData(client->net_proto_version)));
1624 data_buffer.append(serializeLongString(""));
1626 // Add to known objects
1627 client->m_known_objects.insert(i.getNode()->getKey(), false);
1630 obj->m_known_by_count++;
1634 SharedBuffer<u8> reply(2 + data_buffer.size());
1635 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1636 memcpy((char*)&reply[2], data_buffer.c_str(),
1637 data_buffer.size());
1639 m_con.Send(client->peer_id, 0, reply, true);
1641 verbosestream<<"Server: Sent object remove/add: "
1642 <<removed_objects.size()<<" removed, "
1643 <<added_objects.size()<<" added, "
1644 <<"packet size is "<<reply.getSize()<<std::endl;
1649 Collect a list of all the objects known by the clients
1650 and report it back to the environment.
1653 core::map<u16, bool> all_known_objects;
1655 for(core::map<u16, RemoteClient*>::Iterator
1656 i = m_clients.getIterator();
1657 i.atEnd() == false; i++)
1659 RemoteClient *client = i.getNode()->getValue();
1660 // Go through all known objects of client
1661 for(core::map<u16, bool>::Iterator
1662 i = client->m_known_objects.getIterator();
1663 i.atEnd()==false; i++)
1665 u16 id = i.getNode()->getKey();
1666 all_known_objects[id] = true;
1670 m_env->setKnownActiveObjects(whatever);
1676 Send object messages
1679 JMutexAutoLock envlock(m_env_mutex);
1680 JMutexAutoLock conlock(m_con_mutex);
1682 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1685 // Value = data sent by object
1686 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1688 // Get active object messages from environment
1691 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1695 core::list<ActiveObjectMessage>* message_list = NULL;
1696 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1697 n = buffered_messages.find(aom.id);
1700 message_list = new core::list<ActiveObjectMessage>;
1701 buffered_messages.insert(aom.id, message_list);
1705 message_list = n->getValue();
1707 message_list->push_back(aom);
1710 // Route data to every client
1711 for(core::map<u16, RemoteClient*>::Iterator
1712 i = m_clients.getIterator();
1713 i.atEnd()==false; i++)
1715 RemoteClient *client = i.getNode()->getValue();
1716 std::string reliable_data;
1717 std::string unreliable_data;
1718 // Go through all objects in message buffer
1719 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1720 j = buffered_messages.getIterator();
1721 j.atEnd()==false; j++)
1723 // If object is not known by client, skip it
1724 u16 id = j.getNode()->getKey();
1725 if(client->m_known_objects.find(id) == NULL)
1727 // Get message list of object
1728 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1729 // Go through every message
1730 for(core::list<ActiveObjectMessage>::Iterator
1731 k = list->begin(); k != list->end(); k++)
1733 // Compose the full new data with header
1734 ActiveObjectMessage aom = *k;
1735 std::string new_data;
1738 writeU16((u8*)&buf[0], aom.id);
1739 new_data.append(buf, 2);
1741 new_data += serializeString(aom.datastring);
1742 // Add data to buffer
1744 reliable_data += new_data;
1746 unreliable_data += new_data;
1750 reliable_data and unreliable_data are now ready.
1753 if(reliable_data.size() > 0)
1755 SharedBuffer<u8> reply(2 + reliable_data.size());
1756 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1757 memcpy((char*)&reply[2], reliable_data.c_str(),
1758 reliable_data.size());
1760 m_con.Send(client->peer_id, 0, reply, true);
1762 if(unreliable_data.size() > 0)
1764 SharedBuffer<u8> reply(2 + unreliable_data.size());
1765 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1766 memcpy((char*)&reply[2], unreliable_data.c_str(),
1767 unreliable_data.size());
1768 // Send as unreliable
1769 m_con.Send(client->peer_id, 0, reply, false);
1772 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1774 infostream<<"Server: Size of object message data: "
1775 <<"reliable: "<<reliable_data.size()
1776 <<", unreliable: "<<unreliable_data.size()
1781 // Clear buffered_messages
1782 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1783 i = buffered_messages.getIterator();
1784 i.atEnd()==false; i++)
1786 delete i.getNode()->getValue();
1790 } // enable_experimental
1793 Send queued-for-sending map edit events.
1796 // We will be accessing the environment and the connection
1797 JMutexAutoLock lock(m_env_mutex);
1798 JMutexAutoLock conlock(m_con_mutex);
1800 // Don't send too many at a time
1803 // Single change sending is disabled if queue size is not small
1804 bool disable_single_change_sending = false;
1805 if(m_unsent_map_edit_queue.size() >= 4)
1806 disable_single_change_sending = true;
1808 int event_count = m_unsent_map_edit_queue.size();
1810 // We'll log the amount of each
1813 while(m_unsent_map_edit_queue.size() != 0)
1815 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1817 // Players far away from the change are stored here.
1818 // Instead of sending the changes, MapBlocks are set not sent
1820 core::list<u16> far_players;
1822 if(event->type == MEET_ADDNODE)
1824 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1825 prof.add("MEET_ADDNODE", 1);
1826 if(disable_single_change_sending)
1827 sendAddNode(event->p, event->n, event->already_known_by_peer,
1830 sendAddNode(event->p, event->n, event->already_known_by_peer,
1833 else if(event->type == MEET_REMOVENODE)
1835 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1836 prof.add("MEET_REMOVENODE", 1);
1837 if(disable_single_change_sending)
1838 sendRemoveNode(event->p, event->already_known_by_peer,
1841 sendRemoveNode(event->p, event->already_known_by_peer,
1844 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1846 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1847 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1848 setBlockNotSent(event->p);
1850 else if(event->type == MEET_OTHER)
1852 infostream<<"Server: MEET_OTHER"<<std::endl;
1853 prof.add("MEET_OTHER", 1);
1854 for(core::map<v3s16, bool>::Iterator
1855 i = event->modified_blocks.getIterator();
1856 i.atEnd()==false; i++)
1858 v3s16 p = i.getNode()->getKey();
1864 prof.add("unknown", 1);
1865 infostream<<"WARNING: Server: Unknown MapEditEvent "
1866 <<((u32)event->type)<<std::endl;
1870 Set blocks not sent to far players
1872 if(far_players.size() > 0)
1874 // Convert list format to that wanted by SetBlocksNotSent
1875 core::map<v3s16, MapBlock*> modified_blocks2;
1876 for(core::map<v3s16, bool>::Iterator
1877 i = event->modified_blocks.getIterator();
1878 i.atEnd()==false; i++)
1880 v3s16 p = i.getNode()->getKey();
1881 modified_blocks2.insert(p,
1882 m_env->getMap().getBlockNoCreateNoEx(p));
1884 // Set blocks not sent
1885 for(core::list<u16>::Iterator
1886 i = far_players.begin();
1887 i != far_players.end(); i++)
1890 RemoteClient *client = getClient(peer_id);
1893 client->SetBlocksNotSent(modified_blocks2);
1899 /*// Don't send too many at a time
1901 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1905 if(event_count >= 5){
1906 infostream<<"Server: MapEditEvents:"<<std::endl;
1907 prof.print(infostream);
1908 } else if(event_count != 0){
1909 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1910 prof.print(verbosestream);
1916 Trigger emergethread (it somehow gets to a non-triggered but
1917 bysy state sometimes)
1920 float &counter = m_emergethread_trigger_timer;
1926 m_emergethread.trigger();
1928 // Update m_enable_rollback_recording here too
1929 m_enable_rollback_recording =
1930 g_settings->getBool("enable_rollback_recording");
1934 // Save map, players and auth stuff
1936 float &counter = m_savemap_timer;
1938 if(counter >= g_settings->getFloat("server_map_save_interval"))
1941 JMutexAutoLock lock(m_env_mutex);
1943 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1946 if(m_banmanager.isModified())
1947 m_banmanager.save();
1949 // Save changed parts of map
1950 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1953 m_env->serializePlayers(m_path_world);
1955 // Save environment metadata
1956 m_env->saveMeta(m_path_world);
1961 void Server::Receive()
1963 DSTACK(__FUNCTION_NAME);
1964 SharedBuffer<u8> data;
1969 JMutexAutoLock conlock(m_con_mutex);
1970 datasize = m_con.Receive(peer_id, data);
1973 // This has to be called so that the client list gets synced
1974 // with the peer list of the connection
1975 handlePeerChanges();
1977 ProcessData(*data, datasize, peer_id);
1979 catch(con::InvalidIncomingDataException &e)
1981 infostream<<"Server::Receive(): "
1982 "InvalidIncomingDataException: what()="
1983 <<e.what()<<std::endl;
1985 catch(con::PeerNotFoundException &e)
1987 //NOTE: This is not needed anymore
1989 // The peer has been disconnected.
1990 // Find the associated player and remove it.
1992 /*JMutexAutoLock envlock(m_env_mutex);
1994 infostream<<"ServerThread: peer_id="<<peer_id
1995 <<" has apparently closed connection. "
1996 <<"Removing player."<<std::endl;
1998 m_env->removePlayer(peer_id);*/
2002 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
2004 DSTACK(__FUNCTION_NAME);
2005 // Environment is locked first.
2006 JMutexAutoLock envlock(m_env_mutex);
2007 JMutexAutoLock conlock(m_con_mutex);
2009 ScopeProfiler sp(g_profiler, "Server::ProcessData");
2012 Address address = m_con.GetPeerAddress(peer_id);
2013 std::string addr_s = address.serializeString();
2015 // drop player if is ip is banned
2016 if(m_banmanager.isIpBanned(addr_s)){
2017 infostream<<"Server: A banned client tried to connect from "
2018 <<addr_s<<"; banned name was "
2019 <<m_banmanager.getBanName(addr_s)<<std::endl;
2020 // This actually doesn't seem to transfer to the client
2021 SendAccessDenied(m_con, peer_id,
2022 L"Your ip is banned. Banned name was "
2023 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
2024 m_con.DeletePeer(peer_id);
2028 catch(con::PeerNotFoundException &e)
2030 infostream<<"Server::ProcessData(): Cancelling: peer "
2031 <<peer_id<<" not found"<<std::endl;
2035 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
2037 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
2045 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
2047 if(command == TOSERVER_INIT)
2049 // [0] u16 TOSERVER_INIT
2050 // [2] u8 SER_FMT_VER_HIGHEST
2051 // [3] u8[20] player_name
2052 // [23] u8[28] password <--- can be sent without this, from old versions
2054 if(datasize < 2+1+PLAYERNAME_SIZE)
2057 verbosestream<<"Server: Got TOSERVER_INIT from "
2058 <<peer_id<<std::endl;
2060 // First byte after command is maximum supported
2061 // serialization version
2062 u8 client_max = data[2];
2063 u8 our_max = SER_FMT_VER_HIGHEST;
2064 // Use the highest version supported by both
2065 u8 deployed = core::min_(client_max, our_max);
2066 // If it's lower than the lowest supported, give up.
2067 if(deployed < SER_FMT_VER_LOWEST)
2068 deployed = SER_FMT_VER_INVALID;
2070 //peer->serialization_version = deployed;
2071 getClient(peer_id)->pending_serialization_version = deployed;
2073 if(deployed == SER_FMT_VER_INVALID)
2075 actionstream<<"Server: A mismatched client tried to connect from "
2076 <<addr_s<<std::endl;
2077 infostream<<"Server: Cannot negotiate "
2078 "serialization version with peer "
2079 <<peer_id<<std::endl;
2080 SendAccessDenied(m_con, peer_id, std::wstring(
2081 L"Your client's version is not supported.\n"
2082 L"Server version is ")
2083 + narrow_to_wide(VERSION_STRING) + L"."
2089 Read and check network protocol version
2092 u16 min_net_proto_version = 0;
2093 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2094 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2096 // Use same version as minimum and maximum if maximum version field
2097 // doesn't exist (backwards compatibility)
2098 u16 max_net_proto_version = min_net_proto_version;
2099 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
2100 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
2102 // Start with client's maximum version
2103 u16 net_proto_version = max_net_proto_version;
2105 // Figure out a working version if it is possible at all
2106 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
2107 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
2109 // If maximum is larger than our maximum, go with our maximum
2110 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2111 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
2112 // Else go with client's maximum
2114 net_proto_version = max_net_proto_version;
2117 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
2118 <<min_net_proto_version<<", max: "<<max_net_proto_version
2119 <<", chosen: "<<net_proto_version<<std::endl;
2121 getClient(peer_id)->net_proto_version = net_proto_version;
2123 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
2124 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2126 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
2128 SendAccessDenied(m_con, peer_id, std::wstring(
2129 L"Your client's version is not supported.\n"
2130 L"Server version is ")
2131 + narrow_to_wide(VERSION_STRING) + L",\n"
2132 + L"server's PROTOCOL_VERSION is "
2133 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
2135 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
2136 + L", client's PROTOCOL_VERSION is "
2137 + narrow_to_wide(itos(min_net_proto_version))
2139 + narrow_to_wide(itos(max_net_proto_version))
2144 if(g_settings->getBool("strict_protocol_version_checking"))
2146 if(net_proto_version != LATEST_PROTOCOL_VERSION)
2148 actionstream<<"Server: A mismatched (strict) client tried to "
2149 <<"connect from "<<addr_s<<std::endl;
2150 SendAccessDenied(m_con, peer_id, std::wstring(
2151 L"Your client's version is not supported.\n"
2152 L"Server version is ")
2153 + narrow_to_wide(VERSION_STRING) + L",\n"
2154 + L"server's PROTOCOL_VERSION (strict) is "
2155 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
2156 + L", client's PROTOCOL_VERSION is "
2157 + narrow_to_wide(itos(min_net_proto_version))
2159 + narrow_to_wide(itos(max_net_proto_version))
2170 char playername[PLAYERNAME_SIZE];
2171 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2173 playername[i] = data[3+i];
2175 playername[PLAYERNAME_SIZE-1] = 0;
2177 if(playername[0]=='\0')
2179 actionstream<<"Server: Player with an empty name "
2180 <<"tried to connect from "<<addr_s<<std::endl;
2181 SendAccessDenied(m_con, peer_id,
2186 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2188 actionstream<<"Server: Player with an invalid name "
2189 <<"tried to connect from "<<addr_s<<std::endl;
2190 SendAccessDenied(m_con, peer_id,
2191 L"Name contains unallowed characters");
2195 infostream<<"Server: New connection: \""<<playername<<"\" from "
2196 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2199 char given_password[PASSWORD_SIZE];
2200 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2202 // old version - assume blank password
2203 given_password[0] = 0;
2207 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2209 given_password[i] = data[23+i];
2211 given_password[PASSWORD_SIZE-1] = 0;
2214 if(!base64_is_valid(given_password)){
2215 infostream<<"Server: "<<playername
2216 <<" supplied invalid password hash"<<std::endl;
2217 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2221 std::string checkpwd; // Password hash to check against
2222 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2224 // If no authentication info exists for user, create it
2226 if(!isSingleplayer() &&
2227 g_settings->getBool("disallow_empty_password") &&
2228 std::string(given_password) == ""){
2229 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2230 L"disallowed. Set a password and try again.");
2233 std::wstring raw_default_password =
2234 narrow_to_wide(g_settings->get("default_password"));
2235 std::string initial_password =
2236 translatePassword(playername, raw_default_password);
2238 // If default_password is empty, allow any initial password
2239 if (raw_default_password.length() == 0)
2240 initial_password = given_password;
2242 scriptapi_create_auth(m_lua, playername, initial_password);
2245 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2248 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2252 if(given_password != checkpwd){
2253 infostream<<"Server: peer_id="<<peer_id
2254 <<": supplied invalid password for "
2255 <<playername<<std::endl;
2256 SendAccessDenied(m_con, peer_id, L"Invalid password");
2260 // Do not allow multiple players in simple singleplayer mode.
2261 // This isn't a perfect way to do it, but will suffice for now.
2262 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2263 infostream<<"Server: Not allowing another client to connect in"
2264 <<" simple singleplayer mode"<<std::endl;
2265 SendAccessDenied(m_con, peer_id,
2266 L"Running in simple singleplayer mode.");
2270 // Enforce user limit.
2271 // Don't enforce for users that have some admin right
2272 if(m_clients.size() >= g_settings->getU16("max_users") &&
2273 !checkPriv(playername, "server") &&
2274 !checkPriv(playername, "ban") &&
2275 !checkPriv(playername, "privs") &&
2276 !checkPriv(playername, "password") &&
2277 playername != g_settings->get("name"))
2279 actionstream<<"Server: "<<playername<<" tried to join, but there"
2280 <<" are already max_users="
2281 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2282 SendAccessDenied(m_con, peer_id, L"Too many users.");
2287 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2289 // If failed, cancel
2290 if(playersao == NULL)
2292 errorstream<<"Server: peer_id="<<peer_id
2293 <<": failed to emerge player"<<std::endl;
2298 Answer with a TOCLIENT_INIT
2301 SharedBuffer<u8> reply(2+1+6+8+4);
2302 writeU16(&reply[0], TOCLIENT_INIT);
2303 writeU8(&reply[2], deployed);
2304 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2305 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2306 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2309 m_con.Send(peer_id, 0, reply, true);
2313 Send complete position information
2315 SendMovePlayer(peer_id);
2320 if(command == TOSERVER_INIT2)
2322 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2323 <<peer_id<<std::endl;
2325 Player *player = m_env->getPlayer(peer_id);
2327 verbosestream<<"Server: TOSERVER_INIT2: "
2328 <<"Player not found; ignoring."<<std::endl;
2332 RemoteClient *client = getClient(peer_id);
2333 client->serialization_version =
2334 getClient(peer_id)->pending_serialization_version;
2337 Send some initialization data
2340 infostream<<"Server: Sending content to "
2341 <<getPlayerName(peer_id)<<std::endl;
2343 // Send item definitions
2344 SendItemDef(m_con, peer_id, m_itemdef);
2346 // Send node definitions
2347 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2349 // Send media announcement
2350 sendMediaAnnouncement(peer_id);
2353 SendPlayerPrivileges(peer_id);
2355 // Send inventory formspec
2356 SendPlayerInventoryFormspec(peer_id);
2359 UpdateCrafting(peer_id);
2360 SendInventory(peer_id);
2363 if(g_settings->getBool("enable_damage"))
2364 SendPlayerHP(peer_id);
2366 // Send detached inventories
2367 sendDetachedInventories(peer_id);
2369 // Show death screen if necessary
2371 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2375 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2376 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2377 m_con.Send(peer_id, 0, data, true);
2380 // Note things in chat if not in simple singleplayer mode
2381 if(!m_simple_singleplayer_mode)
2383 // Send information about server to player in chat
2384 SendChatMessage(peer_id, getStatusString());
2386 // Send information about joining in chat
2388 std::wstring name = L"unknown";
2389 Player *player = m_env->getPlayer(peer_id);
2391 name = narrow_to_wide(player->getName());
2393 std::wstring message;
2396 message += L" joined the game.";
2397 BroadcastChatMessage(message);
2401 // Warnings about protocol version can be issued here
2402 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2404 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2405 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2412 std::ostringstream os(std::ios_base::binary);
2413 for(core::map<u16, RemoteClient*>::Iterator
2414 i = m_clients.getIterator();
2415 i.atEnd() == false; i++)
2417 RemoteClient *client = i.getNode()->getValue();
2418 assert(client->peer_id == i.getNode()->getKey());
2419 if(client->serialization_version == SER_FMT_VER_INVALID)
2422 Player *player = m_env->getPlayer(client->peer_id);
2425 // Get name of player
2426 os<<player->getName()<<" ";
2429 actionstream<<player->getName()<<" joins game. List of players: "
2430 <<os.str()<<std::endl;
2436 if(peer_ser_ver == SER_FMT_VER_INVALID)
2438 infostream<<"Server::ProcessData(): Cancelling: Peer"
2439 " serialization format invalid or not initialized."
2440 " Skipping incoming command="<<command<<std::endl;
2444 Player *player = m_env->getPlayer(peer_id);
2446 infostream<<"Server::ProcessData(): Cancelling: "
2447 "No player for peer_id="<<peer_id
2452 PlayerSAO *playersao = player->getPlayerSAO();
2453 if(playersao == NULL){
2454 infostream<<"Server::ProcessData(): Cancelling: "
2455 "No player object for peer_id="<<peer_id
2460 if(command == TOSERVER_PLAYERPOS)
2462 if(datasize < 2+12+12+4+4)
2466 v3s32 ps = readV3S32(&data[start+2]);
2467 v3s32 ss = readV3S32(&data[start+2+12]);
2468 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2469 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2471 if(datasize >= 2+12+12+4+4+4)
2472 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2473 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2474 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2475 pitch = wrapDegrees(pitch);
2476 yaw = wrapDegrees(yaw);
2478 player->setPosition(position);
2479 player->setSpeed(speed);
2480 player->setPitch(pitch);
2481 player->setYaw(yaw);
2482 player->keyPressed=keyPressed;
2483 player->control.up = (bool)(keyPressed&1);
2484 player->control.down = (bool)(keyPressed&2);
2485 player->control.left = (bool)(keyPressed&4);
2486 player->control.right = (bool)(keyPressed&8);
2487 player->control.jump = (bool)(keyPressed&16);
2488 player->control.aux1 = (bool)(keyPressed&32);
2489 player->control.sneak = (bool)(keyPressed&64);
2490 player->control.LMB = (bool)(keyPressed&128);
2491 player->control.RMB = (bool)(keyPressed&256);
2493 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2494 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2495 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2497 else if(command == TOSERVER_GOTBLOCKS)
2510 u16 count = data[2];
2511 for(u16 i=0; i<count; i++)
2513 if((s16)datasize < 2+1+(i+1)*6)
2514 throw con::InvalidIncomingDataException
2515 ("GOTBLOCKS length is too short");
2516 v3s16 p = readV3S16(&data[2+1+i*6]);
2517 /*infostream<<"Server: GOTBLOCKS ("
2518 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2519 RemoteClient *client = getClient(peer_id);
2520 client->GotBlock(p);
2523 else if(command == TOSERVER_DELETEDBLOCKS)
2536 u16 count = data[2];
2537 for(u16 i=0; i<count; i++)
2539 if((s16)datasize < 2+1+(i+1)*6)
2540 throw con::InvalidIncomingDataException
2541 ("DELETEDBLOCKS length is too short");
2542 v3s16 p = readV3S16(&data[2+1+i*6]);
2543 /*infostream<<"Server: DELETEDBLOCKS ("
2544 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2545 RemoteClient *client = getClient(peer_id);
2546 client->SetBlockNotSent(p);
2549 else if(command == TOSERVER_CLICK_OBJECT)
2551 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2554 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2556 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2559 else if(command == TOSERVER_GROUND_ACTION)
2561 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2565 else if(command == TOSERVER_RELEASE)
2567 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2570 else if(command == TOSERVER_SIGNTEXT)
2572 infostream<<"Server: SIGNTEXT not supported anymore"
2576 else if(command == TOSERVER_SIGNNODETEXT)
2578 infostream<<"Server: SIGNNODETEXT not supported anymore"
2582 else if(command == TOSERVER_INVENTORY_ACTION)
2584 // Strip command and create a stream
2585 std::string datastring((char*)&data[2], datasize-2);
2586 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2587 std::istringstream is(datastring, std::ios_base::binary);
2589 InventoryAction *a = InventoryAction::deSerialize(is);
2592 infostream<<"TOSERVER_INVENTORY_ACTION: "
2593 <<"InventoryAction::deSerialize() returned NULL"
2598 // If something goes wrong, this player is to blame
2599 RollbackScopeActor rollback_scope(m_rollback,
2600 std::string("player:")+player->getName());
2603 Note: Always set inventory not sent, to repair cases
2604 where the client made a bad prediction.
2608 Handle restrictions and special cases of the move action
2610 if(a->getType() == IACTION_MOVE)
2612 IMoveAction *ma = (IMoveAction*)a;
2614 ma->from_inv.applyCurrentPlayer(player->getName());
2615 ma->to_inv.applyCurrentPlayer(player->getName());
2617 setInventoryModified(ma->from_inv);
2618 setInventoryModified(ma->to_inv);
2620 bool from_inv_is_current_player =
2621 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2622 (ma->from_inv.name == player->getName());
2624 bool to_inv_is_current_player =
2625 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2626 (ma->to_inv.name == player->getName());
2629 Disable moving items out of craftpreview
2631 if(ma->from_list == "craftpreview")
2633 infostream<<"Ignoring IMoveAction from "
2634 <<(ma->from_inv.dump())<<":"<<ma->from_list
2635 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2636 <<" because src is "<<ma->from_list<<std::endl;
2642 Disable moving items into craftresult and craftpreview
2644 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2646 infostream<<"Ignoring IMoveAction from "
2647 <<(ma->from_inv.dump())<<":"<<ma->from_list
2648 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2649 <<" because dst is "<<ma->to_list<<std::endl;
2654 // Disallow moving items in elsewhere than player's inventory
2655 // if not allowed to interact
2656 if(!checkPriv(player->getName(), "interact") &&
2657 (!from_inv_is_current_player ||
2658 !to_inv_is_current_player))
2660 infostream<<"Cannot move outside of player's inventory: "
2661 <<"No interact privilege"<<std::endl;
2667 Handle restrictions and special cases of the drop action
2669 else if(a->getType() == IACTION_DROP)
2671 IDropAction *da = (IDropAction*)a;
2673 da->from_inv.applyCurrentPlayer(player->getName());
2675 setInventoryModified(da->from_inv);
2677 // Disallow dropping items if not allowed to interact
2678 if(!checkPriv(player->getName(), "interact"))
2685 Handle restrictions and special cases of the craft action
2687 else if(a->getType() == IACTION_CRAFT)
2689 ICraftAction *ca = (ICraftAction*)a;
2691 ca->craft_inv.applyCurrentPlayer(player->getName());
2693 setInventoryModified(ca->craft_inv);
2695 //bool craft_inv_is_current_player =
2696 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2697 // (ca->craft_inv.name == player->getName());
2699 // Disallow crafting if not allowed to interact
2700 if(!checkPriv(player->getName(), "interact"))
2702 infostream<<"Cannot craft: "
2703 <<"No interact privilege"<<std::endl;
2710 a->apply(this, playersao, this);
2714 else if(command == TOSERVER_CHAT_MESSAGE)
2722 std::string datastring((char*)&data[2], datasize-2);
2723 std::istringstream is(datastring, std::ios_base::binary);
2726 is.read((char*)buf, 2);
2727 u16 len = readU16(buf);
2729 std::wstring message;
2730 for(u16 i=0; i<len; i++)
2732 is.read((char*)buf, 2);
2733 message += (wchar_t)readU16(buf);
2736 // If something goes wrong, this player is to blame
2737 RollbackScopeActor rollback_scope(m_rollback,
2738 std::string("player:")+player->getName());
2740 // Get player name of this client
2741 std::wstring name = narrow_to_wide(player->getName());
2744 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2745 wide_to_narrow(message));
2746 // If script ate the message, don't proceed
2750 // Line to send to players
2752 // Whether to send to the player that sent the line
2753 bool send_to_sender = false;
2754 // Whether to send to other players
2755 bool send_to_others = false;
2757 // Commands are implemented in Lua, so only catch invalid
2758 // commands that were not "eaten" and send an error back
2759 if(message[0] == L'/')
2761 message = message.substr(1);
2762 send_to_sender = true;
2763 if(message.length() == 0)
2764 line += L"-!- Empty command";
2766 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2770 if(checkPriv(player->getName(), "shout")){
2775 send_to_others = true;
2777 line += L"-!- You don't have permission to shout.";
2778 send_to_sender = true;
2785 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2788 Send the message to clients
2790 for(core::map<u16, RemoteClient*>::Iterator
2791 i = m_clients.getIterator();
2792 i.atEnd() == false; i++)
2794 // Get client and check that it is valid
2795 RemoteClient *client = i.getNode()->getValue();
2796 assert(client->peer_id == i.getNode()->getKey());
2797 if(client->serialization_version == SER_FMT_VER_INVALID)
2801 bool sender_selected = (peer_id == client->peer_id);
2802 if(sender_selected == true && send_to_sender == false)
2804 if(sender_selected == false && send_to_others == false)
2807 SendChatMessage(client->peer_id, line);
2811 else if(command == TOSERVER_DAMAGE)
2813 std::string datastring((char*)&data[2], datasize-2);
2814 std::istringstream is(datastring, std::ios_base::binary);
2815 u8 damage = readU8(is);
2817 if(g_settings->getBool("enable_damage"))
2819 actionstream<<player->getName()<<" damaged by "
2820 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2823 playersao->setHP(playersao->getHP() - damage);
2825 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2828 if(playersao->m_hp_not_sent)
2829 SendPlayerHP(peer_id);
2832 else if(command == TOSERVER_PASSWORD)
2835 [0] u16 TOSERVER_PASSWORD
2836 [2] u8[28] old password
2837 [30] u8[28] new password
2840 if(datasize != 2+PASSWORD_SIZE*2)
2842 /*char password[PASSWORD_SIZE];
2843 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2844 password[i] = data[2+i];
2845 password[PASSWORD_SIZE-1] = 0;*/
2847 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2855 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2857 char c = data[2+PASSWORD_SIZE+i];
2863 if(!base64_is_valid(newpwd)){
2864 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2865 // Wrong old password supplied!!
2866 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2870 infostream<<"Server: Client requests a password change from "
2871 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2873 std::string playername = player->getName();
2875 std::string checkpwd;
2876 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2878 if(oldpwd != checkpwd)
2880 infostream<<"Server: invalid old password"<<std::endl;
2881 // Wrong old password supplied!!
2882 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2886 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2888 actionstream<<player->getName()<<" changes password"<<std::endl;
2889 SendChatMessage(peer_id, L"Password change successful.");
2891 actionstream<<player->getName()<<" tries to change password but "
2892 <<"it fails"<<std::endl;
2893 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2896 else if(command == TOSERVER_PLAYERITEM)
2901 u16 item = readU16(&data[2]);
2902 playersao->setWieldIndex(item);
2904 else if(command == TOSERVER_RESPAWN)
2906 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2909 RespawnPlayer(peer_id);
2911 actionstream<<player->getName()<<" respawns at "
2912 <<PP(player->getPosition()/BS)<<std::endl;
2914 // ActiveObject is added to environment in AsyncRunStep after
2915 // the previous addition has been succesfully removed
2917 else if(command == TOSERVER_REQUEST_MEDIA) {
2918 std::string datastring((char*)&data[2], datasize-2);
2919 std::istringstream is(datastring, std::ios_base::binary);
2921 core::list<MediaRequest> tosend;
2922 u16 numfiles = readU16(is);
2924 infostream<<"Sending "<<numfiles<<" files to "
2925 <<getPlayerName(peer_id)<<std::endl;
2926 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2928 for(int i = 0; i < numfiles; i++) {
2929 std::string name = deSerializeString(is);
2930 tosend.push_back(MediaRequest(name));
2931 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2935 sendRequestedMedia(peer_id, tosend);
2937 // Now the client should know about everything
2938 // (definitions and files)
2939 getClient(peer_id)->definitions_sent = true;
2941 else if(command == TOSERVER_RECEIVED_MEDIA) {
2942 getClient(peer_id)->definitions_sent = true;
2944 else if(command == TOSERVER_INTERACT)
2946 std::string datastring((char*)&data[2], datasize-2);
2947 std::istringstream is(datastring, std::ios_base::binary);
2953 [5] u32 length of the next item
2954 [9] serialized PointedThing
2956 0: start digging (from undersurface) or use
2957 1: stop digging (all parameters ignored)
2958 2: digging completed
2959 3: place block or item (to abovesurface)
2962 u8 action = readU8(is);
2963 u16 item_i = readU16(is);
2964 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2965 PointedThing pointed;
2966 pointed.deSerialize(tmp_is);
2968 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2969 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2973 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2974 <<" tried to interact, but is dead!"<<std::endl;
2978 v3f player_pos = playersao->getLastGoodPosition();
2980 // Update wielded item
2981 playersao->setWieldIndex(item_i);
2983 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2984 v3s16 p_under = pointed.node_undersurface;
2985 v3s16 p_above = pointed.node_abovesurface;
2987 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2988 ServerActiveObject *pointed_object = NULL;
2989 if(pointed.type == POINTEDTHING_OBJECT)
2991 pointed_object = m_env->getActiveObject(pointed.object_id);
2992 if(pointed_object == NULL)
2994 verbosestream<<"TOSERVER_INTERACT: "
2995 "pointed object is NULL"<<std::endl;
3001 v3f pointed_pos_under = player_pos;
3002 v3f pointed_pos_above = player_pos;
3003 if(pointed.type == POINTEDTHING_NODE)
3005 pointed_pos_under = intToFloat(p_under, BS);
3006 pointed_pos_above = intToFloat(p_above, BS);
3008 else if(pointed.type == POINTEDTHING_OBJECT)
3010 pointed_pos_under = pointed_object->getBasePosition();
3011 pointed_pos_above = pointed_pos_under;
3015 Check that target is reasonably close
3016 (only when digging or placing things)
3018 if(action == 0 || action == 2 || action == 3)
3020 float d = player_pos.getDistanceFrom(pointed_pos_under);
3021 float max_d = BS * 14; // Just some large enough value
3023 actionstream<<"Player "<<player->getName()
3024 <<" tried to access "<<pointed.dump()
3026 <<"d="<<d<<", max_d="<<max_d
3027 <<". ignoring."<<std::endl;
3028 // Re-send block to revert change on client-side
3029 RemoteClient *client = getClient(peer_id);
3030 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3031 client->SetBlockNotSent(blockpos);
3038 Make sure the player is allowed to do it
3040 if(!checkPriv(player->getName(), "interact"))
3042 actionstream<<player->getName()<<" attempted to interact with "
3043 <<pointed.dump()<<" without 'interact' privilege"
3045 // Re-send block to revert change on client-side
3046 RemoteClient *client = getClient(peer_id);
3047 // Digging completed -> under
3049 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3050 client->SetBlockNotSent(blockpos);
3052 // Placement -> above
3054 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3055 client->SetBlockNotSent(blockpos);
3061 If something goes wrong, this player is to blame
3063 RollbackScopeActor rollback_scope(m_rollback,
3064 std::string("player:")+player->getName());
3067 0: start digging or punch object
3071 if(pointed.type == POINTEDTHING_NODE)
3074 NOTE: This can be used in the future to check if
3075 somebody is cheating, by checking the timing.
3077 MapNode n(CONTENT_IGNORE);
3080 n = m_env->getMap().getNode(p_under);
3082 catch(InvalidPositionException &e)
3084 infostream<<"Server: Not punching: Node not found."
3085 <<" Adding block to emerge queue."
3087 m_emerge_queue.addBlock(peer_id,
3088 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3090 if(n.getContent() != CONTENT_IGNORE)
3091 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3093 playersao->noCheatDigStart(p_under);
3095 else if(pointed.type == POINTEDTHING_OBJECT)
3097 // Skip if object has been removed
3098 if(pointed_object->m_removed)
3101 actionstream<<player->getName()<<" punches object "
3102 <<pointed.object_id<<": "
3103 <<pointed_object->getDescription()<<std::endl;
3105 ItemStack punchitem = playersao->getWieldedItem();
3106 ToolCapabilities toolcap =
3107 punchitem.getToolCapabilities(m_itemdef);
3108 v3f dir = (pointed_object->getBasePosition() -
3109 (player->getPosition() + player->getEyeOffset())
3111 float time_from_last_punch =
3112 playersao->resetTimeFromLastPunch();
3113 pointed_object->punch(dir, &toolcap, playersao,
3114 time_from_last_punch);
3122 else if(action == 1)
3127 2: Digging completed
3129 else if(action == 2)
3131 // Only digging of nodes
3132 if(pointed.type == POINTEDTHING_NODE)
3134 MapNode n(CONTENT_IGNORE);
3137 n = m_env->getMap().getNode(p_under);
3139 catch(InvalidPositionException &e)
3141 infostream<<"Server: Not finishing digging: Node not found."
3142 <<" Adding block to emerge queue."
3144 m_emerge_queue.addBlock(peer_id,
3145 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3148 /* Cheat prevention */
3149 bool is_valid_dig = true;
3150 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3152 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3153 float nocheat_t = playersao->getNoCheatDigTime();
3154 playersao->noCheatDigEnd();
3155 // If player didn't start digging this, ignore dig
3156 if(nocheat_p != p_under){
3157 infostream<<"Server: NoCheat: "<<player->getName()
3158 <<" started digging "
3159 <<PP(nocheat_p)<<" and completed digging "
3160 <<PP(p_under)<<"; not digging."<<std::endl;
3161 is_valid_dig = false;
3163 // Get player's wielded item
3164 ItemStack playeritem;
3165 InventoryList *mlist = playersao->getInventory()->getList("main");
3167 playeritem = mlist->getItem(playersao->getWieldIndex());
3168 ToolCapabilities playeritem_toolcap =
3169 playeritem.getToolCapabilities(m_itemdef);
3170 // Get diggability and expected digging time
3171 DigParams params = getDigParams(m_nodedef->get(n).groups,
3172 &playeritem_toolcap);
3173 // If can't dig, try hand
3174 if(!params.diggable){
3175 const ItemDefinition &hand = m_itemdef->get("");
3176 const ToolCapabilities *tp = hand.tool_capabilities;
3178 params = getDigParams(m_nodedef->get(n).groups, tp);
3180 // If can't dig, ignore dig
3181 if(!params.diggable){
3182 infostream<<"Server: NoCheat: "<<player->getName()
3183 <<" completed digging "<<PP(p_under)
3184 <<", which is not diggable with tool. not digging."
3186 is_valid_dig = false;
3188 // If time is considerably too short, ignore dig
3189 // Check time only for medium and slow timed digs
3190 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3191 infostream<<"Server: NoCheat: "<<player->getName()
3192 <<" completed digging "
3193 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3194 <<params.time<<"s; not digging."<<std::endl;
3195 is_valid_dig = false;
3199 /* Actually dig node */
3201 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3202 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3204 // Send unusual result (that is, node not being removed)
3205 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3207 // Re-send block to revert change on client-side
3208 RemoteClient *client = getClient(peer_id);
3209 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3210 client->SetBlockNotSent(blockpos);
3216 3: place block or right-click object
3218 else if(action == 3)
3220 ItemStack item = playersao->getWieldedItem();
3222 // Reset build time counter
3223 if(pointed.type == POINTEDTHING_NODE &&
3224 item.getDefinition(m_itemdef).type == ITEM_NODE)
3225 getClient(peer_id)->m_time_from_building = 0.0;
3227 if(pointed.type == POINTEDTHING_OBJECT)
3229 // Right click object
3231 // Skip if object has been removed
3232 if(pointed_object->m_removed)
3235 actionstream<<player->getName()<<" right-clicks object "
3236 <<pointed.object_id<<": "
3237 <<pointed_object->getDescription()<<std::endl;
3240 pointed_object->rightClick(playersao);
3242 else if(scriptapi_item_on_place(m_lua,
3243 item, playersao, pointed))
3245 // Placement was handled in lua
3247 // Apply returned ItemStack
3248 playersao->setWieldedItem(item);
3251 // If item has node placement prediction, always send the above
3252 // node to make sure the client knows what exactly happened
3253 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3254 RemoteClient *client = getClient(peer_id);
3255 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3256 client->SetBlockNotSent(blockpos);
3263 else if(action == 4)
3265 ItemStack item = playersao->getWieldedItem();
3267 actionstream<<player->getName()<<" uses "<<item.name
3268 <<", pointing at "<<pointed.dump()<<std::endl;
3270 if(scriptapi_item_on_use(m_lua,
3271 item, playersao, pointed))
3273 // Apply returned ItemStack
3274 playersao->setWieldedItem(item);
3281 Catch invalid actions
3285 infostream<<"WARNING: Server: Invalid action "
3286 <<action<<std::endl;
3289 else if(command == TOSERVER_REMOVED_SOUNDS)
3291 std::string datastring((char*)&data[2], datasize-2);
3292 std::istringstream is(datastring, std::ios_base::binary);
3294 int num = readU16(is);
3295 for(int k=0; k<num; k++){
3296 s32 id = readS32(is);
3297 std::map<s32, ServerPlayingSound>::iterator i =
3298 m_playing_sounds.find(id);
3299 if(i == m_playing_sounds.end())
3301 ServerPlayingSound &psound = i->second;
3302 psound.clients.erase(peer_id);
3303 if(psound.clients.size() == 0)
3304 m_playing_sounds.erase(i++);
3307 else if(command == TOSERVER_NODEMETA_FIELDS)
3309 std::string datastring((char*)&data[2], datasize-2);
3310 std::istringstream is(datastring, std::ios_base::binary);
3312 v3s16 p = readV3S16(is);
3313 std::string formname = deSerializeString(is);
3314 int num = readU16(is);
3315 std::map<std::string, std::string> fields;
3316 for(int k=0; k<num; k++){
3317 std::string fieldname = deSerializeString(is);
3318 std::string fieldvalue = deSerializeLongString(is);
3319 fields[fieldname] = fieldvalue;
3322 // If something goes wrong, this player is to blame
3323 RollbackScopeActor rollback_scope(m_rollback,
3324 std::string("player:")+player->getName());
3326 // Check the target node for rollback data; leave others unnoticed
3327 RollbackNode rn_old(&m_env->getMap(), p, this);
3329 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3332 // Report rollback data
3333 RollbackNode rn_new(&m_env->getMap(), p, this);
3334 if(rollback() && rn_new != rn_old){
3335 RollbackAction action;
3336 action.setSetNode(p, rn_old, rn_new);
3337 rollback()->reportAction(action);
3340 else if(command == TOSERVER_INVENTORY_FIELDS)
3342 std::string datastring((char*)&data[2], datasize-2);
3343 std::istringstream is(datastring, std::ios_base::binary);
3345 std::string formname = deSerializeString(is);
3346 int num = readU16(is);
3347 std::map<std::string, std::string> fields;
3348 for(int k=0; k<num; k++){
3349 std::string fieldname = deSerializeString(is);
3350 std::string fieldvalue = deSerializeLongString(is);
3351 fields[fieldname] = fieldvalue;
3354 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3358 infostream<<"Server::ProcessData(): Ignoring "
3359 "unknown command "<<command<<std::endl;
3363 catch(SendFailedException &e)
3365 errorstream<<"Server::ProcessData(): SendFailedException: "
3371 void Server::onMapEditEvent(MapEditEvent *event)
3373 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3374 if(m_ignore_map_edit_events)
3376 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3378 MapEditEvent *e = event->clone();
3379 m_unsent_map_edit_queue.push_back(e);
3382 Inventory* Server::getInventory(const InventoryLocation &loc)
3385 case InventoryLocation::UNDEFINED:
3388 case InventoryLocation::CURRENT_PLAYER:
3391 case InventoryLocation::PLAYER:
3393 Player *player = m_env->getPlayer(loc.name.c_str());
3396 PlayerSAO *playersao = player->getPlayerSAO();
3399 return playersao->getInventory();
3402 case InventoryLocation::NODEMETA:
3404 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3407 return meta->getInventory();
3410 case InventoryLocation::DETACHED:
3412 if(m_detached_inventories.count(loc.name) == 0)
3414 return m_detached_inventories[loc.name];
3422 void Server::setInventoryModified(const InventoryLocation &loc)
3425 case InventoryLocation::UNDEFINED:
3428 case InventoryLocation::PLAYER:
3430 Player *player = m_env->getPlayer(loc.name.c_str());
3433 PlayerSAO *playersao = player->getPlayerSAO();
3436 playersao->m_inventory_not_sent = true;
3437 playersao->m_wielded_item_not_sent = true;
3440 case InventoryLocation::NODEMETA:
3442 v3s16 blockpos = getNodeBlockPos(loc.p);
3444 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3446 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3448 setBlockNotSent(blockpos);
3451 case InventoryLocation::DETACHED:
3453 sendDetachedInventoryToAll(loc.name);
3461 core::list<PlayerInfo> Server::getPlayerInfo()
3463 DSTACK(__FUNCTION_NAME);
3464 JMutexAutoLock envlock(m_env_mutex);
3465 JMutexAutoLock conlock(m_con_mutex);
3467 core::list<PlayerInfo> list;
3469 core::list<Player*> players = m_env->getPlayers();
3471 core::list<Player*>::Iterator i;
3472 for(i = players.begin();
3473 i != players.end(); i++)
3477 Player *player = *i;
3480 // Copy info from connection to info struct
3481 info.id = player->peer_id;
3482 info.address = m_con.GetPeerAddress(player->peer_id);
3483 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3485 catch(con::PeerNotFoundException &e)
3487 // Set dummy peer info
3489 info.address = Address(0,0,0,0,0);
3493 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3494 info.position = player->getPosition();
3496 list.push_back(info);
3503 void Server::peerAdded(con::Peer *peer)
3505 DSTACK(__FUNCTION_NAME);
3506 verbosestream<<"Server::peerAdded(): peer->id="
3507 <<peer->id<<std::endl;
3510 c.type = PEER_ADDED;
3511 c.peer_id = peer->id;
3513 m_peer_change_queue.push_back(c);
3516 void Server::deletingPeer(con::Peer *peer, bool timeout)
3518 DSTACK(__FUNCTION_NAME);
3519 verbosestream<<"Server::deletingPeer(): peer->id="
3520 <<peer->id<<", timeout="<<timeout<<std::endl;
3523 c.type = PEER_REMOVED;
3524 c.peer_id = peer->id;
3525 c.timeout = timeout;
3526 m_peer_change_queue.push_back(c);
3533 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3535 DSTACK(__FUNCTION_NAME);
3536 std::ostringstream os(std::ios_base::binary);
3538 writeU16(os, TOCLIENT_HP);
3542 std::string s = os.str();
3543 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3545 con.Send(peer_id, 0, data, true);
3548 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3549 const std::wstring &reason)
3551 DSTACK(__FUNCTION_NAME);
3552 std::ostringstream os(std::ios_base::binary);
3554 writeU16(os, TOCLIENT_ACCESS_DENIED);
3555 os<<serializeWideString(reason);
3558 std::string s = os.str();
3559 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3561 con.Send(peer_id, 0, data, true);
3564 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3565 bool set_camera_point_target, v3f camera_point_target)
3567 DSTACK(__FUNCTION_NAME);
3568 std::ostringstream os(std::ios_base::binary);
3570 writeU16(os, TOCLIENT_DEATHSCREEN);
3571 writeU8(os, set_camera_point_target);
3572 writeV3F1000(os, camera_point_target);
3575 std::string s = os.str();
3576 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3578 con.Send(peer_id, 0, data, true);
3581 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3582 IItemDefManager *itemdef)
3584 DSTACK(__FUNCTION_NAME);
3585 std::ostringstream os(std::ios_base::binary);
3589 u32 length of the next item
3590 zlib-compressed serialized ItemDefManager
3592 writeU16(os, TOCLIENT_ITEMDEF);
3593 std::ostringstream tmp_os(std::ios::binary);
3594 itemdef->serialize(tmp_os);
3595 std::ostringstream tmp_os2(std::ios::binary);
3596 compressZlib(tmp_os.str(), tmp_os2);
3597 os<<serializeLongString(tmp_os2.str());
3600 std::string s = os.str();
3601 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3602 <<"): size="<<s.size()<<std::endl;
3603 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3605 con.Send(peer_id, 0, data, true);
3608 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3609 INodeDefManager *nodedef, u16 protocol_version)
3611 DSTACK(__FUNCTION_NAME);
3612 std::ostringstream os(std::ios_base::binary);
3616 u32 length of the next item
3617 zlib-compressed serialized NodeDefManager
3619 writeU16(os, TOCLIENT_NODEDEF);
3620 std::ostringstream tmp_os(std::ios::binary);
3621 nodedef->serialize(tmp_os, protocol_version);
3622 std::ostringstream tmp_os2(std::ios::binary);
3623 compressZlib(tmp_os.str(), tmp_os2);
3624 os<<serializeLongString(tmp_os2.str());
3627 std::string s = os.str();
3628 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3629 <<"): size="<<s.size()<<std::endl;
3630 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3632 con.Send(peer_id, 0, data, true);
3636 Non-static send methods
3639 void Server::SendInventory(u16 peer_id)
3641 DSTACK(__FUNCTION_NAME);
3643 PlayerSAO *playersao = getPlayerSAO(peer_id);
3646 playersao->m_inventory_not_sent = false;
3652 std::ostringstream os;
3653 playersao->getInventory()->serialize(os);
3655 std::string s = os.str();
3657 SharedBuffer<u8> data(s.size()+2);
3658 writeU16(&data[0], TOCLIENT_INVENTORY);
3659 memcpy(&data[2], s.c_str(), s.size());
3662 m_con.Send(peer_id, 0, data, true);
3665 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3667 DSTACK(__FUNCTION_NAME);
3669 std::ostringstream os(std::ios_base::binary);
3673 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3674 os.write((char*)buf, 2);
3677 writeU16(buf, message.size());
3678 os.write((char*)buf, 2);
3681 for(u32 i=0; i<message.size(); i++)
3685 os.write((char*)buf, 2);
3689 std::string s = os.str();
3690 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3692 m_con.Send(peer_id, 0, data, true);
3694 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3696 DSTACK(__FUNCTION_NAME);
3698 std::ostringstream os(std::ios_base::binary);
3702 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3703 os.write((char*)buf, 2);
3704 os<<serializeLongString(formspec);
3705 os<<serializeString(formname);
3708 std::string s = os.str();
3709 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3711 m_con.Send(peer_id, 0, data, true);
3714 void Server::BroadcastChatMessage(const std::wstring &message)
3716 for(core::map<u16, RemoteClient*>::Iterator
3717 i = m_clients.getIterator();
3718 i.atEnd() == false; i++)
3720 // Get client and check that it is valid
3721 RemoteClient *client = i.getNode()->getValue();
3722 assert(client->peer_id == i.getNode()->getKey());
3723 if(client->serialization_version == SER_FMT_VER_INVALID)
3726 SendChatMessage(client->peer_id, message);
3730 void Server::SendPlayerHP(u16 peer_id)
3732 DSTACK(__FUNCTION_NAME);
3733 PlayerSAO *playersao = getPlayerSAO(peer_id);
3735 playersao->m_hp_not_sent = false;
3736 SendHP(m_con, peer_id, playersao->getHP());
3739 void Server::SendMovePlayer(u16 peer_id)
3741 DSTACK(__FUNCTION_NAME);
3742 Player *player = m_env->getPlayer(peer_id);
3745 std::ostringstream os(std::ios_base::binary);
3746 writeU16(os, TOCLIENT_MOVE_PLAYER);
3747 writeV3F1000(os, player->getPosition());
3748 writeF1000(os, player->getPitch());
3749 writeF1000(os, player->getYaw());
3752 v3f pos = player->getPosition();
3753 f32 pitch = player->getPitch();
3754 f32 yaw = player->getYaw();
3755 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3756 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3763 std::string s = os.str();
3764 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3766 m_con.Send(peer_id, 0, data, true);
3769 void Server::SendPlayerPrivileges(u16 peer_id)
3771 Player *player = m_env->getPlayer(peer_id);
3773 if(player->peer_id == PEER_ID_INEXISTENT)
3776 std::set<std::string> privs;
3777 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3779 std::ostringstream os(std::ios_base::binary);
3780 writeU16(os, TOCLIENT_PRIVILEGES);
3781 writeU16(os, privs.size());
3782 for(std::set<std::string>::const_iterator i = privs.begin();
3783 i != privs.end(); i++){
3784 os<<serializeString(*i);
3788 std::string s = os.str();
3789 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3791 m_con.Send(peer_id, 0, data, true);
3794 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3796 Player *player = m_env->getPlayer(peer_id);
3798 if(player->peer_id == PEER_ID_INEXISTENT)
3801 std::ostringstream os(std::ios_base::binary);
3802 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3803 os<<serializeLongString(player->inventory_formspec);
3806 std::string s = os.str();
3807 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3809 m_con.Send(peer_id, 0, data, true);
3812 s32 Server::playSound(const SimpleSoundSpec &spec,
3813 const ServerSoundParams ¶ms)
3815 // Find out initial position of sound
3816 bool pos_exists = false;
3817 v3f pos = params.getPos(m_env, &pos_exists);
3818 // If position is not found while it should be, cancel sound
3819 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3821 // Filter destination clients
3822 std::set<RemoteClient*> dst_clients;
3823 if(params.to_player != "")
3825 Player *player = m_env->getPlayer(params.to_player.c_str());
3827 infostream<<"Server::playSound: Player \""<<params.to_player
3828 <<"\" not found"<<std::endl;
3831 if(player->peer_id == PEER_ID_INEXISTENT){
3832 infostream<<"Server::playSound: Player \""<<params.to_player
3833 <<"\" not connected"<<std::endl;
3836 RemoteClient *client = getClient(player->peer_id);
3837 dst_clients.insert(client);
3841 for(core::map<u16, RemoteClient*>::Iterator
3842 i = m_clients.getIterator(); i.atEnd() == false; i++)
3844 RemoteClient *client = i.getNode()->getValue();
3845 Player *player = m_env->getPlayer(client->peer_id);
3849 if(player->getPosition().getDistanceFrom(pos) >
3850 params.max_hear_distance)
3853 dst_clients.insert(client);
3856 if(dst_clients.size() == 0)
3859 s32 id = m_next_sound_id++;
3860 // The sound will exist as a reference in m_playing_sounds
3861 m_playing_sounds[id] = ServerPlayingSound();
3862 ServerPlayingSound &psound = m_playing_sounds[id];
3863 psound.params = params;
3864 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3865 i != dst_clients.end(); i++)
3866 psound.clients.insert((*i)->peer_id);
3868 std::ostringstream os(std::ios_base::binary);
3869 writeU16(os, TOCLIENT_PLAY_SOUND);
3871 os<<serializeString(spec.name);
3872 writeF1000(os, spec.gain * params.gain);
3873 writeU8(os, params.type);
3874 writeV3F1000(os, pos);
3875 writeU16(os, params.object);
3876 writeU8(os, params.loop);
3878 std::string s = os.str();
3879 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3881 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3882 i != dst_clients.end(); i++){
3884 m_con.Send((*i)->peer_id, 0, data, true);
3888 void Server::stopSound(s32 handle)
3890 // Get sound reference
3891 std::map<s32, ServerPlayingSound>::iterator i =
3892 m_playing_sounds.find(handle);
3893 if(i == m_playing_sounds.end())
3895 ServerPlayingSound &psound = i->second;
3897 std::ostringstream os(std::ios_base::binary);
3898 writeU16(os, TOCLIENT_STOP_SOUND);
3899 writeS32(os, handle);
3901 std::string s = os.str();
3902 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3904 for(std::set<u16>::iterator i = psound.clients.begin();
3905 i != psound.clients.end(); i++){
3907 m_con.Send(*i, 0, data, true);
3909 // Remove sound reference
3910 m_playing_sounds.erase(i);
3913 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3914 core::list<u16> *far_players, float far_d_nodes)
3916 float maxd = far_d_nodes*BS;
3917 v3f p_f = intToFloat(p, BS);
3921 SharedBuffer<u8> reply(replysize);
3922 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3923 writeS16(&reply[2], p.X);
3924 writeS16(&reply[4], p.Y);
3925 writeS16(&reply[6], p.Z);
3927 for(core::map<u16, RemoteClient*>::Iterator
3928 i = m_clients.getIterator();
3929 i.atEnd() == false; i++)
3931 // Get client and check that it is valid
3932 RemoteClient *client = i.getNode()->getValue();
3933 assert(client->peer_id == i.getNode()->getKey());
3934 if(client->serialization_version == SER_FMT_VER_INVALID)
3937 // Don't send if it's the same one
3938 if(client->peer_id == ignore_id)
3944 Player *player = m_env->getPlayer(client->peer_id);
3947 // If player is far away, only set modified blocks not sent
3948 v3f player_pos = player->getPosition();
3949 if(player_pos.getDistanceFrom(p_f) > maxd)
3951 far_players->push_back(client->peer_id);
3958 m_con.Send(client->peer_id, 0, reply, true);
3962 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3963 core::list<u16> *far_players, float far_d_nodes)
3965 float maxd = far_d_nodes*BS;
3966 v3f p_f = intToFloat(p, BS);
3968 for(core::map<u16, RemoteClient*>::Iterator
3969 i = m_clients.getIterator();
3970 i.atEnd() == false; i++)
3972 // Get client and check that it is valid
3973 RemoteClient *client = i.getNode()->getValue();
3974 assert(client->peer_id == i.getNode()->getKey());
3975 if(client->serialization_version == SER_FMT_VER_INVALID)
3978 // Don't send if it's the same one
3979 if(client->peer_id == ignore_id)
3985 Player *player = m_env->getPlayer(client->peer_id);
3988 // If player is far away, only set modified blocks not sent
3989 v3f player_pos = player->getPosition();
3990 if(player_pos.getDistanceFrom(p_f) > maxd)
3992 far_players->push_back(client->peer_id);
3999 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4000 SharedBuffer<u8> reply(replysize);
4001 writeU16(&reply[0], TOCLIENT_ADDNODE);
4002 writeS16(&reply[2], p.X);
4003 writeS16(&reply[4], p.Y);
4004 writeS16(&reply[6], p.Z);
4005 n.serialize(&reply[8], client->serialization_version);
4008 m_con.Send(client->peer_id, 0, reply, true);
4012 void Server::setBlockNotSent(v3s16 p)
4014 for(core::map<u16, RemoteClient*>::Iterator
4015 i = m_clients.getIterator();
4016 i.atEnd()==false; i++)
4018 RemoteClient *client = i.getNode()->getValue();
4019 client->SetBlockNotSent(p);
4023 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4025 DSTACK(__FUNCTION_NAME);
4027 v3s16 p = block->getPos();
4031 bool completely_air = true;
4032 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4033 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4034 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4036 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4038 completely_air = false;
4039 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4044 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4046 infostream<<"[completely air] ";
4047 infostream<<std::endl;
4051 Create a packet with the block in the right format
4054 std::ostringstream os(std::ios_base::binary);
4055 block->serialize(os, ver, false);
4056 std::string s = os.str();
4057 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4059 u32 replysize = 8 + blockdata.getSize();
4060 SharedBuffer<u8> reply(replysize);
4061 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4062 writeS16(&reply[2], p.X);
4063 writeS16(&reply[4], p.Y);
4064 writeS16(&reply[6], p.Z);
4065 memcpy(&reply[8], *blockdata, blockdata.getSize());
4067 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4068 <<": \tpacket size: "<<replysize<<std::endl;*/
4073 m_con.Send(peer_id, 1, reply, true);
4076 void Server::SendBlocks(float dtime)
4078 DSTACK(__FUNCTION_NAME);
4080 JMutexAutoLock envlock(m_env_mutex);
4081 JMutexAutoLock conlock(m_con_mutex);
4083 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4085 core::array<PrioritySortedBlockTransfer> queue;
4087 s32 total_sending = 0;
4090 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4092 for(core::map<u16, RemoteClient*>::Iterator
4093 i = m_clients.getIterator();
4094 i.atEnd() == false; i++)
4096 RemoteClient *client = i.getNode()->getValue();
4097 assert(client->peer_id == i.getNode()->getKey());
4099 // If definitions and textures have not been sent, don't
4100 // send MapBlocks either
4101 if(!client->definitions_sent)
4104 total_sending += client->SendingCount();
4106 if(client->serialization_version == SER_FMT_VER_INVALID)
4109 client->GetNextBlocks(this, dtime, queue);
4114 // Lowest priority number comes first.
4115 // Lowest is most important.
4118 for(u32 i=0; i<queue.size(); i++)
4120 //TODO: Calculate limit dynamically
4121 if(total_sending >= g_settings->getS32
4122 ("max_simultaneous_block_sends_server_total"))
4125 PrioritySortedBlockTransfer q = queue[i];
4127 MapBlock *block = NULL;
4130 block = m_env->getMap().getBlockNoCreate(q.pos);
4132 catch(InvalidPositionException &e)
4137 RemoteClient *client = getClient(q.peer_id);
4139 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4141 client->SentBlock(q.pos);
4147 void Server::fillMediaCache()
4149 DSTACK(__FUNCTION_NAME);
4151 infostream<<"Server: Calculating media file checksums"<<std::endl;
4153 // Collect all media file paths
4154 std::list<std::string> paths;
4155 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4156 i != m_mods.end(); i++){
4157 const ModSpec &mod = *i;
4158 paths.push_back(mod.path + DIR_DELIM + "textures");
4159 paths.push_back(mod.path + DIR_DELIM + "sounds");
4160 paths.push_back(mod.path + DIR_DELIM + "media");
4161 paths.push_back(mod.path + DIR_DELIM + "models");
4163 std::string path_all = "textures";
4164 paths.push_back(path_all + DIR_DELIM + "all");
4166 // Collect media file information from paths into cache
4167 for(std::list<std::string>::iterator i = paths.begin();
4168 i != paths.end(); i++)
4170 std::string mediapath = *i;
4171 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4172 for(u32 j=0; j<dirlist.size(); j++){
4173 if(dirlist[j].dir) // Ignode dirs
4175 std::string filename = dirlist[j].name;
4176 // If name contains illegal characters, ignore the file
4177 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4178 infostream<<"Server: ignoring illegal file name: \""
4179 <<filename<<"\""<<std::endl;
4182 // If name is not in a supported format, ignore it
4183 const char *supported_ext[] = {
4184 ".png", ".jpg", ".bmp", ".tga",
4185 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4187 ".x", ".b3d", ".md2", ".obj",
4190 if(removeStringEnd(filename, supported_ext) == ""){
4191 infostream<<"Server: ignoring unsupported file extension: \""
4192 <<filename<<"\""<<std::endl;
4195 // Ok, attempt to load the file and add to cache
4196 std::string filepath = mediapath + DIR_DELIM + filename;
4198 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4199 if(fis.good() == false){
4200 errorstream<<"Server::fillMediaCache(): Could not open \""
4201 <<filename<<"\" for reading"<<std::endl;
4204 std::ostringstream tmp_os(std::ios_base::binary);
4208 fis.read(buf, 1024);
4209 std::streamsize len = fis.gcount();
4210 tmp_os.write(buf, len);
4219 errorstream<<"Server::fillMediaCache(): Failed to read \""
4220 <<filename<<"\""<<std::endl;
4223 if(tmp_os.str().length() == 0){
4224 errorstream<<"Server::fillMediaCache(): Empty file \""
4225 <<filepath<<"\""<<std::endl;
4230 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4232 unsigned char *digest = sha1.getDigest();
4233 std::string sha1_base64 = base64_encode(digest, 20);
4234 std::string sha1_hex = hex_encode((char*)digest, 20);
4238 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4239 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4244 struct SendableMediaAnnouncement
4247 std::string sha1_digest;
4249 SendableMediaAnnouncement(const std::string name_="",
4250 const std::string sha1_digest_=""):
4252 sha1_digest(sha1_digest_)
4256 void Server::sendMediaAnnouncement(u16 peer_id)
4258 DSTACK(__FUNCTION_NAME);
4260 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4263 core::list<SendableMediaAnnouncement> file_announcements;
4265 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4266 i != m_media.end(); i++){
4268 file_announcements.push_back(
4269 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4273 std::ostringstream os(std::ios_base::binary);
4281 u16 length of sha1_digest
4286 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4287 writeU16(os, file_announcements.size());
4289 for(core::list<SendableMediaAnnouncement>::Iterator
4290 j = file_announcements.begin();
4291 j != file_announcements.end(); j++){
4292 os<<serializeString(j->name);
4293 os<<serializeString(j->sha1_digest);
4295 os<<serializeString(g_settings->get("remote_media"));
4298 std::string s = os.str();
4299 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4302 m_con.Send(peer_id, 0, data, true);
4305 struct SendableMedia
4311 SendableMedia(const std::string &name_="", const std::string path_="",
4312 const std::string &data_=""):
4319 void Server::sendRequestedMedia(u16 peer_id,
4320 const core::list<MediaRequest> &tosend)
4322 DSTACK(__FUNCTION_NAME);
4324 verbosestream<<"Server::sendRequestedMedia(): "
4325 <<"Sending files to client"<<std::endl;
4329 // Put 5kB in one bunch (this is not accurate)
4330 u32 bytes_per_bunch = 5000;
4332 core::array< core::list<SendableMedia> > file_bunches;
4333 file_bunches.push_back(core::list<SendableMedia>());
4335 u32 file_size_bunch_total = 0;
4337 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4338 i != tosend.end(); i++)
4340 if(m_media.find(i->name) == m_media.end()){
4341 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4342 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4346 //TODO get path + name
4347 std::string tpath = m_media[(*i).name].path;
4350 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4351 if(fis.good() == false){
4352 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4353 <<tpath<<"\" for reading"<<std::endl;
4356 std::ostringstream tmp_os(std::ios_base::binary);
4360 fis.read(buf, 1024);
4361 std::streamsize len = fis.gcount();
4362 tmp_os.write(buf, len);
4363 file_size_bunch_total += len;
4372 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4373 <<(*i).name<<"\""<<std::endl;
4376 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4377 <<tname<<"\""<<std::endl;*/
4379 file_bunches[file_bunches.size()-1].push_back(
4380 SendableMedia((*i).name, tpath, tmp_os.str()));
4382 // Start next bunch if got enough data
4383 if(file_size_bunch_total >= bytes_per_bunch){
4384 file_bunches.push_back(core::list<SendableMedia>());
4385 file_size_bunch_total = 0;
4390 /* Create and send packets */
4392 u32 num_bunches = file_bunches.size();
4393 for(u32 i=0; i<num_bunches; i++)
4395 std::ostringstream os(std::ios_base::binary);
4399 u16 total number of texture bunches
4400 u16 index of this bunch
4401 u32 number of files in this bunch
4410 writeU16(os, TOCLIENT_MEDIA);
4411 writeU16(os, num_bunches);
4413 writeU32(os, file_bunches[i].size());
4415 for(core::list<SendableMedia>::Iterator
4416 j = file_bunches[i].begin();
4417 j != file_bunches[i].end(); j++){
4418 os<<serializeString(j->name);
4419 os<<serializeLongString(j->data);
4423 std::string s = os.str();
4424 verbosestream<<"Server::sendRequestedMedia(): bunch "
4425 <<i<<"/"<<num_bunches
4426 <<" files="<<file_bunches[i].size()
4427 <<" size=" <<s.size()<<std::endl;
4428 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4430 m_con.Send(peer_id, 0, data, true);
4434 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4436 if(m_detached_inventories.count(name) == 0){
4437 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4440 Inventory *inv = m_detached_inventories[name];
4442 std::ostringstream os(std::ios_base::binary);
4443 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4444 os<<serializeString(name);
4448 std::string s = os.str();
4449 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4451 m_con.Send(peer_id, 0, data, true);
4454 void Server::sendDetachedInventoryToAll(const std::string &name)
4456 DSTACK(__FUNCTION_NAME);
4458 for(core::map<u16, RemoteClient*>::Iterator
4459 i = m_clients.getIterator();
4460 i.atEnd() == false; i++){
4461 RemoteClient *client = i.getNode()->getValue();
4462 sendDetachedInventory(name, client->peer_id);
4466 void Server::sendDetachedInventories(u16 peer_id)
4468 DSTACK(__FUNCTION_NAME);
4470 for(std::map<std::string, Inventory*>::iterator
4471 i = m_detached_inventories.begin();
4472 i != m_detached_inventories.end(); i++){
4473 const std::string &name = i->first;
4474 //Inventory *inv = i->second;
4475 sendDetachedInventory(name, peer_id);
4483 void Server::DiePlayer(u16 peer_id)
4485 DSTACK(__FUNCTION_NAME);
4487 PlayerSAO *playersao = getPlayerSAO(peer_id);
4490 infostream<<"Server::DiePlayer(): Player "
4491 <<playersao->getPlayer()->getName()
4492 <<" dies"<<std::endl;
4494 playersao->setHP(0);
4496 // Trigger scripted stuff
4497 scriptapi_on_dieplayer(m_lua, playersao);
4499 SendPlayerHP(peer_id);
4500 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4503 void Server::RespawnPlayer(u16 peer_id)
4505 DSTACK(__FUNCTION_NAME);
4507 PlayerSAO *playersao = getPlayerSAO(peer_id);
4510 infostream<<"Server::RespawnPlayer(): Player "
4511 <<playersao->getPlayer()->getName()
4512 <<" respawns"<<std::endl;
4514 playersao->setHP(PLAYER_MAX_HP);
4516 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4518 v3f pos = findSpawnPos(m_env->getServerMap());
4519 playersao->setPos(pos);
4523 void Server::UpdateCrafting(u16 peer_id)
4525 DSTACK(__FUNCTION_NAME);
4527 Player* player = m_env->getPlayer(peer_id);
4530 // Get a preview for crafting
4532 getCraftingResult(&player->inventory, preview, false, this);
4534 // Put the new preview in
4535 InventoryList *plist = player->inventory.getList("craftpreview");
4537 assert(plist->getSize() >= 1);
4538 plist->changeItem(0, preview);
4541 RemoteClient* Server::getClient(u16 peer_id)
4543 DSTACK(__FUNCTION_NAME);
4544 //JMutexAutoLock lock(m_con_mutex);
4545 core::map<u16, RemoteClient*>::Node *n;
4546 n = m_clients.find(peer_id);
4547 // A client should exist for all peers
4549 return n->getValue();
4552 std::wstring Server::getStatusString()
4554 std::wostringstream os(std::ios_base::binary);
4557 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4559 os<<L", uptime="<<m_uptime.get();
4560 // Information about clients
4561 core::map<u16, RemoteClient*>::Iterator i;
4564 for(i = m_clients.getIterator(), first = true;
4565 i.atEnd() == false; i++)
4567 // Get client and check that it is valid
4568 RemoteClient *client = i.getNode()->getValue();
4569 assert(client->peer_id == i.getNode()->getKey());
4570 if(client->serialization_version == SER_FMT_VER_INVALID)
4573 Player *player = m_env->getPlayer(client->peer_id);
4574 // Get name of player
4575 std::wstring name = L"unknown";
4577 name = narrow_to_wide(player->getName());
4578 // Add name to information string
4586 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4587 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4588 if(g_settings->get("motd") != "")
4589 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4593 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4595 std::set<std::string> privs;
4596 scriptapi_get_auth(m_lua, name, NULL, &privs);
4600 bool Server::checkPriv(const std::string &name, const std::string &priv)
4602 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4603 return (privs.count(priv) != 0);
4606 void Server::reportPrivsModified(const std::string &name)
4609 for(core::map<u16, RemoteClient*>::Iterator
4610 i = m_clients.getIterator();
4611 i.atEnd() == false; i++){
4612 RemoteClient *client = i.getNode()->getValue();
4613 Player *player = m_env->getPlayer(client->peer_id);
4614 reportPrivsModified(player->getName());
4617 Player *player = m_env->getPlayer(name.c_str());
4620 SendPlayerPrivileges(player->peer_id);
4621 PlayerSAO *sao = player->getPlayerSAO();
4624 sao->updatePrivileges(
4625 getPlayerEffectivePrivs(name),
4630 void Server::reportInventoryFormspecModified(const std::string &name)
4632 Player *player = m_env->getPlayer(name.c_str());
4635 SendPlayerInventoryFormspec(player->peer_id);
4638 // Saves g_settings to configpath given at initialization
4639 void Server::saveConfig()
4641 if(m_path_config != "")
4642 g_settings->updateConfigFile(m_path_config.c_str());
4645 void Server::notifyPlayer(const char *name, const std::wstring msg)
4647 Player *player = m_env->getPlayer(name);
4650 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4653 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4655 Player *player = m_env->getPlayer(playername);
4659 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4663 SendShowFormspecMessage(player->peer_id, formspec, formname);
4667 void Server::notifyPlayers(const std::wstring msg)
4669 BroadcastChatMessage(msg);
4672 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4676 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4677 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4680 Inventory* Server::createDetachedInventory(const std::string &name)
4682 if(m_detached_inventories.count(name) > 0){
4683 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4684 delete m_detached_inventories[name];
4686 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4688 Inventory *inv = new Inventory(m_itemdef);
4690 m_detached_inventories[name] = inv;
4691 sendDetachedInventoryToAll(name);
4698 BoolScopeSet(bool *dst, bool val):
4701 m_orig_state = *m_dst;
4706 *m_dst = m_orig_state;
4713 // actions: time-reversed list
4714 // Return value: success/failure
4715 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4716 std::list<std::string> *log)
4718 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4719 ServerMap *map = (ServerMap*)(&m_env->getMap());
4720 // Disable rollback report sink while reverting
4721 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4723 // Fail if no actions to handle
4724 if(actions.empty()){
4725 log->push_back("Nothing to do.");
4732 for(std::list<RollbackAction>::const_iterator
4733 i = actions.begin();
4734 i != actions.end(); i++)
4736 const RollbackAction &action = *i;
4738 bool success = action.applyRevert(map, this, this);
4741 std::ostringstream os;
4742 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4743 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4745 log->push_back(os.str());
4747 std::ostringstream os;
4748 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4749 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4751 log->push_back(os.str());
4755 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4756 <<" failed"<<std::endl;
4758 // Call it done if less than half failed
4759 return num_failed <= num_tried/2;
4762 // IGameDef interface
4764 IItemDefManager* Server::getItemDefManager()
4768 INodeDefManager* Server::getNodeDefManager()
4772 ICraftDefManager* Server::getCraftDefManager()
4776 ITextureSource* Server::getTextureSource()
4780 IShaderSource* Server::getShaderSource()
4784 u16 Server::allocateUnknownNodeId(const std::string &name)
4786 return m_nodedef->allocateDummy(name);
4788 ISoundManager* Server::getSoundManager()
4790 return &dummySoundManager;
4792 MtEventManager* Server::getEventManager()
4796 IRollbackReportSink* Server::getRollbackReportSink()
4798 if(!m_enable_rollback_recording)
4800 if(!m_rollback_sink_enabled)
4805 IWritableItemDefManager* Server::getWritableItemDefManager()
4809 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4813 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4818 const ModSpec* Server::getModSpec(const std::string &modname)
4820 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4821 i != m_mods.end(); i++){
4822 const ModSpec &mod = *i;
4823 if(mod.name == modname)
4828 void Server::getModNames(core::list<std::string> &modlist)
4830 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4832 modlist.push_back((*i).name);
4835 std::string Server::getBuiltinLuaPath()
4837 return porting::path_share + DIR_DELIM + "builtin";
4840 v3f findSpawnPos(ServerMap &map)
4842 //return v3f(50,50,50)*BS;
4847 nodepos = v2s16(0,0);
4852 s16 water_level = map.m_emerge->water_level; //g_settings->getS16("default_water_level");
4854 // Try to find a good place a few times
4855 for(s32 i=0; i<1000; i++)
4858 // We're going to try to throw the player to this position
4859 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4860 -range + (myrand()%(range*2)));
4861 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4862 // Get ground height at point (fallbacks to heightmap function)
4863 s16 groundheight = map.findGroundLevel(nodepos2d);
4864 // Don't go underwater
4865 if(groundheight <= water_level)
4867 //infostream<<"-> Underwater"<<std::endl;
4870 // Don't go to high places
4871 if(groundheight > water_level + 6)
4873 //infostream<<"-> Underwater"<<std::endl;
4877 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4878 bool is_good = false;
4880 for(s32 i=0; i<10; i++){
4881 v3s16 blockpos = getNodeBlockPos(nodepos);
4882 map.emergeBlock(blockpos, true);
4883 MapNode n = map.getNodeNoEx(nodepos);
4884 if(n.getContent() == CONTENT_AIR){
4895 // Found a good place
4896 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4902 return intToFloat(nodepos, BS);
4905 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4907 RemotePlayer *player = NULL;
4908 bool newplayer = false;
4911 Try to get an existing player
4913 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4915 // If player is already connected, cancel
4916 if(player != NULL && player->peer_id != 0)
4918 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4923 If player with the wanted peer_id already exists, cancel.
4925 if(m_env->getPlayer(peer_id) != NULL)
4927 infostream<<"emergePlayer(): Player with wrong name but same"
4928 " peer_id already exists"<<std::endl;
4933 Create a new player if it doesn't exist yet
4938 player = new RemotePlayer(this);
4939 player->updateName(name);
4941 /* Set player position */
4942 infostream<<"Server: Finding spawn place for player \""
4943 <<name<<"\""<<std::endl;
4944 v3f pos = findSpawnPos(m_env->getServerMap());
4945 player->setPosition(pos);
4947 /* Add player to environment */
4948 m_env->addPlayer(player);
4952 Create a new player active object
4954 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4955 getPlayerEffectivePrivs(player->getName()),
4958 /* Add object to environment */
4959 m_env->addActiveObject(playersao);
4963 scriptapi_on_newplayer(m_lua, playersao);
4965 scriptapi_on_joinplayer(m_lua, playersao);
4970 void Server::handlePeerChange(PeerChange &c)
4972 JMutexAutoLock envlock(m_env_mutex);
4973 JMutexAutoLock conlock(m_con_mutex);
4975 if(c.type == PEER_ADDED)
4982 core::map<u16, RemoteClient*>::Node *n;
4983 n = m_clients.find(c.peer_id);
4984 // The client shouldn't already exist
4988 RemoteClient *client = new RemoteClient();
4989 client->peer_id = c.peer_id;
4990 m_clients.insert(client->peer_id, client);
4993 else if(c.type == PEER_REMOVED)
5000 core::map<u16, RemoteClient*>::Node *n;
5001 n = m_clients.find(c.peer_id);
5002 // The client should exist
5006 Mark objects to be not known by the client
5008 RemoteClient *client = n->getValue();
5010 for(core::map<u16, bool>::Iterator
5011 i = client->m_known_objects.getIterator();
5012 i.atEnd()==false; i++)
5015 u16 id = i.getNode()->getKey();
5016 ServerActiveObject* obj = m_env->getActiveObject(id);
5018 if(obj && obj->m_known_by_count > 0)
5019 obj->m_known_by_count--;
5023 Clear references to playing sounds
5025 for(std::map<s32, ServerPlayingSound>::iterator
5026 i = m_playing_sounds.begin();
5027 i != m_playing_sounds.end();)
5029 ServerPlayingSound &psound = i->second;
5030 psound.clients.erase(c.peer_id);
5031 if(psound.clients.size() == 0)
5032 m_playing_sounds.erase(i++);
5037 Player *player = m_env->getPlayer(c.peer_id);
5039 // Collect information about leaving in chat
5040 std::wstring message;
5044 std::wstring name = narrow_to_wide(player->getName());
5047 message += L" left the game.";
5049 message += L" (timed out)";
5053 /* Run scripts and remove from environment */
5057 PlayerSAO *playersao = player->getPlayerSAO();
5060 scriptapi_on_leaveplayer(m_lua, playersao);
5062 playersao->disconnected();
5072 std::ostringstream os(std::ios_base::binary);
5073 for(core::map<u16, RemoteClient*>::Iterator
5074 i = m_clients.getIterator();
5075 i.atEnd() == false; i++)
5077 RemoteClient *client = i.getNode()->getValue();
5078 assert(client->peer_id == i.getNode()->getKey());
5079 if(client->serialization_version == SER_FMT_VER_INVALID)
5082 Player *player = m_env->getPlayer(client->peer_id);
5085 // Get name of player
5086 os<<player->getName()<<" ";
5089 actionstream<<player->getName()<<" "
5090 <<(c.timeout?"times out.":"leaves game.")
5091 <<" List of players: "
5092 <<os.str()<<std::endl;
5097 delete m_clients[c.peer_id];
5098 m_clients.remove(c.peer_id);
5100 // Send player info to all remaining clients
5101 //SendPlayerInfos();
5103 // Send leave chat message to all remaining clients
5104 if(message.length() != 0)
5105 BroadcastChatMessage(message);
5114 void Server::handlePeerChanges()
5116 while(m_peer_change_queue.size() > 0)
5118 PeerChange c = m_peer_change_queue.pop_front();
5120 verbosestream<<"Server: Handling peer change: "
5121 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5124 handlePeerChange(c);
5128 void dedicated_server_loop(Server &server, bool &kill)
5130 DSTACK(__FUNCTION_NAME);
5132 verbosestream<<"dedicated_server_loop()"<<std::endl;
5134 IntervalLimiter m_profiler_interval;
5138 float steplen = g_settings->getFloat("dedicated_server_step");
5139 // This is kind of a hack but can be done like this
5140 // because server.step() is very light
5142 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5143 sleep_ms((int)(steplen*1000.0));
5145 server.step(steplen);
5147 if(server.getShutdownRequested() || kill)
5149 infostream<<"Dedicated server quitting"<<std::endl;
5156 float profiler_print_interval =
5157 g_settings->getFloat("profiler_print_interval");
5158 if(profiler_print_interval != 0)
5160 if(m_profiler_interval.step(steplen, profiler_print_interval))
5162 infostream<<"Profiler:"<<std::endl;
5163 g_profiler->print(infostream);
5164 g_profiler->clear();