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 = new Mapgen( m_server->m_emerge->biomedef,/*mapgenid*/ 0, map.getSeed()); ////////fix this...!
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;
805 if(nearest_sent_d == -1)
809 Add block to send queue
812 /*errorstream<<"sending from d="<<d<<" to "
813 <<server->getPlayerName(peer_id)<<std::endl;*/
815 PrioritySortedBlockTransfer q((float)d, p, peer_id);
819 num_blocks_selected += 1;
824 //infostream<<"Stopped at "<<d<<std::endl;
826 // If nothing was found for sending and nothing was queued for
827 // emerging, continue next time browsing from here
828 if(nearest_emerged_d != -1){
829 new_nearest_unsent_d = nearest_emerged_d;
830 } else if(nearest_emergefull_d != -1){
831 new_nearest_unsent_d = nearest_emergefull_d;
833 if(d > g_settings->getS16("max_block_send_distance")){
834 new_nearest_unsent_d = 0;
835 m_nothing_to_send_pause_timer = 2.0;
836 /*infostream<<"GetNextBlocks(): d wrapped around for "
837 <<server->getPlayerName(peer_id)
838 <<"; setting to 0 and pausing"<<std::endl;*/
840 if(nearest_sent_d != -1)
841 new_nearest_unsent_d = nearest_sent_d;
843 new_nearest_unsent_d = d;
847 if(new_nearest_unsent_d != -1)
848 m_nearest_unsent_d = new_nearest_unsent_d;
850 /*timer_result = timer.stop(true);
851 if(timer_result != 0)
852 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
855 void RemoteClient::GotBlock(v3s16 p)
857 if(m_blocks_sending.find(p) != NULL)
858 m_blocks_sending.remove(p);
861 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
862 " m_blocks_sending"<<std::endl;*/
863 m_excess_gotblocks++;
865 m_blocks_sent.insert(p, true);
868 void RemoteClient::SentBlock(v3s16 p)
870 if(m_blocks_sending.find(p) == NULL)
871 m_blocks_sending.insert(p, 0.0);
873 infostream<<"RemoteClient::SentBlock(): Sent block"
874 " already in m_blocks_sending"<<std::endl;
877 void RemoteClient::SetBlockNotSent(v3s16 p)
879 m_nearest_unsent_d = 0;
881 if(m_blocks_sending.find(p) != NULL)
882 m_blocks_sending.remove(p);
883 if(m_blocks_sent.find(p) != NULL)
884 m_blocks_sent.remove(p);
887 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
889 m_nearest_unsent_d = 0;
891 for(core::map<v3s16, MapBlock*>::Iterator
892 i = blocks.getIterator();
893 i.atEnd()==false; i++)
895 v3s16 p = i.getNode()->getKey();
897 if(m_blocks_sending.find(p) != NULL)
898 m_blocks_sending.remove(p);
899 if(m_blocks_sent.find(p) != NULL)
900 m_blocks_sent.remove(p);
908 PlayerInfo::PlayerInfo()
914 void PlayerInfo::PrintLine(std::ostream *s)
917 (*s)<<"\""<<name<<"\" ("
918 <<(position.X/10)<<","<<(position.Y/10)
919 <<","<<(position.Z/10)<<") ";
921 (*s)<<" avg_rtt="<<avg_rtt;
930 const std::string &path_world,
931 const std::string &path_config,
932 const SubgameSpec &gamespec,
933 bool simple_singleplayer_mode
935 m_path_world(path_world),
936 m_path_config(path_config),
937 m_gamespec(gamespec),
938 m_simple_singleplayer_mode(simple_singleplayer_mode),
939 m_async_fatal_error(""),
941 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
942 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
944 m_rollback_sink_enabled(true),
945 m_enable_rollback_recording(false),
948 m_itemdef(createItemDefManager()),
949 m_nodedef(createNodeDefManager()),
950 m_craftdef(createCraftDefManager()),
951 m_event(new EventManager()),
953 m_emergethread(this),
954 m_time_of_day_send_timer(0),
956 m_shutdown_requested(false),
957 m_ignore_map_edit_events(false),
958 m_ignore_map_edit_events_peer_id(0)
960 m_liquid_transform_timer = 0.0;
961 m_print_info_timer = 0.0;
962 m_objectdata_timer = 0.0;
963 m_emergethread_trigger_timer = 0.0;
964 m_savemap_timer = 0.0;
968 m_step_dtime_mutex.Init();
972 throw ServerError("Supplied empty world path");
974 if(!gamespec.isValid())
975 throw ServerError("Supplied invalid gamespec");
977 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
978 if(m_simple_singleplayer_mode)
979 infostream<<" in simple singleplayer mode"<<std::endl;
981 infostream<<std::endl;
982 infostream<<"- world: "<<m_path_world<<std::endl;
983 infostream<<"- config: "<<m_path_config<<std::endl;
984 infostream<<"- game: "<<m_gamespec.path<<std::endl;
986 // Create emerge manager
987 m_emerge = new EmergeManager(this);
989 // Create rollback manager
990 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
991 m_rollback = createRollbackManager(rollback_path, this);
993 // Create world if it doesn't exist
994 if(!initializeWorld(m_path_world, m_gamespec.id))
995 throw ServerError("Failed to initialize world");
997 ModConfiguration modconf(m_path_world);
998 m_mods = modconf.getMods();
999 // complain about mods with unsatisfied dependencies
1000 if(!modconf.isConsistent())
1002 errorstream << "The following mods have unsatisfied dependencies: ";
1003 std::list<ModSpec> modlist = modconf.getUnsatisfiedMods();
1004 for(std::list<ModSpec>::iterator it = modlist.begin();
1005 it != modlist.end(); ++it)
1007 errorstream << (*it).name << " ";
1009 errorstream << std::endl;
1012 Settings worldmt_settings;
1013 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
1014 worldmt_settings.readConfigFile(worldmt.c_str());
1015 std::vector<std::string> names = worldmt_settings.getNames();
1016 std::set<std::string> exclude_mod_names;
1017 std::set<std::string> load_mod_names;
1018 for(std::vector<std::string>::iterator it = names.begin();
1019 it != names.end(); ++it)
1021 std::string name = *it;
1022 if (name.compare(0,9,"load_mod_")==0)
1024 if(worldmt_settings.getBool(name))
1025 load_mod_names.insert(name.substr(9));
1027 exclude_mod_names.insert(name.substr(9));
1030 // complain about mods declared to be loaded, but not found
1031 for(std::vector<ModSpec>::iterator it = m_mods.begin();
1032 it != m_mods.end(); ++it)
1033 load_mod_names.erase((*it).name);
1034 if(!load_mod_names.empty())
1036 errorstream << "The following mods could not be found: ";
1037 for(std::set<std::string>::iterator it = load_mod_names.begin();
1038 it != load_mod_names.end(); ++it)
1039 errorstream << (*it) << " ";
1040 errorstream << std::endl;
1043 // Path to builtin.lua
1044 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
1047 JMutexAutoLock envlock(m_env_mutex);
1048 JMutexAutoLock conlock(m_con_mutex);
1050 // Initialize scripting
1052 infostream<<"Server: Initializing Lua"<<std::endl;
1053 m_lua = script_init();
1056 scriptapi_export(m_lua, this);
1057 // Load and run builtin.lua
1058 infostream<<"Server: Loading builtin.lua [\""
1059 <<builtinpath<<"\"]"<<std::endl;
1060 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1062 errorstream<<"Server: Failed to load and run "
1063 <<builtinpath<<std::endl;
1064 throw ModError("Failed to load and run "+builtinpath);
1067 infostream<<"Server: Loading mods: ";
1068 for(std::vector<ModSpec>::iterator i = m_mods.begin();
1069 i != m_mods.end(); i++){
1070 const ModSpec &mod = *i;
1071 infostream<<mod.name<<" ";
1073 infostream<<std::endl;
1074 // Load and run "mod" scripts
1075 for(std::vector<ModSpec>::iterator i = m_mods.begin();
1076 i != m_mods.end(); i++){
1077 const ModSpec &mod = *i;
1078 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1079 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1080 <<scriptpath<<"\"]"<<std::endl;
1081 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1083 errorstream<<"Server: Failed to load and run "
1084 <<scriptpath<<std::endl;
1085 throw ModError("Failed to load and run "+scriptpath);
1089 // Read Textures and calculate sha1 sums
1092 // Apply item aliases in the node definition manager
1093 m_nodedef->updateAliases(m_itemdef);
1095 // Add default biomes after nodedef had its aliases added
1096 m_emerge->biomedef->addDefaultBiomes();
1098 // Initialize Environment
1100 m_env = new ServerEnvironment(new ServerMap(path_world, this, m_emerge), m_lua,
1103 // Give environment reference to scripting api
1104 scriptapi_add_environment(m_lua, m_env);
1106 // Register us to receive map edit events
1107 m_env->getMap().addEventReceiver(this);
1109 // If file exists, load environment metadata
1110 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1112 infostream<<"Server: Loading environment metadata"<<std::endl;
1113 m_env->loadMeta(m_path_world);
1117 infostream<<"Server: Loading players"<<std::endl;
1118 m_env->deSerializePlayers(m_path_world);
1121 Add some test ActiveBlockModifiers to environment
1123 add_legacy_abms(m_env, m_nodedef);
1128 infostream<<"Server destructing"<<std::endl;
1131 Send shutdown message
1134 JMutexAutoLock conlock(m_con_mutex);
1136 std::wstring line = L"*** Server shutting down";
1139 Send the message to clients
1141 for(core::map<u16, RemoteClient*>::Iterator
1142 i = m_clients.getIterator();
1143 i.atEnd() == false; i++)
1145 // Get client and check that it is valid
1146 RemoteClient *client = i.getNode()->getValue();
1147 assert(client->peer_id == i.getNode()->getKey());
1148 if(client->serialization_version == SER_FMT_VER_INVALID)
1152 SendChatMessage(client->peer_id, line);
1154 catch(con::PeerNotFoundException &e)
1160 JMutexAutoLock envlock(m_env_mutex);
1161 JMutexAutoLock conlock(m_con_mutex);
1164 Execute script shutdown hooks
1166 scriptapi_on_shutdown(m_lua);
1170 JMutexAutoLock envlock(m_env_mutex);
1175 infostream<<"Server: Saving players"<<std::endl;
1176 m_env->serializePlayers(m_path_world);
1179 Save environment metadata
1181 infostream<<"Server: Saving environment metadata"<<std::endl;
1182 m_env->saveMeta(m_path_world);
1194 JMutexAutoLock clientslock(m_con_mutex);
1196 for(core::map<u16, RemoteClient*>::Iterator
1197 i = m_clients.getIterator();
1198 i.atEnd() == false; i++)
1202 delete i.getNode()->getValue();
1206 // Delete things in the reverse order of creation
1215 // Deinitialize scripting
1216 infostream<<"Server: Deinitializing scripting"<<std::endl;
1217 script_deinit(m_lua);
1219 // Delete detached inventories
1221 for(std::map<std::string, Inventory*>::iterator
1222 i = m_detached_inventories.begin();
1223 i != m_detached_inventories.end(); i++){
1229 void Server::start(unsigned short port)
1231 DSTACK(__FUNCTION_NAME);
1232 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1234 // Stop thread if already running
1237 // Initialize connection
1238 m_con.SetTimeoutMs(30);
1242 m_thread.setRun(true);
1245 // ASCII art for the win!
1247 <<" .__ __ __ "<<std::endl
1248 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1249 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1250 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1251 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1252 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1253 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1254 actionstream<<"Server for gameid=\""<<m_gamespec.id
1255 <<"\" listening on port "<<port<<"."<<std::endl;
1260 DSTACK(__FUNCTION_NAME);
1262 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1264 // Stop threads (set run=false first so both start stopping)
1265 m_thread.setRun(false);
1266 m_emergethread.setRun(false);
1268 m_emergethread.stop();
1270 infostream<<"Server: Threads stopped"<<std::endl;
1273 void Server::step(float dtime)
1275 DSTACK(__FUNCTION_NAME);
1280 JMutexAutoLock lock(m_step_dtime_mutex);
1281 m_step_dtime += dtime;
1283 // Throw if fatal error occurred in thread
1284 std::string async_err = m_async_fatal_error.get();
1285 if(async_err != ""){
1286 throw ServerError(async_err);
1290 void Server::AsyncRunStep()
1292 DSTACK(__FUNCTION_NAME);
1294 g_profiler->add("Server::AsyncRunStep (num)", 1);
1298 JMutexAutoLock lock1(m_step_dtime_mutex);
1299 dtime = m_step_dtime;
1303 // Send blocks to clients
1310 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1312 //infostream<<"Server steps "<<dtime<<std::endl;
1313 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1316 JMutexAutoLock lock1(m_step_dtime_mutex);
1317 m_step_dtime -= dtime;
1324 m_uptime.set(m_uptime.get() + dtime);
1328 // Process connection's timeouts
1329 JMutexAutoLock lock2(m_con_mutex);
1330 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1331 m_con.RunTimeouts(dtime);
1335 // This has to be called so that the client list gets synced
1336 // with the peer list of the connection
1337 handlePeerChanges();
1341 Update time of day and overall game time
1344 JMutexAutoLock envlock(m_env_mutex);
1346 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1349 Send to clients at constant intervals
1352 m_time_of_day_send_timer -= dtime;
1353 if(m_time_of_day_send_timer < 0.0)
1355 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1357 //JMutexAutoLock envlock(m_env_mutex);
1358 JMutexAutoLock conlock(m_con_mutex);
1360 for(core::map<u16, RemoteClient*>::Iterator
1361 i = m_clients.getIterator();
1362 i.atEnd() == false; i++)
1364 RemoteClient *client = i.getNode()->getValue();
1365 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1366 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1368 m_con.Send(client->peer_id, 0, data, true);
1374 JMutexAutoLock lock(m_env_mutex);
1376 ScopeProfiler sp(g_profiler, "SEnv step");
1377 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1381 const float map_timer_and_unload_dtime = 2.92;
1382 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1384 JMutexAutoLock lock(m_env_mutex);
1385 // Run Map's timers and unload unused data
1386 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1387 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1388 g_settings->getFloat("server_unload_unused_data_timeout"));
1399 JMutexAutoLock lock(m_env_mutex);
1400 JMutexAutoLock lock2(m_con_mutex);
1402 ScopeProfiler sp(g_profiler, "Server: handle players");
1404 for(core::map<u16, RemoteClient*>::Iterator
1405 i = m_clients.getIterator();
1406 i.atEnd() == false; i++)
1408 RemoteClient *client = i.getNode()->getValue();
1409 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1410 if(playersao == NULL)
1414 Handle player HPs (die if hp=0)
1416 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1418 if(playersao->getHP() == 0)
1419 DiePlayer(client->peer_id);
1421 SendPlayerHP(client->peer_id);
1425 Send player inventories if necessary
1427 if(playersao->m_moved){
1428 SendMovePlayer(client->peer_id);
1429 playersao->m_moved = false;
1431 if(playersao->m_inventory_not_sent){
1432 UpdateCrafting(client->peer_id);
1433 SendInventory(client->peer_id);
1438 /* Transform liquids */
1439 m_liquid_transform_timer += dtime;
1440 if(m_liquid_transform_timer >= 1.00)
1442 m_liquid_transform_timer -= 1.00;
1444 JMutexAutoLock lock(m_env_mutex);
1446 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1448 core::map<v3s16, MapBlock*> modified_blocks;
1449 m_env->getMap().transformLiquids(modified_blocks);
1454 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1455 ServerMap &map = ((ServerMap&)m_env->getMap());
1456 map.updateLighting(modified_blocks, lighting_modified_blocks);
1458 // Add blocks modified by lighting to modified_blocks
1459 for(core::map<v3s16, MapBlock*>::Iterator
1460 i = lighting_modified_blocks.getIterator();
1461 i.atEnd() == false; i++)
1463 MapBlock *block = i.getNode()->getValue();
1464 modified_blocks.insert(block->getPos(), block);
1468 Set the modified blocks unsent for all the clients
1471 JMutexAutoLock lock2(m_con_mutex);
1473 for(core::map<u16, RemoteClient*>::Iterator
1474 i = m_clients.getIterator();
1475 i.atEnd() == false; i++)
1477 RemoteClient *client = i.getNode()->getValue();
1479 if(modified_blocks.size() > 0)
1481 // Remove block from sent history
1482 client->SetBlocksNotSent(modified_blocks);
1487 // Periodically print some info
1489 float &counter = m_print_info_timer;
1495 JMutexAutoLock lock2(m_con_mutex);
1497 if(m_clients.size() != 0)
1498 infostream<<"Players:"<<std::endl;
1499 for(core::map<u16, RemoteClient*>::Iterator
1500 i = m_clients.getIterator();
1501 i.atEnd() == false; i++)
1503 //u16 peer_id = i.getNode()->getKey();
1504 RemoteClient *client = i.getNode()->getValue();
1505 Player *player = m_env->getPlayer(client->peer_id);
1508 infostream<<"* "<<player->getName()<<"\t";
1509 client->PrintInfo(infostream);
1514 //if(g_settings->getBool("enable_experimental"))
1518 Check added and deleted active objects
1521 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1522 JMutexAutoLock envlock(m_env_mutex);
1523 JMutexAutoLock conlock(m_con_mutex);
1525 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1527 // Radius inside which objects are active
1528 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1529 radius *= MAP_BLOCKSIZE;
1531 for(core::map<u16, RemoteClient*>::Iterator
1532 i = m_clients.getIterator();
1533 i.atEnd() == false; i++)
1535 RemoteClient *client = i.getNode()->getValue();
1537 // If definitions and textures have not been sent, don't
1538 // send objects either
1539 if(!client->definitions_sent)
1542 Player *player = m_env->getPlayer(client->peer_id);
1545 // This can happen if the client timeouts somehow
1546 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1548 <<" has no associated player"<<std::endl;*/
1551 v3s16 pos = floatToInt(player->getPosition(), BS);
1553 core::map<u16, bool> removed_objects;
1554 core::map<u16, bool> added_objects;
1555 m_env->getRemovedActiveObjects(pos, radius,
1556 client->m_known_objects, removed_objects);
1557 m_env->getAddedActiveObjects(pos, radius,
1558 client->m_known_objects, added_objects);
1560 // Ignore if nothing happened
1561 if(removed_objects.size() == 0 && added_objects.size() == 0)
1563 //infostream<<"active objects: none changed"<<std::endl;
1567 std::string data_buffer;
1571 // Handle removed objects
1572 writeU16((u8*)buf, removed_objects.size());
1573 data_buffer.append(buf, 2);
1574 for(core::map<u16, bool>::Iterator
1575 i = removed_objects.getIterator();
1576 i.atEnd()==false; i++)
1579 u16 id = i.getNode()->getKey();
1580 ServerActiveObject* obj = m_env->getActiveObject(id);
1582 // Add to data buffer for sending
1583 writeU16((u8*)buf, i.getNode()->getKey());
1584 data_buffer.append(buf, 2);
1586 // Remove from known objects
1587 client->m_known_objects.remove(i.getNode()->getKey());
1589 if(obj && obj->m_known_by_count > 0)
1590 obj->m_known_by_count--;
1593 // Handle added objects
1594 writeU16((u8*)buf, added_objects.size());
1595 data_buffer.append(buf, 2);
1596 for(core::map<u16, bool>::Iterator
1597 i = added_objects.getIterator();
1598 i.atEnd()==false; i++)
1601 u16 id = i.getNode()->getKey();
1602 ServerActiveObject* obj = m_env->getActiveObject(id);
1605 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1607 infostream<<"WARNING: "<<__FUNCTION_NAME
1608 <<": NULL object"<<std::endl;
1610 type = obj->getSendType();
1612 // Add to data buffer for sending
1613 writeU16((u8*)buf, id);
1614 data_buffer.append(buf, 2);
1615 writeU8((u8*)buf, type);
1616 data_buffer.append(buf, 1);
1619 data_buffer.append(serializeLongString(
1620 obj->getClientInitializationData(client->net_proto_version)));
1622 data_buffer.append(serializeLongString(""));
1624 // Add to known objects
1625 client->m_known_objects.insert(i.getNode()->getKey(), false);
1628 obj->m_known_by_count++;
1632 SharedBuffer<u8> reply(2 + data_buffer.size());
1633 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1634 memcpy((char*)&reply[2], data_buffer.c_str(),
1635 data_buffer.size());
1637 m_con.Send(client->peer_id, 0, reply, true);
1639 verbosestream<<"Server: Sent object remove/add: "
1640 <<removed_objects.size()<<" removed, "
1641 <<added_objects.size()<<" added, "
1642 <<"packet size is "<<reply.getSize()<<std::endl;
1647 Collect a list of all the objects known by the clients
1648 and report it back to the environment.
1651 core::map<u16, bool> all_known_objects;
1653 for(core::map<u16, RemoteClient*>::Iterator
1654 i = m_clients.getIterator();
1655 i.atEnd() == false; i++)
1657 RemoteClient *client = i.getNode()->getValue();
1658 // Go through all known objects of client
1659 for(core::map<u16, bool>::Iterator
1660 i = client->m_known_objects.getIterator();
1661 i.atEnd()==false; i++)
1663 u16 id = i.getNode()->getKey();
1664 all_known_objects[id] = true;
1668 m_env->setKnownActiveObjects(whatever);
1674 Send object messages
1677 JMutexAutoLock envlock(m_env_mutex);
1678 JMutexAutoLock conlock(m_con_mutex);
1680 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1683 // Value = data sent by object
1684 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1686 // Get active object messages from environment
1689 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1693 core::list<ActiveObjectMessage>* message_list = NULL;
1694 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1695 n = buffered_messages.find(aom.id);
1698 message_list = new core::list<ActiveObjectMessage>;
1699 buffered_messages.insert(aom.id, message_list);
1703 message_list = n->getValue();
1705 message_list->push_back(aom);
1708 // Route data to every client
1709 for(core::map<u16, RemoteClient*>::Iterator
1710 i = m_clients.getIterator();
1711 i.atEnd()==false; i++)
1713 RemoteClient *client = i.getNode()->getValue();
1714 std::string reliable_data;
1715 std::string unreliable_data;
1716 // Go through all objects in message buffer
1717 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1718 j = buffered_messages.getIterator();
1719 j.atEnd()==false; j++)
1721 // If object is not known by client, skip it
1722 u16 id = j.getNode()->getKey();
1723 if(client->m_known_objects.find(id) == NULL)
1725 // Get message list of object
1726 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1727 // Go through every message
1728 for(core::list<ActiveObjectMessage>::Iterator
1729 k = list->begin(); k != list->end(); k++)
1731 // Compose the full new data with header
1732 ActiveObjectMessage aom = *k;
1733 std::string new_data;
1736 writeU16((u8*)&buf[0], aom.id);
1737 new_data.append(buf, 2);
1739 new_data += serializeString(aom.datastring);
1740 // Add data to buffer
1742 reliable_data += new_data;
1744 unreliable_data += new_data;
1748 reliable_data and unreliable_data are now ready.
1751 if(reliable_data.size() > 0)
1753 SharedBuffer<u8> reply(2 + reliable_data.size());
1754 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1755 memcpy((char*)&reply[2], reliable_data.c_str(),
1756 reliable_data.size());
1758 m_con.Send(client->peer_id, 0, reply, true);
1760 if(unreliable_data.size() > 0)
1762 SharedBuffer<u8> reply(2 + unreliable_data.size());
1763 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1764 memcpy((char*)&reply[2], unreliable_data.c_str(),
1765 unreliable_data.size());
1766 // Send as unreliable
1767 m_con.Send(client->peer_id, 0, reply, false);
1770 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1772 infostream<<"Server: Size of object message data: "
1773 <<"reliable: "<<reliable_data.size()
1774 <<", unreliable: "<<unreliable_data.size()
1779 // Clear buffered_messages
1780 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1781 i = buffered_messages.getIterator();
1782 i.atEnd()==false; i++)
1784 delete i.getNode()->getValue();
1788 } // enable_experimental
1791 Send queued-for-sending map edit events.
1794 // We will be accessing the environment and the connection
1795 JMutexAutoLock lock(m_env_mutex);
1796 JMutexAutoLock conlock(m_con_mutex);
1798 // Don't send too many at a time
1801 // Single change sending is disabled if queue size is not small
1802 bool disable_single_change_sending = false;
1803 if(m_unsent_map_edit_queue.size() >= 4)
1804 disable_single_change_sending = true;
1806 int event_count = m_unsent_map_edit_queue.size();
1808 // We'll log the amount of each
1811 while(m_unsent_map_edit_queue.size() != 0)
1813 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1815 // Players far away from the change are stored here.
1816 // Instead of sending the changes, MapBlocks are set not sent
1818 core::list<u16> far_players;
1820 if(event->type == MEET_ADDNODE)
1822 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1823 prof.add("MEET_ADDNODE", 1);
1824 if(disable_single_change_sending)
1825 sendAddNode(event->p, event->n, event->already_known_by_peer,
1828 sendAddNode(event->p, event->n, event->already_known_by_peer,
1831 else if(event->type == MEET_REMOVENODE)
1833 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1834 prof.add("MEET_REMOVENODE", 1);
1835 if(disable_single_change_sending)
1836 sendRemoveNode(event->p, event->already_known_by_peer,
1839 sendRemoveNode(event->p, event->already_known_by_peer,
1842 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1844 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1845 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1846 setBlockNotSent(event->p);
1848 else if(event->type == MEET_OTHER)
1850 infostream<<"Server: MEET_OTHER"<<std::endl;
1851 prof.add("MEET_OTHER", 1);
1852 for(core::map<v3s16, bool>::Iterator
1853 i = event->modified_blocks.getIterator();
1854 i.atEnd()==false; i++)
1856 v3s16 p = i.getNode()->getKey();
1862 prof.add("unknown", 1);
1863 infostream<<"WARNING: Server: Unknown MapEditEvent "
1864 <<((u32)event->type)<<std::endl;
1868 Set blocks not sent to far players
1870 if(far_players.size() > 0)
1872 // Convert list format to that wanted by SetBlocksNotSent
1873 core::map<v3s16, MapBlock*> modified_blocks2;
1874 for(core::map<v3s16, bool>::Iterator
1875 i = event->modified_blocks.getIterator();
1876 i.atEnd()==false; i++)
1878 v3s16 p = i.getNode()->getKey();
1879 modified_blocks2.insert(p,
1880 m_env->getMap().getBlockNoCreateNoEx(p));
1882 // Set blocks not sent
1883 for(core::list<u16>::Iterator
1884 i = far_players.begin();
1885 i != far_players.end(); i++)
1888 RemoteClient *client = getClient(peer_id);
1891 client->SetBlocksNotSent(modified_blocks2);
1897 /*// Don't send too many at a time
1899 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1903 if(event_count >= 5){
1904 infostream<<"Server: MapEditEvents:"<<std::endl;
1905 prof.print(infostream);
1906 } else if(event_count != 0){
1907 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1908 prof.print(verbosestream);
1914 Trigger emergethread (it somehow gets to a non-triggered but
1915 bysy state sometimes)
1918 float &counter = m_emergethread_trigger_timer;
1924 m_emergethread.trigger();
1926 // Update m_enable_rollback_recording here too
1927 m_enable_rollback_recording =
1928 g_settings->getBool("enable_rollback_recording");
1932 // Save map, players and auth stuff
1934 float &counter = m_savemap_timer;
1936 if(counter >= g_settings->getFloat("server_map_save_interval"))
1939 JMutexAutoLock lock(m_env_mutex);
1941 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1944 if(m_banmanager.isModified())
1945 m_banmanager.save();
1947 // Save changed parts of map
1948 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1951 m_env->serializePlayers(m_path_world);
1953 // Save environment metadata
1954 m_env->saveMeta(m_path_world);
1959 void Server::Receive()
1961 DSTACK(__FUNCTION_NAME);
1962 SharedBuffer<u8> data;
1967 JMutexAutoLock conlock(m_con_mutex);
1968 datasize = m_con.Receive(peer_id, data);
1971 // This has to be called so that the client list gets synced
1972 // with the peer list of the connection
1973 handlePeerChanges();
1975 ProcessData(*data, datasize, peer_id);
1977 catch(con::InvalidIncomingDataException &e)
1979 infostream<<"Server::Receive(): "
1980 "InvalidIncomingDataException: what()="
1981 <<e.what()<<std::endl;
1983 catch(con::PeerNotFoundException &e)
1985 //NOTE: This is not needed anymore
1987 // The peer has been disconnected.
1988 // Find the associated player and remove it.
1990 /*JMutexAutoLock envlock(m_env_mutex);
1992 infostream<<"ServerThread: peer_id="<<peer_id
1993 <<" has apparently closed connection. "
1994 <<"Removing player."<<std::endl;
1996 m_env->removePlayer(peer_id);*/
2000 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
2002 DSTACK(__FUNCTION_NAME);
2003 // Environment is locked first.
2004 JMutexAutoLock envlock(m_env_mutex);
2005 JMutexAutoLock conlock(m_con_mutex);
2007 ScopeProfiler sp(g_profiler, "Server::ProcessData");
2010 Address address = m_con.GetPeerAddress(peer_id);
2011 std::string addr_s = address.serializeString();
2013 // drop player if is ip is banned
2014 if(m_banmanager.isIpBanned(addr_s)){
2015 infostream<<"Server: A banned client tried to connect from "
2016 <<addr_s<<"; banned name was "
2017 <<m_banmanager.getBanName(addr_s)<<std::endl;
2018 // This actually doesn't seem to transfer to the client
2019 SendAccessDenied(m_con, peer_id,
2020 L"Your ip is banned. Banned name was "
2021 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
2022 m_con.DeletePeer(peer_id);
2026 catch(con::PeerNotFoundException &e)
2028 infostream<<"Server::ProcessData(): Cancelling: peer "
2029 <<peer_id<<" not found"<<std::endl;
2033 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
2035 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
2043 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
2045 if(command == TOSERVER_INIT)
2047 // [0] u16 TOSERVER_INIT
2048 // [2] u8 SER_FMT_VER_HIGHEST
2049 // [3] u8[20] player_name
2050 // [23] u8[28] password <--- can be sent without this, from old versions
2052 if(datasize < 2+1+PLAYERNAME_SIZE)
2055 verbosestream<<"Server: Got TOSERVER_INIT from "
2056 <<peer_id<<std::endl;
2058 // First byte after command is maximum supported
2059 // serialization version
2060 u8 client_max = data[2];
2061 u8 our_max = SER_FMT_VER_HIGHEST;
2062 // Use the highest version supported by both
2063 u8 deployed = core::min_(client_max, our_max);
2064 // If it's lower than the lowest supported, give up.
2065 if(deployed < SER_FMT_VER_LOWEST)
2066 deployed = SER_FMT_VER_INVALID;
2068 //peer->serialization_version = deployed;
2069 getClient(peer_id)->pending_serialization_version = deployed;
2071 if(deployed == SER_FMT_VER_INVALID)
2073 actionstream<<"Server: A mismatched client tried to connect from "
2074 <<addr_s<<std::endl;
2075 infostream<<"Server: Cannot negotiate "
2076 "serialization version with peer "
2077 <<peer_id<<std::endl;
2078 SendAccessDenied(m_con, peer_id, std::wstring(
2079 L"Your client's version is not supported.\n"
2080 L"Server version is ")
2081 + narrow_to_wide(VERSION_STRING) + L"."
2087 Read and check network protocol version
2090 u16 min_net_proto_version = 0;
2091 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2092 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2094 // Use same version as minimum and maximum if maximum version field
2095 // doesn't exist (backwards compatibility)
2096 u16 max_net_proto_version = min_net_proto_version;
2097 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
2098 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
2100 // Start with client's maximum version
2101 u16 net_proto_version = max_net_proto_version;
2103 // Figure out a working version if it is possible at all
2104 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
2105 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
2107 // If maximum is larger than our maximum, go with our maximum
2108 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2109 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
2110 // Else go with client's maximum
2112 net_proto_version = max_net_proto_version;
2115 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
2116 <<min_net_proto_version<<", max: "<<max_net_proto_version
2117 <<", chosen: "<<net_proto_version<<std::endl;
2119 getClient(peer_id)->net_proto_version = net_proto_version;
2121 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
2122 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2124 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
2126 SendAccessDenied(m_con, peer_id, std::wstring(
2127 L"Your client's version is not supported.\n"
2128 L"Server version is ")
2129 + narrow_to_wide(VERSION_STRING) + L",\n"
2130 + L"server's PROTOCOL_VERSION is "
2131 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
2133 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
2134 + L", client's PROTOCOL_VERSION is "
2135 + narrow_to_wide(itos(min_net_proto_version))
2137 + narrow_to_wide(itos(max_net_proto_version))
2142 if(g_settings->getBool("strict_protocol_version_checking"))
2144 if(net_proto_version != LATEST_PROTOCOL_VERSION)
2146 actionstream<<"Server: A mismatched (strict) client tried to "
2147 <<"connect from "<<addr_s<<std::endl;
2148 SendAccessDenied(m_con, peer_id, std::wstring(
2149 L"Your client's version is not supported.\n"
2150 L"Server version is ")
2151 + narrow_to_wide(VERSION_STRING) + L",\n"
2152 + L"server's PROTOCOL_VERSION (strict) is "
2153 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
2154 + L", client's PROTOCOL_VERSION is "
2155 + narrow_to_wide(itos(min_net_proto_version))
2157 + narrow_to_wide(itos(max_net_proto_version))
2168 char playername[PLAYERNAME_SIZE];
2169 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2171 playername[i] = data[3+i];
2173 playername[PLAYERNAME_SIZE-1] = 0;
2175 if(playername[0]=='\0')
2177 actionstream<<"Server: Player with an empty name "
2178 <<"tried to connect from "<<addr_s<<std::endl;
2179 SendAccessDenied(m_con, peer_id,
2184 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2186 actionstream<<"Server: Player with an invalid name "
2187 <<"tried to connect from "<<addr_s<<std::endl;
2188 SendAccessDenied(m_con, peer_id,
2189 L"Name contains unallowed characters");
2193 infostream<<"Server: New connection: \""<<playername<<"\" from "
2194 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2197 char given_password[PASSWORD_SIZE];
2198 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2200 // old version - assume blank password
2201 given_password[0] = 0;
2205 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2207 given_password[i] = data[23+i];
2209 given_password[PASSWORD_SIZE-1] = 0;
2212 if(!base64_is_valid(given_password)){
2213 infostream<<"Server: "<<playername
2214 <<" supplied invalid password hash"<<std::endl;
2215 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2219 std::string checkpwd; // Password hash to check against
2220 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2222 // If no authentication info exists for user, create it
2224 if(!isSingleplayer() &&
2225 g_settings->getBool("disallow_empty_password") &&
2226 std::string(given_password) == ""){
2227 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2228 L"disallowed. Set a password and try again.");
2231 std::wstring raw_default_password =
2232 narrow_to_wide(g_settings->get("default_password"));
2233 std::string initial_password =
2234 translatePassword(playername, raw_default_password);
2236 // If default_password is empty, allow any initial password
2237 if (raw_default_password.length() == 0)
2238 initial_password = given_password;
2240 scriptapi_create_auth(m_lua, playername, initial_password);
2243 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2246 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2250 if(given_password != checkpwd){
2251 infostream<<"Server: peer_id="<<peer_id
2252 <<": supplied invalid password for "
2253 <<playername<<std::endl;
2254 SendAccessDenied(m_con, peer_id, L"Invalid password");
2258 // Do not allow multiple players in simple singleplayer mode.
2259 // This isn't a perfect way to do it, but will suffice for now.
2260 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2261 infostream<<"Server: Not allowing another client to connect in"
2262 <<" simple singleplayer mode"<<std::endl;
2263 SendAccessDenied(m_con, peer_id,
2264 L"Running in simple singleplayer mode.");
2268 // Enforce user limit.
2269 // Don't enforce for users that have some admin right
2270 if(m_clients.size() >= g_settings->getU16("max_users") &&
2271 !checkPriv(playername, "server") &&
2272 !checkPriv(playername, "ban") &&
2273 !checkPriv(playername, "privs") &&
2274 !checkPriv(playername, "password") &&
2275 playername != g_settings->get("name"))
2277 actionstream<<"Server: "<<playername<<" tried to join, but there"
2278 <<" are already max_users="
2279 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2280 SendAccessDenied(m_con, peer_id, L"Too many users.");
2285 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2287 // If failed, cancel
2288 if(playersao == NULL)
2290 errorstream<<"Server: peer_id="<<peer_id
2291 <<": failed to emerge player"<<std::endl;
2296 Answer with a TOCLIENT_INIT
2299 SharedBuffer<u8> reply(2+1+6+8+4);
2300 writeU16(&reply[0], TOCLIENT_INIT);
2301 writeU8(&reply[2], deployed);
2302 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2303 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2304 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2307 m_con.Send(peer_id, 0, reply, true);
2311 Send complete position information
2313 SendMovePlayer(peer_id);
2318 if(command == TOSERVER_INIT2)
2320 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2321 <<peer_id<<std::endl;
2323 Player *player = m_env->getPlayer(peer_id);
2325 verbosestream<<"Server: TOSERVER_INIT2: "
2326 <<"Player not found; ignoring."<<std::endl;
2330 RemoteClient *client = getClient(peer_id);
2331 client->serialization_version =
2332 getClient(peer_id)->pending_serialization_version;
2335 Send some initialization data
2338 infostream<<"Server: Sending content to "
2339 <<getPlayerName(peer_id)<<std::endl;
2341 // Send item definitions
2342 SendItemDef(m_con, peer_id, m_itemdef);
2344 // Send node definitions
2345 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2347 // Send media announcement
2348 sendMediaAnnouncement(peer_id);
2351 SendPlayerPrivileges(peer_id);
2353 // Send inventory formspec
2354 SendPlayerInventoryFormspec(peer_id);
2357 UpdateCrafting(peer_id);
2358 SendInventory(peer_id);
2361 if(g_settings->getBool("enable_damage"))
2362 SendPlayerHP(peer_id);
2364 // Send detached inventories
2365 sendDetachedInventories(peer_id);
2367 // Show death screen if necessary
2369 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2373 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2374 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2375 m_con.Send(peer_id, 0, data, true);
2378 // Note things in chat if not in simple singleplayer mode
2379 if(!m_simple_singleplayer_mode)
2381 // Send information about server to player in chat
2382 SendChatMessage(peer_id, getStatusString());
2384 // Send information about joining in chat
2386 std::wstring name = L"unknown";
2387 Player *player = m_env->getPlayer(peer_id);
2389 name = narrow_to_wide(player->getName());
2391 std::wstring message;
2394 message += L" joined the game.";
2395 BroadcastChatMessage(message);
2399 // Warnings about protocol version can be issued here
2400 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2402 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2403 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2410 std::ostringstream os(std::ios_base::binary);
2411 for(core::map<u16, RemoteClient*>::Iterator
2412 i = m_clients.getIterator();
2413 i.atEnd() == false; i++)
2415 RemoteClient *client = i.getNode()->getValue();
2416 assert(client->peer_id == i.getNode()->getKey());
2417 if(client->serialization_version == SER_FMT_VER_INVALID)
2420 Player *player = m_env->getPlayer(client->peer_id);
2423 // Get name of player
2424 os<<player->getName()<<" ";
2427 actionstream<<player->getName()<<" joins game. List of players: "
2428 <<os.str()<<std::endl;
2434 if(peer_ser_ver == SER_FMT_VER_INVALID)
2436 infostream<<"Server::ProcessData(): Cancelling: Peer"
2437 " serialization format invalid or not initialized."
2438 " Skipping incoming command="<<command<<std::endl;
2442 Player *player = m_env->getPlayer(peer_id);
2444 infostream<<"Server::ProcessData(): Cancelling: "
2445 "No player for peer_id="<<peer_id
2450 PlayerSAO *playersao = player->getPlayerSAO();
2451 if(playersao == NULL){
2452 infostream<<"Server::ProcessData(): Cancelling: "
2453 "No player object for peer_id="<<peer_id
2458 if(command == TOSERVER_PLAYERPOS)
2460 if(datasize < 2+12+12+4+4)
2464 v3s32 ps = readV3S32(&data[start+2]);
2465 v3s32 ss = readV3S32(&data[start+2+12]);
2466 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2467 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2469 if(datasize >= 2+12+12+4+4+4)
2470 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2471 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2472 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2473 pitch = wrapDegrees(pitch);
2474 yaw = wrapDegrees(yaw);
2476 player->setPosition(position);
2477 player->setSpeed(speed);
2478 player->setPitch(pitch);
2479 player->setYaw(yaw);
2480 player->keyPressed=keyPressed;
2481 player->control.up = (bool)(keyPressed&1);
2482 player->control.down = (bool)(keyPressed&2);
2483 player->control.left = (bool)(keyPressed&4);
2484 player->control.right = (bool)(keyPressed&8);
2485 player->control.jump = (bool)(keyPressed&16);
2486 player->control.aux1 = (bool)(keyPressed&32);
2487 player->control.sneak = (bool)(keyPressed&64);
2488 player->control.LMB = (bool)(keyPressed&128);
2489 player->control.RMB = (bool)(keyPressed&256);
2491 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2492 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2493 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2495 else if(command == TOSERVER_GOTBLOCKS)
2508 u16 count = data[2];
2509 for(u16 i=0; i<count; i++)
2511 if((s16)datasize < 2+1+(i+1)*6)
2512 throw con::InvalidIncomingDataException
2513 ("GOTBLOCKS length is too short");
2514 v3s16 p = readV3S16(&data[2+1+i*6]);
2515 /*infostream<<"Server: GOTBLOCKS ("
2516 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2517 RemoteClient *client = getClient(peer_id);
2518 client->GotBlock(p);
2521 else if(command == TOSERVER_DELETEDBLOCKS)
2534 u16 count = data[2];
2535 for(u16 i=0; i<count; i++)
2537 if((s16)datasize < 2+1+(i+1)*6)
2538 throw con::InvalidIncomingDataException
2539 ("DELETEDBLOCKS length is too short");
2540 v3s16 p = readV3S16(&data[2+1+i*6]);
2541 /*infostream<<"Server: DELETEDBLOCKS ("
2542 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2543 RemoteClient *client = getClient(peer_id);
2544 client->SetBlockNotSent(p);
2547 else if(command == TOSERVER_CLICK_OBJECT)
2549 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2552 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2554 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2557 else if(command == TOSERVER_GROUND_ACTION)
2559 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2563 else if(command == TOSERVER_RELEASE)
2565 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2568 else if(command == TOSERVER_SIGNTEXT)
2570 infostream<<"Server: SIGNTEXT not supported anymore"
2574 else if(command == TOSERVER_SIGNNODETEXT)
2576 infostream<<"Server: SIGNNODETEXT not supported anymore"
2580 else if(command == TOSERVER_INVENTORY_ACTION)
2582 // Strip command and create a stream
2583 std::string datastring((char*)&data[2], datasize-2);
2584 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2585 std::istringstream is(datastring, std::ios_base::binary);
2587 InventoryAction *a = InventoryAction::deSerialize(is);
2590 infostream<<"TOSERVER_INVENTORY_ACTION: "
2591 <<"InventoryAction::deSerialize() returned NULL"
2596 // If something goes wrong, this player is to blame
2597 RollbackScopeActor rollback_scope(m_rollback,
2598 std::string("player:")+player->getName());
2601 Note: Always set inventory not sent, to repair cases
2602 where the client made a bad prediction.
2606 Handle restrictions and special cases of the move action
2608 if(a->getType() == IACTION_MOVE)
2610 IMoveAction *ma = (IMoveAction*)a;
2612 ma->from_inv.applyCurrentPlayer(player->getName());
2613 ma->to_inv.applyCurrentPlayer(player->getName());
2615 setInventoryModified(ma->from_inv);
2616 setInventoryModified(ma->to_inv);
2618 bool from_inv_is_current_player =
2619 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2620 (ma->from_inv.name == player->getName());
2622 bool to_inv_is_current_player =
2623 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2624 (ma->to_inv.name == player->getName());
2627 Disable moving items out of craftpreview
2629 if(ma->from_list == "craftpreview")
2631 infostream<<"Ignoring IMoveAction from "
2632 <<(ma->from_inv.dump())<<":"<<ma->from_list
2633 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2634 <<" because src is "<<ma->from_list<<std::endl;
2640 Disable moving items into craftresult and craftpreview
2642 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2644 infostream<<"Ignoring IMoveAction from "
2645 <<(ma->from_inv.dump())<<":"<<ma->from_list
2646 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2647 <<" because dst is "<<ma->to_list<<std::endl;
2652 // Disallow moving items in elsewhere than player's inventory
2653 // if not allowed to interact
2654 if(!checkPriv(player->getName(), "interact") &&
2655 (!from_inv_is_current_player ||
2656 !to_inv_is_current_player))
2658 infostream<<"Cannot move outside of player's inventory: "
2659 <<"No interact privilege"<<std::endl;
2665 Handle restrictions and special cases of the drop action
2667 else if(a->getType() == IACTION_DROP)
2669 IDropAction *da = (IDropAction*)a;
2671 da->from_inv.applyCurrentPlayer(player->getName());
2673 setInventoryModified(da->from_inv);
2675 // Disallow dropping items if not allowed to interact
2676 if(!checkPriv(player->getName(), "interact"))
2683 Handle restrictions and special cases of the craft action
2685 else if(a->getType() == IACTION_CRAFT)
2687 ICraftAction *ca = (ICraftAction*)a;
2689 ca->craft_inv.applyCurrentPlayer(player->getName());
2691 setInventoryModified(ca->craft_inv);
2693 //bool craft_inv_is_current_player =
2694 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2695 // (ca->craft_inv.name == player->getName());
2697 // Disallow crafting if not allowed to interact
2698 if(!checkPriv(player->getName(), "interact"))
2700 infostream<<"Cannot craft: "
2701 <<"No interact privilege"<<std::endl;
2708 a->apply(this, playersao, this);
2712 else if(command == TOSERVER_CHAT_MESSAGE)
2720 std::string datastring((char*)&data[2], datasize-2);
2721 std::istringstream is(datastring, std::ios_base::binary);
2724 is.read((char*)buf, 2);
2725 u16 len = readU16(buf);
2727 std::wstring message;
2728 for(u16 i=0; i<len; i++)
2730 is.read((char*)buf, 2);
2731 message += (wchar_t)readU16(buf);
2734 // If something goes wrong, this player is to blame
2735 RollbackScopeActor rollback_scope(m_rollback,
2736 std::string("player:")+player->getName());
2738 // Get player name of this client
2739 std::wstring name = narrow_to_wide(player->getName());
2742 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2743 wide_to_narrow(message));
2744 // If script ate the message, don't proceed
2748 // Line to send to players
2750 // Whether to send to the player that sent the line
2751 bool send_to_sender = false;
2752 // Whether to send to other players
2753 bool send_to_others = false;
2755 // Commands are implemented in Lua, so only catch invalid
2756 // commands that were not "eaten" and send an error back
2757 if(message[0] == L'/')
2759 message = message.substr(1);
2760 send_to_sender = true;
2761 if(message.length() == 0)
2762 line += L"-!- Empty command";
2764 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2768 if(checkPriv(player->getName(), "shout")){
2773 send_to_others = true;
2775 line += L"-!- You don't have permission to shout.";
2776 send_to_sender = true;
2783 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2786 Send the message to clients
2788 for(core::map<u16, RemoteClient*>::Iterator
2789 i = m_clients.getIterator();
2790 i.atEnd() == false; i++)
2792 // Get client and check that it is valid
2793 RemoteClient *client = i.getNode()->getValue();
2794 assert(client->peer_id == i.getNode()->getKey());
2795 if(client->serialization_version == SER_FMT_VER_INVALID)
2799 bool sender_selected = (peer_id == client->peer_id);
2800 if(sender_selected == true && send_to_sender == false)
2802 if(sender_selected == false && send_to_others == false)
2805 SendChatMessage(client->peer_id, line);
2809 else if(command == TOSERVER_DAMAGE)
2811 std::string datastring((char*)&data[2], datasize-2);
2812 std::istringstream is(datastring, std::ios_base::binary);
2813 u8 damage = readU8(is);
2815 if(g_settings->getBool("enable_damage"))
2817 actionstream<<player->getName()<<" damaged by "
2818 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2821 playersao->setHP(playersao->getHP() - damage);
2823 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2826 if(playersao->m_hp_not_sent)
2827 SendPlayerHP(peer_id);
2830 else if(command == TOSERVER_PASSWORD)
2833 [0] u16 TOSERVER_PASSWORD
2834 [2] u8[28] old password
2835 [30] u8[28] new password
2838 if(datasize != 2+PASSWORD_SIZE*2)
2840 /*char password[PASSWORD_SIZE];
2841 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2842 password[i] = data[2+i];
2843 password[PASSWORD_SIZE-1] = 0;*/
2845 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2853 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2855 char c = data[2+PASSWORD_SIZE+i];
2861 if(!base64_is_valid(newpwd)){
2862 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2863 // Wrong old password supplied!!
2864 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2868 infostream<<"Server: Client requests a password change from "
2869 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2871 std::string playername = player->getName();
2873 std::string checkpwd;
2874 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2876 if(oldpwd != checkpwd)
2878 infostream<<"Server: invalid old password"<<std::endl;
2879 // Wrong old password supplied!!
2880 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2884 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2886 actionstream<<player->getName()<<" changes password"<<std::endl;
2887 SendChatMessage(peer_id, L"Password change successful.");
2889 actionstream<<player->getName()<<" tries to change password but "
2890 <<"it fails"<<std::endl;
2891 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2894 else if(command == TOSERVER_PLAYERITEM)
2899 u16 item = readU16(&data[2]);
2900 playersao->setWieldIndex(item);
2902 else if(command == TOSERVER_RESPAWN)
2904 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2907 RespawnPlayer(peer_id);
2909 actionstream<<player->getName()<<" respawns at "
2910 <<PP(player->getPosition()/BS)<<std::endl;
2912 // ActiveObject is added to environment in AsyncRunStep after
2913 // the previous addition has been succesfully removed
2915 else if(command == TOSERVER_REQUEST_MEDIA) {
2916 std::string datastring((char*)&data[2], datasize-2);
2917 std::istringstream is(datastring, std::ios_base::binary);
2919 core::list<MediaRequest> tosend;
2920 u16 numfiles = readU16(is);
2922 infostream<<"Sending "<<numfiles<<" files to "
2923 <<getPlayerName(peer_id)<<std::endl;
2924 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2926 for(int i = 0; i < numfiles; i++) {
2927 std::string name = deSerializeString(is);
2928 tosend.push_back(MediaRequest(name));
2929 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2933 sendRequestedMedia(peer_id, tosend);
2935 // Now the client should know about everything
2936 // (definitions and files)
2937 getClient(peer_id)->definitions_sent = true;
2939 else if(command == TOSERVER_RECEIVED_MEDIA) {
2940 getClient(peer_id)->definitions_sent = true;
2942 else if(command == TOSERVER_INTERACT)
2944 std::string datastring((char*)&data[2], datasize-2);
2945 std::istringstream is(datastring, std::ios_base::binary);
2951 [5] u32 length of the next item
2952 [9] serialized PointedThing
2954 0: start digging (from undersurface) or use
2955 1: stop digging (all parameters ignored)
2956 2: digging completed
2957 3: place block or item (to abovesurface)
2960 u8 action = readU8(is);
2961 u16 item_i = readU16(is);
2962 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2963 PointedThing pointed;
2964 pointed.deSerialize(tmp_is);
2966 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2967 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2971 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2972 <<" tried to interact, but is dead!"<<std::endl;
2976 v3f player_pos = playersao->getLastGoodPosition();
2978 // Update wielded item
2979 playersao->setWieldIndex(item_i);
2981 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2982 v3s16 p_under = pointed.node_undersurface;
2983 v3s16 p_above = pointed.node_abovesurface;
2985 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2986 ServerActiveObject *pointed_object = NULL;
2987 if(pointed.type == POINTEDTHING_OBJECT)
2989 pointed_object = m_env->getActiveObject(pointed.object_id);
2990 if(pointed_object == NULL)
2992 verbosestream<<"TOSERVER_INTERACT: "
2993 "pointed object is NULL"<<std::endl;
2999 v3f pointed_pos_under = player_pos;
3000 v3f pointed_pos_above = player_pos;
3001 if(pointed.type == POINTEDTHING_NODE)
3003 pointed_pos_under = intToFloat(p_under, BS);
3004 pointed_pos_above = intToFloat(p_above, BS);
3006 else if(pointed.type == POINTEDTHING_OBJECT)
3008 pointed_pos_under = pointed_object->getBasePosition();
3009 pointed_pos_above = pointed_pos_under;
3013 Check that target is reasonably close
3014 (only when digging or placing things)
3016 if(action == 0 || action == 2 || action == 3)
3018 float d = player_pos.getDistanceFrom(pointed_pos_under);
3019 float max_d = BS * 14; // Just some large enough value
3021 actionstream<<"Player "<<player->getName()
3022 <<" tried to access "<<pointed.dump()
3024 <<"d="<<d<<", max_d="<<max_d
3025 <<". ignoring."<<std::endl;
3026 // Re-send block to revert change on client-side
3027 RemoteClient *client = getClient(peer_id);
3028 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3029 client->SetBlockNotSent(blockpos);
3036 Make sure the player is allowed to do it
3038 if(!checkPriv(player->getName(), "interact"))
3040 actionstream<<player->getName()<<" attempted to interact with "
3041 <<pointed.dump()<<" without 'interact' privilege"
3043 // Re-send block to revert change on client-side
3044 RemoteClient *client = getClient(peer_id);
3045 // Digging completed -> under
3047 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3048 client->SetBlockNotSent(blockpos);
3050 // Placement -> above
3052 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3053 client->SetBlockNotSent(blockpos);
3059 If something goes wrong, this player is to blame
3061 RollbackScopeActor rollback_scope(m_rollback,
3062 std::string("player:")+player->getName());
3065 0: start digging or punch object
3069 if(pointed.type == POINTEDTHING_NODE)
3072 NOTE: This can be used in the future to check if
3073 somebody is cheating, by checking the timing.
3075 MapNode n(CONTENT_IGNORE);
3078 n = m_env->getMap().getNode(p_under);
3080 catch(InvalidPositionException &e)
3082 infostream<<"Server: Not punching: Node not found."
3083 <<" Adding block to emerge queue."
3085 m_emerge_queue.addBlock(peer_id,
3086 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3088 if(n.getContent() != CONTENT_IGNORE)
3089 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3091 playersao->noCheatDigStart(p_under);
3093 else if(pointed.type == POINTEDTHING_OBJECT)
3095 // Skip if object has been removed
3096 if(pointed_object->m_removed)
3099 actionstream<<player->getName()<<" punches object "
3100 <<pointed.object_id<<": "
3101 <<pointed_object->getDescription()<<std::endl;
3103 ItemStack punchitem = playersao->getWieldedItem();
3104 ToolCapabilities toolcap =
3105 punchitem.getToolCapabilities(m_itemdef);
3106 v3f dir = (pointed_object->getBasePosition() -
3107 (player->getPosition() + player->getEyeOffset())
3109 float time_from_last_punch =
3110 playersao->resetTimeFromLastPunch();
3111 pointed_object->punch(dir, &toolcap, playersao,
3112 time_from_last_punch);
3120 else if(action == 1)
3125 2: Digging completed
3127 else if(action == 2)
3129 // Only digging of nodes
3130 if(pointed.type == POINTEDTHING_NODE)
3132 MapNode n(CONTENT_IGNORE);
3135 n = m_env->getMap().getNode(p_under);
3137 catch(InvalidPositionException &e)
3139 infostream<<"Server: Not finishing digging: Node not found."
3140 <<" Adding block to emerge queue."
3142 m_emerge_queue.addBlock(peer_id,
3143 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3146 /* Cheat prevention */
3147 bool is_valid_dig = true;
3148 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3150 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3151 float nocheat_t = playersao->getNoCheatDigTime();
3152 playersao->noCheatDigEnd();
3153 // If player didn't start digging this, ignore dig
3154 if(nocheat_p != p_under){
3155 infostream<<"Server: NoCheat: "<<player->getName()
3156 <<" started digging "
3157 <<PP(nocheat_p)<<" and completed digging "
3158 <<PP(p_under)<<"; not digging."<<std::endl;
3159 is_valid_dig = false;
3161 // Get player's wielded item
3162 ItemStack playeritem;
3163 InventoryList *mlist = playersao->getInventory()->getList("main");
3165 playeritem = mlist->getItem(playersao->getWieldIndex());
3166 ToolCapabilities playeritem_toolcap =
3167 playeritem.getToolCapabilities(m_itemdef);
3168 // Get diggability and expected digging time
3169 DigParams params = getDigParams(m_nodedef->get(n).groups,
3170 &playeritem_toolcap);
3171 // If can't dig, try hand
3172 if(!params.diggable){
3173 const ItemDefinition &hand = m_itemdef->get("");
3174 const ToolCapabilities *tp = hand.tool_capabilities;
3176 params = getDigParams(m_nodedef->get(n).groups, tp);
3178 // If can't dig, ignore dig
3179 if(!params.diggable){
3180 infostream<<"Server: NoCheat: "<<player->getName()
3181 <<" completed digging "<<PP(p_under)
3182 <<", which is not diggable with tool. not digging."
3184 is_valid_dig = false;
3186 // If time is considerably too short, ignore dig
3187 // Check time only for medium and slow timed digs
3188 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3189 infostream<<"Server: NoCheat: "<<player->getName()
3190 <<" completed digging "
3191 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3192 <<params.time<<"s; not digging."<<std::endl;
3193 is_valid_dig = false;
3197 /* Actually dig node */
3199 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3200 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3202 // Send unusual result (that is, node not being removed)
3203 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3205 // Re-send block to revert change on client-side
3206 RemoteClient *client = getClient(peer_id);
3207 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3208 client->SetBlockNotSent(blockpos);
3214 3: place block or right-click object
3216 else if(action == 3)
3218 ItemStack item = playersao->getWieldedItem();
3220 // Reset build time counter
3221 if(pointed.type == POINTEDTHING_NODE &&
3222 item.getDefinition(m_itemdef).type == ITEM_NODE)
3223 getClient(peer_id)->m_time_from_building = 0.0;
3225 if(pointed.type == POINTEDTHING_OBJECT)
3227 // Right click object
3229 // Skip if object has been removed
3230 if(pointed_object->m_removed)
3233 actionstream<<player->getName()<<" right-clicks object "
3234 <<pointed.object_id<<": "
3235 <<pointed_object->getDescription()<<std::endl;
3238 pointed_object->rightClick(playersao);
3240 else if(scriptapi_item_on_place(m_lua,
3241 item, playersao, pointed))
3243 // Placement was handled in lua
3245 // Apply returned ItemStack
3246 playersao->setWieldedItem(item);
3249 // If item has node placement prediction, always send the above
3250 // node to make sure the client knows what exactly happened
3251 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3252 RemoteClient *client = getClient(peer_id);
3253 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3254 client->SetBlockNotSent(blockpos);
3261 else if(action == 4)
3263 ItemStack item = playersao->getWieldedItem();
3265 actionstream<<player->getName()<<" uses "<<item.name
3266 <<", pointing at "<<pointed.dump()<<std::endl;
3268 if(scriptapi_item_on_use(m_lua,
3269 item, playersao, pointed))
3271 // Apply returned ItemStack
3272 playersao->setWieldedItem(item);
3279 Catch invalid actions
3283 infostream<<"WARNING: Server: Invalid action "
3284 <<action<<std::endl;
3287 else if(command == TOSERVER_REMOVED_SOUNDS)
3289 std::string datastring((char*)&data[2], datasize-2);
3290 std::istringstream is(datastring, std::ios_base::binary);
3292 int num = readU16(is);
3293 for(int k=0; k<num; k++){
3294 s32 id = readS32(is);
3295 std::map<s32, ServerPlayingSound>::iterator i =
3296 m_playing_sounds.find(id);
3297 if(i == m_playing_sounds.end())
3299 ServerPlayingSound &psound = i->second;
3300 psound.clients.erase(peer_id);
3301 if(psound.clients.size() == 0)
3302 m_playing_sounds.erase(i++);
3305 else if(command == TOSERVER_NODEMETA_FIELDS)
3307 std::string datastring((char*)&data[2], datasize-2);
3308 std::istringstream is(datastring, std::ios_base::binary);
3310 v3s16 p = readV3S16(is);
3311 std::string formname = deSerializeString(is);
3312 int num = readU16(is);
3313 std::map<std::string, std::string> fields;
3314 for(int k=0; k<num; k++){
3315 std::string fieldname = deSerializeString(is);
3316 std::string fieldvalue = deSerializeLongString(is);
3317 fields[fieldname] = fieldvalue;
3320 // If something goes wrong, this player is to blame
3321 RollbackScopeActor rollback_scope(m_rollback,
3322 std::string("player:")+player->getName());
3324 // Check the target node for rollback data; leave others unnoticed
3325 RollbackNode rn_old(&m_env->getMap(), p, this);
3327 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3330 // Report rollback data
3331 RollbackNode rn_new(&m_env->getMap(), p, this);
3332 if(rollback() && rn_new != rn_old){
3333 RollbackAction action;
3334 action.setSetNode(p, rn_old, rn_new);
3335 rollback()->reportAction(action);
3338 else if(command == TOSERVER_INVENTORY_FIELDS)
3340 std::string datastring((char*)&data[2], datasize-2);
3341 std::istringstream is(datastring, std::ios_base::binary);
3343 std::string formname = deSerializeString(is);
3344 int num = readU16(is);
3345 std::map<std::string, std::string> fields;
3346 for(int k=0; k<num; k++){
3347 std::string fieldname = deSerializeString(is);
3348 std::string fieldvalue = deSerializeLongString(is);
3349 fields[fieldname] = fieldvalue;
3352 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3356 infostream<<"Server::ProcessData(): Ignoring "
3357 "unknown command "<<command<<std::endl;
3361 catch(SendFailedException &e)
3363 errorstream<<"Server::ProcessData(): SendFailedException: "
3369 void Server::onMapEditEvent(MapEditEvent *event)
3371 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3372 if(m_ignore_map_edit_events)
3374 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3376 MapEditEvent *e = event->clone();
3377 m_unsent_map_edit_queue.push_back(e);
3380 Inventory* Server::getInventory(const InventoryLocation &loc)
3383 case InventoryLocation::UNDEFINED:
3386 case InventoryLocation::CURRENT_PLAYER:
3389 case InventoryLocation::PLAYER:
3391 Player *player = m_env->getPlayer(loc.name.c_str());
3394 PlayerSAO *playersao = player->getPlayerSAO();
3397 return playersao->getInventory();
3400 case InventoryLocation::NODEMETA:
3402 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3405 return meta->getInventory();
3408 case InventoryLocation::DETACHED:
3410 if(m_detached_inventories.count(loc.name) == 0)
3412 return m_detached_inventories[loc.name];
3420 void Server::setInventoryModified(const InventoryLocation &loc)
3423 case InventoryLocation::UNDEFINED:
3426 case InventoryLocation::PLAYER:
3428 Player *player = m_env->getPlayer(loc.name.c_str());
3431 PlayerSAO *playersao = player->getPlayerSAO();
3434 playersao->m_inventory_not_sent = true;
3435 playersao->m_wielded_item_not_sent = true;
3438 case InventoryLocation::NODEMETA:
3440 v3s16 blockpos = getNodeBlockPos(loc.p);
3442 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3444 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3446 setBlockNotSent(blockpos);
3449 case InventoryLocation::DETACHED:
3451 sendDetachedInventoryToAll(loc.name);
3459 core::list<PlayerInfo> Server::getPlayerInfo()
3461 DSTACK(__FUNCTION_NAME);
3462 JMutexAutoLock envlock(m_env_mutex);
3463 JMutexAutoLock conlock(m_con_mutex);
3465 core::list<PlayerInfo> list;
3467 core::list<Player*> players = m_env->getPlayers();
3469 core::list<Player*>::Iterator i;
3470 for(i = players.begin();
3471 i != players.end(); i++)
3475 Player *player = *i;
3478 // Copy info from connection to info struct
3479 info.id = player->peer_id;
3480 info.address = m_con.GetPeerAddress(player->peer_id);
3481 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3483 catch(con::PeerNotFoundException &e)
3485 // Set dummy peer info
3487 info.address = Address(0,0,0,0,0);
3491 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3492 info.position = player->getPosition();
3494 list.push_back(info);
3501 void Server::peerAdded(con::Peer *peer)
3503 DSTACK(__FUNCTION_NAME);
3504 verbosestream<<"Server::peerAdded(): peer->id="
3505 <<peer->id<<std::endl;
3508 c.type = PEER_ADDED;
3509 c.peer_id = peer->id;
3511 m_peer_change_queue.push_back(c);
3514 void Server::deletingPeer(con::Peer *peer, bool timeout)
3516 DSTACK(__FUNCTION_NAME);
3517 verbosestream<<"Server::deletingPeer(): peer->id="
3518 <<peer->id<<", timeout="<<timeout<<std::endl;
3521 c.type = PEER_REMOVED;
3522 c.peer_id = peer->id;
3523 c.timeout = timeout;
3524 m_peer_change_queue.push_back(c);
3531 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3533 DSTACK(__FUNCTION_NAME);
3534 std::ostringstream os(std::ios_base::binary);
3536 writeU16(os, TOCLIENT_HP);
3540 std::string s = os.str();
3541 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3543 con.Send(peer_id, 0, data, true);
3546 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3547 const std::wstring &reason)
3549 DSTACK(__FUNCTION_NAME);
3550 std::ostringstream os(std::ios_base::binary);
3552 writeU16(os, TOCLIENT_ACCESS_DENIED);
3553 os<<serializeWideString(reason);
3556 std::string s = os.str();
3557 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3559 con.Send(peer_id, 0, data, true);
3562 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3563 bool set_camera_point_target, v3f camera_point_target)
3565 DSTACK(__FUNCTION_NAME);
3566 std::ostringstream os(std::ios_base::binary);
3568 writeU16(os, TOCLIENT_DEATHSCREEN);
3569 writeU8(os, set_camera_point_target);
3570 writeV3F1000(os, camera_point_target);
3573 std::string s = os.str();
3574 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3576 con.Send(peer_id, 0, data, true);
3579 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3580 IItemDefManager *itemdef)
3582 DSTACK(__FUNCTION_NAME);
3583 std::ostringstream os(std::ios_base::binary);
3587 u32 length of the next item
3588 zlib-compressed serialized ItemDefManager
3590 writeU16(os, TOCLIENT_ITEMDEF);
3591 std::ostringstream tmp_os(std::ios::binary);
3592 itemdef->serialize(tmp_os);
3593 std::ostringstream tmp_os2(std::ios::binary);
3594 compressZlib(tmp_os.str(), tmp_os2);
3595 os<<serializeLongString(tmp_os2.str());
3598 std::string s = os.str();
3599 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3600 <<"): size="<<s.size()<<std::endl;
3601 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3603 con.Send(peer_id, 0, data, true);
3606 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3607 INodeDefManager *nodedef, u16 protocol_version)
3609 DSTACK(__FUNCTION_NAME);
3610 std::ostringstream os(std::ios_base::binary);
3614 u32 length of the next item
3615 zlib-compressed serialized NodeDefManager
3617 writeU16(os, TOCLIENT_NODEDEF);
3618 std::ostringstream tmp_os(std::ios::binary);
3619 nodedef->serialize(tmp_os, protocol_version);
3620 std::ostringstream tmp_os2(std::ios::binary);
3621 compressZlib(tmp_os.str(), tmp_os2);
3622 os<<serializeLongString(tmp_os2.str());
3625 std::string s = os.str();
3626 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3627 <<"): size="<<s.size()<<std::endl;
3628 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3630 con.Send(peer_id, 0, data, true);
3634 Non-static send methods
3637 void Server::SendInventory(u16 peer_id)
3639 DSTACK(__FUNCTION_NAME);
3641 PlayerSAO *playersao = getPlayerSAO(peer_id);
3644 playersao->m_inventory_not_sent = false;
3650 std::ostringstream os;
3651 playersao->getInventory()->serialize(os);
3653 std::string s = os.str();
3655 SharedBuffer<u8> data(s.size()+2);
3656 writeU16(&data[0], TOCLIENT_INVENTORY);
3657 memcpy(&data[2], s.c_str(), s.size());
3660 m_con.Send(peer_id, 0, data, true);
3663 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3665 DSTACK(__FUNCTION_NAME);
3667 std::ostringstream os(std::ios_base::binary);
3671 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3672 os.write((char*)buf, 2);
3675 writeU16(buf, message.size());
3676 os.write((char*)buf, 2);
3679 for(u32 i=0; i<message.size(); i++)
3683 os.write((char*)buf, 2);
3687 std::string s = os.str();
3688 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3690 m_con.Send(peer_id, 0, data, true);
3692 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3694 DSTACK(__FUNCTION_NAME);
3696 std::ostringstream os(std::ios_base::binary);
3700 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3701 os.write((char*)buf, 2);
3702 os<<serializeLongString(formspec);
3703 os<<serializeString(formname);
3706 std::string s = os.str();
3707 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3709 m_con.Send(peer_id, 0, data, true);
3712 void Server::BroadcastChatMessage(const std::wstring &message)
3714 for(core::map<u16, RemoteClient*>::Iterator
3715 i = m_clients.getIterator();
3716 i.atEnd() == false; i++)
3718 // Get client and check that it is valid
3719 RemoteClient *client = i.getNode()->getValue();
3720 assert(client->peer_id == i.getNode()->getKey());
3721 if(client->serialization_version == SER_FMT_VER_INVALID)
3724 SendChatMessage(client->peer_id, message);
3728 void Server::SendPlayerHP(u16 peer_id)
3730 DSTACK(__FUNCTION_NAME);
3731 PlayerSAO *playersao = getPlayerSAO(peer_id);
3733 playersao->m_hp_not_sent = false;
3734 SendHP(m_con, peer_id, playersao->getHP());
3737 void Server::SendMovePlayer(u16 peer_id)
3739 DSTACK(__FUNCTION_NAME);
3740 Player *player = m_env->getPlayer(peer_id);
3743 std::ostringstream os(std::ios_base::binary);
3744 writeU16(os, TOCLIENT_MOVE_PLAYER);
3745 writeV3F1000(os, player->getPosition());
3746 writeF1000(os, player->getPitch());
3747 writeF1000(os, player->getYaw());
3750 v3f pos = player->getPosition();
3751 f32 pitch = player->getPitch();
3752 f32 yaw = player->getYaw();
3753 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3754 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3761 std::string s = os.str();
3762 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3764 m_con.Send(peer_id, 0, data, true);
3767 void Server::SendPlayerPrivileges(u16 peer_id)
3769 Player *player = m_env->getPlayer(peer_id);
3771 if(player->peer_id == PEER_ID_INEXISTENT)
3774 std::set<std::string> privs;
3775 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3777 std::ostringstream os(std::ios_base::binary);
3778 writeU16(os, TOCLIENT_PRIVILEGES);
3779 writeU16(os, privs.size());
3780 for(std::set<std::string>::const_iterator i = privs.begin();
3781 i != privs.end(); i++){
3782 os<<serializeString(*i);
3786 std::string s = os.str();
3787 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3789 m_con.Send(peer_id, 0, data, true);
3792 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3794 Player *player = m_env->getPlayer(peer_id);
3796 if(player->peer_id == PEER_ID_INEXISTENT)
3799 std::ostringstream os(std::ios_base::binary);
3800 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3801 os<<serializeLongString(player->inventory_formspec);
3804 std::string s = os.str();
3805 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3807 m_con.Send(peer_id, 0, data, true);
3810 s32 Server::playSound(const SimpleSoundSpec &spec,
3811 const ServerSoundParams ¶ms)
3813 // Find out initial position of sound
3814 bool pos_exists = false;
3815 v3f pos = params.getPos(m_env, &pos_exists);
3816 // If position is not found while it should be, cancel sound
3817 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3819 // Filter destination clients
3820 std::set<RemoteClient*> dst_clients;
3821 if(params.to_player != "")
3823 Player *player = m_env->getPlayer(params.to_player.c_str());
3825 infostream<<"Server::playSound: Player \""<<params.to_player
3826 <<"\" not found"<<std::endl;
3829 if(player->peer_id == PEER_ID_INEXISTENT){
3830 infostream<<"Server::playSound: Player \""<<params.to_player
3831 <<"\" not connected"<<std::endl;
3834 RemoteClient *client = getClient(player->peer_id);
3835 dst_clients.insert(client);
3839 for(core::map<u16, RemoteClient*>::Iterator
3840 i = m_clients.getIterator(); i.atEnd() == false; i++)
3842 RemoteClient *client = i.getNode()->getValue();
3843 Player *player = m_env->getPlayer(client->peer_id);
3847 if(player->getPosition().getDistanceFrom(pos) >
3848 params.max_hear_distance)
3851 dst_clients.insert(client);
3854 if(dst_clients.size() == 0)
3857 s32 id = m_next_sound_id++;
3858 // The sound will exist as a reference in m_playing_sounds
3859 m_playing_sounds[id] = ServerPlayingSound();
3860 ServerPlayingSound &psound = m_playing_sounds[id];
3861 psound.params = params;
3862 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3863 i != dst_clients.end(); i++)
3864 psound.clients.insert((*i)->peer_id);
3866 std::ostringstream os(std::ios_base::binary);
3867 writeU16(os, TOCLIENT_PLAY_SOUND);
3869 os<<serializeString(spec.name);
3870 writeF1000(os, spec.gain * params.gain);
3871 writeU8(os, params.type);
3872 writeV3F1000(os, pos);
3873 writeU16(os, params.object);
3874 writeU8(os, params.loop);
3876 std::string s = os.str();
3877 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3879 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3880 i != dst_clients.end(); i++){
3882 m_con.Send((*i)->peer_id, 0, data, true);
3886 void Server::stopSound(s32 handle)
3888 // Get sound reference
3889 std::map<s32, ServerPlayingSound>::iterator i =
3890 m_playing_sounds.find(handle);
3891 if(i == m_playing_sounds.end())
3893 ServerPlayingSound &psound = i->second;
3895 std::ostringstream os(std::ios_base::binary);
3896 writeU16(os, TOCLIENT_STOP_SOUND);
3897 writeS32(os, handle);
3899 std::string s = os.str();
3900 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3902 for(std::set<u16>::iterator i = psound.clients.begin();
3903 i != psound.clients.end(); i++){
3905 m_con.Send(*i, 0, data, true);
3907 // Remove sound reference
3908 m_playing_sounds.erase(i);
3911 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3912 core::list<u16> *far_players, float far_d_nodes)
3914 float maxd = far_d_nodes*BS;
3915 v3f p_f = intToFloat(p, BS);
3919 SharedBuffer<u8> reply(replysize);
3920 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3921 writeS16(&reply[2], p.X);
3922 writeS16(&reply[4], p.Y);
3923 writeS16(&reply[6], p.Z);
3925 for(core::map<u16, RemoteClient*>::Iterator
3926 i = m_clients.getIterator();
3927 i.atEnd() == false; i++)
3929 // Get client and check that it is valid
3930 RemoteClient *client = i.getNode()->getValue();
3931 assert(client->peer_id == i.getNode()->getKey());
3932 if(client->serialization_version == SER_FMT_VER_INVALID)
3935 // Don't send if it's the same one
3936 if(client->peer_id == ignore_id)
3942 Player *player = m_env->getPlayer(client->peer_id);
3945 // If player is far away, only set modified blocks not sent
3946 v3f player_pos = player->getPosition();
3947 if(player_pos.getDistanceFrom(p_f) > maxd)
3949 far_players->push_back(client->peer_id);
3956 m_con.Send(client->peer_id, 0, reply, true);
3960 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3961 core::list<u16> *far_players, float far_d_nodes)
3963 float maxd = far_d_nodes*BS;
3964 v3f p_f = intToFloat(p, BS);
3966 for(core::map<u16, RemoteClient*>::Iterator
3967 i = m_clients.getIterator();
3968 i.atEnd() == false; i++)
3970 // Get client and check that it is valid
3971 RemoteClient *client = i.getNode()->getValue();
3972 assert(client->peer_id == i.getNode()->getKey());
3973 if(client->serialization_version == SER_FMT_VER_INVALID)
3976 // Don't send if it's the same one
3977 if(client->peer_id == ignore_id)
3983 Player *player = m_env->getPlayer(client->peer_id);
3986 // If player is far away, only set modified blocks not sent
3987 v3f player_pos = player->getPosition();
3988 if(player_pos.getDistanceFrom(p_f) > maxd)
3990 far_players->push_back(client->peer_id);
3997 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3998 SharedBuffer<u8> reply(replysize);
3999 writeU16(&reply[0], TOCLIENT_ADDNODE);
4000 writeS16(&reply[2], p.X);
4001 writeS16(&reply[4], p.Y);
4002 writeS16(&reply[6], p.Z);
4003 n.serialize(&reply[8], client->serialization_version);
4006 m_con.Send(client->peer_id, 0, reply, true);
4010 void Server::setBlockNotSent(v3s16 p)
4012 for(core::map<u16, RemoteClient*>::Iterator
4013 i = m_clients.getIterator();
4014 i.atEnd()==false; i++)
4016 RemoteClient *client = i.getNode()->getValue();
4017 client->SetBlockNotSent(p);
4021 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4023 DSTACK(__FUNCTION_NAME);
4025 v3s16 p = block->getPos();
4029 bool completely_air = true;
4030 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4031 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4032 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4034 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4036 completely_air = false;
4037 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4042 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4044 infostream<<"[completely air] ";
4045 infostream<<std::endl;
4049 Create a packet with the block in the right format
4052 std::ostringstream os(std::ios_base::binary);
4053 block->serialize(os, ver, false);
4054 std::string s = os.str();
4055 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4057 u32 replysize = 8 + blockdata.getSize();
4058 SharedBuffer<u8> reply(replysize);
4059 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4060 writeS16(&reply[2], p.X);
4061 writeS16(&reply[4], p.Y);
4062 writeS16(&reply[6], p.Z);
4063 memcpy(&reply[8], *blockdata, blockdata.getSize());
4065 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4066 <<": \tpacket size: "<<replysize<<std::endl;*/
4071 m_con.Send(peer_id, 1, reply, true);
4074 void Server::SendBlocks(float dtime)
4076 DSTACK(__FUNCTION_NAME);
4078 JMutexAutoLock envlock(m_env_mutex);
4079 JMutexAutoLock conlock(m_con_mutex);
4081 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4083 core::array<PrioritySortedBlockTransfer> queue;
4085 s32 total_sending = 0;
4088 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4090 for(core::map<u16, RemoteClient*>::Iterator
4091 i = m_clients.getIterator();
4092 i.atEnd() == false; i++)
4094 RemoteClient *client = i.getNode()->getValue();
4095 assert(client->peer_id == i.getNode()->getKey());
4097 // If definitions and textures have not been sent, don't
4098 // send MapBlocks either
4099 if(!client->definitions_sent)
4102 total_sending += client->SendingCount();
4104 if(client->serialization_version == SER_FMT_VER_INVALID)
4107 client->GetNextBlocks(this, dtime, queue);
4112 // Lowest priority number comes first.
4113 // Lowest is most important.
4116 for(u32 i=0; i<queue.size(); i++)
4118 //TODO: Calculate limit dynamically
4119 if(total_sending >= g_settings->getS32
4120 ("max_simultaneous_block_sends_server_total"))
4123 PrioritySortedBlockTransfer q = queue[i];
4125 MapBlock *block = NULL;
4128 block = m_env->getMap().getBlockNoCreate(q.pos);
4130 catch(InvalidPositionException &e)
4135 RemoteClient *client = getClient(q.peer_id);
4137 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4139 client->SentBlock(q.pos);
4145 void Server::fillMediaCache()
4147 DSTACK(__FUNCTION_NAME);
4149 infostream<<"Server: Calculating media file checksums"<<std::endl;
4151 // Collect all media file paths
4152 std::list<std::string> paths;
4153 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4154 i != m_mods.end(); i++){
4155 const ModSpec &mod = *i;
4156 paths.push_back(mod.path + DIR_DELIM + "textures");
4157 paths.push_back(mod.path + DIR_DELIM + "sounds");
4158 paths.push_back(mod.path + DIR_DELIM + "media");
4159 paths.push_back(mod.path + DIR_DELIM + "models");
4161 std::string path_all = "textures";
4162 paths.push_back(path_all + DIR_DELIM + "all");
4164 // Collect media file information from paths into cache
4165 for(std::list<std::string>::iterator i = paths.begin();
4166 i != paths.end(); i++)
4168 std::string mediapath = *i;
4169 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4170 for(u32 j=0; j<dirlist.size(); j++){
4171 if(dirlist[j].dir) // Ignode dirs
4173 std::string filename = dirlist[j].name;
4174 // If name contains illegal characters, ignore the file
4175 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4176 infostream<<"Server: ignoring illegal file name: \""
4177 <<filename<<"\""<<std::endl;
4180 // If name is not in a supported format, ignore it
4181 const char *supported_ext[] = {
4182 ".png", ".jpg", ".bmp", ".tga",
4183 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4185 ".x", ".b3d", ".md2", ".obj",
4188 if(removeStringEnd(filename, supported_ext) == ""){
4189 infostream<<"Server: ignoring unsupported file extension: \""
4190 <<filename<<"\""<<std::endl;
4193 // Ok, attempt to load the file and add to cache
4194 std::string filepath = mediapath + DIR_DELIM + filename;
4196 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4197 if(fis.good() == false){
4198 errorstream<<"Server::fillMediaCache(): Could not open \""
4199 <<filename<<"\" for reading"<<std::endl;
4202 std::ostringstream tmp_os(std::ios_base::binary);
4206 fis.read(buf, 1024);
4207 std::streamsize len = fis.gcount();
4208 tmp_os.write(buf, len);
4217 errorstream<<"Server::fillMediaCache(): Failed to read \""
4218 <<filename<<"\""<<std::endl;
4221 if(tmp_os.str().length() == 0){
4222 errorstream<<"Server::fillMediaCache(): Empty file \""
4223 <<filepath<<"\""<<std::endl;
4228 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4230 unsigned char *digest = sha1.getDigest();
4231 std::string sha1_base64 = base64_encode(digest, 20);
4232 std::string sha1_hex = hex_encode((char*)digest, 20);
4236 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4237 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4242 struct SendableMediaAnnouncement
4245 std::string sha1_digest;
4247 SendableMediaAnnouncement(const std::string name_="",
4248 const std::string sha1_digest_=""):
4250 sha1_digest(sha1_digest_)
4254 void Server::sendMediaAnnouncement(u16 peer_id)
4256 DSTACK(__FUNCTION_NAME);
4258 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4261 core::list<SendableMediaAnnouncement> file_announcements;
4263 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4264 i != m_media.end(); i++){
4266 file_announcements.push_back(
4267 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4271 std::ostringstream os(std::ios_base::binary);
4279 u16 length of sha1_digest
4284 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4285 writeU16(os, file_announcements.size());
4287 for(core::list<SendableMediaAnnouncement>::Iterator
4288 j = file_announcements.begin();
4289 j != file_announcements.end(); j++){
4290 os<<serializeString(j->name);
4291 os<<serializeString(j->sha1_digest);
4293 os<<serializeString(g_settings->get("remote_media"));
4296 std::string s = os.str();
4297 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4300 m_con.Send(peer_id, 0, data, true);
4303 struct SendableMedia
4309 SendableMedia(const std::string &name_="", const std::string path_="",
4310 const std::string &data_=""):
4317 void Server::sendRequestedMedia(u16 peer_id,
4318 const core::list<MediaRequest> &tosend)
4320 DSTACK(__FUNCTION_NAME);
4322 verbosestream<<"Server::sendRequestedMedia(): "
4323 <<"Sending files to client"<<std::endl;
4327 // Put 5kB in one bunch (this is not accurate)
4328 u32 bytes_per_bunch = 5000;
4330 core::array< core::list<SendableMedia> > file_bunches;
4331 file_bunches.push_back(core::list<SendableMedia>());
4333 u32 file_size_bunch_total = 0;
4335 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4336 i != tosend.end(); i++)
4338 if(m_media.find(i->name) == m_media.end()){
4339 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4340 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4344 //TODO get path + name
4345 std::string tpath = m_media[(*i).name].path;
4348 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4349 if(fis.good() == false){
4350 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4351 <<tpath<<"\" for reading"<<std::endl;
4354 std::ostringstream tmp_os(std::ios_base::binary);
4358 fis.read(buf, 1024);
4359 std::streamsize len = fis.gcount();
4360 tmp_os.write(buf, len);
4361 file_size_bunch_total += len;
4370 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4371 <<(*i).name<<"\""<<std::endl;
4374 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4375 <<tname<<"\""<<std::endl;*/
4377 file_bunches[file_bunches.size()-1].push_back(
4378 SendableMedia((*i).name, tpath, tmp_os.str()));
4380 // Start next bunch if got enough data
4381 if(file_size_bunch_total >= bytes_per_bunch){
4382 file_bunches.push_back(core::list<SendableMedia>());
4383 file_size_bunch_total = 0;
4388 /* Create and send packets */
4390 u32 num_bunches = file_bunches.size();
4391 for(u32 i=0; i<num_bunches; i++)
4393 std::ostringstream os(std::ios_base::binary);
4397 u16 total number of texture bunches
4398 u16 index of this bunch
4399 u32 number of files in this bunch
4408 writeU16(os, TOCLIENT_MEDIA);
4409 writeU16(os, num_bunches);
4411 writeU32(os, file_bunches[i].size());
4413 for(core::list<SendableMedia>::Iterator
4414 j = file_bunches[i].begin();
4415 j != file_bunches[i].end(); j++){
4416 os<<serializeString(j->name);
4417 os<<serializeLongString(j->data);
4421 std::string s = os.str();
4422 verbosestream<<"Server::sendRequestedMedia(): bunch "
4423 <<i<<"/"<<num_bunches
4424 <<" files="<<file_bunches[i].size()
4425 <<" size=" <<s.size()<<std::endl;
4426 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4428 m_con.Send(peer_id, 0, data, true);
4432 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4434 if(m_detached_inventories.count(name) == 0){
4435 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4438 Inventory *inv = m_detached_inventories[name];
4440 std::ostringstream os(std::ios_base::binary);
4441 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4442 os<<serializeString(name);
4446 std::string s = os.str();
4447 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4449 m_con.Send(peer_id, 0, data, true);
4452 void Server::sendDetachedInventoryToAll(const std::string &name)
4454 DSTACK(__FUNCTION_NAME);
4456 for(core::map<u16, RemoteClient*>::Iterator
4457 i = m_clients.getIterator();
4458 i.atEnd() == false; i++){
4459 RemoteClient *client = i.getNode()->getValue();
4460 sendDetachedInventory(name, client->peer_id);
4464 void Server::sendDetachedInventories(u16 peer_id)
4466 DSTACK(__FUNCTION_NAME);
4468 for(std::map<std::string, Inventory*>::iterator
4469 i = m_detached_inventories.begin();
4470 i != m_detached_inventories.end(); i++){
4471 const std::string &name = i->first;
4472 //Inventory *inv = i->second;
4473 sendDetachedInventory(name, peer_id);
4481 void Server::DiePlayer(u16 peer_id)
4483 DSTACK(__FUNCTION_NAME);
4485 PlayerSAO *playersao = getPlayerSAO(peer_id);
4488 infostream<<"Server::DiePlayer(): Player "
4489 <<playersao->getPlayer()->getName()
4490 <<" dies"<<std::endl;
4492 playersao->setHP(0);
4494 // Trigger scripted stuff
4495 scriptapi_on_dieplayer(m_lua, playersao);
4497 SendPlayerHP(peer_id);
4498 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4501 void Server::RespawnPlayer(u16 peer_id)
4503 DSTACK(__FUNCTION_NAME);
4505 PlayerSAO *playersao = getPlayerSAO(peer_id);
4508 infostream<<"Server::RespawnPlayer(): Player "
4509 <<playersao->getPlayer()->getName()
4510 <<" respawns"<<std::endl;
4512 playersao->setHP(PLAYER_MAX_HP);
4514 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4516 v3f pos = findSpawnPos(m_env->getServerMap());
4517 playersao->setPos(pos);
4521 void Server::UpdateCrafting(u16 peer_id)
4523 DSTACK(__FUNCTION_NAME);
4525 Player* player = m_env->getPlayer(peer_id);
4528 // Get a preview for crafting
4530 getCraftingResult(&player->inventory, preview, false, this);
4532 // Put the new preview in
4533 InventoryList *plist = player->inventory.getList("craftpreview");
4535 assert(plist->getSize() >= 1);
4536 plist->changeItem(0, preview);
4539 RemoteClient* Server::getClient(u16 peer_id)
4541 DSTACK(__FUNCTION_NAME);
4542 //JMutexAutoLock lock(m_con_mutex);
4543 core::map<u16, RemoteClient*>::Node *n;
4544 n = m_clients.find(peer_id);
4545 // A client should exist for all peers
4547 return n->getValue();
4550 std::wstring Server::getStatusString()
4552 std::wostringstream os(std::ios_base::binary);
4555 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4557 os<<L", uptime="<<m_uptime.get();
4558 // Information about clients
4559 core::map<u16, RemoteClient*>::Iterator i;
4562 for(i = m_clients.getIterator(), first = true;
4563 i.atEnd() == false; i++)
4565 // Get client and check that it is valid
4566 RemoteClient *client = i.getNode()->getValue();
4567 assert(client->peer_id == i.getNode()->getKey());
4568 if(client->serialization_version == SER_FMT_VER_INVALID)
4571 Player *player = m_env->getPlayer(client->peer_id);
4572 // Get name of player
4573 std::wstring name = L"unknown";
4575 name = narrow_to_wide(player->getName());
4576 // Add name to information string
4584 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4585 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4586 if(g_settings->get("motd") != "")
4587 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4591 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4593 std::set<std::string> privs;
4594 scriptapi_get_auth(m_lua, name, NULL, &privs);
4598 bool Server::checkPriv(const std::string &name, const std::string &priv)
4600 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4601 return (privs.count(priv) != 0);
4604 void Server::reportPrivsModified(const std::string &name)
4607 for(core::map<u16, RemoteClient*>::Iterator
4608 i = m_clients.getIterator();
4609 i.atEnd() == false; i++){
4610 RemoteClient *client = i.getNode()->getValue();
4611 Player *player = m_env->getPlayer(client->peer_id);
4612 reportPrivsModified(player->getName());
4615 Player *player = m_env->getPlayer(name.c_str());
4618 SendPlayerPrivileges(player->peer_id);
4619 PlayerSAO *sao = player->getPlayerSAO();
4622 sao->updatePrivileges(
4623 getPlayerEffectivePrivs(name),
4628 void Server::reportInventoryFormspecModified(const std::string &name)
4630 Player *player = m_env->getPlayer(name.c_str());
4633 SendPlayerInventoryFormspec(player->peer_id);
4636 // Saves g_settings to configpath given at initialization
4637 void Server::saveConfig()
4639 if(m_path_config != "")
4640 g_settings->updateConfigFile(m_path_config.c_str());
4643 void Server::notifyPlayer(const char *name, const std::wstring msg)
4645 Player *player = m_env->getPlayer(name);
4648 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4651 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4653 Player *player = m_env->getPlayer(playername);
4657 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4661 SendShowFormspecMessage(player->peer_id, formspec, formname);
4665 void Server::notifyPlayers(const std::wstring msg)
4667 BroadcastChatMessage(msg);
4670 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4674 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4675 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4678 Inventory* Server::createDetachedInventory(const std::string &name)
4680 if(m_detached_inventories.count(name) > 0){
4681 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4682 delete m_detached_inventories[name];
4684 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4686 Inventory *inv = new Inventory(m_itemdef);
4688 m_detached_inventories[name] = inv;
4689 sendDetachedInventoryToAll(name);
4696 BoolScopeSet(bool *dst, bool val):
4699 m_orig_state = *m_dst;
4704 *m_dst = m_orig_state;
4711 // actions: time-reversed list
4712 // Return value: success/failure
4713 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4714 std::list<std::string> *log)
4716 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4717 ServerMap *map = (ServerMap*)(&m_env->getMap());
4718 // Disable rollback report sink while reverting
4719 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4721 // Fail if no actions to handle
4722 if(actions.empty()){
4723 log->push_back("Nothing to do.");
4730 for(std::list<RollbackAction>::const_iterator
4731 i = actions.begin();
4732 i != actions.end(); i++)
4734 const RollbackAction &action = *i;
4736 bool success = action.applyRevert(map, this, this);
4739 std::ostringstream os;
4740 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4741 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4743 log->push_back(os.str());
4745 std::ostringstream os;
4746 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4747 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4749 log->push_back(os.str());
4753 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4754 <<" failed"<<std::endl;
4756 // Call it done if less than half failed
4757 return num_failed <= num_tried/2;
4760 // IGameDef interface
4762 IItemDefManager* Server::getItemDefManager()
4766 INodeDefManager* Server::getNodeDefManager()
4770 ICraftDefManager* Server::getCraftDefManager()
4774 ITextureSource* Server::getTextureSource()
4778 IShaderSource* Server::getShaderSource()
4782 u16 Server::allocateUnknownNodeId(const std::string &name)
4784 return m_nodedef->allocateDummy(name);
4786 ISoundManager* Server::getSoundManager()
4788 return &dummySoundManager;
4790 MtEventManager* Server::getEventManager()
4794 IRollbackReportSink* Server::getRollbackReportSink()
4796 if(!m_enable_rollback_recording)
4798 if(!m_rollback_sink_enabled)
4803 IWritableItemDefManager* Server::getWritableItemDefManager()
4807 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4811 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4816 const ModSpec* Server::getModSpec(const std::string &modname)
4818 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4819 i != m_mods.end(); i++){
4820 const ModSpec &mod = *i;
4821 if(mod.name == modname)
4826 void Server::getModNames(core::list<std::string> &modlist)
4828 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4830 modlist.push_back((*i).name);
4833 std::string Server::getBuiltinLuaPath()
4835 return porting::path_share + DIR_DELIM + "builtin";
4838 v3f findSpawnPos(ServerMap &map)
4840 //return v3f(50,50,50)*BS;
4845 nodepos = v2s16(0,0);
4850 s16 water_level = map.m_emerge->water_level; //g_settings->getS16("default_water_level");
4852 // Try to find a good place a few times
4853 for(s32 i=0; i<1000; i++)
4856 // We're going to try to throw the player to this position
4857 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4858 -range + (myrand()%(range*2)));
4859 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4860 // Get ground height at point (fallbacks to heightmap function)
4861 s16 groundheight = map.findGroundLevel(nodepos2d);
4862 // Don't go underwater
4863 if(groundheight <= water_level)
4865 //infostream<<"-> Underwater"<<std::endl;
4868 // Don't go to high places
4869 if(groundheight > water_level + 6)
4871 //infostream<<"-> Underwater"<<std::endl;
4875 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4876 bool is_good = false;
4878 for(s32 i=0; i<10; i++){
4879 v3s16 blockpos = getNodeBlockPos(nodepos);
4880 map.emergeBlock(blockpos, true);
4881 MapNode n = map.getNodeNoEx(nodepos);
4882 if(n.getContent() == CONTENT_AIR){
4893 // Found a good place
4894 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4900 return intToFloat(nodepos, BS);
4903 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4905 RemotePlayer *player = NULL;
4906 bool newplayer = false;
4909 Try to get an existing player
4911 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4913 // If player is already connected, cancel
4914 if(player != NULL && player->peer_id != 0)
4916 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4921 If player with the wanted peer_id already exists, cancel.
4923 if(m_env->getPlayer(peer_id) != NULL)
4925 infostream<<"emergePlayer(): Player with wrong name but same"
4926 " peer_id already exists"<<std::endl;
4931 Create a new player if it doesn't exist yet
4936 player = new RemotePlayer(this);
4937 player->updateName(name);
4939 /* Set player position */
4940 infostream<<"Server: Finding spawn place for player \""
4941 <<name<<"\""<<std::endl;
4942 v3f pos = findSpawnPos(m_env->getServerMap());
4943 player->setPosition(pos);
4945 /* Add player to environment */
4946 m_env->addPlayer(player);
4950 Create a new player active object
4952 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4953 getPlayerEffectivePrivs(player->getName()),
4956 /* Add object to environment */
4957 m_env->addActiveObject(playersao);
4961 scriptapi_on_newplayer(m_lua, playersao);
4963 scriptapi_on_joinplayer(m_lua, playersao);
4968 void Server::handlePeerChange(PeerChange &c)
4970 JMutexAutoLock envlock(m_env_mutex);
4971 JMutexAutoLock conlock(m_con_mutex);
4973 if(c.type == PEER_ADDED)
4980 core::map<u16, RemoteClient*>::Node *n;
4981 n = m_clients.find(c.peer_id);
4982 // The client shouldn't already exist
4986 RemoteClient *client = new RemoteClient();
4987 client->peer_id = c.peer_id;
4988 m_clients.insert(client->peer_id, client);
4991 else if(c.type == PEER_REMOVED)
4998 core::map<u16, RemoteClient*>::Node *n;
4999 n = m_clients.find(c.peer_id);
5000 // The client should exist
5004 Mark objects to be not known by the client
5006 RemoteClient *client = n->getValue();
5008 for(core::map<u16, bool>::Iterator
5009 i = client->m_known_objects.getIterator();
5010 i.atEnd()==false; i++)
5013 u16 id = i.getNode()->getKey();
5014 ServerActiveObject* obj = m_env->getActiveObject(id);
5016 if(obj && obj->m_known_by_count > 0)
5017 obj->m_known_by_count--;
5021 Clear references to playing sounds
5023 for(std::map<s32, ServerPlayingSound>::iterator
5024 i = m_playing_sounds.begin();
5025 i != m_playing_sounds.end();)
5027 ServerPlayingSound &psound = i->second;
5028 psound.clients.erase(c.peer_id);
5029 if(psound.clients.size() == 0)
5030 m_playing_sounds.erase(i++);
5035 Player *player = m_env->getPlayer(c.peer_id);
5037 // Collect information about leaving in chat
5038 std::wstring message;
5042 std::wstring name = narrow_to_wide(player->getName());
5045 message += L" left the game.";
5047 message += L" (timed out)";
5051 /* Run scripts and remove from environment */
5055 PlayerSAO *playersao = player->getPlayerSAO();
5058 scriptapi_on_leaveplayer(m_lua, playersao);
5060 playersao->disconnected();
5070 std::ostringstream os(std::ios_base::binary);
5071 for(core::map<u16, RemoteClient*>::Iterator
5072 i = m_clients.getIterator();
5073 i.atEnd() == false; i++)
5075 RemoteClient *client = i.getNode()->getValue();
5076 assert(client->peer_id == i.getNode()->getKey());
5077 if(client->serialization_version == SER_FMT_VER_INVALID)
5080 Player *player = m_env->getPlayer(client->peer_id);
5083 // Get name of player
5084 os<<player->getName()<<" ";
5087 actionstream<<player->getName()<<" "
5088 <<(c.timeout?"times out.":"leaves game.")
5089 <<" List of players: "
5090 <<os.str()<<std::endl;
5095 delete m_clients[c.peer_id];
5096 m_clients.remove(c.peer_id);
5098 // Send player info to all remaining clients
5099 //SendPlayerInfos();
5101 // Send leave chat message to all remaining clients
5102 if(message.length() != 0)
5103 BroadcastChatMessage(message);
5112 void Server::handlePeerChanges()
5114 while(m_peer_change_queue.size() > 0)
5116 PeerChange c = m_peer_change_queue.pop_front();
5118 verbosestream<<"Server: Handling peer change: "
5119 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5122 handlePeerChange(c);
5126 void dedicated_server_loop(Server &server, bool &kill)
5128 DSTACK(__FUNCTION_NAME);
5130 verbosestream<<"dedicated_server_loop()"<<std::endl;
5132 IntervalLimiter m_profiler_interval;
5136 float steplen = g_settings->getFloat("dedicated_server_step");
5137 // This is kind of a hack but can be done like this
5138 // because server.step() is very light
5140 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5141 sleep_ms((int)(steplen*1000.0));
5143 server.step(steplen);
5145 if(server.getShutdownRequested() || kill)
5147 infostream<<"Dedicated server quitting"<<std::endl;
5154 float profiler_print_interval =
5155 g_settings->getFloat("profiler_print_interval");
5156 if(profiler_print_interval != 0)
5158 if(m_profiler_interval.step(steplen, profiler_print_interval))
5160 infostream<<"Profiler:"<<std::endl;
5161 g_profiler->print(infostream);
5162 g_profiler->clear();