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 "serverlist.h"
55 #include "util/string.h"
56 #include "util/pointedthing.h"
57 #include "util/mathconstants.h"
59 #include "util/serialize.h"
61 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
63 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
65 class MapEditEventIgnorer
68 MapEditEventIgnorer(bool *flag):
77 ~MapEditEventIgnorer()
90 class MapEditEventAreaIgnorer
93 MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
94 m_ignorevariable(ignorevariable)
96 if(m_ignorevariable->getVolume() == 0)
97 *m_ignorevariable = a;
99 m_ignorevariable = NULL;
102 ~MapEditEventAreaIgnorer()
106 assert(m_ignorevariable->getVolume() != 0);
107 *m_ignorevariable = VoxelArea();
112 VoxelArea *m_ignorevariable;
115 void * ServerThread::Thread()
119 log_register_thread("ServerThread");
121 DSTACK(__FUNCTION_NAME);
123 BEGIN_DEBUG_EXCEPTION_HANDLER
128 //TimeTaker timer("AsyncRunStep() + Receive()");
131 //TimeTaker timer("AsyncRunStep()");
132 m_server->AsyncRunStep();
135 //infostream<<"Running m_server->Receive()"<<std::endl;
138 catch(con::NoIncomingDataException &e)
141 catch(con::PeerNotFoundException &e)
143 infostream<<"Server: PeerNotFoundException"<<std::endl;
145 catch(con::ConnectionBindFailed &e)
147 m_server->setAsyncFatalError(e.what());
151 m_server->setAsyncFatalError(e.what());
155 END_DEBUG_EXCEPTION_HANDLER(errorstream)
160 void * EmergeThread::Thread()
164 log_register_thread("EmergeThread");
166 DSTACK(__FUNCTION_NAME);
168 BEGIN_DEBUG_EXCEPTION_HANDLER
170 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
172 v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
174 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
175 EmergeManager *emerge = m_server->m_emerge;
176 Mapgen *mapgen = emerge->getMapgen();
179 Get block info from queue, emerge them and send them
182 After queue is empty, exit.
186 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
190 SharedPtr<QueuedBlockEmerge> q(qptr);
198 Do not generate over-limit
200 if(blockpos_over_limit(p))
203 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
205 //TimeTaker timer("block emerge");
208 Try to emerge it from somewhere.
210 If it is only wanted as optional, only loading from disk
215 Check if any peer wants it as non-optional. In that case it
218 Also decrement the emerge queue count in clients.
221 bool only_from_disk = true;
224 core::map<u16, u8>::Iterator i;
225 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
227 //u16 peer_id = i.getNode()->getKey();
230 u8 flags = i.getNode()->getValue();
231 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
232 only_from_disk = false;
237 if(enable_mapgen_debug_info)
238 infostream<<"EmergeThread: p="
239 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
240 <<"only_from_disk="<<only_from_disk<<std::endl;
244 MapBlock *block = NULL;
245 bool got_block = true;
246 core::map<v3s16, MapBlock*> modified_blocks;
249 Try to fetch block from memory or disk.
250 If not found and asked to generate, initialize generator.
253 bool started_generate = false;
257 JMutexAutoLock envlock(m_server->m_env_mutex);
259 // Load sector if it isn't loaded
260 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
261 map.loadSectorMeta(p2d);
263 // Attempt to load block
264 block = map.getBlockNoCreateNoEx(p);
265 if(!block || block->isDummy() || !block->isGenerated())
267 if(enable_mapgen_debug_info)
268 infostream<<"EmergeThread: not in memory, "
269 <<"attempting to load from disk"<<std::endl;
271 block = map.loadBlock(p);
274 // If could not load and allowed to generate, start generation
275 // inside this same envlock
276 if(only_from_disk == false &&
277 (block == NULL || block->isGenerated() == false)){
278 if(enable_mapgen_debug_info)
279 infostream<<"EmergeThread: generating"<<std::endl;
280 started_generate = true;
282 map.initBlockMake(&data, p);
287 If generator was initialized, generate now when envlock is free.
292 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
294 TimeTaker t("mapgen::make_block()");
296 mapgen->makeChunk(&data);
297 //mapgen::make_block(&data);
299 if(enable_mapgen_debug_info == false)
300 t.stop(true); // Hide output
304 // Lock environment again to access the map
305 JMutexAutoLock envlock(m_server->m_env_mutex);
307 ScopeProfiler sp(g_profiler, "EmergeThread: after "
308 "mapgen::make_block (envlock)", SPT_AVG);
310 // Blit data back on map, update lighting, add mobs and
311 // whatever this does
312 map.finishBlockMake(&data, modified_blocks);
315 block = map.getBlockNoCreateNoEx(p);
317 // If block doesn't exist, don't try doing anything with it
318 // This happens if the block is not in generation boundaries
323 Do some post-generate stuff
326 v3s16 minp = data.blockpos_min*MAP_BLOCKSIZE;
327 v3s16 maxp = data.blockpos_max*MAP_BLOCKSIZE +
328 v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
331 Ignore map edit events, they will not need to be
332 sent to anybody because the block hasn't been sent
335 //MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
336 MapEditEventAreaIgnorer ign(
337 &m_server->m_ignore_map_edit_events_area,
338 VoxelArea(minp, maxp));
340 TimeTaker timer("on_generated");
341 scriptapi_environment_on_generated(m_server->m_lua,
342 minp, maxp, emerge->getBlockSeed(minp));
343 /*int t = timer.stop(true);
344 dstream<<"on_generated took "<<t<<"ms"<<std::endl;*/
347 if(enable_mapgen_debug_info)
348 infostream<<"EmergeThread: ended up with: "
349 <<analyze_block(block)<<std::endl;
351 // Activate objects and stuff
352 m_server->m_env->activateBlock(block, 0);
360 Set sent status of modified blocks on clients
363 // NOTE: Server's clients are also behind the connection mutex
364 JMutexAutoLock lock(m_server->m_con_mutex);
367 Add the originally fetched block to the modified list
371 modified_blocks.insert(p, block);
375 Set the modified blocks unsent for all the clients
378 for(core::map<u16, RemoteClient*>::Iterator
379 i = m_server->m_clients.getIterator();
380 i.atEnd() == false; i++)
382 RemoteClient *client = i.getNode()->getValue();
384 if(modified_blocks.size() > 0)
386 // Remove block from sent history
387 client->SetBlocksNotSent(modified_blocks);
391 catch(VersionMismatchException &e)
393 std::ostringstream err;
394 err<<"World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl;
395 err<<"----"<<std::endl;
396 err<<"\""<<e.what()<<"\""<<std::endl;
397 err<<"See debug.txt."<<std::endl;
398 err<<"World probably saved by a newer version of Minetest."<<std::endl;
399 m_server->setAsyncFatalError(err.str());
401 catch(SerializationError &e)
403 std::ostringstream err;
404 err<<"Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl;
405 err<<"----"<<std::endl;
406 err<<"\""<<e.what()<<"\""<<std::endl;
407 err<<"See debug.txt."<<std::endl;
408 err<<"You can ignore this using [ignore_world_load_errors = true]."<<std::endl;
409 m_server->setAsyncFatalError(err.str());
412 END_DEBUG_EXCEPTION_HANDLER(errorstream)
414 log_deregister_thread();
419 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
421 if(pos_exists) *pos_exists = false;
426 if(pos_exists) *pos_exists = true;
431 ServerActiveObject *sao = env->getActiveObject(object);
434 if(pos_exists) *pos_exists = true;
435 return sao->getBasePosition(); }
440 void RemoteClient::GetNextBlocks(Server *server, float dtime,
441 core::array<PrioritySortedBlockTransfer> &dest)
443 DSTACK(__FUNCTION_NAME);
446 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
449 m_nothing_to_send_pause_timer -= dtime;
450 m_nearest_unsent_reset_timer += dtime;
452 if(m_nothing_to_send_pause_timer >= 0)
455 Player *player = server->m_env->getPlayer(peer_id);
456 // This can happen sometimes; clients and players are not in perfect sync.
460 // Won't send anything if already sending
461 if(m_blocks_sending.size() >= g_settings->getU16
462 ("max_simultaneous_block_sends_per_client"))
464 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
468 //TimeTaker timer("RemoteClient::GetNextBlocks");
470 v3f playerpos = player->getPosition();
471 v3f playerspeed = player->getSpeed();
472 v3f playerspeeddir(0,0,0);
473 if(playerspeed.getLength() > 1.0*BS)
474 playerspeeddir = playerspeed / playerspeed.getLength();
475 // Predict to next block
476 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
478 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
480 v3s16 center = getNodeBlockPos(center_nodepos);
482 // Camera position and direction
483 v3f camera_pos = player->getEyePosition();
484 v3f camera_dir = v3f(0,0,1);
485 camera_dir.rotateYZBy(player->getPitch());
486 camera_dir.rotateXZBy(player->getYaw());
488 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
489 <<camera_dir.Z<<")"<<std::endl;*/
492 Get the starting value of the block finder radius.
495 if(m_last_center != center)
497 m_nearest_unsent_d = 0;
498 m_last_center = center;
501 /*infostream<<"m_nearest_unsent_reset_timer="
502 <<m_nearest_unsent_reset_timer<<std::endl;*/
504 // Reset periodically to workaround for some bugs or stuff
505 if(m_nearest_unsent_reset_timer > 20.0)
507 m_nearest_unsent_reset_timer = 0;
508 m_nearest_unsent_d = 0;
509 //infostream<<"Resetting m_nearest_unsent_d for "
510 // <<server->getPlayerName(peer_id)<<std::endl;
513 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
514 s16 d_start = m_nearest_unsent_d;
516 //infostream<<"d_start="<<d_start<<std::endl;
518 u16 max_simul_sends_setting = g_settings->getU16
519 ("max_simultaneous_block_sends_per_client");
520 u16 max_simul_sends_usually = max_simul_sends_setting;
523 Check the time from last addNode/removeNode.
525 Decrease send rate if player is building stuff.
527 m_time_from_building += dtime;
528 if(m_time_from_building < g_settings->getFloat(
529 "full_block_send_enable_min_time_from_building"))
531 max_simul_sends_usually
532 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
536 Number of blocks sending + number of blocks selected for sending
538 u32 num_blocks_selected = m_blocks_sending.size();
541 next time d will be continued from the d from which the nearest
542 unsent block was found this time.
544 This is because not necessarily any of the blocks found this
545 time are actually sent.
547 s32 new_nearest_unsent_d = -1;
549 s16 d_max = g_settings->getS16("max_block_send_distance");
550 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
552 // Don't loop very much at a time
553 s16 max_d_increment_at_time = 2;
554 if(d_max > d_start + max_d_increment_at_time)
555 d_max = d_start + max_d_increment_at_time;
556 /*if(d_max_gen > d_start+2)
557 d_max_gen = d_start+2;*/
559 //infostream<<"Starting from "<<d_start<<std::endl;
561 s32 nearest_emerged_d = -1;
562 s32 nearest_emergefull_d = -1;
563 s32 nearest_sent_d = -1;
564 bool queue_is_full = false;
567 for(d = d_start; d <= d_max; d++)
569 /*errorstream<<"checking d="<<d<<" for "
570 <<server->getPlayerName(peer_id)<<std::endl;*/
571 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
574 If m_nearest_unsent_d was changed by the EmergeThread
575 (it can change it to 0 through SetBlockNotSent),
577 Else update m_nearest_unsent_d
579 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
581 d = m_nearest_unsent_d;
582 last_nearest_unsent_d = m_nearest_unsent_d;
586 Get the border/face dot coordinates of a "d-radiused"
589 core::list<v3s16> list;
590 getFacePositions(list, d);
592 core::list<v3s16>::Iterator li;
593 for(li=list.begin(); li!=list.end(); li++)
595 v3s16 p = *li + center;
599 - Don't allow too many simultaneous transfers
600 - EXCEPT when the blocks are very close
602 Also, don't send blocks that are already flying.
605 // Start with the usual maximum
606 u16 max_simul_dynamic = max_simul_sends_usually;
608 // If block is very close, allow full maximum
609 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
610 max_simul_dynamic = max_simul_sends_setting;
612 // Don't select too many blocks for sending
613 if(num_blocks_selected >= max_simul_dynamic)
615 queue_is_full = true;
616 goto queue_full_break;
619 // Don't send blocks that are currently being transferred
620 if(m_blocks_sending.find(p) != NULL)
626 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
627 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
628 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
629 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
630 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
631 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
634 // If this is true, inexistent block will be made from scratch
635 bool generate = d <= d_max_gen;
638 /*// Limit the generating area vertically to 2/3
639 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
642 // Limit the send area vertically to 1/2
643 if(abs(p.Y - center.Y) > d_max / 2)
649 If block is far away, don't generate it unless it is
655 // Block center y in nodes
656 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
657 // Don't generate if it's very high or very low
658 if(y < -64 || y > 64)
662 v2s16 p2d_nodes_center(
666 // Get ground height in nodes
667 s16 gh = server->m_env->getServerMap().findGroundLevel(
670 // If differs a lot, don't generate
671 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
673 // Actually, don't even send it
679 //infostream<<"d="<<d<<std::endl;
682 Don't generate or send if not in sight
683 FIXME This only works if the client uses a small enough
684 FOV setting. The default of 72 degrees is fine.
687 float camera_fov = (72.0*M_PI/180) * 4./3.;
688 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
694 Don't send already sent blocks
697 if(m_blocks_sent.find(p) != NULL)
704 Check if map has this block
706 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
708 bool surely_not_found_on_disk = false;
709 bool block_is_invalid = false;
712 // Reset usage timer, this block will be of use in the future.
713 block->resetUsageTimer();
715 // Block is dummy if data doesn't exist.
716 // It means it has been not found from disk and not generated
719 surely_not_found_on_disk = true;
722 // Block is valid if lighting is up-to-date and data exists
723 if(block->isValid() == false)
725 block_is_invalid = true;
728 /*if(block->isFullyGenerated() == false)
730 block_is_invalid = true;
735 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
736 v2s16 chunkpos = map->sector_to_chunk(p2d);
737 if(map->chunkNonVolatile(chunkpos) == false)
738 block_is_invalid = true;
740 if(block->isGenerated() == false)
741 block_is_invalid = true;
744 If block is not close, don't send it unless it is near
747 Block is near ground level if night-time mesh
748 differs from day-time mesh.
752 if(block->getDayNightDiff() == false)
759 If block has been marked to not exist on disk (dummy)
760 and generating new ones is not wanted, skip block.
762 if(generate == false && surely_not_found_on_disk == true)
769 Add inexistent block to emerge queue.
771 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
773 //TODO: Get value from somewhere
774 // Allow only one block in emerge queue
775 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
776 // Allow two blocks in queue per client
777 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
779 // Make it more responsive when needing to generate stuff
780 if(surely_not_found_on_disk)
782 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
784 //infostream<<"Adding block to emerge queue"<<std::endl;
786 // Add it to the emerge queue and trigger the thread
789 if(generate == false)
790 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
792 server->m_emerge_queue.addBlock(peer_id, p, flags);
793 server->m_emergethread.trigger();
795 if(nearest_emerged_d == -1)
796 nearest_emerged_d = d;
798 if(nearest_emergefull_d == -1)
799 nearest_emergefull_d = d;
800 goto queue_full_break;
807 if(nearest_sent_d == -1)
811 Add block to send queue
814 /*errorstream<<"sending from d="<<d<<" to "
815 <<server->getPlayerName(peer_id)<<std::endl;*/
817 PrioritySortedBlockTransfer q((float)d, p, peer_id);
821 num_blocks_selected += 1;
826 //infostream<<"Stopped at "<<d<<std::endl;
828 // If nothing was found for sending and nothing was queued for
829 // emerging, continue next time browsing from here
830 if(nearest_emerged_d != -1){
831 new_nearest_unsent_d = nearest_emerged_d;
832 } else if(nearest_emergefull_d != -1){
833 new_nearest_unsent_d = nearest_emergefull_d;
835 if(d > g_settings->getS16("max_block_send_distance")){
836 new_nearest_unsent_d = 0;
837 m_nothing_to_send_pause_timer = 2.0;
838 /*infostream<<"GetNextBlocks(): d wrapped around for "
839 <<server->getPlayerName(peer_id)
840 <<"; setting to 0 and pausing"<<std::endl;*/
842 if(nearest_sent_d != -1)
843 new_nearest_unsent_d = nearest_sent_d;
845 new_nearest_unsent_d = d;
849 if(new_nearest_unsent_d != -1)
850 m_nearest_unsent_d = new_nearest_unsent_d;
852 /*timer_result = timer.stop(true);
853 if(timer_result != 0)
854 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
857 void RemoteClient::GotBlock(v3s16 p)
859 if(m_blocks_sending.find(p) != NULL)
860 m_blocks_sending.remove(p);
863 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
864 " m_blocks_sending"<<std::endl;*/
865 m_excess_gotblocks++;
867 m_blocks_sent.insert(p, true);
870 void RemoteClient::SentBlock(v3s16 p)
872 if(m_blocks_sending.find(p) == NULL)
873 m_blocks_sending.insert(p, 0.0);
875 infostream<<"RemoteClient::SentBlock(): Sent block"
876 " already in m_blocks_sending"<<std::endl;
879 void RemoteClient::SetBlockNotSent(v3s16 p)
881 m_nearest_unsent_d = 0;
883 if(m_blocks_sending.find(p) != NULL)
884 m_blocks_sending.remove(p);
885 if(m_blocks_sent.find(p) != NULL)
886 m_blocks_sent.remove(p);
889 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
891 m_nearest_unsent_d = 0;
893 for(core::map<v3s16, MapBlock*>::Iterator
894 i = blocks.getIterator();
895 i.atEnd()==false; i++)
897 v3s16 p = i.getNode()->getKey();
899 if(m_blocks_sending.find(p) != NULL)
900 m_blocks_sending.remove(p);
901 if(m_blocks_sent.find(p) != NULL)
902 m_blocks_sent.remove(p);
910 PlayerInfo::PlayerInfo()
916 void PlayerInfo::PrintLine(std::ostream *s)
919 (*s)<<"\""<<name<<"\" ("
920 <<(position.X/10)<<","<<(position.Y/10)
921 <<","<<(position.Z/10)<<") ";
923 (*s)<<" avg_rtt="<<avg_rtt;
932 const std::string &path_world,
933 const std::string &path_config,
934 const SubgameSpec &gamespec,
935 bool simple_singleplayer_mode
937 m_path_world(path_world),
938 m_path_config(path_config),
939 m_gamespec(gamespec),
940 m_simple_singleplayer_mode(simple_singleplayer_mode),
941 m_async_fatal_error(""),
943 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
944 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
946 m_rollback_sink_enabled(true),
947 m_enable_rollback_recording(false),
951 m_itemdef(createItemDefManager()),
952 m_nodedef(createNodeDefManager()),
953 m_craftdef(createCraftDefManager()),
954 m_event(new EventManager()),
956 m_emergethread(this),
957 m_time_of_day_send_timer(0),
959 m_shutdown_requested(false),
960 m_ignore_map_edit_events(false),
961 m_ignore_map_edit_events_peer_id(0)
963 m_liquid_transform_timer = 0.0;
964 m_print_info_timer = 0.0;
965 m_masterserver_timer = 0.0;
966 m_objectdata_timer = 0.0;
967 m_emergethread_trigger_timer = 0.0;
968 m_savemap_timer = 0.0;
969 m_clients_number = 0;
973 m_step_dtime_mutex.Init();
977 throw ServerError("Supplied empty world path");
979 if(!gamespec.isValid())
980 throw ServerError("Supplied invalid gamespec");
982 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
983 if(m_simple_singleplayer_mode)
984 infostream<<" in simple singleplayer mode"<<std::endl;
986 infostream<<std::endl;
987 infostream<<"- world: "<<m_path_world<<std::endl;
988 infostream<<"- config: "<<m_path_config<<std::endl;
989 infostream<<"- game: "<<m_gamespec.path<<std::endl;
991 // Create biome definition manager
992 m_biomedef = new BiomeDefManager(this);
994 // Create rollback manager
995 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
996 m_rollback = createRollbackManager(rollback_path, this);
998 // Create world if it doesn't exist
999 if(!initializeWorld(m_path_world, m_gamespec.id))
1000 throw ServerError("Failed to initialize world");
1002 ModConfiguration modconf(m_path_world);
1003 m_mods = modconf.getMods();
1004 std::list<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
1005 // complain about mods with unsatisfied dependencies
1006 if(!modconf.isConsistent())
1008 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
1009 it != unsatisfied_mods.end(); ++it)
1012 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
1013 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
1014 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
1015 errorstream << " \"" << *dep_it << "\"";
1016 errorstream << std::endl;
1020 Settings worldmt_settings;
1021 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
1022 worldmt_settings.readConfigFile(worldmt.c_str());
1023 std::vector<std::string> names = worldmt_settings.getNames();
1024 std::set<std::string> exclude_mod_names;
1025 std::set<std::string> load_mod_names;
1026 for(std::vector<std::string>::iterator it = names.begin();
1027 it != names.end(); ++it)
1029 std::string name = *it;
1030 if (name.compare(0,9,"load_mod_")==0)
1032 if(worldmt_settings.getBool(name))
1033 load_mod_names.insert(name.substr(9));
1035 exclude_mod_names.insert(name.substr(9));
1038 // complain about mods declared to be loaded, but not found
1039 for(std::vector<ModSpec>::iterator it = m_mods.begin();
1040 it != m_mods.end(); ++it)
1041 load_mod_names.erase((*it).name);
1042 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
1043 it != unsatisfied_mods.end(); ++it)
1044 load_mod_names.erase((*it).name);
1045 if(!load_mod_names.empty())
1047 errorstream << "The following mods could not be found:";
1048 for(std::set<std::string>::iterator it = load_mod_names.begin();
1049 it != load_mod_names.end(); ++it)
1050 errorstream << " \"" << (*it) << "\"";
1051 errorstream << std::endl;
1054 // Path to builtin.lua
1055 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
1058 JMutexAutoLock envlock(m_env_mutex);
1059 JMutexAutoLock conlock(m_con_mutex);
1061 // Initialize scripting
1063 infostream<<"Server: Initializing Lua"<<std::endl;
1064 m_lua = script_init();
1067 scriptapi_export(m_lua, this);
1068 // Load and run builtin.lua
1069 infostream<<"Server: Loading builtin.lua [\""
1070 <<builtinpath<<"\"]"<<std::endl;
1071 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1073 errorstream<<"Server: Failed to load and run "
1074 <<builtinpath<<std::endl;
1075 throw ModError("Failed to load and run "+builtinpath);
1078 infostream<<"Server: Loading mods: ";
1079 for(std::vector<ModSpec>::iterator i = m_mods.begin();
1080 i != m_mods.end(); i++){
1081 const ModSpec &mod = *i;
1082 infostream<<mod.name<<" ";
1084 infostream<<std::endl;
1085 // Load and run "mod" scripts
1086 for(std::vector<ModSpec>::iterator i = m_mods.begin();
1087 i != m_mods.end(); i++){
1088 const ModSpec &mod = *i;
1089 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1090 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1091 <<scriptpath<<"\"]"<<std::endl;
1092 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1094 errorstream<<"Server: Failed to load and run "
1095 <<scriptpath<<std::endl;
1096 throw ModError("Failed to load and run "+scriptpath);
1100 // Read Textures and calculate sha1 sums
1103 // Apply item aliases in the node definition manager
1104 m_nodedef->updateAliases(m_itemdef);
1106 // Add default biomes after nodedef had its aliases added
1107 m_biomedef->addDefaultBiomes();
1109 // Create emerge manager
1110 m_emerge = new EmergeManager(this, m_biomedef);
1112 // Initialize Environment
1113 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
1114 m_env = new ServerEnvironment(servermap, m_lua, this, this);
1116 m_emerge->initMapgens(servermap->getMapgenParams());
1118 // Give environment reference to scripting api
1119 scriptapi_add_environment(m_lua, m_env);
1121 // Register us to receive map edit events
1122 servermap->addEventReceiver(this);
1124 // If file exists, load environment metadata
1125 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1127 infostream<<"Server: Loading environment metadata"<<std::endl;
1128 m_env->loadMeta(m_path_world);
1132 infostream<<"Server: Loading players"<<std::endl;
1133 m_env->deSerializePlayers(m_path_world);
1136 Add some test ActiveBlockModifiers to environment
1138 add_legacy_abms(m_env, m_nodedef);
1143 infostream<<"Server destructing"<<std::endl;
1146 Send shutdown message
1149 JMutexAutoLock conlock(m_con_mutex);
1151 std::wstring line = L"*** Server shutting down";
1154 Send the message to clients
1156 for(core::map<u16, RemoteClient*>::Iterator
1157 i = m_clients.getIterator();
1158 i.atEnd() == false; i++)
1160 // Get client and check that it is valid
1161 RemoteClient *client = i.getNode()->getValue();
1162 assert(client->peer_id == i.getNode()->getKey());
1163 if(client->serialization_version == SER_FMT_VER_INVALID)
1167 SendChatMessage(client->peer_id, line);
1169 catch(con::PeerNotFoundException &e)
1175 JMutexAutoLock envlock(m_env_mutex);
1176 JMutexAutoLock conlock(m_con_mutex);
1179 Execute script shutdown hooks
1181 scriptapi_on_shutdown(m_lua);
1185 JMutexAutoLock envlock(m_env_mutex);
1190 infostream<<"Server: Saving players"<<std::endl;
1191 m_env->serializePlayers(m_path_world);
1194 Save environment metadata
1196 infostream<<"Server: Saving environment metadata"<<std::endl;
1197 m_env->saveMeta(m_path_world);
1209 JMutexAutoLock clientslock(m_con_mutex);
1211 for(core::map<u16, RemoteClient*>::Iterator
1212 i = m_clients.getIterator();
1213 i.atEnd() == false; i++)
1217 delete i.getNode()->getValue();
1221 // Delete things in the reverse order of creation
1230 // Deinitialize scripting
1231 infostream<<"Server: Deinitializing scripting"<<std::endl;
1232 script_deinit(m_lua);
1234 // Delete detached inventories
1236 for(std::map<std::string, Inventory*>::iterator
1237 i = m_detached_inventories.begin();
1238 i != m_detached_inventories.end(); i++){
1244 void Server::start(unsigned short port)
1246 DSTACK(__FUNCTION_NAME);
1247 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1249 // Stop thread if already running
1252 // Initialize connection
1253 m_con.SetTimeoutMs(30);
1257 m_thread.setRun(true);
1260 // ASCII art for the win!
1262 <<" .__ __ __ "<<std::endl
1263 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1264 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1265 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1266 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1267 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1268 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1269 actionstream<<"Server for gameid=\""<<m_gamespec.id
1270 <<"\" listening on port "<<port<<"."<<std::endl;
1275 DSTACK(__FUNCTION_NAME);
1277 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1279 // Stop threads (set run=false first so both start stopping)
1280 m_thread.setRun(false);
1281 m_emergethread.setRun(false);
1283 m_emergethread.stop();
1285 infostream<<"Server: Threads stopped"<<std::endl;
1288 void Server::step(float dtime)
1290 DSTACK(__FUNCTION_NAME);
1295 JMutexAutoLock lock(m_step_dtime_mutex);
1296 m_step_dtime += dtime;
1298 // Throw if fatal error occurred in thread
1299 std::string async_err = m_async_fatal_error.get();
1300 if(async_err != ""){
1301 throw ServerError(async_err);
1305 void Server::AsyncRunStep()
1307 DSTACK(__FUNCTION_NAME);
1309 g_profiler->add("Server::AsyncRunStep (num)", 1);
1313 JMutexAutoLock lock1(m_step_dtime_mutex);
1314 dtime = m_step_dtime;
1318 // Send blocks to clients
1325 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1327 //infostream<<"Server steps "<<dtime<<std::endl;
1328 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1331 JMutexAutoLock lock1(m_step_dtime_mutex);
1332 m_step_dtime -= dtime;
1339 m_uptime.set(m_uptime.get() + dtime);
1343 // Process connection's timeouts
1344 JMutexAutoLock lock2(m_con_mutex);
1345 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1346 m_con.RunTimeouts(dtime);
1350 // This has to be called so that the client list gets synced
1351 // with the peer list of the connection
1352 handlePeerChanges();
1356 Update time of day and overall game time
1359 JMutexAutoLock envlock(m_env_mutex);
1361 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1364 Send to clients at constant intervals
1367 m_time_of_day_send_timer -= dtime;
1368 if(m_time_of_day_send_timer < 0.0)
1370 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1372 //JMutexAutoLock envlock(m_env_mutex);
1373 JMutexAutoLock conlock(m_con_mutex);
1375 for(core::map<u16, RemoteClient*>::Iterator
1376 i = m_clients.getIterator();
1377 i.atEnd() == false; i++)
1379 RemoteClient *client = i.getNode()->getValue();
1380 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1381 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1383 m_con.Send(client->peer_id, 0, data, true);
1389 JMutexAutoLock lock(m_env_mutex);
1391 ScopeProfiler sp(g_profiler, "SEnv step");
1392 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1396 const float map_timer_and_unload_dtime = 2.92;
1397 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1399 JMutexAutoLock lock(m_env_mutex);
1400 // Run Map's timers and unload unused data
1401 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1402 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1403 g_settings->getFloat("server_unload_unused_data_timeout"));
1414 JMutexAutoLock lock(m_env_mutex);
1415 JMutexAutoLock lock2(m_con_mutex);
1417 ScopeProfiler sp(g_profiler, "Server: handle players");
1419 for(core::map<u16, RemoteClient*>::Iterator
1420 i = m_clients.getIterator();
1421 i.atEnd() == false; i++)
1423 RemoteClient *client = i.getNode()->getValue();
1424 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1425 if(playersao == NULL)
1429 Handle player HPs (die if hp=0)
1431 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1433 if(playersao->getHP() == 0)
1434 DiePlayer(client->peer_id);
1436 SendPlayerHP(client->peer_id);
1440 Send player inventories if necessary
1442 if(playersao->m_moved){
1443 SendMovePlayer(client->peer_id);
1444 playersao->m_moved = false;
1446 if(playersao->m_inventory_not_sent){
1447 UpdateCrafting(client->peer_id);
1448 SendInventory(client->peer_id);
1453 /* Transform liquids */
1454 m_liquid_transform_timer += dtime;
1455 if(m_liquid_transform_timer >= 1.00)
1457 m_liquid_transform_timer -= 1.00;
1459 JMutexAutoLock lock(m_env_mutex);
1461 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1463 core::map<v3s16, MapBlock*> modified_blocks;
1464 m_env->getMap().transformLiquids(modified_blocks);
1469 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1470 ServerMap &map = ((ServerMap&)m_env->getMap());
1471 map.updateLighting(modified_blocks, lighting_modified_blocks);
1473 // Add blocks modified by lighting to modified_blocks
1474 for(core::map<v3s16, MapBlock*>::Iterator
1475 i = lighting_modified_blocks.getIterator();
1476 i.atEnd() == false; i++)
1478 MapBlock *block = i.getNode()->getValue();
1479 modified_blocks.insert(block->getPos(), block);
1483 Set the modified blocks unsent for all the clients
1486 JMutexAutoLock lock2(m_con_mutex);
1488 for(core::map<u16, RemoteClient*>::Iterator
1489 i = m_clients.getIterator();
1490 i.atEnd() == false; i++)
1492 RemoteClient *client = i.getNode()->getValue();
1494 if(modified_blocks.size() > 0)
1496 // Remove block from sent history
1497 client->SetBlocksNotSent(modified_blocks);
1502 // Periodically print some info
1504 float &counter = m_print_info_timer;
1510 JMutexAutoLock lock2(m_con_mutex);
1511 m_clients_number = 0;
1512 if(m_clients.size() != 0)
1513 infostream<<"Players:"<<std::endl;
1514 for(core::map<u16, RemoteClient*>::Iterator
1515 i = m_clients.getIterator();
1516 i.atEnd() == false; i++)
1518 //u16 peer_id = i.getNode()->getKey();
1519 RemoteClient *client = i.getNode()->getValue();
1520 Player *player = m_env->getPlayer(client->peer_id);
1523 infostream<<"* "<<player->getName()<<"\t";
1524 client->PrintInfo(infostream);
1532 // send masterserver announce
1534 float &counter = m_masterserver_timer;
1535 if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1537 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number);
1544 //if(g_settings->getBool("enable_experimental"))
1548 Check added and deleted active objects
1551 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1552 JMutexAutoLock envlock(m_env_mutex);
1553 JMutexAutoLock conlock(m_con_mutex);
1555 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1557 // Radius inside which objects are active
1558 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1559 radius *= MAP_BLOCKSIZE;
1561 for(core::map<u16, RemoteClient*>::Iterator
1562 i = m_clients.getIterator();
1563 i.atEnd() == false; i++)
1565 RemoteClient *client = i.getNode()->getValue();
1567 // If definitions and textures have not been sent, don't
1568 // send objects either
1569 if(!client->definitions_sent)
1572 Player *player = m_env->getPlayer(client->peer_id);
1575 // This can happen if the client timeouts somehow
1576 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1578 <<" has no associated player"<<std::endl;*/
1581 v3s16 pos = floatToInt(player->getPosition(), BS);
1583 core::map<u16, bool> removed_objects;
1584 core::map<u16, bool> added_objects;
1585 m_env->getRemovedActiveObjects(pos, radius,
1586 client->m_known_objects, removed_objects);
1587 m_env->getAddedActiveObjects(pos, radius,
1588 client->m_known_objects, added_objects);
1590 // Ignore if nothing happened
1591 if(removed_objects.size() == 0 && added_objects.size() == 0)
1593 //infostream<<"active objects: none changed"<<std::endl;
1597 std::string data_buffer;
1601 // Handle removed objects
1602 writeU16((u8*)buf, removed_objects.size());
1603 data_buffer.append(buf, 2);
1604 for(core::map<u16, bool>::Iterator
1605 i = removed_objects.getIterator();
1606 i.atEnd()==false; i++)
1609 u16 id = i.getNode()->getKey();
1610 ServerActiveObject* obj = m_env->getActiveObject(id);
1612 // Add to data buffer for sending
1613 writeU16((u8*)buf, i.getNode()->getKey());
1614 data_buffer.append(buf, 2);
1616 // Remove from known objects
1617 client->m_known_objects.remove(i.getNode()->getKey());
1619 if(obj && obj->m_known_by_count > 0)
1620 obj->m_known_by_count--;
1623 // Handle added objects
1624 writeU16((u8*)buf, added_objects.size());
1625 data_buffer.append(buf, 2);
1626 for(core::map<u16, bool>::Iterator
1627 i = added_objects.getIterator();
1628 i.atEnd()==false; i++)
1631 u16 id = i.getNode()->getKey();
1632 ServerActiveObject* obj = m_env->getActiveObject(id);
1635 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1637 infostream<<"WARNING: "<<__FUNCTION_NAME
1638 <<": NULL object"<<std::endl;
1640 type = obj->getSendType();
1642 // Add to data buffer for sending
1643 writeU16((u8*)buf, id);
1644 data_buffer.append(buf, 2);
1645 writeU8((u8*)buf, type);
1646 data_buffer.append(buf, 1);
1649 data_buffer.append(serializeLongString(
1650 obj->getClientInitializationData(client->net_proto_version)));
1652 data_buffer.append(serializeLongString(""));
1654 // Add to known objects
1655 client->m_known_objects.insert(i.getNode()->getKey(), false);
1658 obj->m_known_by_count++;
1662 SharedBuffer<u8> reply(2 + data_buffer.size());
1663 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1664 memcpy((char*)&reply[2], data_buffer.c_str(),
1665 data_buffer.size());
1667 m_con.Send(client->peer_id, 0, reply, true);
1669 verbosestream<<"Server: Sent object remove/add: "
1670 <<removed_objects.size()<<" removed, "
1671 <<added_objects.size()<<" added, "
1672 <<"packet size is "<<reply.getSize()<<std::endl;
1677 Collect a list of all the objects known by the clients
1678 and report it back to the environment.
1681 core::map<u16, bool> all_known_objects;
1683 for(core::map<u16, RemoteClient*>::Iterator
1684 i = m_clients.getIterator();
1685 i.atEnd() == false; i++)
1687 RemoteClient *client = i.getNode()->getValue();
1688 // Go through all known objects of client
1689 for(core::map<u16, bool>::Iterator
1690 i = client->m_known_objects.getIterator();
1691 i.atEnd()==false; i++)
1693 u16 id = i.getNode()->getKey();
1694 all_known_objects[id] = true;
1698 m_env->setKnownActiveObjects(whatever);
1704 Send object messages
1707 JMutexAutoLock envlock(m_env_mutex);
1708 JMutexAutoLock conlock(m_con_mutex);
1710 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1713 // Value = data sent by object
1714 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1716 // Get active object messages from environment
1719 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1723 core::list<ActiveObjectMessage>* message_list = NULL;
1724 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1725 n = buffered_messages.find(aom.id);
1728 message_list = new core::list<ActiveObjectMessage>;
1729 buffered_messages.insert(aom.id, message_list);
1733 message_list = n->getValue();
1735 message_list->push_back(aom);
1738 // Route data to every client
1739 for(core::map<u16, RemoteClient*>::Iterator
1740 i = m_clients.getIterator();
1741 i.atEnd()==false; i++)
1743 RemoteClient *client = i.getNode()->getValue();
1744 std::string reliable_data;
1745 std::string unreliable_data;
1746 // Go through all objects in message buffer
1747 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1748 j = buffered_messages.getIterator();
1749 j.atEnd()==false; j++)
1751 // If object is not known by client, skip it
1752 u16 id = j.getNode()->getKey();
1753 if(client->m_known_objects.find(id) == NULL)
1755 // Get message list of object
1756 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1757 // Go through every message
1758 for(core::list<ActiveObjectMessage>::Iterator
1759 k = list->begin(); k != list->end(); k++)
1761 // Compose the full new data with header
1762 ActiveObjectMessage aom = *k;
1763 std::string new_data;
1766 writeU16((u8*)&buf[0], aom.id);
1767 new_data.append(buf, 2);
1769 new_data += serializeString(aom.datastring);
1770 // Add data to buffer
1772 reliable_data += new_data;
1774 unreliable_data += new_data;
1778 reliable_data and unreliable_data are now ready.
1781 if(reliable_data.size() > 0)
1783 SharedBuffer<u8> reply(2 + reliable_data.size());
1784 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1785 memcpy((char*)&reply[2], reliable_data.c_str(),
1786 reliable_data.size());
1788 m_con.Send(client->peer_id, 0, reply, true);
1790 if(unreliable_data.size() > 0)
1792 SharedBuffer<u8> reply(2 + unreliable_data.size());
1793 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1794 memcpy((char*)&reply[2], unreliable_data.c_str(),
1795 unreliable_data.size());
1796 // Send as unreliable
1797 m_con.Send(client->peer_id, 0, reply, false);
1800 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1802 infostream<<"Server: Size of object message data: "
1803 <<"reliable: "<<reliable_data.size()
1804 <<", unreliable: "<<unreliable_data.size()
1809 // Clear buffered_messages
1810 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1811 i = buffered_messages.getIterator();
1812 i.atEnd()==false; i++)
1814 delete i.getNode()->getValue();
1818 } // enable_experimental
1821 Send queued-for-sending map edit events.
1824 // We will be accessing the environment and the connection
1825 JMutexAutoLock lock(m_env_mutex);
1826 JMutexAutoLock conlock(m_con_mutex);
1828 // Don't send too many at a time
1831 // Single change sending is disabled if queue size is not small
1832 bool disable_single_change_sending = false;
1833 if(m_unsent_map_edit_queue.size() >= 4)
1834 disable_single_change_sending = true;
1836 int event_count = m_unsent_map_edit_queue.size();
1838 // We'll log the amount of each
1841 while(m_unsent_map_edit_queue.size() != 0)
1843 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1845 // Players far away from the change are stored here.
1846 // Instead of sending the changes, MapBlocks are set not sent
1848 core::list<u16> far_players;
1850 if(event->type == MEET_ADDNODE)
1852 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1853 prof.add("MEET_ADDNODE", 1);
1854 if(disable_single_change_sending)
1855 sendAddNode(event->p, event->n, event->already_known_by_peer,
1858 sendAddNode(event->p, event->n, event->already_known_by_peer,
1861 else if(event->type == MEET_REMOVENODE)
1863 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1864 prof.add("MEET_REMOVENODE", 1);
1865 if(disable_single_change_sending)
1866 sendRemoveNode(event->p, event->already_known_by_peer,
1869 sendRemoveNode(event->p, event->already_known_by_peer,
1872 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1874 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1875 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1876 setBlockNotSent(event->p);
1878 else if(event->type == MEET_OTHER)
1880 infostream<<"Server: MEET_OTHER"<<std::endl;
1881 prof.add("MEET_OTHER", 1);
1882 for(core::map<v3s16, bool>::Iterator
1883 i = event->modified_blocks.getIterator();
1884 i.atEnd()==false; i++)
1886 v3s16 p = i.getNode()->getKey();
1892 prof.add("unknown", 1);
1893 infostream<<"WARNING: Server: Unknown MapEditEvent "
1894 <<((u32)event->type)<<std::endl;
1898 Set blocks not sent to far players
1900 if(far_players.size() > 0)
1902 // Convert list format to that wanted by SetBlocksNotSent
1903 core::map<v3s16, MapBlock*> modified_blocks2;
1904 for(core::map<v3s16, bool>::Iterator
1905 i = event->modified_blocks.getIterator();
1906 i.atEnd()==false; i++)
1908 v3s16 p = i.getNode()->getKey();
1909 modified_blocks2.insert(p,
1910 m_env->getMap().getBlockNoCreateNoEx(p));
1912 // Set blocks not sent
1913 for(core::list<u16>::Iterator
1914 i = far_players.begin();
1915 i != far_players.end(); i++)
1918 RemoteClient *client = getClient(peer_id);
1921 client->SetBlocksNotSent(modified_blocks2);
1927 /*// Don't send too many at a time
1929 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1933 if(event_count >= 5){
1934 infostream<<"Server: MapEditEvents:"<<std::endl;
1935 prof.print(infostream);
1936 } else if(event_count != 0){
1937 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1938 prof.print(verbosestream);
1944 Trigger emergethread (it somehow gets to a non-triggered but
1945 bysy state sometimes)
1948 float &counter = m_emergethread_trigger_timer;
1954 m_emergethread.trigger();
1956 // Update m_enable_rollback_recording here too
1957 m_enable_rollback_recording =
1958 g_settings->getBool("enable_rollback_recording");
1962 // Save map, players and auth stuff
1964 float &counter = m_savemap_timer;
1966 if(counter >= g_settings->getFloat("server_map_save_interval"))
1969 JMutexAutoLock lock(m_env_mutex);
1971 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1974 if(m_banmanager.isModified())
1975 m_banmanager.save();
1977 // Save changed parts of map
1978 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1981 m_env->serializePlayers(m_path_world);
1983 // Save environment metadata
1984 m_env->saveMeta(m_path_world);
1989 void Server::Receive()
1991 DSTACK(__FUNCTION_NAME);
1992 SharedBuffer<u8> data;
1997 JMutexAutoLock conlock(m_con_mutex);
1998 datasize = m_con.Receive(peer_id, data);
2001 // This has to be called so that the client list gets synced
2002 // with the peer list of the connection
2003 handlePeerChanges();
2005 ProcessData(*data, datasize, peer_id);
2007 catch(con::InvalidIncomingDataException &e)
2009 infostream<<"Server::Receive(): "
2010 "InvalidIncomingDataException: what()="
2011 <<e.what()<<std::endl;
2013 catch(con::PeerNotFoundException &e)
2015 //NOTE: This is not needed anymore
2017 // The peer has been disconnected.
2018 // Find the associated player and remove it.
2020 /*JMutexAutoLock envlock(m_env_mutex);
2022 infostream<<"ServerThread: peer_id="<<peer_id
2023 <<" has apparently closed connection. "
2024 <<"Removing player."<<std::endl;
2026 m_env->removePlayer(peer_id);*/
2030 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
2032 DSTACK(__FUNCTION_NAME);
2033 // Environment is locked first.
2034 JMutexAutoLock envlock(m_env_mutex);
2035 JMutexAutoLock conlock(m_con_mutex);
2037 ScopeProfiler sp(g_profiler, "Server::ProcessData");
2040 Address address = m_con.GetPeerAddress(peer_id);
2041 std::string addr_s = address.serializeString();
2043 // drop player if is ip is banned
2044 if(m_banmanager.isIpBanned(addr_s)){
2045 infostream<<"Server: A banned client tried to connect from "
2046 <<addr_s<<"; banned name was "
2047 <<m_banmanager.getBanName(addr_s)<<std::endl;
2048 // This actually doesn't seem to transfer to the client
2049 SendAccessDenied(m_con, peer_id,
2050 L"Your ip is banned. Banned name was "
2051 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
2052 m_con.DeletePeer(peer_id);
2056 catch(con::PeerNotFoundException &e)
2058 infostream<<"Server::ProcessData(): Cancelling: peer "
2059 <<peer_id<<" not found"<<std::endl;
2063 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
2065 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
2073 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
2075 if(command == TOSERVER_INIT)
2077 // [0] u16 TOSERVER_INIT
2078 // [2] u8 SER_FMT_VER_HIGHEST
2079 // [3] u8[20] player_name
2080 // [23] u8[28] password <--- can be sent without this, from old versions
2082 if(datasize < 2+1+PLAYERNAME_SIZE)
2085 verbosestream<<"Server: Got TOSERVER_INIT from "
2086 <<peer_id<<std::endl;
2088 // First byte after command is maximum supported
2089 // serialization version
2090 u8 client_max = data[2];
2091 u8 our_max = SER_FMT_VER_HIGHEST;
2092 // Use the highest version supported by both
2093 u8 deployed = core::min_(client_max, our_max);
2094 // If it's lower than the lowest supported, give up.
2095 if(deployed < SER_FMT_VER_LOWEST)
2096 deployed = SER_FMT_VER_INVALID;
2098 //peer->serialization_version = deployed;
2099 getClient(peer_id)->pending_serialization_version = deployed;
2101 if(deployed == SER_FMT_VER_INVALID)
2103 actionstream<<"Server: A mismatched client tried to connect from "
2104 <<addr_s<<std::endl;
2105 infostream<<"Server: Cannot negotiate "
2106 "serialization version with peer "
2107 <<peer_id<<std::endl;
2108 SendAccessDenied(m_con, peer_id, std::wstring(
2109 L"Your client's version is not supported.\n"
2110 L"Server version is ")
2111 + narrow_to_wide(VERSION_STRING) + L"."
2117 Read and check network protocol version
2120 u16 min_net_proto_version = 0;
2121 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2122 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2124 // Use same version as minimum and maximum if maximum version field
2125 // doesn't exist (backwards compatibility)
2126 u16 max_net_proto_version = min_net_proto_version;
2127 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
2128 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
2130 // Start with client's maximum version
2131 u16 net_proto_version = max_net_proto_version;
2133 // Figure out a working version if it is possible at all
2134 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
2135 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
2137 // If maximum is larger than our maximum, go with our maximum
2138 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2139 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
2140 // Else go with client's maximum
2142 net_proto_version = max_net_proto_version;
2145 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
2146 <<min_net_proto_version<<", max: "<<max_net_proto_version
2147 <<", chosen: "<<net_proto_version<<std::endl;
2149 getClient(peer_id)->net_proto_version = net_proto_version;
2151 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
2152 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2154 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
2156 SendAccessDenied(m_con, peer_id, std::wstring(
2157 L"Your client's version is not supported.\n"
2158 L"Server version is ")
2159 + narrow_to_wide(VERSION_STRING) + L",\n"
2160 + L"server's PROTOCOL_VERSION is "
2161 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
2163 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
2164 + L", client's PROTOCOL_VERSION is "
2165 + narrow_to_wide(itos(min_net_proto_version))
2167 + narrow_to_wide(itos(max_net_proto_version))
2172 if(g_settings->getBool("strict_protocol_version_checking"))
2174 if(net_proto_version != LATEST_PROTOCOL_VERSION)
2176 actionstream<<"Server: A mismatched (strict) client tried to "
2177 <<"connect from "<<addr_s<<std::endl;
2178 SendAccessDenied(m_con, peer_id, std::wstring(
2179 L"Your client's version is not supported.\n"
2180 L"Server version is ")
2181 + narrow_to_wide(VERSION_STRING) + L",\n"
2182 + L"server's PROTOCOL_VERSION (strict) is "
2183 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
2184 + L", client's PROTOCOL_VERSION is "
2185 + narrow_to_wide(itos(min_net_proto_version))
2187 + narrow_to_wide(itos(max_net_proto_version))
2198 char playername[PLAYERNAME_SIZE];
2199 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2201 playername[i] = data[3+i];
2203 playername[PLAYERNAME_SIZE-1] = 0;
2205 if(playername[0]=='\0')
2207 actionstream<<"Server: Player with an empty name "
2208 <<"tried to connect from "<<addr_s<<std::endl;
2209 SendAccessDenied(m_con, peer_id,
2214 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2216 actionstream<<"Server: Player with an invalid name "
2217 <<"tried to connect from "<<addr_s<<std::endl;
2218 SendAccessDenied(m_con, peer_id,
2219 L"Name contains unallowed characters");
2223 infostream<<"Server: New connection: \""<<playername<<"\" from "
2224 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2227 char given_password[PASSWORD_SIZE];
2228 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2230 // old version - assume blank password
2231 given_password[0] = 0;
2235 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2237 given_password[i] = data[23+i];
2239 given_password[PASSWORD_SIZE-1] = 0;
2242 if(!base64_is_valid(given_password)){
2243 infostream<<"Server: "<<playername
2244 <<" supplied invalid password hash"<<std::endl;
2245 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2249 std::string checkpwd; // Password hash to check against
2250 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2252 // If no authentication info exists for user, create it
2254 if(!isSingleplayer() &&
2255 g_settings->getBool("disallow_empty_password") &&
2256 std::string(given_password) == ""){
2257 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2258 L"disallowed. Set a password and try again.");
2261 std::wstring raw_default_password =
2262 narrow_to_wide(g_settings->get("default_password"));
2263 std::string initial_password =
2264 translatePassword(playername, raw_default_password);
2266 // If default_password is empty, allow any initial password
2267 if (raw_default_password.length() == 0)
2268 initial_password = given_password;
2270 scriptapi_create_auth(m_lua, playername, initial_password);
2273 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2276 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2280 if(given_password != checkpwd){
2281 infostream<<"Server: peer_id="<<peer_id
2282 <<": supplied invalid password for "
2283 <<playername<<std::endl;
2284 SendAccessDenied(m_con, peer_id, L"Invalid password");
2288 // Do not allow multiple players in simple singleplayer mode.
2289 // This isn't a perfect way to do it, but will suffice for now.
2290 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2291 infostream<<"Server: Not allowing another client to connect in"
2292 <<" simple singleplayer mode"<<std::endl;
2293 SendAccessDenied(m_con, peer_id,
2294 L"Running in simple singleplayer mode.");
2298 // Enforce user limit.
2299 // Don't enforce for users that have some admin right
2300 if(m_clients.size() >= g_settings->getU16("max_users") &&
2301 !checkPriv(playername, "server") &&
2302 !checkPriv(playername, "ban") &&
2303 !checkPriv(playername, "privs") &&
2304 !checkPriv(playername, "password") &&
2305 playername != g_settings->get("name"))
2307 actionstream<<"Server: "<<playername<<" tried to join, but there"
2308 <<" are already max_users="
2309 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2310 SendAccessDenied(m_con, peer_id, L"Too many users.");
2315 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2317 // If failed, cancel
2318 if(playersao == NULL)
2320 errorstream<<"Server: peer_id="<<peer_id
2321 <<": failed to emerge player"<<std::endl;
2326 Answer with a TOCLIENT_INIT
2329 SharedBuffer<u8> reply(2+1+6+8+4);
2330 writeU16(&reply[0], TOCLIENT_INIT);
2331 writeU8(&reply[2], deployed);
2332 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2333 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2334 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2337 m_con.Send(peer_id, 0, reply, true);
2341 Send complete position information
2343 SendMovePlayer(peer_id);
2348 if(command == TOSERVER_INIT2)
2350 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2351 <<peer_id<<std::endl;
2353 Player *player = m_env->getPlayer(peer_id);
2355 verbosestream<<"Server: TOSERVER_INIT2: "
2356 <<"Player not found; ignoring."<<std::endl;
2360 RemoteClient *client = getClient(peer_id);
2361 client->serialization_version =
2362 getClient(peer_id)->pending_serialization_version;
2365 Send some initialization data
2368 infostream<<"Server: Sending content to "
2369 <<getPlayerName(peer_id)<<std::endl;
2371 // Send player movement settings
2372 SendMovement(m_con, peer_id);
2374 // Send item definitions
2375 SendItemDef(m_con, peer_id, m_itemdef);
2377 // Send node definitions
2378 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2380 // Send media announcement
2381 sendMediaAnnouncement(peer_id);
2384 SendPlayerPrivileges(peer_id);
2386 // Send inventory formspec
2387 SendPlayerInventoryFormspec(peer_id);
2390 UpdateCrafting(peer_id);
2391 SendInventory(peer_id);
2394 if(g_settings->getBool("enable_damage"))
2395 SendPlayerHP(peer_id);
2397 // Send detached inventories
2398 sendDetachedInventories(peer_id);
2400 // Show death screen if necessary
2402 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2406 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2407 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2408 m_con.Send(peer_id, 0, data, true);
2411 // Note things in chat if not in simple singleplayer mode
2412 if(!m_simple_singleplayer_mode)
2414 // Send information about server to player in chat
2415 SendChatMessage(peer_id, getStatusString());
2417 // Send information about joining in chat
2419 std::wstring name = L"unknown";
2420 Player *player = m_env->getPlayer(peer_id);
2422 name = narrow_to_wide(player->getName());
2424 std::wstring message;
2427 message += L" joined the game.";
2428 BroadcastChatMessage(message);
2432 // Warnings about protocol version can be issued here
2433 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2435 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2436 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2443 std::ostringstream os(std::ios_base::binary);
2444 for(core::map<u16, RemoteClient*>::Iterator
2445 i = m_clients.getIterator();
2446 i.atEnd() == false; i++)
2448 RemoteClient *client = i.getNode()->getValue();
2449 assert(client->peer_id == i.getNode()->getKey());
2450 if(client->serialization_version == SER_FMT_VER_INVALID)
2453 Player *player = m_env->getPlayer(client->peer_id);
2456 // Get name of player
2457 os<<player->getName()<<" ";
2460 actionstream<<player->getName()<<" joins game. List of players: "
2461 <<os.str()<<std::endl;
2467 if(peer_ser_ver == SER_FMT_VER_INVALID)
2469 infostream<<"Server::ProcessData(): Cancelling: Peer"
2470 " serialization format invalid or not initialized."
2471 " Skipping incoming command="<<command<<std::endl;
2475 Player *player = m_env->getPlayer(peer_id);
2477 infostream<<"Server::ProcessData(): Cancelling: "
2478 "No player for peer_id="<<peer_id
2483 PlayerSAO *playersao = player->getPlayerSAO();
2484 if(playersao == NULL){
2485 infostream<<"Server::ProcessData(): Cancelling: "
2486 "No player object for peer_id="<<peer_id
2491 if(command == TOSERVER_PLAYERPOS)
2493 if(datasize < 2+12+12+4+4)
2497 v3s32 ps = readV3S32(&data[start+2]);
2498 v3s32 ss = readV3S32(&data[start+2+12]);
2499 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2500 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2502 if(datasize >= 2+12+12+4+4+4)
2503 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2504 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2505 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2506 pitch = wrapDegrees(pitch);
2507 yaw = wrapDegrees(yaw);
2509 player->setPosition(position);
2510 player->setSpeed(speed);
2511 player->setPitch(pitch);
2512 player->setYaw(yaw);
2513 player->keyPressed=keyPressed;
2514 player->control.up = (bool)(keyPressed&1);
2515 player->control.down = (bool)(keyPressed&2);
2516 player->control.left = (bool)(keyPressed&4);
2517 player->control.right = (bool)(keyPressed&8);
2518 player->control.jump = (bool)(keyPressed&16);
2519 player->control.aux1 = (bool)(keyPressed&32);
2520 player->control.sneak = (bool)(keyPressed&64);
2521 player->control.LMB = (bool)(keyPressed&128);
2522 player->control.RMB = (bool)(keyPressed&256);
2524 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2525 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2526 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2528 else if(command == TOSERVER_GOTBLOCKS)
2541 u16 count = data[2];
2542 for(u16 i=0; i<count; i++)
2544 if((s16)datasize < 2+1+(i+1)*6)
2545 throw con::InvalidIncomingDataException
2546 ("GOTBLOCKS length is too short");
2547 v3s16 p = readV3S16(&data[2+1+i*6]);
2548 /*infostream<<"Server: GOTBLOCKS ("
2549 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2550 RemoteClient *client = getClient(peer_id);
2551 client->GotBlock(p);
2554 else if(command == TOSERVER_DELETEDBLOCKS)
2567 u16 count = data[2];
2568 for(u16 i=0; i<count; i++)
2570 if((s16)datasize < 2+1+(i+1)*6)
2571 throw con::InvalidIncomingDataException
2572 ("DELETEDBLOCKS length is too short");
2573 v3s16 p = readV3S16(&data[2+1+i*6]);
2574 /*infostream<<"Server: DELETEDBLOCKS ("
2575 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2576 RemoteClient *client = getClient(peer_id);
2577 client->SetBlockNotSent(p);
2580 else if(command == TOSERVER_CLICK_OBJECT)
2582 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2585 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2587 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2590 else if(command == TOSERVER_GROUND_ACTION)
2592 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2596 else if(command == TOSERVER_RELEASE)
2598 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2601 else if(command == TOSERVER_SIGNTEXT)
2603 infostream<<"Server: SIGNTEXT not supported anymore"
2607 else if(command == TOSERVER_SIGNNODETEXT)
2609 infostream<<"Server: SIGNNODETEXT not supported anymore"
2613 else if(command == TOSERVER_INVENTORY_ACTION)
2615 // Strip command and create a stream
2616 std::string datastring((char*)&data[2], datasize-2);
2617 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2618 std::istringstream is(datastring, std::ios_base::binary);
2620 InventoryAction *a = InventoryAction::deSerialize(is);
2623 infostream<<"TOSERVER_INVENTORY_ACTION: "
2624 <<"InventoryAction::deSerialize() returned NULL"
2629 // If something goes wrong, this player is to blame
2630 RollbackScopeActor rollback_scope(m_rollback,
2631 std::string("player:")+player->getName());
2634 Note: Always set inventory not sent, to repair cases
2635 where the client made a bad prediction.
2639 Handle restrictions and special cases of the move action
2641 if(a->getType() == IACTION_MOVE)
2643 IMoveAction *ma = (IMoveAction*)a;
2645 ma->from_inv.applyCurrentPlayer(player->getName());
2646 ma->to_inv.applyCurrentPlayer(player->getName());
2648 setInventoryModified(ma->from_inv);
2649 setInventoryModified(ma->to_inv);
2651 bool from_inv_is_current_player =
2652 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2653 (ma->from_inv.name == player->getName());
2655 bool to_inv_is_current_player =
2656 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2657 (ma->to_inv.name == player->getName());
2660 Disable moving items out of craftpreview
2662 if(ma->from_list == "craftpreview")
2664 infostream<<"Ignoring IMoveAction from "
2665 <<(ma->from_inv.dump())<<":"<<ma->from_list
2666 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2667 <<" because src is "<<ma->from_list<<std::endl;
2673 Disable moving items into craftresult and craftpreview
2675 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2677 infostream<<"Ignoring IMoveAction from "
2678 <<(ma->from_inv.dump())<<":"<<ma->from_list
2679 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2680 <<" because dst is "<<ma->to_list<<std::endl;
2685 // Disallow moving items in elsewhere than player's inventory
2686 // if not allowed to interact
2687 if(!checkPriv(player->getName(), "interact") &&
2688 (!from_inv_is_current_player ||
2689 !to_inv_is_current_player))
2691 infostream<<"Cannot move outside of player's inventory: "
2692 <<"No interact privilege"<<std::endl;
2698 Handle restrictions and special cases of the drop action
2700 else if(a->getType() == IACTION_DROP)
2702 IDropAction *da = (IDropAction*)a;
2704 da->from_inv.applyCurrentPlayer(player->getName());
2706 setInventoryModified(da->from_inv);
2708 // Disallow dropping items if not allowed to interact
2709 if(!checkPriv(player->getName(), "interact"))
2716 Handle restrictions and special cases of the craft action
2718 else if(a->getType() == IACTION_CRAFT)
2720 ICraftAction *ca = (ICraftAction*)a;
2722 ca->craft_inv.applyCurrentPlayer(player->getName());
2724 setInventoryModified(ca->craft_inv);
2726 //bool craft_inv_is_current_player =
2727 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2728 // (ca->craft_inv.name == player->getName());
2730 // Disallow crafting if not allowed to interact
2731 if(!checkPriv(player->getName(), "interact"))
2733 infostream<<"Cannot craft: "
2734 <<"No interact privilege"<<std::endl;
2741 a->apply(this, playersao, this);
2745 else if(command == TOSERVER_CHAT_MESSAGE)
2753 std::string datastring((char*)&data[2], datasize-2);
2754 std::istringstream is(datastring, std::ios_base::binary);
2757 is.read((char*)buf, 2);
2758 u16 len = readU16(buf);
2760 std::wstring message;
2761 for(u16 i=0; i<len; i++)
2763 is.read((char*)buf, 2);
2764 message += (wchar_t)readU16(buf);
2767 // If something goes wrong, this player is to blame
2768 RollbackScopeActor rollback_scope(m_rollback,
2769 std::string("player:")+player->getName());
2771 // Get player name of this client
2772 std::wstring name = narrow_to_wide(player->getName());
2775 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2776 wide_to_narrow(message));
2777 // If script ate the message, don't proceed
2781 // Line to send to players
2783 // Whether to send to the player that sent the line
2784 bool send_to_sender = false;
2785 // Whether to send to other players
2786 bool send_to_others = false;
2788 // Commands are implemented in Lua, so only catch invalid
2789 // commands that were not "eaten" and send an error back
2790 if(message[0] == L'/')
2792 message = message.substr(1);
2793 send_to_sender = true;
2794 if(message.length() == 0)
2795 line += L"-!- Empty command";
2797 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2801 if(checkPriv(player->getName(), "shout")){
2806 send_to_others = true;
2808 line += L"-!- You don't have permission to shout.";
2809 send_to_sender = true;
2816 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2819 Send the message to clients
2821 for(core::map<u16, RemoteClient*>::Iterator
2822 i = m_clients.getIterator();
2823 i.atEnd() == false; i++)
2825 // Get client and check that it is valid
2826 RemoteClient *client = i.getNode()->getValue();
2827 assert(client->peer_id == i.getNode()->getKey());
2828 if(client->serialization_version == SER_FMT_VER_INVALID)
2832 bool sender_selected = (peer_id == client->peer_id);
2833 if(sender_selected == true && send_to_sender == false)
2835 if(sender_selected == false && send_to_others == false)
2838 SendChatMessage(client->peer_id, line);
2842 else if(command == TOSERVER_DAMAGE)
2844 std::string datastring((char*)&data[2], datasize-2);
2845 std::istringstream is(datastring, std::ios_base::binary);
2846 u8 damage = readU8(is);
2848 if(g_settings->getBool("enable_damage"))
2850 actionstream<<player->getName()<<" damaged by "
2851 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2854 playersao->setHP(playersao->getHP() - damage);
2856 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2859 if(playersao->m_hp_not_sent)
2860 SendPlayerHP(peer_id);
2863 else if(command == TOSERVER_PASSWORD)
2866 [0] u16 TOSERVER_PASSWORD
2867 [2] u8[28] old password
2868 [30] u8[28] new password
2871 if(datasize != 2+PASSWORD_SIZE*2)
2873 /*char password[PASSWORD_SIZE];
2874 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2875 password[i] = data[2+i];
2876 password[PASSWORD_SIZE-1] = 0;*/
2878 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2886 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2888 char c = data[2+PASSWORD_SIZE+i];
2894 if(!base64_is_valid(newpwd)){
2895 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2896 // Wrong old password supplied!!
2897 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2901 infostream<<"Server: Client requests a password change from "
2902 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2904 std::string playername = player->getName();
2906 std::string checkpwd;
2907 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2909 if(oldpwd != checkpwd)
2911 infostream<<"Server: invalid old password"<<std::endl;
2912 // Wrong old password supplied!!
2913 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2917 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2919 actionstream<<player->getName()<<" changes password"<<std::endl;
2920 SendChatMessage(peer_id, L"Password change successful.");
2922 actionstream<<player->getName()<<" tries to change password but "
2923 <<"it fails"<<std::endl;
2924 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2927 else if(command == TOSERVER_PLAYERITEM)
2932 u16 item = readU16(&data[2]);
2933 playersao->setWieldIndex(item);
2935 else if(command == TOSERVER_RESPAWN)
2937 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2940 RespawnPlayer(peer_id);
2942 actionstream<<player->getName()<<" respawns at "
2943 <<PP(player->getPosition()/BS)<<std::endl;
2945 // ActiveObject is added to environment in AsyncRunStep after
2946 // the previous addition has been succesfully removed
2948 else if(command == TOSERVER_REQUEST_MEDIA) {
2949 std::string datastring((char*)&data[2], datasize-2);
2950 std::istringstream is(datastring, std::ios_base::binary);
2952 core::list<MediaRequest> tosend;
2953 u16 numfiles = readU16(is);
2955 infostream<<"Sending "<<numfiles<<" files to "
2956 <<getPlayerName(peer_id)<<std::endl;
2957 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2959 for(int i = 0; i < numfiles; i++) {
2960 std::string name = deSerializeString(is);
2961 tosend.push_back(MediaRequest(name));
2962 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2966 sendRequestedMedia(peer_id, tosend);
2968 // Now the client should know about everything
2969 // (definitions and files)
2970 getClient(peer_id)->definitions_sent = true;
2972 else if(command == TOSERVER_RECEIVED_MEDIA) {
2973 getClient(peer_id)->definitions_sent = true;
2975 else if(command == TOSERVER_INTERACT)
2977 std::string datastring((char*)&data[2], datasize-2);
2978 std::istringstream is(datastring, std::ios_base::binary);
2984 [5] u32 length of the next item
2985 [9] serialized PointedThing
2987 0: start digging (from undersurface) or use
2988 1: stop digging (all parameters ignored)
2989 2: digging completed
2990 3: place block or item (to abovesurface)
2993 u8 action = readU8(is);
2994 u16 item_i = readU16(is);
2995 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2996 PointedThing pointed;
2997 pointed.deSerialize(tmp_is);
2999 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
3000 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
3004 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
3005 <<" tried to interact, but is dead!"<<std::endl;
3009 v3f player_pos = playersao->getLastGoodPosition();
3011 // Update wielded item
3012 playersao->setWieldIndex(item_i);
3014 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
3015 v3s16 p_under = pointed.node_undersurface;
3016 v3s16 p_above = pointed.node_abovesurface;
3018 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
3019 ServerActiveObject *pointed_object = NULL;
3020 if(pointed.type == POINTEDTHING_OBJECT)
3022 pointed_object = m_env->getActiveObject(pointed.object_id);
3023 if(pointed_object == NULL)
3025 verbosestream<<"TOSERVER_INTERACT: "
3026 "pointed object is NULL"<<std::endl;
3032 v3f pointed_pos_under = player_pos;
3033 v3f pointed_pos_above = player_pos;
3034 if(pointed.type == POINTEDTHING_NODE)
3036 pointed_pos_under = intToFloat(p_under, BS);
3037 pointed_pos_above = intToFloat(p_above, BS);
3039 else if(pointed.type == POINTEDTHING_OBJECT)
3041 pointed_pos_under = pointed_object->getBasePosition();
3042 pointed_pos_above = pointed_pos_under;
3046 Check that target is reasonably close
3047 (only when digging or placing things)
3049 if(action == 0 || action == 2 || action == 3)
3051 float d = player_pos.getDistanceFrom(pointed_pos_under);
3052 float max_d = BS * 14; // Just some large enough value
3054 actionstream<<"Player "<<player->getName()
3055 <<" tried to access "<<pointed.dump()
3057 <<"d="<<d<<", max_d="<<max_d
3058 <<". ignoring."<<std::endl;
3059 // Re-send block to revert change on client-side
3060 RemoteClient *client = getClient(peer_id);
3061 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3062 client->SetBlockNotSent(blockpos);
3069 Make sure the player is allowed to do it
3071 if(!checkPriv(player->getName(), "interact"))
3073 actionstream<<player->getName()<<" attempted to interact with "
3074 <<pointed.dump()<<" without 'interact' privilege"
3076 // Re-send block to revert change on client-side
3077 RemoteClient *client = getClient(peer_id);
3078 // Digging completed -> under
3080 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3081 client->SetBlockNotSent(blockpos);
3083 // Placement -> above
3085 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3086 client->SetBlockNotSent(blockpos);
3092 If something goes wrong, this player is to blame
3094 RollbackScopeActor rollback_scope(m_rollback,
3095 std::string("player:")+player->getName());
3098 0: start digging or punch object
3102 if(pointed.type == POINTEDTHING_NODE)
3105 NOTE: This can be used in the future to check if
3106 somebody is cheating, by checking the timing.
3108 MapNode n(CONTENT_IGNORE);
3111 n = m_env->getMap().getNode(p_under);
3113 catch(InvalidPositionException &e)
3115 infostream<<"Server: Not punching: Node not found."
3116 <<" Adding block to emerge queue."
3118 m_emerge_queue.addBlock(peer_id,
3119 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3121 if(n.getContent() != CONTENT_IGNORE)
3122 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3124 playersao->noCheatDigStart(p_under);
3126 else if(pointed.type == POINTEDTHING_OBJECT)
3128 // Skip if object has been removed
3129 if(pointed_object->m_removed)
3132 actionstream<<player->getName()<<" punches object "
3133 <<pointed.object_id<<": "
3134 <<pointed_object->getDescription()<<std::endl;
3136 ItemStack punchitem = playersao->getWieldedItem();
3137 ToolCapabilities toolcap =
3138 punchitem.getToolCapabilities(m_itemdef);
3139 v3f dir = (pointed_object->getBasePosition() -
3140 (player->getPosition() + player->getEyeOffset())
3142 float time_from_last_punch =
3143 playersao->resetTimeFromLastPunch();
3144 pointed_object->punch(dir, &toolcap, playersao,
3145 time_from_last_punch);
3153 else if(action == 1)
3158 2: Digging completed
3160 else if(action == 2)
3162 // Only digging of nodes
3163 if(pointed.type == POINTEDTHING_NODE)
3165 MapNode n(CONTENT_IGNORE);
3168 n = m_env->getMap().getNode(p_under);
3170 catch(InvalidPositionException &e)
3172 infostream<<"Server: Not finishing digging: Node not found."
3173 <<" Adding block to emerge queue."
3175 m_emerge_queue.addBlock(peer_id,
3176 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3179 /* Cheat prevention */
3180 bool is_valid_dig = true;
3181 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3183 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3184 float nocheat_t = playersao->getNoCheatDigTime();
3185 playersao->noCheatDigEnd();
3186 // If player didn't start digging this, ignore dig
3187 if(nocheat_p != p_under){
3188 infostream<<"Server: NoCheat: "<<player->getName()
3189 <<" started digging "
3190 <<PP(nocheat_p)<<" and completed digging "
3191 <<PP(p_under)<<"; not digging."<<std::endl;
3192 is_valid_dig = false;
3194 // Get player's wielded item
3195 ItemStack playeritem;
3196 InventoryList *mlist = playersao->getInventory()->getList("main");
3198 playeritem = mlist->getItem(playersao->getWieldIndex());
3199 ToolCapabilities playeritem_toolcap =
3200 playeritem.getToolCapabilities(m_itemdef);
3201 // Get diggability and expected digging time
3202 DigParams params = getDigParams(m_nodedef->get(n).groups,
3203 &playeritem_toolcap);
3204 // If can't dig, try hand
3205 if(!params.diggable){
3206 const ItemDefinition &hand = m_itemdef->get("");
3207 const ToolCapabilities *tp = hand.tool_capabilities;
3209 params = getDigParams(m_nodedef->get(n).groups, tp);
3211 // If can't dig, ignore dig
3212 if(!params.diggable){
3213 infostream<<"Server: NoCheat: "<<player->getName()
3214 <<" completed digging "<<PP(p_under)
3215 <<", which is not diggable with tool. not digging."
3217 is_valid_dig = false;
3219 // If time is considerably too short, ignore dig
3220 // Check time only for medium and slow timed digs
3221 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3222 infostream<<"Server: NoCheat: "<<player->getName()
3223 <<" completed digging "
3224 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3225 <<params.time<<"s; not digging."<<std::endl;
3226 is_valid_dig = false;
3230 /* Actually dig node */
3232 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3233 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3235 // Send unusual result (that is, node not being removed)
3236 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3238 // Re-send block to revert change on client-side
3239 RemoteClient *client = getClient(peer_id);
3240 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3241 client->SetBlockNotSent(blockpos);
3247 3: place block or right-click object
3249 else if(action == 3)
3251 ItemStack item = playersao->getWieldedItem();
3253 // Reset build time counter
3254 if(pointed.type == POINTEDTHING_NODE &&
3255 item.getDefinition(m_itemdef).type == ITEM_NODE)
3256 getClient(peer_id)->m_time_from_building = 0.0;
3258 if(pointed.type == POINTEDTHING_OBJECT)
3260 // Right click object
3262 // Skip if object has been removed
3263 if(pointed_object->m_removed)
3266 actionstream<<player->getName()<<" right-clicks object "
3267 <<pointed.object_id<<": "
3268 <<pointed_object->getDescription()<<std::endl;
3271 pointed_object->rightClick(playersao);
3273 else if(scriptapi_item_on_place(m_lua,
3274 item, playersao, pointed))
3276 // Placement was handled in lua
3278 // Apply returned ItemStack
3279 playersao->setWieldedItem(item);
3282 // If item has node placement prediction, always send the above
3283 // node to make sure the client knows what exactly happened
3284 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3285 RemoteClient *client = getClient(peer_id);
3286 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3287 client->SetBlockNotSent(blockpos);
3294 else if(action == 4)
3296 ItemStack item = playersao->getWieldedItem();
3298 actionstream<<player->getName()<<" uses "<<item.name
3299 <<", pointing at "<<pointed.dump()<<std::endl;
3301 if(scriptapi_item_on_use(m_lua,
3302 item, playersao, pointed))
3304 // Apply returned ItemStack
3305 playersao->setWieldedItem(item);
3312 Catch invalid actions
3316 infostream<<"WARNING: Server: Invalid action "
3317 <<action<<std::endl;
3320 else if(command == TOSERVER_REMOVED_SOUNDS)
3322 std::string datastring((char*)&data[2], datasize-2);
3323 std::istringstream is(datastring, std::ios_base::binary);
3325 int num = readU16(is);
3326 for(int k=0; k<num; k++){
3327 s32 id = readS32(is);
3328 std::map<s32, ServerPlayingSound>::iterator i =
3329 m_playing_sounds.find(id);
3330 if(i == m_playing_sounds.end())
3332 ServerPlayingSound &psound = i->second;
3333 psound.clients.erase(peer_id);
3334 if(psound.clients.size() == 0)
3335 m_playing_sounds.erase(i++);
3338 else if(command == TOSERVER_NODEMETA_FIELDS)
3340 std::string datastring((char*)&data[2], datasize-2);
3341 std::istringstream is(datastring, std::ios_base::binary);
3343 v3s16 p = readV3S16(is);
3344 std::string formname = deSerializeString(is);
3345 int num = readU16(is);
3346 std::map<std::string, std::string> fields;
3347 for(int k=0; k<num; k++){
3348 std::string fieldname = deSerializeString(is);
3349 std::string fieldvalue = deSerializeLongString(is);
3350 fields[fieldname] = fieldvalue;
3353 // If something goes wrong, this player is to blame
3354 RollbackScopeActor rollback_scope(m_rollback,
3355 std::string("player:")+player->getName());
3357 // Check the target node for rollback data; leave others unnoticed
3358 RollbackNode rn_old(&m_env->getMap(), p, this);
3360 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3363 // Report rollback data
3364 RollbackNode rn_new(&m_env->getMap(), p, this);
3365 if(rollback() && rn_new != rn_old){
3366 RollbackAction action;
3367 action.setSetNode(p, rn_old, rn_new);
3368 rollback()->reportAction(action);
3371 else if(command == TOSERVER_INVENTORY_FIELDS)
3373 std::string datastring((char*)&data[2], datasize-2);
3374 std::istringstream is(datastring, std::ios_base::binary);
3376 std::string formname = deSerializeString(is);
3377 int num = readU16(is);
3378 std::map<std::string, std::string> fields;
3379 for(int k=0; k<num; k++){
3380 std::string fieldname = deSerializeString(is);
3381 std::string fieldvalue = deSerializeLongString(is);
3382 fields[fieldname] = fieldvalue;
3385 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3389 infostream<<"Server::ProcessData(): Ignoring "
3390 "unknown command "<<command<<std::endl;
3394 catch(SendFailedException &e)
3396 errorstream<<"Server::ProcessData(): SendFailedException: "
3402 void Server::onMapEditEvent(MapEditEvent *event)
3404 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3405 if(m_ignore_map_edit_events)
3407 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3409 MapEditEvent *e = event->clone();
3410 m_unsent_map_edit_queue.push_back(e);
3413 Inventory* Server::getInventory(const InventoryLocation &loc)
3416 case InventoryLocation::UNDEFINED:
3419 case InventoryLocation::CURRENT_PLAYER:
3422 case InventoryLocation::PLAYER:
3424 Player *player = m_env->getPlayer(loc.name.c_str());
3427 PlayerSAO *playersao = player->getPlayerSAO();
3430 return playersao->getInventory();
3433 case InventoryLocation::NODEMETA:
3435 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3438 return meta->getInventory();
3441 case InventoryLocation::DETACHED:
3443 if(m_detached_inventories.count(loc.name) == 0)
3445 return m_detached_inventories[loc.name];
3453 void Server::setInventoryModified(const InventoryLocation &loc)
3456 case InventoryLocation::UNDEFINED:
3459 case InventoryLocation::PLAYER:
3461 Player *player = m_env->getPlayer(loc.name.c_str());
3464 PlayerSAO *playersao = player->getPlayerSAO();
3467 playersao->m_inventory_not_sent = true;
3468 playersao->m_wielded_item_not_sent = true;
3471 case InventoryLocation::NODEMETA:
3473 v3s16 blockpos = getNodeBlockPos(loc.p);
3475 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3477 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3479 setBlockNotSent(blockpos);
3482 case InventoryLocation::DETACHED:
3484 sendDetachedInventoryToAll(loc.name);
3492 core::list<PlayerInfo> Server::getPlayerInfo()
3494 DSTACK(__FUNCTION_NAME);
3495 JMutexAutoLock envlock(m_env_mutex);
3496 JMutexAutoLock conlock(m_con_mutex);
3498 core::list<PlayerInfo> list;
3500 core::list<Player*> players = m_env->getPlayers();
3502 core::list<Player*>::Iterator i;
3503 for(i = players.begin();
3504 i != players.end(); i++)
3508 Player *player = *i;
3511 // Copy info from connection to info struct
3512 info.id = player->peer_id;
3513 info.address = m_con.GetPeerAddress(player->peer_id);
3514 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3516 catch(con::PeerNotFoundException &e)
3518 // Set dummy peer info
3520 info.address = Address(0,0,0,0,0);
3524 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3525 info.position = player->getPosition();
3527 list.push_back(info);
3534 void Server::peerAdded(con::Peer *peer)
3536 DSTACK(__FUNCTION_NAME);
3537 verbosestream<<"Server::peerAdded(): peer->id="
3538 <<peer->id<<std::endl;
3541 c.type = PEER_ADDED;
3542 c.peer_id = peer->id;
3544 m_peer_change_queue.push_back(c);
3547 void Server::deletingPeer(con::Peer *peer, bool timeout)
3549 DSTACK(__FUNCTION_NAME);
3550 verbosestream<<"Server::deletingPeer(): peer->id="
3551 <<peer->id<<", timeout="<<timeout<<std::endl;
3554 c.type = PEER_REMOVED;
3555 c.peer_id = peer->id;
3556 c.timeout = timeout;
3557 m_peer_change_queue.push_back(c);
3564 void Server::SendMovement(con::Connection &con, u16 peer_id)
3566 DSTACK(__FUNCTION_NAME);
3567 std::ostringstream os(std::ios_base::binary);
3569 writeU16(os, TOCLIENT_MOVEMENT);
3570 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3571 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3572 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3573 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3574 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3575 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3576 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3577 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3578 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3579 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3580 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3581 writeF1000(os, g_settings->getFloat("movement_gravity"));
3584 std::string s = os.str();
3585 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3587 con.Send(peer_id, 0, data, true);
3590 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3592 DSTACK(__FUNCTION_NAME);
3593 std::ostringstream os(std::ios_base::binary);
3595 writeU16(os, TOCLIENT_HP);
3599 std::string s = os.str();
3600 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3602 con.Send(peer_id, 0, data, true);
3605 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3606 const std::wstring &reason)
3608 DSTACK(__FUNCTION_NAME);
3609 std::ostringstream os(std::ios_base::binary);
3611 writeU16(os, TOCLIENT_ACCESS_DENIED);
3612 os<<serializeWideString(reason);
3615 std::string s = os.str();
3616 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3618 con.Send(peer_id, 0, data, true);
3621 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3622 bool set_camera_point_target, v3f camera_point_target)
3624 DSTACK(__FUNCTION_NAME);
3625 std::ostringstream os(std::ios_base::binary);
3627 writeU16(os, TOCLIENT_DEATHSCREEN);
3628 writeU8(os, set_camera_point_target);
3629 writeV3F1000(os, camera_point_target);
3632 std::string s = os.str();
3633 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3635 con.Send(peer_id, 0, data, true);
3638 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3639 IItemDefManager *itemdef)
3641 DSTACK(__FUNCTION_NAME);
3642 std::ostringstream os(std::ios_base::binary);
3646 u32 length of the next item
3647 zlib-compressed serialized ItemDefManager
3649 writeU16(os, TOCLIENT_ITEMDEF);
3650 std::ostringstream tmp_os(std::ios::binary);
3651 itemdef->serialize(tmp_os);
3652 std::ostringstream tmp_os2(std::ios::binary);
3653 compressZlib(tmp_os.str(), tmp_os2);
3654 os<<serializeLongString(tmp_os2.str());
3657 std::string s = os.str();
3658 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3659 <<"): size="<<s.size()<<std::endl;
3660 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3662 con.Send(peer_id, 0, data, true);
3665 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3666 INodeDefManager *nodedef, u16 protocol_version)
3668 DSTACK(__FUNCTION_NAME);
3669 std::ostringstream os(std::ios_base::binary);
3673 u32 length of the next item
3674 zlib-compressed serialized NodeDefManager
3676 writeU16(os, TOCLIENT_NODEDEF);
3677 std::ostringstream tmp_os(std::ios::binary);
3678 nodedef->serialize(tmp_os, protocol_version);
3679 std::ostringstream tmp_os2(std::ios::binary);
3680 compressZlib(tmp_os.str(), tmp_os2);
3681 os<<serializeLongString(tmp_os2.str());
3684 std::string s = os.str();
3685 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3686 <<"): size="<<s.size()<<std::endl;
3687 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3689 con.Send(peer_id, 0, data, true);
3693 Non-static send methods
3696 void Server::SendInventory(u16 peer_id)
3698 DSTACK(__FUNCTION_NAME);
3700 PlayerSAO *playersao = getPlayerSAO(peer_id);
3703 playersao->m_inventory_not_sent = false;
3709 std::ostringstream os;
3710 playersao->getInventory()->serialize(os);
3712 std::string s = os.str();
3714 SharedBuffer<u8> data(s.size()+2);
3715 writeU16(&data[0], TOCLIENT_INVENTORY);
3716 memcpy(&data[2], s.c_str(), s.size());
3719 m_con.Send(peer_id, 0, data, true);
3722 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3724 DSTACK(__FUNCTION_NAME);
3726 std::ostringstream os(std::ios_base::binary);
3730 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3731 os.write((char*)buf, 2);
3734 writeU16(buf, message.size());
3735 os.write((char*)buf, 2);
3738 for(u32 i=0; i<message.size(); i++)
3742 os.write((char*)buf, 2);
3746 std::string s = os.str();
3747 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3749 m_con.Send(peer_id, 0, data, true);
3751 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3753 DSTACK(__FUNCTION_NAME);
3755 std::ostringstream os(std::ios_base::binary);
3759 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3760 os.write((char*)buf, 2);
3761 os<<serializeLongString(formspec);
3762 os<<serializeString(formname);
3765 std::string s = os.str();
3766 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3768 m_con.Send(peer_id, 0, data, true);
3771 void Server::BroadcastChatMessage(const std::wstring &message)
3773 for(core::map<u16, RemoteClient*>::Iterator
3774 i = m_clients.getIterator();
3775 i.atEnd() == false; i++)
3777 // Get client and check that it is valid
3778 RemoteClient *client = i.getNode()->getValue();
3779 assert(client->peer_id == i.getNode()->getKey());
3780 if(client->serialization_version == SER_FMT_VER_INVALID)
3783 SendChatMessage(client->peer_id, message);
3787 void Server::SendPlayerHP(u16 peer_id)
3789 DSTACK(__FUNCTION_NAME);
3790 PlayerSAO *playersao = getPlayerSAO(peer_id);
3792 playersao->m_hp_not_sent = false;
3793 SendHP(m_con, peer_id, playersao->getHP());
3796 void Server::SendMovePlayer(u16 peer_id)
3798 DSTACK(__FUNCTION_NAME);
3799 Player *player = m_env->getPlayer(peer_id);
3802 std::ostringstream os(std::ios_base::binary);
3803 writeU16(os, TOCLIENT_MOVE_PLAYER);
3804 writeV3F1000(os, player->getPosition());
3805 writeF1000(os, player->getPitch());
3806 writeF1000(os, player->getYaw());
3809 v3f pos = player->getPosition();
3810 f32 pitch = player->getPitch();
3811 f32 yaw = player->getYaw();
3812 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3813 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3820 std::string s = os.str();
3821 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3823 m_con.Send(peer_id, 0, data, true);
3826 void Server::SendPlayerPrivileges(u16 peer_id)
3828 Player *player = m_env->getPlayer(peer_id);
3830 if(player->peer_id == PEER_ID_INEXISTENT)
3833 std::set<std::string> privs;
3834 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3836 std::ostringstream os(std::ios_base::binary);
3837 writeU16(os, TOCLIENT_PRIVILEGES);
3838 writeU16(os, privs.size());
3839 for(std::set<std::string>::const_iterator i = privs.begin();
3840 i != privs.end(); i++){
3841 os<<serializeString(*i);
3845 std::string s = os.str();
3846 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3848 m_con.Send(peer_id, 0, data, true);
3851 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3853 Player *player = m_env->getPlayer(peer_id);
3855 if(player->peer_id == PEER_ID_INEXISTENT)
3858 std::ostringstream os(std::ios_base::binary);
3859 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3860 os<<serializeLongString(player->inventory_formspec);
3863 std::string s = os.str();
3864 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3866 m_con.Send(peer_id, 0, data, true);
3869 s32 Server::playSound(const SimpleSoundSpec &spec,
3870 const ServerSoundParams ¶ms)
3872 // Find out initial position of sound
3873 bool pos_exists = false;
3874 v3f pos = params.getPos(m_env, &pos_exists);
3875 // If position is not found while it should be, cancel sound
3876 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3878 // Filter destination clients
3879 std::set<RemoteClient*> dst_clients;
3880 if(params.to_player != "")
3882 Player *player = m_env->getPlayer(params.to_player.c_str());
3884 infostream<<"Server::playSound: Player \""<<params.to_player
3885 <<"\" not found"<<std::endl;
3888 if(player->peer_id == PEER_ID_INEXISTENT){
3889 infostream<<"Server::playSound: Player \""<<params.to_player
3890 <<"\" not connected"<<std::endl;
3893 RemoteClient *client = getClient(player->peer_id);
3894 dst_clients.insert(client);
3898 for(core::map<u16, RemoteClient*>::Iterator
3899 i = m_clients.getIterator(); i.atEnd() == false; i++)
3901 RemoteClient *client = i.getNode()->getValue();
3902 Player *player = m_env->getPlayer(client->peer_id);
3906 if(player->getPosition().getDistanceFrom(pos) >
3907 params.max_hear_distance)
3910 dst_clients.insert(client);
3913 if(dst_clients.size() == 0)
3916 s32 id = m_next_sound_id++;
3917 // The sound will exist as a reference in m_playing_sounds
3918 m_playing_sounds[id] = ServerPlayingSound();
3919 ServerPlayingSound &psound = m_playing_sounds[id];
3920 psound.params = params;
3921 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3922 i != dst_clients.end(); i++)
3923 psound.clients.insert((*i)->peer_id);
3925 std::ostringstream os(std::ios_base::binary);
3926 writeU16(os, TOCLIENT_PLAY_SOUND);
3928 os<<serializeString(spec.name);
3929 writeF1000(os, spec.gain * params.gain);
3930 writeU8(os, params.type);
3931 writeV3F1000(os, pos);
3932 writeU16(os, params.object);
3933 writeU8(os, params.loop);
3935 std::string s = os.str();
3936 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3938 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3939 i != dst_clients.end(); i++){
3941 m_con.Send((*i)->peer_id, 0, data, true);
3945 void Server::stopSound(s32 handle)
3947 // Get sound reference
3948 std::map<s32, ServerPlayingSound>::iterator i =
3949 m_playing_sounds.find(handle);
3950 if(i == m_playing_sounds.end())
3952 ServerPlayingSound &psound = i->second;
3954 std::ostringstream os(std::ios_base::binary);
3955 writeU16(os, TOCLIENT_STOP_SOUND);
3956 writeS32(os, handle);
3958 std::string s = os.str();
3959 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3961 for(std::set<u16>::iterator i = psound.clients.begin();
3962 i != psound.clients.end(); i++){
3964 m_con.Send(*i, 0, data, true);
3966 // Remove sound reference
3967 m_playing_sounds.erase(i);
3970 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3971 core::list<u16> *far_players, float far_d_nodes)
3973 float maxd = far_d_nodes*BS;
3974 v3f p_f = intToFloat(p, BS);
3978 SharedBuffer<u8> reply(replysize);
3979 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3980 writeS16(&reply[2], p.X);
3981 writeS16(&reply[4], p.Y);
3982 writeS16(&reply[6], p.Z);
3984 for(core::map<u16, RemoteClient*>::Iterator
3985 i = m_clients.getIterator();
3986 i.atEnd() == false; i++)
3988 // Get client and check that it is valid
3989 RemoteClient *client = i.getNode()->getValue();
3990 assert(client->peer_id == i.getNode()->getKey());
3991 if(client->serialization_version == SER_FMT_VER_INVALID)
3994 // Don't send if it's the same one
3995 if(client->peer_id == ignore_id)
4001 Player *player = m_env->getPlayer(client->peer_id);
4004 // If player is far away, only set modified blocks not sent
4005 v3f player_pos = player->getPosition();
4006 if(player_pos.getDistanceFrom(p_f) > maxd)
4008 far_players->push_back(client->peer_id);
4015 m_con.Send(client->peer_id, 0, reply, true);
4019 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4020 core::list<u16> *far_players, float far_d_nodes)
4022 float maxd = far_d_nodes*BS;
4023 v3f p_f = intToFloat(p, BS);
4025 for(core::map<u16, RemoteClient*>::Iterator
4026 i = m_clients.getIterator();
4027 i.atEnd() == false; i++)
4029 // Get client and check that it is valid
4030 RemoteClient *client = i.getNode()->getValue();
4031 assert(client->peer_id == i.getNode()->getKey());
4032 if(client->serialization_version == SER_FMT_VER_INVALID)
4035 // Don't send if it's the same one
4036 if(client->peer_id == ignore_id)
4042 Player *player = m_env->getPlayer(client->peer_id);
4045 // If player is far away, only set modified blocks not sent
4046 v3f player_pos = player->getPosition();
4047 if(player_pos.getDistanceFrom(p_f) > maxd)
4049 far_players->push_back(client->peer_id);
4056 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4057 SharedBuffer<u8> reply(replysize);
4058 writeU16(&reply[0], TOCLIENT_ADDNODE);
4059 writeS16(&reply[2], p.X);
4060 writeS16(&reply[4], p.Y);
4061 writeS16(&reply[6], p.Z);
4062 n.serialize(&reply[8], client->serialization_version);
4065 m_con.Send(client->peer_id, 0, reply, true);
4069 void Server::setBlockNotSent(v3s16 p)
4071 for(core::map<u16, RemoteClient*>::Iterator
4072 i = m_clients.getIterator();
4073 i.atEnd()==false; i++)
4075 RemoteClient *client = i.getNode()->getValue();
4076 client->SetBlockNotSent(p);
4080 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4082 DSTACK(__FUNCTION_NAME);
4084 v3s16 p = block->getPos();
4088 bool completely_air = true;
4089 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4090 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4091 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4093 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4095 completely_air = false;
4096 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4101 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4103 infostream<<"[completely air] ";
4104 infostream<<std::endl;
4108 Create a packet with the block in the right format
4111 std::ostringstream os(std::ios_base::binary);
4112 block->serialize(os, ver, false);
4113 std::string s = os.str();
4114 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4116 u32 replysize = 8 + blockdata.getSize();
4117 SharedBuffer<u8> reply(replysize);
4118 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4119 writeS16(&reply[2], p.X);
4120 writeS16(&reply[4], p.Y);
4121 writeS16(&reply[6], p.Z);
4122 memcpy(&reply[8], *blockdata, blockdata.getSize());
4124 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4125 <<": \tpacket size: "<<replysize<<std::endl;*/
4130 m_con.Send(peer_id, 1, reply, true);
4133 void Server::SendBlocks(float dtime)
4135 DSTACK(__FUNCTION_NAME);
4137 JMutexAutoLock envlock(m_env_mutex);
4138 JMutexAutoLock conlock(m_con_mutex);
4140 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4142 core::array<PrioritySortedBlockTransfer> queue;
4144 s32 total_sending = 0;
4147 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4149 for(core::map<u16, RemoteClient*>::Iterator
4150 i = m_clients.getIterator();
4151 i.atEnd() == false; i++)
4153 RemoteClient *client = i.getNode()->getValue();
4154 assert(client->peer_id == i.getNode()->getKey());
4156 // If definitions and textures have not been sent, don't
4157 // send MapBlocks either
4158 if(!client->definitions_sent)
4161 total_sending += client->SendingCount();
4163 if(client->serialization_version == SER_FMT_VER_INVALID)
4166 client->GetNextBlocks(this, dtime, queue);
4171 // Lowest priority number comes first.
4172 // Lowest is most important.
4175 for(u32 i=0; i<queue.size(); i++)
4177 //TODO: Calculate limit dynamically
4178 if(total_sending >= g_settings->getS32
4179 ("max_simultaneous_block_sends_server_total"))
4182 PrioritySortedBlockTransfer q = queue[i];
4184 MapBlock *block = NULL;
4187 block = m_env->getMap().getBlockNoCreate(q.pos);
4189 catch(InvalidPositionException &e)
4194 RemoteClient *client = getClient(q.peer_id);
4196 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4198 client->SentBlock(q.pos);
4204 void Server::fillMediaCache()
4206 DSTACK(__FUNCTION_NAME);
4208 infostream<<"Server: Calculating media file checksums"<<std::endl;
4210 // Collect all media file paths
4211 std::list<std::string> paths;
4212 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4213 i != m_mods.end(); i++){
4214 const ModSpec &mod = *i;
4215 paths.push_back(mod.path + DIR_DELIM + "textures");
4216 paths.push_back(mod.path + DIR_DELIM + "sounds");
4217 paths.push_back(mod.path + DIR_DELIM + "media");
4218 paths.push_back(mod.path + DIR_DELIM + "models");
4220 std::string path_all = "textures";
4221 paths.push_back(path_all + DIR_DELIM + "all");
4223 // Collect media file information from paths into cache
4224 for(std::list<std::string>::iterator i = paths.begin();
4225 i != paths.end(); i++)
4227 std::string mediapath = *i;
4228 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4229 for(u32 j=0; j<dirlist.size(); j++){
4230 if(dirlist[j].dir) // Ignode dirs
4232 std::string filename = dirlist[j].name;
4233 // If name contains illegal characters, ignore the file
4234 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4235 infostream<<"Server: ignoring illegal file name: \""
4236 <<filename<<"\""<<std::endl;
4239 // If name is not in a supported format, ignore it
4240 const char *supported_ext[] = {
4241 ".png", ".jpg", ".bmp", ".tga",
4242 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4244 ".x", ".b3d", ".md2", ".obj",
4247 if(removeStringEnd(filename, supported_ext) == ""){
4248 infostream<<"Server: ignoring unsupported file extension: \""
4249 <<filename<<"\""<<std::endl;
4252 // Ok, attempt to load the file and add to cache
4253 std::string filepath = mediapath + DIR_DELIM + filename;
4255 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4256 if(fis.good() == false){
4257 errorstream<<"Server::fillMediaCache(): Could not open \""
4258 <<filename<<"\" for reading"<<std::endl;
4261 std::ostringstream tmp_os(std::ios_base::binary);
4265 fis.read(buf, 1024);
4266 std::streamsize len = fis.gcount();
4267 tmp_os.write(buf, len);
4276 errorstream<<"Server::fillMediaCache(): Failed to read \""
4277 <<filename<<"\""<<std::endl;
4280 if(tmp_os.str().length() == 0){
4281 errorstream<<"Server::fillMediaCache(): Empty file \""
4282 <<filepath<<"\""<<std::endl;
4287 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4289 unsigned char *digest = sha1.getDigest();
4290 std::string sha1_base64 = base64_encode(digest, 20);
4291 std::string sha1_hex = hex_encode((char*)digest, 20);
4295 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4296 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4301 struct SendableMediaAnnouncement
4304 std::string sha1_digest;
4306 SendableMediaAnnouncement(const std::string name_="",
4307 const std::string sha1_digest_=""):
4309 sha1_digest(sha1_digest_)
4313 void Server::sendMediaAnnouncement(u16 peer_id)
4315 DSTACK(__FUNCTION_NAME);
4317 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4320 core::list<SendableMediaAnnouncement> file_announcements;
4322 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4323 i != m_media.end(); i++){
4325 file_announcements.push_back(
4326 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4330 std::ostringstream os(std::ios_base::binary);
4338 u16 length of sha1_digest
4343 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4344 writeU16(os, file_announcements.size());
4346 for(core::list<SendableMediaAnnouncement>::Iterator
4347 j = file_announcements.begin();
4348 j != file_announcements.end(); j++){
4349 os<<serializeString(j->name);
4350 os<<serializeString(j->sha1_digest);
4352 os<<serializeString(g_settings->get("remote_media"));
4355 std::string s = os.str();
4356 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4359 m_con.Send(peer_id, 0, data, true);
4362 struct SendableMedia
4368 SendableMedia(const std::string &name_="", const std::string path_="",
4369 const std::string &data_=""):
4376 void Server::sendRequestedMedia(u16 peer_id,
4377 const core::list<MediaRequest> &tosend)
4379 DSTACK(__FUNCTION_NAME);
4381 verbosestream<<"Server::sendRequestedMedia(): "
4382 <<"Sending files to client"<<std::endl;
4386 // Put 5kB in one bunch (this is not accurate)
4387 u32 bytes_per_bunch = 5000;
4389 core::array< core::list<SendableMedia> > file_bunches;
4390 file_bunches.push_back(core::list<SendableMedia>());
4392 u32 file_size_bunch_total = 0;
4394 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4395 i != tosend.end(); i++)
4397 if(m_media.find(i->name) == m_media.end()){
4398 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4399 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4403 //TODO get path + name
4404 std::string tpath = m_media[(*i).name].path;
4407 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4408 if(fis.good() == false){
4409 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4410 <<tpath<<"\" for reading"<<std::endl;
4413 std::ostringstream tmp_os(std::ios_base::binary);
4417 fis.read(buf, 1024);
4418 std::streamsize len = fis.gcount();
4419 tmp_os.write(buf, len);
4420 file_size_bunch_total += len;
4429 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4430 <<(*i).name<<"\""<<std::endl;
4433 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4434 <<tname<<"\""<<std::endl;*/
4436 file_bunches[file_bunches.size()-1].push_back(
4437 SendableMedia((*i).name, tpath, tmp_os.str()));
4439 // Start next bunch if got enough data
4440 if(file_size_bunch_total >= bytes_per_bunch){
4441 file_bunches.push_back(core::list<SendableMedia>());
4442 file_size_bunch_total = 0;
4447 /* Create and send packets */
4449 u32 num_bunches = file_bunches.size();
4450 for(u32 i=0; i<num_bunches; i++)
4452 std::ostringstream os(std::ios_base::binary);
4456 u16 total number of texture bunches
4457 u16 index of this bunch
4458 u32 number of files in this bunch
4467 writeU16(os, TOCLIENT_MEDIA);
4468 writeU16(os, num_bunches);
4470 writeU32(os, file_bunches[i].size());
4472 for(core::list<SendableMedia>::Iterator
4473 j = file_bunches[i].begin();
4474 j != file_bunches[i].end(); j++){
4475 os<<serializeString(j->name);
4476 os<<serializeLongString(j->data);
4480 std::string s = os.str();
4481 verbosestream<<"Server::sendRequestedMedia(): bunch "
4482 <<i<<"/"<<num_bunches
4483 <<" files="<<file_bunches[i].size()
4484 <<" size=" <<s.size()<<std::endl;
4485 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4487 m_con.Send(peer_id, 0, data, true);
4491 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4493 if(m_detached_inventories.count(name) == 0){
4494 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4497 Inventory *inv = m_detached_inventories[name];
4499 std::ostringstream os(std::ios_base::binary);
4500 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4501 os<<serializeString(name);
4505 std::string s = os.str();
4506 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4508 m_con.Send(peer_id, 0, data, true);
4511 void Server::sendDetachedInventoryToAll(const std::string &name)
4513 DSTACK(__FUNCTION_NAME);
4515 for(core::map<u16, RemoteClient*>::Iterator
4516 i = m_clients.getIterator();
4517 i.atEnd() == false; i++){
4518 RemoteClient *client = i.getNode()->getValue();
4519 sendDetachedInventory(name, client->peer_id);
4523 void Server::sendDetachedInventories(u16 peer_id)
4525 DSTACK(__FUNCTION_NAME);
4527 for(std::map<std::string, Inventory*>::iterator
4528 i = m_detached_inventories.begin();
4529 i != m_detached_inventories.end(); i++){
4530 const std::string &name = i->first;
4531 //Inventory *inv = i->second;
4532 sendDetachedInventory(name, peer_id);
4540 void Server::DiePlayer(u16 peer_id)
4542 DSTACK(__FUNCTION_NAME);
4544 PlayerSAO *playersao = getPlayerSAO(peer_id);
4547 infostream<<"Server::DiePlayer(): Player "
4548 <<playersao->getPlayer()->getName()
4549 <<" dies"<<std::endl;
4551 playersao->setHP(0);
4553 // Trigger scripted stuff
4554 scriptapi_on_dieplayer(m_lua, playersao);
4556 SendPlayerHP(peer_id);
4557 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4560 void Server::RespawnPlayer(u16 peer_id)
4562 DSTACK(__FUNCTION_NAME);
4564 PlayerSAO *playersao = getPlayerSAO(peer_id);
4567 infostream<<"Server::RespawnPlayer(): Player "
4568 <<playersao->getPlayer()->getName()
4569 <<" respawns"<<std::endl;
4571 playersao->setHP(PLAYER_MAX_HP);
4573 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4575 v3f pos = findSpawnPos(m_env->getServerMap());
4576 playersao->setPos(pos);
4580 void Server::UpdateCrafting(u16 peer_id)
4582 DSTACK(__FUNCTION_NAME);
4584 Player* player = m_env->getPlayer(peer_id);
4587 // Get a preview for crafting
4589 getCraftingResult(&player->inventory, preview, false, this);
4591 // Put the new preview in
4592 InventoryList *plist = player->inventory.getList("craftpreview");
4594 assert(plist->getSize() >= 1);
4595 plist->changeItem(0, preview);
4598 RemoteClient* Server::getClient(u16 peer_id)
4600 DSTACK(__FUNCTION_NAME);
4601 //JMutexAutoLock lock(m_con_mutex);
4602 core::map<u16, RemoteClient*>::Node *n;
4603 n = m_clients.find(peer_id);
4604 // A client should exist for all peers
4606 return n->getValue();
4609 std::wstring Server::getStatusString()
4611 std::wostringstream os(std::ios_base::binary);
4614 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4616 os<<L", uptime="<<m_uptime.get();
4617 // Information about clients
4618 core::map<u16, RemoteClient*>::Iterator i;
4621 for(i = m_clients.getIterator(), first = true;
4622 i.atEnd() == false; i++)
4624 // Get client and check that it is valid
4625 RemoteClient *client = i.getNode()->getValue();
4626 assert(client->peer_id == i.getNode()->getKey());
4627 if(client->serialization_version == SER_FMT_VER_INVALID)
4630 Player *player = m_env->getPlayer(client->peer_id);
4631 // Get name of player
4632 std::wstring name = L"unknown";
4634 name = narrow_to_wide(player->getName());
4635 // Add name to information string
4643 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4644 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4645 if(g_settings->get("motd") != "")
4646 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4650 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4652 std::set<std::string> privs;
4653 scriptapi_get_auth(m_lua, name, NULL, &privs);
4657 bool Server::checkPriv(const std::string &name, const std::string &priv)
4659 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4660 return (privs.count(priv) != 0);
4663 void Server::reportPrivsModified(const std::string &name)
4666 for(core::map<u16, RemoteClient*>::Iterator
4667 i = m_clients.getIterator();
4668 i.atEnd() == false; i++){
4669 RemoteClient *client = i.getNode()->getValue();
4670 Player *player = m_env->getPlayer(client->peer_id);
4671 reportPrivsModified(player->getName());
4674 Player *player = m_env->getPlayer(name.c_str());
4677 SendPlayerPrivileges(player->peer_id);
4678 PlayerSAO *sao = player->getPlayerSAO();
4681 sao->updatePrivileges(
4682 getPlayerEffectivePrivs(name),
4687 void Server::reportInventoryFormspecModified(const std::string &name)
4689 Player *player = m_env->getPlayer(name.c_str());
4692 SendPlayerInventoryFormspec(player->peer_id);
4695 // Saves g_settings to configpath given at initialization
4696 void Server::saveConfig()
4698 if(m_path_config != "")
4699 g_settings->updateConfigFile(m_path_config.c_str());
4702 void Server::notifyPlayer(const char *name, const std::wstring msg)
4704 Player *player = m_env->getPlayer(name);
4707 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4710 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4712 Player *player = m_env->getPlayer(playername);
4716 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4720 SendShowFormspecMessage(player->peer_id, formspec, formname);
4724 void Server::notifyPlayers(const std::wstring msg)
4726 BroadcastChatMessage(msg);
4729 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4733 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4734 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4737 Inventory* Server::createDetachedInventory(const std::string &name)
4739 if(m_detached_inventories.count(name) > 0){
4740 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4741 delete m_detached_inventories[name];
4743 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4745 Inventory *inv = new Inventory(m_itemdef);
4747 m_detached_inventories[name] = inv;
4748 sendDetachedInventoryToAll(name);
4755 BoolScopeSet(bool *dst, bool val):
4758 m_orig_state = *m_dst;
4763 *m_dst = m_orig_state;
4770 // actions: time-reversed list
4771 // Return value: success/failure
4772 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4773 std::list<std::string> *log)
4775 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4776 ServerMap *map = (ServerMap*)(&m_env->getMap());
4777 // Disable rollback report sink while reverting
4778 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4780 // Fail if no actions to handle
4781 if(actions.empty()){
4782 log->push_back("Nothing to do.");
4789 for(std::list<RollbackAction>::const_iterator
4790 i = actions.begin();
4791 i != actions.end(); i++)
4793 const RollbackAction &action = *i;
4795 bool success = action.applyRevert(map, this, this);
4798 std::ostringstream os;
4799 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4800 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4802 log->push_back(os.str());
4804 std::ostringstream os;
4805 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4806 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4808 log->push_back(os.str());
4812 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4813 <<" failed"<<std::endl;
4815 // Call it done if less than half failed
4816 return num_failed <= num_tried/2;
4819 // IGameDef interface
4821 IItemDefManager* Server::getItemDefManager()
4825 INodeDefManager* Server::getNodeDefManager()
4829 ICraftDefManager* Server::getCraftDefManager()
4833 ITextureSource* Server::getTextureSource()
4837 IShaderSource* Server::getShaderSource()
4841 u16 Server::allocateUnknownNodeId(const std::string &name)
4843 return m_nodedef->allocateDummy(name);
4845 ISoundManager* Server::getSoundManager()
4847 return &dummySoundManager;
4849 MtEventManager* Server::getEventManager()
4853 IRollbackReportSink* Server::getRollbackReportSink()
4855 if(!m_enable_rollback_recording)
4857 if(!m_rollback_sink_enabled)
4862 IWritableItemDefManager* Server::getWritableItemDefManager()
4866 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4870 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4875 const ModSpec* Server::getModSpec(const std::string &modname)
4877 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4878 i != m_mods.end(); i++){
4879 const ModSpec &mod = *i;
4880 if(mod.name == modname)
4885 void Server::getModNames(core::list<std::string> &modlist)
4887 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4889 modlist.push_back((*i).name);
4892 std::string Server::getBuiltinLuaPath()
4894 return porting::path_share + DIR_DELIM + "builtin";
4897 v3f findSpawnPos(ServerMap &map)
4899 //return v3f(50,50,50)*BS;
4904 nodepos = v2s16(0,0);
4909 s16 water_level = map.m_mgparams->water_level;
4911 // Try to find a good place a few times
4912 for(s32 i=0; i<1000; i++)
4915 // We're going to try to throw the player to this position
4916 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4917 -range + (myrand()%(range*2)));
4918 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4919 // Get ground height at point (fallbacks to heightmap function)
4920 s16 groundheight = map.findGroundLevel(nodepos2d);
4921 // Don't go underwater
4922 if(groundheight <= water_level)
4924 //infostream<<"-> Underwater"<<std::endl;
4927 // Don't go to high places
4928 if(groundheight > water_level + 6)
4930 //infostream<<"-> Underwater"<<std::endl;
4934 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4935 bool is_good = false;
4937 for(s32 i=0; i<10; i++){
4938 v3s16 blockpos = getNodeBlockPos(nodepos);
4939 map.emergeBlock(blockpos, true);
4940 MapNode n = map.getNodeNoEx(nodepos);
4941 if(n.getContent() == CONTENT_AIR){
4952 // Found a good place
4953 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4959 return intToFloat(nodepos, BS);
4962 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4964 RemotePlayer *player = NULL;
4965 bool newplayer = false;
4968 Try to get an existing player
4970 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4972 // If player is already connected, cancel
4973 if(player != NULL && player->peer_id != 0)
4975 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4980 If player with the wanted peer_id already exists, cancel.
4982 if(m_env->getPlayer(peer_id) != NULL)
4984 infostream<<"emergePlayer(): Player with wrong name but same"
4985 " peer_id already exists"<<std::endl;
4990 Create a new player if it doesn't exist yet
4995 player = new RemotePlayer(this);
4996 player->updateName(name);
4998 /* Set player position */
4999 infostream<<"Server: Finding spawn place for player \""
5000 <<name<<"\""<<std::endl;
5001 v3f pos = findSpawnPos(m_env->getServerMap());
5002 player->setPosition(pos);
5004 /* Add player to environment */
5005 m_env->addPlayer(player);
5009 Create a new player active object
5011 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5012 getPlayerEffectivePrivs(player->getName()),
5015 /* Add object to environment */
5016 m_env->addActiveObject(playersao);
5020 scriptapi_on_newplayer(m_lua, playersao);
5022 scriptapi_on_joinplayer(m_lua, playersao);
5027 void Server::handlePeerChange(PeerChange &c)
5029 JMutexAutoLock envlock(m_env_mutex);
5030 JMutexAutoLock conlock(m_con_mutex);
5032 if(c.type == PEER_ADDED)
5039 core::map<u16, RemoteClient*>::Node *n;
5040 n = m_clients.find(c.peer_id);
5041 // The client shouldn't already exist
5045 RemoteClient *client = new RemoteClient();
5046 client->peer_id = c.peer_id;
5047 m_clients.insert(client->peer_id, client);
5050 else if(c.type == PEER_REMOVED)
5057 core::map<u16, RemoteClient*>::Node *n;
5058 n = m_clients.find(c.peer_id);
5059 // The client should exist
5063 Mark objects to be not known by the client
5065 RemoteClient *client = n->getValue();
5067 for(core::map<u16, bool>::Iterator
5068 i = client->m_known_objects.getIterator();
5069 i.atEnd()==false; i++)
5072 u16 id = i.getNode()->getKey();
5073 ServerActiveObject* obj = m_env->getActiveObject(id);
5075 if(obj && obj->m_known_by_count > 0)
5076 obj->m_known_by_count--;
5080 Clear references to playing sounds
5082 for(std::map<s32, ServerPlayingSound>::iterator
5083 i = m_playing_sounds.begin();
5084 i != m_playing_sounds.end();)
5086 ServerPlayingSound &psound = i->second;
5087 psound.clients.erase(c.peer_id);
5088 if(psound.clients.size() == 0)
5089 m_playing_sounds.erase(i++);
5094 Player *player = m_env->getPlayer(c.peer_id);
5096 // Collect information about leaving in chat
5097 std::wstring message;
5101 std::wstring name = narrow_to_wide(player->getName());
5104 message += L" left the game.";
5106 message += L" (timed out)";
5110 /* Run scripts and remove from environment */
5114 PlayerSAO *playersao = player->getPlayerSAO();
5117 scriptapi_on_leaveplayer(m_lua, playersao);
5119 playersao->disconnected();
5129 std::ostringstream os(std::ios_base::binary);
5130 for(core::map<u16, RemoteClient*>::Iterator
5131 i = m_clients.getIterator();
5132 i.atEnd() == false; i++)
5134 RemoteClient *client = i.getNode()->getValue();
5135 assert(client->peer_id == i.getNode()->getKey());
5136 if(client->serialization_version == SER_FMT_VER_INVALID)
5139 Player *player = m_env->getPlayer(client->peer_id);
5142 // Get name of player
5143 os<<player->getName()<<" ";
5146 actionstream<<player->getName()<<" "
5147 <<(c.timeout?"times out.":"leaves game.")
5148 <<" List of players: "
5149 <<os.str()<<std::endl;
5154 delete m_clients[c.peer_id];
5155 m_clients.remove(c.peer_id);
5157 // Send player info to all remaining clients
5158 //SendPlayerInfos();
5160 // Send leave chat message to all remaining clients
5161 if(message.length() != 0)
5162 BroadcastChatMessage(message);
5171 void Server::handlePeerChanges()
5173 while(m_peer_change_queue.size() > 0)
5175 PeerChange c = m_peer_change_queue.pop_front();
5177 verbosestream<<"Server: Handling peer change: "
5178 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5181 handlePeerChange(c);
5185 void dedicated_server_loop(Server &server, bool &kill)
5187 DSTACK(__FUNCTION_NAME);
5189 verbosestream<<"dedicated_server_loop()"<<std::endl;
5191 IntervalLimiter m_profiler_interval;
5195 float steplen = g_settings->getFloat("dedicated_server_step");
5196 // This is kind of a hack but can be done like this
5197 // because server.step() is very light
5199 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5200 sleep_ms((int)(steplen*1000.0));
5202 server.step(steplen);
5204 if(server.getShutdownRequested() || kill)
5206 infostream<<"Dedicated server quitting"<<std::endl;
5208 if(g_settings->getBool("server_announce") == true)
5209 ServerList::sendAnnounce("delete");
5217 float profiler_print_interval =
5218 g_settings->getFloat("profiler_print_interval");
5219 if(profiler_print_interval != 0)
5221 if(m_profiler_interval.step(steplen, profiler_print_interval))
5223 infostream<<"Profiler:"<<std::endl;
5224 g_profiler->print(infostream);
5225 g_profiler->clear();