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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
15 You should have received a copy of the GNU 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.
24 #include "clientserver.h"
26 #include "jmutexautolock.h"
28 #include "constants.h"
31 #include "servercommand.h"
33 #include "content_mapnode.h"
34 #include "content_nodemeta.h"
36 #include "serverobject.h"
41 #include "scriptapi.h"
46 #include "content_abm.h"
51 #include "utility_string.h"
52 #include "sound.h" // dummySoundManager
53 #include "event_manager.h"
56 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
58 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
60 class MapEditEventIgnorer
63 MapEditEventIgnorer(bool *flag):
72 ~MapEditEventIgnorer()
85 class MapEditEventAreaIgnorer
88 MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
89 m_ignorevariable(ignorevariable)
91 if(m_ignorevariable->getVolume() == 0)
92 *m_ignorevariable = a;
94 m_ignorevariable = NULL;
97 ~MapEditEventAreaIgnorer()
101 assert(m_ignorevariable->getVolume() != 0);
102 *m_ignorevariable = VoxelArea();
107 VoxelArea *m_ignorevariable;
110 void * ServerThread::Thread()
114 log_register_thread("ServerThread");
116 DSTACK(__FUNCTION_NAME);
118 BEGIN_DEBUG_EXCEPTION_HANDLER
123 //TimeTaker timer("AsyncRunStep() + Receive()");
126 //TimeTaker timer("AsyncRunStep()");
127 m_server->AsyncRunStep();
130 //infostream<<"Running m_server->Receive()"<<std::endl;
133 catch(con::NoIncomingDataException &e)
136 catch(con::PeerNotFoundException &e)
138 infostream<<"Server: PeerNotFoundException"<<std::endl;
140 catch(con::ConnectionBindFailed &e)
142 m_server->setAsyncFatalError(e.what());
146 END_DEBUG_EXCEPTION_HANDLER(errorstream)
151 void * EmergeThread::Thread()
155 log_register_thread("EmergeThread");
157 DSTACK(__FUNCTION_NAME);
159 BEGIN_DEBUG_EXCEPTION_HANDLER
161 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
164 Get block info from queue, emerge them and send them
167 After queue is empty, exit.
171 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
175 SharedPtr<QueuedBlockEmerge> q(qptr);
181 Do not generate over-limit
183 if(blockpos_over_limit(p))
186 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
188 //TimeTaker timer("block emerge");
191 Try to emerge it from somewhere.
193 If it is only wanted as optional, only loading from disk
198 Check if any peer wants it as non-optional. In that case it
201 Also decrement the emerge queue count in clients.
204 bool only_from_disk = true;
207 core::map<u16, u8>::Iterator i;
208 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
210 //u16 peer_id = i.getNode()->getKey();
213 u8 flags = i.getNode()->getValue();
214 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
215 only_from_disk = false;
220 if(enable_mapgen_debug_info)
221 infostream<<"EmergeThread: p="
222 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
223 <<"only_from_disk="<<only_from_disk<<std::endl;
225 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
227 MapBlock *block = NULL;
228 bool got_block = true;
229 core::map<v3s16, MapBlock*> modified_blocks;
232 Try to fetch block from memory or disk.
233 If not found and asked to generate, initialize generator.
236 bool started_generate = false;
237 mapgen::BlockMakeData data;
240 JMutexAutoLock envlock(m_server->m_env_mutex);
242 // Load sector if it isn't loaded
243 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
244 map.loadSectorMeta(p2d);
246 // Attempt to load block
247 block = map.getBlockNoCreateNoEx(p);
248 if(!block || block->isDummy() || !block->isGenerated())
250 if(enable_mapgen_debug_info)
251 infostream<<"EmergeThread: not in memory, "
252 <<"attempting to load from disk"<<std::endl;
254 block = map.loadBlock(p);
257 // If could not load and allowed to generate, start generation
258 // inside this same envlock
259 if(only_from_disk == false &&
260 (block == NULL || block->isGenerated() == false)){
261 if(enable_mapgen_debug_info)
262 infostream<<"EmergeThread: generating"<<std::endl;
263 started_generate = true;
265 map.initBlockMake(&data, p);
270 If generator was initialized, generate now when envlock is free.
275 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
277 TimeTaker t("mapgen::make_block()");
279 mapgen::make_block(&data);
281 if(enable_mapgen_debug_info == false)
282 t.stop(true); // Hide output
286 // Lock environment again to access the map
287 JMutexAutoLock envlock(m_server->m_env_mutex);
289 ScopeProfiler sp(g_profiler, "EmergeThread: after "
290 "mapgen::make_block (envlock)", SPT_AVG);
292 // Blit data back on map, update lighting, add mobs and
293 // whatever this does
294 map.finishBlockMake(&data, modified_blocks);
297 block = map.getBlockNoCreateNoEx(p);
299 // If block doesn't exist, don't try doing anything with it
300 // This happens if the block is not in generation boundaries
305 Do some post-generate stuff
308 v3s16 minp = data.blockpos_min*MAP_BLOCKSIZE;
309 v3s16 maxp = data.blockpos_max*MAP_BLOCKSIZE +
310 v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
313 Ignore map edit events, they will not need to be
314 sent to anybody because the block hasn't been sent
317 //MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
318 MapEditEventAreaIgnorer ign(
319 &m_server->m_ignore_map_edit_events_area,
320 VoxelArea(minp, maxp));
322 TimeTaker timer("on_generated");
323 scriptapi_environment_on_generated(m_server->m_lua,
324 minp, maxp, mapgen::get_blockseed(data.seed, minp));
325 /*int t = timer.stop(true);
326 dstream<<"on_generated took "<<t<<"ms"<<std::endl;*/
329 if(enable_mapgen_debug_info)
330 infostream<<"EmergeThread: ended up with: "
331 <<analyze_block(block)<<std::endl;
333 // Activate objects and stuff
334 m_server->m_env->activateBlock(block, 0);
342 Set sent status of modified blocks on clients
345 // NOTE: Server's clients are also behind the connection mutex
346 JMutexAutoLock lock(m_server->m_con_mutex);
349 Add the originally fetched block to the modified list
353 modified_blocks.insert(p, block);
357 Set the modified blocks unsent for all the clients
360 for(core::map<u16, RemoteClient*>::Iterator
361 i = m_server->m_clients.getIterator();
362 i.atEnd() == false; i++)
364 RemoteClient *client = i.getNode()->getValue();
366 if(modified_blocks.size() > 0)
368 // Remove block from sent history
369 client->SetBlocksNotSent(modified_blocks);
375 END_DEBUG_EXCEPTION_HANDLER(errorstream)
377 log_deregister_thread();
382 void RemoteClient::GetNextBlocks(Server *server, float dtime,
383 core::array<PrioritySortedBlockTransfer> &dest)
385 DSTACK(__FUNCTION_NAME);
388 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
391 m_nothing_to_send_pause_timer -= dtime;
392 m_nearest_unsent_reset_timer += dtime;
394 if(m_nothing_to_send_pause_timer >= 0)
399 // Won't send anything if already sending
400 if(m_blocks_sending.size() >= g_settings->getU16
401 ("max_simultaneous_block_sends_per_client"))
403 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
407 //TimeTaker timer("RemoteClient::GetNextBlocks");
409 Player *player = server->m_env->getPlayer(peer_id);
411 assert(player != NULL);
413 v3f playerpos = player->getPosition();
414 v3f playerspeed = player->getSpeed();
415 v3f playerspeeddir(0,0,0);
416 if(playerspeed.getLength() > 1.0*BS)
417 playerspeeddir = playerspeed / playerspeed.getLength();
418 // Predict to next block
419 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
421 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
423 v3s16 center = getNodeBlockPos(center_nodepos);
425 // Camera position and direction
426 v3f camera_pos = player->getEyePosition();
427 v3f camera_dir = v3f(0,0,1);
428 camera_dir.rotateYZBy(player->getPitch());
429 camera_dir.rotateXZBy(player->getYaw());
431 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
432 <<camera_dir.Z<<")"<<std::endl;*/
435 Get the starting value of the block finder radius.
438 if(m_last_center != center)
440 m_nearest_unsent_d = 0;
441 m_last_center = center;
444 /*infostream<<"m_nearest_unsent_reset_timer="
445 <<m_nearest_unsent_reset_timer<<std::endl;*/
447 // Reset periodically to workaround for some bugs or stuff
448 if(m_nearest_unsent_reset_timer > 20.0)
450 m_nearest_unsent_reset_timer = 0;
451 m_nearest_unsent_d = 0;
452 //infostream<<"Resetting m_nearest_unsent_d for "
453 // <<server->getPlayerName(peer_id)<<std::endl;
456 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
457 s16 d_start = m_nearest_unsent_d;
459 //infostream<<"d_start="<<d_start<<std::endl;
461 u16 max_simul_sends_setting = g_settings->getU16
462 ("max_simultaneous_block_sends_per_client");
463 u16 max_simul_sends_usually = max_simul_sends_setting;
466 Check the time from last addNode/removeNode.
468 Decrease send rate if player is building stuff.
470 m_time_from_building += dtime;
471 if(m_time_from_building < g_settings->getFloat(
472 "full_block_send_enable_min_time_from_building"))
474 max_simul_sends_usually
475 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
479 Number of blocks sending + number of blocks selected for sending
481 u32 num_blocks_selected = m_blocks_sending.size();
484 next time d will be continued from the d from which the nearest
485 unsent block was found this time.
487 This is because not necessarily any of the blocks found this
488 time are actually sent.
490 s32 new_nearest_unsent_d = -1;
492 s16 d_max = g_settings->getS16("max_block_send_distance");
493 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
495 // Don't loop very much at a time
496 s16 max_d_increment_at_time = 2;
497 if(d_max > d_start + max_d_increment_at_time)
498 d_max = d_start + max_d_increment_at_time;
499 /*if(d_max_gen > d_start+2)
500 d_max_gen = d_start+2;*/
502 //infostream<<"Starting from "<<d_start<<std::endl;
504 s32 nearest_emerged_d = -1;
505 s32 nearest_emergefull_d = -1;
506 s32 nearest_sent_d = -1;
507 bool queue_is_full = false;
510 for(d = d_start; d <= d_max; d++)
512 /*errorstream<<"checking d="<<d<<" for "
513 <<server->getPlayerName(peer_id)<<std::endl;*/
514 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
517 If m_nearest_unsent_d was changed by the EmergeThread
518 (it can change it to 0 through SetBlockNotSent),
520 Else update m_nearest_unsent_d
522 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
524 d = m_nearest_unsent_d;
525 last_nearest_unsent_d = m_nearest_unsent_d;
529 Get the border/face dot coordinates of a "d-radiused"
532 core::list<v3s16> list;
533 getFacePositions(list, d);
535 core::list<v3s16>::Iterator li;
536 for(li=list.begin(); li!=list.end(); li++)
538 v3s16 p = *li + center;
542 - Don't allow too many simultaneous transfers
543 - EXCEPT when the blocks are very close
545 Also, don't send blocks that are already flying.
548 // Start with the usual maximum
549 u16 max_simul_dynamic = max_simul_sends_usually;
551 // If block is very close, allow full maximum
552 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
553 max_simul_dynamic = max_simul_sends_setting;
555 // Don't select too many blocks for sending
556 if(num_blocks_selected >= max_simul_dynamic)
558 queue_is_full = true;
559 goto queue_full_break;
562 // Don't send blocks that are currently being transferred
563 if(m_blocks_sending.find(p) != NULL)
569 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
570 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
571 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
572 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
573 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
574 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
577 // If this is true, inexistent block will be made from scratch
578 bool generate = d <= d_max_gen;
581 /*// Limit the generating area vertically to 2/3
582 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
585 // Limit the send area vertically to 1/2
586 if(abs(p.Y - center.Y) > d_max / 2)
592 If block is far away, don't generate it unless it is
598 // Block center y in nodes
599 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
600 // Don't generate if it's very high or very low
601 if(y < -64 || y > 64)
605 v2s16 p2d_nodes_center(
609 // Get ground height in nodes
610 s16 gh = server->m_env->getServerMap().findGroundLevel(
613 // If differs a lot, don't generate
614 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
616 // Actually, don't even send it
622 //infostream<<"d="<<d<<std::endl;
625 Don't generate or send if not in sight
626 FIXME This only works if the client uses a small enough
627 FOV setting. The default of 72 degrees is fine.
630 float camera_fov = (72.0*PI/180) * 4./3.;
631 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
637 Don't send already sent blocks
640 if(m_blocks_sent.find(p) != NULL)
647 Check if map has this block
649 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
651 bool surely_not_found_on_disk = false;
652 bool block_is_invalid = false;
655 // Reset usage timer, this block will be of use in the future.
656 block->resetUsageTimer();
658 // Block is dummy if data doesn't exist.
659 // It means it has been not found from disk and not generated
662 surely_not_found_on_disk = true;
665 // Block is valid if lighting is up-to-date and data exists
666 if(block->isValid() == false)
668 block_is_invalid = true;
671 /*if(block->isFullyGenerated() == false)
673 block_is_invalid = true;
678 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
679 v2s16 chunkpos = map->sector_to_chunk(p2d);
680 if(map->chunkNonVolatile(chunkpos) == false)
681 block_is_invalid = true;
683 if(block->isGenerated() == false)
684 block_is_invalid = true;
687 If block is not close, don't send it unless it is near
690 Block is near ground level if night-time mesh
691 differs from day-time mesh.
695 if(block->getDayNightDiff() == false)
702 If block has been marked to not exist on disk (dummy)
703 and generating new ones is not wanted, skip block.
705 if(generate == false && surely_not_found_on_disk == true)
712 Add inexistent block to emerge queue.
714 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
716 //TODO: Get value from somewhere
717 // Allow only one block in emerge queue
718 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
719 // Allow two blocks in queue per client
720 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
722 // Make it more responsive when needing to generate stuff
723 if(surely_not_found_on_disk)
725 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
727 //infostream<<"Adding block to emerge queue"<<std::endl;
729 // Add it to the emerge queue and trigger the thread
732 if(generate == false)
733 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
735 server->m_emerge_queue.addBlock(peer_id, p, flags);
736 server->m_emergethread.trigger();
738 if(nearest_emerged_d == -1)
739 nearest_emerged_d = d;
741 if(nearest_emergefull_d == -1)
742 nearest_emergefull_d = d;
749 if(nearest_sent_d == -1)
753 Add block to send queue
756 /*errorstream<<"sending from d="<<d<<" to "
757 <<server->getPlayerName(peer_id)<<std::endl;*/
759 PrioritySortedBlockTransfer q((float)d, p, peer_id);
763 num_blocks_selected += 1;
768 //infostream<<"Stopped at "<<d<<std::endl;
770 // If nothing was found for sending and nothing was queued for
771 // emerging, continue next time browsing from here
772 if(nearest_emerged_d != -1){
773 new_nearest_unsent_d = nearest_emerged_d;
774 } else if(nearest_emergefull_d != -1){
775 new_nearest_unsent_d = nearest_emergefull_d;
777 if(d > g_settings->getS16("max_block_send_distance")){
778 new_nearest_unsent_d = 0;
779 m_nothing_to_send_pause_timer = 2.0;
780 /*infostream<<"GetNextBlocks(): d wrapped around for "
781 <<server->getPlayerName(peer_id)
782 <<"; setting to 0 and pausing"<<std::endl;*/
784 if(nearest_sent_d != -1)
785 new_nearest_unsent_d = nearest_sent_d;
787 new_nearest_unsent_d = d;
791 if(new_nearest_unsent_d != -1)
792 m_nearest_unsent_d = new_nearest_unsent_d;
794 /*timer_result = timer.stop(true);
795 if(timer_result != 0)
796 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
799 void RemoteClient::GotBlock(v3s16 p)
801 if(m_blocks_sending.find(p) != NULL)
802 m_blocks_sending.remove(p);
805 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
806 " m_blocks_sending"<<std::endl;*/
807 m_excess_gotblocks++;
809 m_blocks_sent.insert(p, true);
812 void RemoteClient::SentBlock(v3s16 p)
814 if(m_blocks_sending.find(p) == NULL)
815 m_blocks_sending.insert(p, 0.0);
817 infostream<<"RemoteClient::SentBlock(): Sent block"
818 " already in m_blocks_sending"<<std::endl;
821 void RemoteClient::SetBlockNotSent(v3s16 p)
823 m_nearest_unsent_d = 0;
825 if(m_blocks_sending.find(p) != NULL)
826 m_blocks_sending.remove(p);
827 if(m_blocks_sent.find(p) != NULL)
828 m_blocks_sent.remove(p);
831 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
833 m_nearest_unsent_d = 0;
835 for(core::map<v3s16, MapBlock*>::Iterator
836 i = blocks.getIterator();
837 i.atEnd()==false; i++)
839 v3s16 p = i.getNode()->getKey();
841 if(m_blocks_sending.find(p) != NULL)
842 m_blocks_sending.remove(p);
843 if(m_blocks_sent.find(p) != NULL)
844 m_blocks_sent.remove(p);
852 PlayerInfo::PlayerInfo()
858 void PlayerInfo::PrintLine(std::ostream *s)
861 (*s)<<"\""<<name<<"\" ("
862 <<(position.X/10)<<","<<(position.Y/10)
863 <<","<<(position.Z/10)<<") ";
865 (*s)<<" avg_rtt="<<avg_rtt;
874 const std::string &path_world,
875 const std::string &path_config,
876 const SubgameSpec &gamespec,
877 bool simple_singleplayer_mode
879 m_path_world(path_world),
880 m_path_config(path_config),
881 m_gamespec(gamespec),
882 m_simple_singleplayer_mode(simple_singleplayer_mode),
883 m_async_fatal_error(""),
885 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
886 m_authmanager(path_world+DIR_DELIM+"auth.txt"),
887 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
889 m_itemdef(createItemDefManager()),
890 m_nodedef(createNodeDefManager()),
891 m_craftdef(createCraftDefManager()),
892 m_event(new EventManager()),
894 m_emergethread(this),
895 m_time_of_day_send_timer(0),
897 m_shutdown_requested(false),
898 m_ignore_map_edit_events(false),
899 m_ignore_map_edit_events_peer_id(0)
901 m_liquid_transform_timer = 0.0;
902 m_print_info_timer = 0.0;
903 m_objectdata_timer = 0.0;
904 m_emergethread_trigger_timer = 0.0;
905 m_savemap_timer = 0.0;
909 m_step_dtime_mutex.Init();
913 throw ServerError("Supplied empty world path");
915 if(!gamespec.isValid())
916 throw ServerError("Supplied invalid gamespec");
918 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
919 if(m_simple_singleplayer_mode)
920 infostream<<" in simple singleplayer mode"<<std::endl;
922 infostream<<std::endl;
923 infostream<<"- world: "<<m_path_world<<std::endl;
924 infostream<<"- config: "<<m_path_config<<std::endl;
925 infostream<<"- game: "<<m_gamespec.path<<std::endl;
927 // Add world mod search path
928 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
929 // Add addon mod search path
930 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
931 i != m_gamespec.mods_paths.end(); i++)
932 m_modspaths.push_front((*i));
934 // Print out mod search paths
935 for(core::list<std::string>::Iterator i = m_modspaths.begin();
936 i != m_modspaths.end(); i++){
937 std::string modspath = *i;
938 infostream<<"- mods: "<<modspath<<std::endl;
941 // Path to builtin.lua
942 std::string builtinpath = porting::path_share + DIR_DELIM + "builtin"
943 + DIR_DELIM + "builtin.lua";
945 // Create world if it doesn't exist
946 if(!initializeWorld(m_path_world, m_gamespec.id))
947 throw ServerError("Failed to initialize world");
950 JMutexAutoLock envlock(m_env_mutex);
951 JMutexAutoLock conlock(m_con_mutex);
953 // Initialize scripting
955 infostream<<"Server: Initializing Lua"<<std::endl;
956 m_lua = script_init();
959 scriptapi_export(m_lua, this);
960 // Load and run builtin.lua
961 infostream<<"Server: Loading builtin.lua [\""
962 <<builtinpath<<"\"]"<<std::endl;
963 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
965 errorstream<<"Server: Failed to load and run "
966 <<builtinpath<<std::endl;
967 throw ModError("Failed to load and run "+builtinpath);
969 // Find mods in mod search paths
970 m_mods = getMods(m_modspaths);
972 infostream<<"Server: Loading mods: ";
973 for(core::list<ModSpec>::Iterator i = m_mods.begin();
974 i != m_mods.end(); i++){
975 const ModSpec &mod = *i;
976 infostream<<mod.name<<" ";
978 infostream<<std::endl;
979 // Load and run "mod" scripts
980 for(core::list<ModSpec>::Iterator i = m_mods.begin();
981 i != m_mods.end(); i++){
982 const ModSpec &mod = *i;
983 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
984 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
985 <<scriptpath<<"\"]"<<std::endl;
986 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
988 errorstream<<"Server: Failed to load and run "
989 <<scriptpath<<std::endl;
990 throw ModError("Failed to load and run "+scriptpath);
994 // Read Textures and calculate sha1 sums
997 // Apply item aliases in the node definition manager
998 m_nodedef->updateAliases(m_itemdef);
1000 // Initialize Environment
1002 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
1005 // Give environment reference to scripting api
1006 scriptapi_add_environment(m_lua, m_env);
1008 // Register us to receive map edit events
1009 m_env->getMap().addEventReceiver(this);
1011 // If file exists, load environment metadata
1012 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1014 infostream<<"Server: Loading environment metadata"<<std::endl;
1015 m_env->loadMeta(m_path_world);
1019 infostream<<"Server: Loading players"<<std::endl;
1020 m_env->deSerializePlayers(m_path_world);
1023 Add some test ActiveBlockModifiers to environment
1025 add_legacy_abms(m_env, m_nodedef);
1030 infostream<<"Server destructing"<<std::endl;
1033 Send shutdown message
1036 JMutexAutoLock conlock(m_con_mutex);
1038 std::wstring line = L"*** Server shutting down";
1041 Send the message to clients
1043 for(core::map<u16, RemoteClient*>::Iterator
1044 i = m_clients.getIterator();
1045 i.atEnd() == false; i++)
1047 // Get client and check that it is valid
1048 RemoteClient *client = i.getNode()->getValue();
1049 assert(client->peer_id == i.getNode()->getKey());
1050 if(client->serialization_version == SER_FMT_VER_INVALID)
1054 SendChatMessage(client->peer_id, line);
1056 catch(con::PeerNotFoundException &e)
1062 JMutexAutoLock envlock(m_env_mutex);
1067 infostream<<"Server: Saving players"<<std::endl;
1068 m_env->serializePlayers(m_path_world);
1071 Save environment metadata
1073 infostream<<"Server: Saving environment metadata"<<std::endl;
1074 m_env->saveMeta(m_path_world);
1086 JMutexAutoLock clientslock(m_con_mutex);
1088 for(core::map<u16, RemoteClient*>::Iterator
1089 i = m_clients.getIterator();
1090 i.atEnd() == false; i++)
1093 // NOTE: These are removed by env destructor
1095 u16 peer_id = i.getNode()->getKey();
1096 JMutexAutoLock envlock(m_env_mutex);
1097 m_env->removePlayer(peer_id);
1101 delete i.getNode()->getValue();
1105 // Delete things in the reverse order of creation
1112 // Deinitialize scripting
1113 infostream<<"Server: Deinitializing scripting"<<std::endl;
1114 script_deinit(m_lua);
1117 void Server::start(unsigned short port)
1119 DSTACK(__FUNCTION_NAME);
1120 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1122 // Stop thread if already running
1125 // Initialize connection
1126 m_con.SetTimeoutMs(30);
1130 m_thread.setRun(true);
1133 // ASCII art for the win!
1135 <<" .__ __ __ "<<std::endl
1136 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1137 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1138 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1139 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1140 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1141 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1142 actionstream<<"Server for gameid=\""<<m_gamespec.id
1143 <<"\" listening on port "<<port<<"."<<std::endl;
1148 DSTACK(__FUNCTION_NAME);
1150 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1152 // Stop threads (set run=false first so both start stopping)
1153 m_thread.setRun(false);
1154 m_emergethread.setRun(false);
1156 m_emergethread.stop();
1158 infostream<<"Server: Threads stopped"<<std::endl;
1161 void Server::step(float dtime)
1163 DSTACK(__FUNCTION_NAME);
1168 JMutexAutoLock lock(m_step_dtime_mutex);
1169 m_step_dtime += dtime;
1171 // Throw if fatal error occurred in thread
1172 std::string async_err = m_async_fatal_error.get();
1173 if(async_err != ""){
1174 throw ServerError(async_err);
1178 void Server::AsyncRunStep()
1180 DSTACK(__FUNCTION_NAME);
1182 g_profiler->add("Server::AsyncRunStep (num)", 1);
1186 JMutexAutoLock lock1(m_step_dtime_mutex);
1187 dtime = m_step_dtime;
1191 // Send blocks to clients
1198 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1200 //infostream<<"Server steps "<<dtime<<std::endl;
1201 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1204 JMutexAutoLock lock1(m_step_dtime_mutex);
1205 m_step_dtime -= dtime;
1212 m_uptime.set(m_uptime.get() + dtime);
1216 // Process connection's timeouts
1217 JMutexAutoLock lock2(m_con_mutex);
1218 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1219 m_con.RunTimeouts(dtime);
1223 // This has to be called so that the client list gets synced
1224 // with the peer list of the connection
1225 handlePeerChanges();
1229 Update time of day and overall game time
1232 JMutexAutoLock envlock(m_env_mutex);
1234 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1237 Send to clients at constant intervals
1240 m_time_of_day_send_timer -= dtime;
1241 if(m_time_of_day_send_timer < 0.0)
1243 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1245 //JMutexAutoLock envlock(m_env_mutex);
1246 JMutexAutoLock conlock(m_con_mutex);
1248 for(core::map<u16, RemoteClient*>::Iterator
1249 i = m_clients.getIterator();
1250 i.atEnd() == false; i++)
1252 RemoteClient *client = i.getNode()->getValue();
1253 //Player *player = m_env->getPlayer(client->peer_id);
1255 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1256 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1258 m_con.Send(client->peer_id, 0, data, true);
1264 JMutexAutoLock lock(m_env_mutex);
1266 ScopeProfiler sp(g_profiler, "SEnv step");
1267 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1271 const float map_timer_and_unload_dtime = 2.92;
1272 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1274 JMutexAutoLock lock(m_env_mutex);
1275 // Run Map's timers and unload unused data
1276 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1277 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1278 g_settings->getFloat("server_unload_unused_data_timeout"));
1289 JMutexAutoLock lock(m_env_mutex);
1290 JMutexAutoLock lock2(m_con_mutex);
1292 ScopeProfiler sp(g_profiler, "Server: handle players");
1294 //float player_max_speed = BS * 4.0; // Normal speed
1295 float player_max_speed = BS * 20; // Fast speed
1296 float player_max_speed_up = BS * 20;
1298 player_max_speed *= 2.5; // Tolerance
1299 player_max_speed_up *= 2.5;
1301 for(core::map<u16, RemoteClient*>::Iterator
1302 i = m_clients.getIterator();
1303 i.atEnd() == false; i++)
1305 RemoteClient *client = i.getNode()->getValue();
1306 ServerRemotePlayer *player =
1307 static_cast<ServerRemotePlayer*>
1308 (m_env->getPlayer(client->peer_id));
1313 Check player movements
1315 NOTE: Actually the server should handle player physics like the
1316 client does and compare player's position to what is calculated
1317 on our side. This is required when eg. players fly due to an
1320 player->m_last_good_position_age += dtime;
1321 if(player->m_last_good_position_age >= 1.0){
1322 float age = player->m_last_good_position_age;
1323 v3f diff = (player->getPosition() - player->m_last_good_position);
1324 float d_vert = diff.Y;
1326 float d_horiz = diff.getLength();
1327 /*infostream<<player->getName()<<"'s horizontal speed is "
1328 <<(d_horiz/age)<<std::endl;*/
1329 if(d_horiz <= age * player_max_speed &&
1330 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1331 player->m_last_good_position = player->getPosition();
1333 actionstream<<"Player "<<player->getName()
1334 <<" moved too fast; resetting position"
1336 player->setPosition(player->m_last_good_position);
1337 SendMovePlayer(player);
1339 player->m_last_good_position_age = 0;
1343 Handle player HPs (die if hp=0)
1345 if(player->hp == 0 && player->m_hp_not_sent)
1349 Send player inventories and HPs if necessary
1351 if(player->m_inventory_not_sent){
1352 UpdateCrafting(player->peer_id);
1353 SendInventory(player->peer_id);
1355 if(player->m_hp_not_sent){
1356 SendPlayerHP(player);
1362 if(!player->m_is_in_environment){
1363 player->m_removed = false;
1365 m_env->addActiveObject(player);
1370 /* Transform liquids */
1371 m_liquid_transform_timer += dtime;
1372 if(m_liquid_transform_timer >= 1.00)
1374 m_liquid_transform_timer -= 1.00;
1376 JMutexAutoLock lock(m_env_mutex);
1378 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1380 core::map<v3s16, MapBlock*> modified_blocks;
1381 m_env->getMap().transformLiquids(modified_blocks);
1386 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1387 ServerMap &map = ((ServerMap&)m_env->getMap());
1388 map.updateLighting(modified_blocks, lighting_modified_blocks);
1390 // Add blocks modified by lighting to modified_blocks
1391 for(core::map<v3s16, MapBlock*>::Iterator
1392 i = lighting_modified_blocks.getIterator();
1393 i.atEnd() == false; i++)
1395 MapBlock *block = i.getNode()->getValue();
1396 modified_blocks.insert(block->getPos(), block);
1400 Set the modified blocks unsent for all the clients
1403 JMutexAutoLock lock2(m_con_mutex);
1405 for(core::map<u16, RemoteClient*>::Iterator
1406 i = m_clients.getIterator();
1407 i.atEnd() == false; i++)
1409 RemoteClient *client = i.getNode()->getValue();
1411 if(modified_blocks.size() > 0)
1413 // Remove block from sent history
1414 client->SetBlocksNotSent(modified_blocks);
1419 // Periodically print some info
1421 float &counter = m_print_info_timer;
1427 JMutexAutoLock lock2(m_con_mutex);
1429 if(m_clients.size() != 0)
1430 infostream<<"Players:"<<std::endl;
1431 for(core::map<u16, RemoteClient*>::Iterator
1432 i = m_clients.getIterator();
1433 i.atEnd() == false; i++)
1435 //u16 peer_id = i.getNode()->getKey();
1436 RemoteClient *client = i.getNode()->getValue();
1437 Player *player = m_env->getPlayer(client->peer_id);
1440 infostream<<"* "<<player->getName()<<"\t";
1441 client->PrintInfo(infostream);
1446 //if(g_settings->getBool("enable_experimental"))
1450 Check added and deleted active objects
1453 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1454 JMutexAutoLock envlock(m_env_mutex);
1455 JMutexAutoLock conlock(m_con_mutex);
1457 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1459 // Radius inside which objects are active
1460 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1461 radius *= MAP_BLOCKSIZE;
1463 for(core::map<u16, RemoteClient*>::Iterator
1464 i = m_clients.getIterator();
1465 i.atEnd() == false; i++)
1467 RemoteClient *client = i.getNode()->getValue();
1469 // If definitions and textures have not been sent, don't
1470 // send objects either
1471 if(!client->definitions_sent)
1474 Player *player = m_env->getPlayer(client->peer_id);
1477 // This can happen if the client timeouts somehow
1478 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1480 <<" has no associated player"<<std::endl;*/
1483 v3s16 pos = floatToInt(player->getPosition(), BS);
1485 core::map<u16, bool> removed_objects;
1486 core::map<u16, bool> added_objects;
1487 m_env->getRemovedActiveObjects(pos, radius,
1488 client->m_known_objects, removed_objects);
1489 m_env->getAddedActiveObjects(pos, radius,
1490 client->m_known_objects, added_objects);
1492 // Ignore if nothing happened
1493 if(removed_objects.size() == 0 && added_objects.size() == 0)
1495 //infostream<<"active objects: none changed"<<std::endl;
1499 std::string data_buffer;
1503 // Handle removed objects
1504 writeU16((u8*)buf, removed_objects.size());
1505 data_buffer.append(buf, 2);
1506 for(core::map<u16, bool>::Iterator
1507 i = removed_objects.getIterator();
1508 i.atEnd()==false; i++)
1511 u16 id = i.getNode()->getKey();
1512 ServerActiveObject* obj = m_env->getActiveObject(id);
1514 // Add to data buffer for sending
1515 writeU16((u8*)buf, i.getNode()->getKey());
1516 data_buffer.append(buf, 2);
1518 // Remove from known objects
1519 client->m_known_objects.remove(i.getNode()->getKey());
1521 if(obj && obj->m_known_by_count > 0)
1522 obj->m_known_by_count--;
1525 // Handle added objects
1526 writeU16((u8*)buf, added_objects.size());
1527 data_buffer.append(buf, 2);
1528 for(core::map<u16, bool>::Iterator
1529 i = added_objects.getIterator();
1530 i.atEnd()==false; i++)
1533 u16 id = i.getNode()->getKey();
1534 ServerActiveObject* obj = m_env->getActiveObject(id);
1537 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1539 infostream<<"WARNING: "<<__FUNCTION_NAME
1540 <<": NULL object"<<std::endl;
1542 type = obj->getType();
1544 // Add to data buffer for sending
1545 writeU16((u8*)buf, id);
1546 data_buffer.append(buf, 2);
1547 writeU8((u8*)buf, type);
1548 data_buffer.append(buf, 1);
1551 data_buffer.append(serializeLongString(
1552 obj->getClientInitializationData()));
1554 data_buffer.append(serializeLongString(""));
1556 // Add to known objects
1557 client->m_known_objects.insert(i.getNode()->getKey(), false);
1560 obj->m_known_by_count++;
1564 SharedBuffer<u8> reply(2 + data_buffer.size());
1565 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1566 memcpy((char*)&reply[2], data_buffer.c_str(),
1567 data_buffer.size());
1569 m_con.Send(client->peer_id, 0, reply, true);
1571 verbosestream<<"Server: Sent object remove/add: "
1572 <<removed_objects.size()<<" removed, "
1573 <<added_objects.size()<<" added, "
1574 <<"packet size is "<<reply.getSize()<<std::endl;
1579 Collect a list of all the objects known by the clients
1580 and report it back to the environment.
1583 core::map<u16, bool> all_known_objects;
1585 for(core::map<u16, RemoteClient*>::Iterator
1586 i = m_clients.getIterator();
1587 i.atEnd() == false; i++)
1589 RemoteClient *client = i.getNode()->getValue();
1590 // Go through all known objects of client
1591 for(core::map<u16, bool>::Iterator
1592 i = client->m_known_objects.getIterator();
1593 i.atEnd()==false; i++)
1595 u16 id = i.getNode()->getKey();
1596 all_known_objects[id] = true;
1600 m_env->setKnownActiveObjects(whatever);
1606 Send object messages
1609 JMutexAutoLock envlock(m_env_mutex);
1610 JMutexAutoLock conlock(m_con_mutex);
1612 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1615 // Value = data sent by object
1616 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1618 // Get active object messages from environment
1621 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1625 core::list<ActiveObjectMessage>* message_list = NULL;
1626 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1627 n = buffered_messages.find(aom.id);
1630 message_list = new core::list<ActiveObjectMessage>;
1631 buffered_messages.insert(aom.id, message_list);
1635 message_list = n->getValue();
1637 message_list->push_back(aom);
1640 // Route data to every client
1641 for(core::map<u16, RemoteClient*>::Iterator
1642 i = m_clients.getIterator();
1643 i.atEnd()==false; i++)
1645 RemoteClient *client = i.getNode()->getValue();
1646 std::string reliable_data;
1647 std::string unreliable_data;
1648 // Go through all objects in message buffer
1649 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1650 j = buffered_messages.getIterator();
1651 j.atEnd()==false; j++)
1653 // If object is not known by client, skip it
1654 u16 id = j.getNode()->getKey();
1655 if(client->m_known_objects.find(id) == NULL)
1657 // Get message list of object
1658 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1659 // Go through every message
1660 for(core::list<ActiveObjectMessage>::Iterator
1661 k = list->begin(); k != list->end(); k++)
1663 // Compose the full new data with header
1664 ActiveObjectMessage aom = *k;
1665 std::string new_data;
1668 writeU16((u8*)&buf[0], aom.id);
1669 new_data.append(buf, 2);
1671 new_data += serializeString(aom.datastring);
1672 // Add data to buffer
1674 reliable_data += new_data;
1676 unreliable_data += new_data;
1680 reliable_data and unreliable_data are now ready.
1683 if(reliable_data.size() > 0)
1685 SharedBuffer<u8> reply(2 + reliable_data.size());
1686 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1687 memcpy((char*)&reply[2], reliable_data.c_str(),
1688 reliable_data.size());
1690 m_con.Send(client->peer_id, 0, reply, true);
1692 if(unreliable_data.size() > 0)
1694 SharedBuffer<u8> reply(2 + unreliable_data.size());
1695 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1696 memcpy((char*)&reply[2], unreliable_data.c_str(),
1697 unreliable_data.size());
1698 // Send as unreliable
1699 m_con.Send(client->peer_id, 0, reply, false);
1702 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1704 infostream<<"Server: Size of object message data: "
1705 <<"reliable: "<<reliable_data.size()
1706 <<", unreliable: "<<unreliable_data.size()
1711 // Clear buffered_messages
1712 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1713 i = buffered_messages.getIterator();
1714 i.atEnd()==false; i++)
1716 delete i.getNode()->getValue();
1720 } // enable_experimental
1723 Send queued-for-sending map edit events.
1726 // We will be accessing the environment and the connection
1727 JMutexAutoLock lock(m_env_mutex);
1728 JMutexAutoLock conlock(m_con_mutex);
1730 // Don't send too many at a time
1733 // Single change sending is disabled if queue size is not small
1734 bool disable_single_change_sending = false;
1735 if(m_unsent_map_edit_queue.size() >= 4)
1736 disable_single_change_sending = true;
1738 int event_count = m_unsent_map_edit_queue.size();
1740 // We'll log the amount of each
1743 while(m_unsent_map_edit_queue.size() != 0)
1745 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1747 // Players far away from the change are stored here.
1748 // Instead of sending the changes, MapBlocks are set not sent
1750 core::list<u16> far_players;
1752 if(event->type == MEET_ADDNODE)
1754 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1755 prof.add("MEET_ADDNODE", 1);
1756 if(disable_single_change_sending)
1757 sendAddNode(event->p, event->n, event->already_known_by_peer,
1760 sendAddNode(event->p, event->n, event->already_known_by_peer,
1763 else if(event->type == MEET_REMOVENODE)
1765 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1766 prof.add("MEET_REMOVENODE", 1);
1767 if(disable_single_change_sending)
1768 sendRemoveNode(event->p, event->already_known_by_peer,
1771 sendRemoveNode(event->p, event->already_known_by_peer,
1774 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1776 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1777 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1778 setBlockNotSent(event->p);
1780 else if(event->type == MEET_OTHER)
1782 infostream<<"Server: MEET_OTHER"<<std::endl;
1783 prof.add("MEET_OTHER", 1);
1784 for(core::map<v3s16, bool>::Iterator
1785 i = event->modified_blocks.getIterator();
1786 i.atEnd()==false; i++)
1788 v3s16 p = i.getNode()->getKey();
1794 prof.add("unknown", 1);
1795 infostream<<"WARNING: Server: Unknown MapEditEvent "
1796 <<((u32)event->type)<<std::endl;
1800 Set blocks not sent to far players
1802 if(far_players.size() > 0)
1804 // Convert list format to that wanted by SetBlocksNotSent
1805 core::map<v3s16, MapBlock*> modified_blocks2;
1806 for(core::map<v3s16, bool>::Iterator
1807 i = event->modified_blocks.getIterator();
1808 i.atEnd()==false; i++)
1810 v3s16 p = i.getNode()->getKey();
1811 modified_blocks2.insert(p,
1812 m_env->getMap().getBlockNoCreateNoEx(p));
1814 // Set blocks not sent
1815 for(core::list<u16>::Iterator
1816 i = far_players.begin();
1817 i != far_players.end(); i++)
1820 RemoteClient *client = getClient(peer_id);
1823 client->SetBlocksNotSent(modified_blocks2);
1829 /*// Don't send too many at a time
1831 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1835 if(event_count >= 5){
1836 infostream<<"Server: MapEditEvents:"<<std::endl;
1837 prof.print(infostream);
1838 } else if(event_count != 0){
1839 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1840 prof.print(verbosestream);
1846 Trigger emergethread (it somehow gets to a non-triggered but
1847 bysy state sometimes)
1850 float &counter = m_emergethread_trigger_timer;
1856 m_emergethread.trigger();
1860 // Save map, players and auth stuff
1862 float &counter = m_savemap_timer;
1864 if(counter >= g_settings->getFloat("server_map_save_interval"))
1867 JMutexAutoLock lock(m_env_mutex);
1869 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1872 if(m_authmanager.isModified())
1873 m_authmanager.save();
1876 if(m_banmanager.isModified())
1877 m_banmanager.save();
1879 // Save changed parts of map
1880 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1883 m_env->serializePlayers(m_path_world);
1885 // Save environment metadata
1886 m_env->saveMeta(m_path_world);
1891 void Server::Receive()
1893 DSTACK(__FUNCTION_NAME);
1894 SharedBuffer<u8> data;
1899 JMutexAutoLock conlock(m_con_mutex);
1900 datasize = m_con.Receive(peer_id, data);
1903 // This has to be called so that the client list gets synced
1904 // with the peer list of the connection
1905 handlePeerChanges();
1907 ProcessData(*data, datasize, peer_id);
1909 catch(con::InvalidIncomingDataException &e)
1911 infostream<<"Server::Receive(): "
1912 "InvalidIncomingDataException: what()="
1913 <<e.what()<<std::endl;
1915 catch(con::PeerNotFoundException &e)
1917 //NOTE: This is not needed anymore
1919 // The peer has been disconnected.
1920 // Find the associated player and remove it.
1922 /*JMutexAutoLock envlock(m_env_mutex);
1924 infostream<<"ServerThread: peer_id="<<peer_id
1925 <<" has apparently closed connection. "
1926 <<"Removing player."<<std::endl;
1928 m_env->removePlayer(peer_id);*/
1932 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1934 DSTACK(__FUNCTION_NAME);
1935 // Environment is locked first.
1936 JMutexAutoLock envlock(m_env_mutex);
1937 JMutexAutoLock conlock(m_con_mutex);
1939 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1942 Address address = m_con.GetPeerAddress(peer_id);
1943 std::string addr_s = address.serializeString();
1945 // drop player if is ip is banned
1946 if(m_banmanager.isIpBanned(addr_s)){
1947 infostream<<"Server: A banned client tried to connect from "
1948 <<addr_s<<"; banned name was "
1949 <<m_banmanager.getBanName(addr_s)<<std::endl;
1950 // This actually doesn't seem to transfer to the client
1951 SendAccessDenied(m_con, peer_id,
1952 L"Your ip is banned. Banned name was "
1953 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1954 m_con.DeletePeer(peer_id);
1958 catch(con::PeerNotFoundException &e)
1960 infostream<<"Server::ProcessData(): Cancelling: peer "
1961 <<peer_id<<" not found"<<std::endl;
1965 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1967 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1975 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1977 if(command == TOSERVER_INIT)
1979 // [0] u16 TOSERVER_INIT
1980 // [2] u8 SER_FMT_VER_HIGHEST
1981 // [3] u8[20] player_name
1982 // [23] u8[28] password <--- can be sent without this, from old versions
1984 if(datasize < 2+1+PLAYERNAME_SIZE)
1987 verbosestream<<"Server: Got TOSERVER_INIT from "
1988 <<peer_id<<std::endl;
1990 // First byte after command is maximum supported
1991 // serialization version
1992 u8 client_max = data[2];
1993 u8 our_max = SER_FMT_VER_HIGHEST;
1994 // Use the highest version supported by both
1995 u8 deployed = core::min_(client_max, our_max);
1996 // If it's lower than the lowest supported, give up.
1997 if(deployed < SER_FMT_VER_LOWEST)
1998 deployed = SER_FMT_VER_INVALID;
2000 //peer->serialization_version = deployed;
2001 getClient(peer_id)->pending_serialization_version = deployed;
2003 if(deployed == SER_FMT_VER_INVALID)
2005 actionstream<<"Server: A mismatched client tried to connect from "
2006 <<addr_s<<std::endl;
2007 infostream<<"Server: Cannot negotiate "
2008 "serialization version with peer "
2009 <<peer_id<<std::endl;
2010 SendAccessDenied(m_con, peer_id, std::wstring(
2011 L"Your client's version is not supported.\n"
2012 L"Server version is ")
2013 + narrow_to_wide(VERSION_STRING) + L"."
2019 Read and check network protocol version
2022 u16 net_proto_version = 0;
2023 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2025 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2028 getClient(peer_id)->net_proto_version = net_proto_version;
2030 if(net_proto_version == 0)
2032 actionstream<<"Server: An old tried to connect from "<<addr_s
2034 SendAccessDenied(m_con, peer_id, std::wstring(
2035 L"Your client's version is not supported.\n"
2036 L"Server version is ")
2037 + narrow_to_wide(VERSION_STRING) + L"."
2042 if(g_settings->getBool("strict_protocol_version_checking"))
2044 if(net_proto_version != PROTOCOL_VERSION)
2046 actionstream<<"Server: A mismatched client tried to connect"
2047 <<" from "<<addr_s<<std::endl;
2048 SendAccessDenied(m_con, peer_id, std::wstring(
2049 L"Your client's version is not supported.\n"
2050 L"Server version is ")
2051 + narrow_to_wide(VERSION_STRING) + L",\n"
2052 + L"server's PROTOCOL_VERSION is "
2053 + narrow_to_wide(itos(PROTOCOL_VERSION))
2054 + L", client's PROTOCOL_VERSION is "
2055 + narrow_to_wide(itos(net_proto_version))
2066 char playername[PLAYERNAME_SIZE];
2067 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2069 playername[i] = data[3+i];
2071 playername[PLAYERNAME_SIZE-1] = 0;
2073 if(playername[0]=='\0')
2075 actionstream<<"Server: Player with an empty name "
2076 <<"tried to connect from "<<addr_s<<std::endl;
2077 SendAccessDenied(m_con, peer_id,
2082 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2084 actionstream<<"Server: Player with an invalid name "
2085 <<"tried to connect from "<<addr_s<<std::endl;
2086 SendAccessDenied(m_con, peer_id,
2087 L"Name contains unallowed characters");
2091 infostream<<"Server: New connection: \""<<playername<<"\" from "
2092 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2095 char password[PASSWORD_SIZE];
2096 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2098 // old version - assume blank password
2103 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2105 password[i] = data[23+i];
2107 password[PASSWORD_SIZE-1] = 0;
2110 // Add player to auth manager
2111 if(m_authmanager.exists(playername) == false)
2113 std::wstring default_password =
2114 narrow_to_wide(g_settings->get("default_password"));
2115 std::string translated_default_password =
2116 translatePassword(playername, default_password);
2118 // If default_password is empty, allow any initial password
2119 if (default_password.length() == 0)
2120 translated_default_password = password;
2122 infostream<<"Server: adding player "<<playername
2123 <<" to auth manager"<<std::endl;
2124 m_authmanager.add(playername);
2125 m_authmanager.setPassword(playername, translated_default_password);
2126 m_authmanager.setPrivs(playername,
2127 stringToPrivs(g_settings->get("default_privs")));
2128 m_authmanager.save();
2131 std::string checkpwd = m_authmanager.getPassword(playername);
2133 /*infostream<<"Server: Client gave password '"<<password
2134 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2136 if(password != checkpwd)
2138 infostream<<"Server: peer_id="<<peer_id
2139 <<": supplied invalid password for "
2140 <<playername<<std::endl;
2141 SendAccessDenied(m_con, peer_id, L"Invalid password");
2145 // Do not allow multiple players in simple singleplayer mode.
2146 // This isn't a perfect way to do it, but will suffice for now.
2147 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2148 infostream<<"Server: Not allowing another client to connect in"
2149 <<" simple singleplayer mode"<<std::endl;
2150 SendAccessDenied(m_con, peer_id,
2151 L"Running in simple singleplayer mode.");
2155 // Enforce user limit.
2156 // Don't enforce for users that have some admin right
2157 if(m_clients.size() >= g_settings->getU16("max_users") &&
2158 (m_authmanager.getPrivs(playername)
2159 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2160 playername != g_settings->get("name"))
2162 actionstream<<"Server: "<<playername<<" tried to join, but there"
2163 <<" are already max_users="
2164 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2165 SendAccessDenied(m_con, peer_id, L"Too many users.");
2170 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2172 // If failed, cancel
2175 errorstream<<"Server: peer_id="<<peer_id
2176 <<": failed to emerge player"<<std::endl;
2181 Answer with a TOCLIENT_INIT
2184 SharedBuffer<u8> reply(2+1+6+8);
2185 writeU16(&reply[0], TOCLIENT_INIT);
2186 writeU8(&reply[2], deployed);
2187 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2188 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2191 m_con.Send(peer_id, 0, reply, true);
2195 Send complete position information
2197 SendMovePlayer(player);
2202 if(command == TOSERVER_INIT2)
2204 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2205 <<peer_id<<std::endl;
2208 getClient(peer_id)->serialization_version
2209 = getClient(peer_id)->pending_serialization_version;
2212 Send some initialization data
2215 infostream<<"Server: Sending content to "
2216 <<getPlayerName(peer_id)<<std::endl;
2218 // Send item definitions
2219 SendItemDef(m_con, peer_id, m_itemdef);
2221 // Send node definitions
2222 SendNodeDef(m_con, peer_id, m_nodedef);
2224 // Send texture announcement
2225 sendMediaAnnouncement(peer_id);
2227 // Send player info to all players
2228 //SendPlayerInfos();
2230 // Send inventory to player
2231 UpdateCrafting(peer_id);
2232 SendInventory(peer_id);
2234 // Send player items to all players
2237 Player *player = m_env->getPlayer(peer_id);
2240 SendPlayerHP(player);
2242 // Show death screen if necessary
2244 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2248 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2249 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2250 m_con.Send(peer_id, 0, data, true);
2253 // Note things in chat if not in simple singleplayer mode
2254 if(!m_simple_singleplayer_mode)
2256 // Send information about server to player in chat
2257 SendChatMessage(peer_id, getStatusString());
2259 // Send information about joining in chat
2261 std::wstring name = L"unknown";
2262 Player *player = m_env->getPlayer(peer_id);
2264 name = narrow_to_wide(player->getName());
2266 std::wstring message;
2269 message += L" joined game";
2270 BroadcastChatMessage(message);
2274 // Warnings about protocol version can be issued here
2275 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2277 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2284 std::ostringstream os(std::ios_base::binary);
2285 for(core::map<u16, RemoteClient*>::Iterator
2286 i = m_clients.getIterator();
2287 i.atEnd() == false; i++)
2289 RemoteClient *client = i.getNode()->getValue();
2290 assert(client->peer_id == i.getNode()->getKey());
2291 if(client->serialization_version == SER_FMT_VER_INVALID)
2294 Player *player = m_env->getPlayer(client->peer_id);
2297 // Get name of player
2298 os<<player->getName()<<" ";
2301 actionstream<<player->getName()<<" joins game. List of players: "
2302 <<os.str()<<std::endl;
2308 if(peer_ser_ver == SER_FMT_VER_INVALID)
2310 infostream<<"Server::ProcessData(): Cancelling: Peer"
2311 " serialization format invalid or not initialized."
2312 " Skipping incoming command="<<command<<std::endl;
2316 Player *player = m_env->getPlayer(peer_id);
2317 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2320 infostream<<"Server::ProcessData(): Cancelling: "
2321 "No player for peer_id="<<peer_id
2325 if(command == TOSERVER_PLAYERPOS)
2327 if(datasize < 2+12+12+4+4)
2331 v3s32 ps = readV3S32(&data[start+2]);
2332 v3s32 ss = readV3S32(&data[start+2+12]);
2333 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2334 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2335 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2336 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2337 pitch = wrapDegrees(pitch);
2338 yaw = wrapDegrees(yaw);
2340 player->setPosition(position);
2341 player->setSpeed(speed);
2342 player->setPitch(pitch);
2343 player->setYaw(yaw);
2345 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2346 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2347 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2349 else if(command == TOSERVER_GOTBLOCKS)
2362 u16 count = data[2];
2363 for(u16 i=0; i<count; i++)
2365 if((s16)datasize < 2+1+(i+1)*6)
2366 throw con::InvalidIncomingDataException
2367 ("GOTBLOCKS length is too short");
2368 v3s16 p = readV3S16(&data[2+1+i*6]);
2369 /*infostream<<"Server: GOTBLOCKS ("
2370 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2371 RemoteClient *client = getClient(peer_id);
2372 client->GotBlock(p);
2375 else if(command == TOSERVER_DELETEDBLOCKS)
2388 u16 count = data[2];
2389 for(u16 i=0; i<count; i++)
2391 if((s16)datasize < 2+1+(i+1)*6)
2392 throw con::InvalidIncomingDataException
2393 ("DELETEDBLOCKS length is too short");
2394 v3s16 p = readV3S16(&data[2+1+i*6]);
2395 /*infostream<<"Server: DELETEDBLOCKS ("
2396 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2397 RemoteClient *client = getClient(peer_id);
2398 client->SetBlockNotSent(p);
2401 else if(command == TOSERVER_CLICK_OBJECT)
2403 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2406 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2408 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2411 else if(command == TOSERVER_GROUND_ACTION)
2413 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2417 else if(command == TOSERVER_RELEASE)
2419 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2422 else if(command == TOSERVER_SIGNTEXT)
2424 infostream<<"Server: SIGNTEXT not supported anymore"
2428 else if(command == TOSERVER_SIGNNODETEXT)
2430 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2438 std::string datastring((char*)&data[2], datasize-2);
2439 std::istringstream is(datastring, std::ios_base::binary);
2442 is.read((char*)buf, 6);
2443 v3s16 p = readV3S16(buf);
2444 is.read((char*)buf, 2);
2445 u16 textlen = readU16(buf);
2447 for(u16 i=0; i<textlen; i++)
2449 is.read((char*)buf, 1);
2450 text += (char)buf[0];
2453 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2457 meta->setText(text);
2459 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2460 <<" at "<<PP(p)<<std::endl;
2462 v3s16 blockpos = getNodeBlockPos(p);
2463 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2466 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2470 setBlockNotSent(blockpos);
2472 else if(command == TOSERVER_INVENTORY_ACTION)
2474 // Strip command and create a stream
2475 std::string datastring((char*)&data[2], datasize-2);
2476 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2477 std::istringstream is(datastring, std::ios_base::binary);
2479 InventoryAction *a = InventoryAction::deSerialize(is);
2482 infostream<<"TOSERVER_INVENTORY_ACTION: "
2483 <<"InventoryAction::deSerialize() returned NULL"
2489 Note: Always set inventory not sent, to repair cases
2490 where the client made a bad prediction.
2494 Handle restrictions and special cases of the move action
2496 if(a->getType() == IACTION_MOVE)
2498 IMoveAction *ma = (IMoveAction*)a;
2500 ma->from_inv.applyCurrentPlayer(player->getName());
2501 ma->to_inv.applyCurrentPlayer(player->getName());
2503 setInventoryModified(ma->from_inv);
2504 setInventoryModified(ma->to_inv);
2506 bool from_inv_is_current_player =
2507 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2508 (ma->from_inv.name == player->getName());
2510 bool to_inv_is_current_player =
2511 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2512 (ma->to_inv.name == player->getName());
2515 Disable moving items out of craftpreview
2517 if(ma->from_list == "craftpreview")
2519 infostream<<"Ignoring IMoveAction from "
2520 <<(ma->from_inv.dump())<<":"<<ma->from_list
2521 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2522 <<" because src is "<<ma->from_list<<std::endl;
2528 Disable moving items into craftresult and craftpreview
2530 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2532 infostream<<"Ignoring IMoveAction from "
2533 <<(ma->from_inv.dump())<<":"<<ma->from_list
2534 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2535 <<" because dst is "<<ma->to_list<<std::endl;
2540 // Disallow moving items in elsewhere than player's inventory
2541 // if not allowed to interact
2542 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2543 && (!from_inv_is_current_player
2544 || !to_inv_is_current_player))
2546 infostream<<"Cannot move outside of player's inventory: "
2547 <<"No interact privilege"<<std::endl;
2552 // If player is not an admin, check for ownership of src and dst
2553 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2555 std::string owner_from = getInventoryOwner(ma->from_inv);
2556 if(owner_from != "" && owner_from != player->getName())
2558 infostream<<"WARNING: "<<player->getName()
2559 <<" tried to access an inventory that"
2560 <<" belongs to "<<owner_from<<std::endl;
2565 std::string owner_to = getInventoryOwner(ma->to_inv);
2566 if(owner_to != "" && owner_to != player->getName())
2568 infostream<<"WARNING: "<<player->getName()
2569 <<" tried to access an inventory that"
2570 <<" belongs to "<<owner_to<<std::endl;
2577 Handle restrictions and special cases of the drop action
2579 else if(a->getType() == IACTION_DROP)
2581 IDropAction *da = (IDropAction*)a;
2583 da->from_inv.applyCurrentPlayer(player->getName());
2585 setInventoryModified(da->from_inv);
2587 // Disallow dropping items if not allowed to interact
2588 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2593 // If player is not an admin, check for ownership
2594 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2596 std::string owner_from = getInventoryOwner(da->from_inv);
2597 if(owner_from != "" && owner_from != player->getName())
2599 infostream<<"WARNING: "<<player->getName()
2600 <<" tried to access an inventory that"
2601 <<" belongs to "<<owner_from<<std::endl;
2608 Handle restrictions and special cases of the craft action
2610 else if(a->getType() == IACTION_CRAFT)
2612 ICraftAction *ca = (ICraftAction*)a;
2614 ca->craft_inv.applyCurrentPlayer(player->getName());
2616 setInventoryModified(ca->craft_inv);
2618 //bool craft_inv_is_current_player =
2619 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2620 // (ca->craft_inv.name == player->getName());
2622 // Disallow crafting if not allowed to interact
2623 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2625 infostream<<"Cannot craft: "
2626 <<"No interact privilege"<<std::endl;
2631 // If player is not an admin, check for ownership of inventory
2632 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2634 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2635 if(owner_craft != "" && owner_craft != player->getName())
2637 infostream<<"WARNING: "<<player->getName()
2638 <<" tried to access an inventory that"
2639 <<" belongs to "<<owner_craft<<std::endl;
2647 a->apply(this, srp, this);
2651 else if(command == TOSERVER_CHAT_MESSAGE)
2659 std::string datastring((char*)&data[2], datasize-2);
2660 std::istringstream is(datastring, std::ios_base::binary);
2663 is.read((char*)buf, 2);
2664 u16 len = readU16(buf);
2666 std::wstring message;
2667 for(u16 i=0; i<len; i++)
2669 is.read((char*)buf, 2);
2670 message += (wchar_t)readU16(buf);
2673 // Get player name of this client
2674 std::wstring name = narrow_to_wide(player->getName());
2677 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2678 wide_to_narrow(message));
2679 // If script ate the message, don't proceed
2683 // Line to send to players
2685 // Whether to send to the player that sent the line
2686 bool send_to_sender = false;
2687 // Whether to send to other players
2688 bool send_to_others = false;
2690 // Local player gets all privileges regardless of
2691 // what's set on their account.
2692 u64 privs = getPlayerPrivs(player);
2695 if(message[0] == L'/')
2697 size_t strip_size = 1;
2698 if (message[1] == L'#') // support old-style commans
2700 message = message.substr(strip_size);
2702 WStrfnd f1(message);
2703 f1.next(L" "); // Skip over /#whatever
2704 std::wstring paramstring = f1.next(L"");
2706 ServerCommandContext *ctx = new ServerCommandContext(
2707 str_split(message, L' '),
2714 std::wstring reply(processServerCommand(ctx));
2715 send_to_sender = ctx->flags & SEND_TO_SENDER;
2716 send_to_others = ctx->flags & SEND_TO_OTHERS;
2718 if (ctx->flags & SEND_NO_PREFIX)
2721 line += L"Server: " + reply;
2728 if(privs & PRIV_SHOUT)
2734 send_to_others = true;
2738 line += L"Server: You are not allowed to shout";
2739 send_to_sender = true;
2746 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2749 Send the message to clients
2751 for(core::map<u16, RemoteClient*>::Iterator
2752 i = m_clients.getIterator();
2753 i.atEnd() == false; i++)
2755 // Get client and check that it is valid
2756 RemoteClient *client = i.getNode()->getValue();
2757 assert(client->peer_id == i.getNode()->getKey());
2758 if(client->serialization_version == SER_FMT_VER_INVALID)
2762 bool sender_selected = (peer_id == client->peer_id);
2763 if(sender_selected == true && send_to_sender == false)
2765 if(sender_selected == false && send_to_others == false)
2768 SendChatMessage(client->peer_id, line);
2772 else if(command == TOSERVER_DAMAGE)
2774 std::string datastring((char*)&data[2], datasize-2);
2775 std::istringstream is(datastring, std::ios_base::binary);
2776 u8 damage = readU8(is);
2778 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2780 if(g_settings->getBool("enable_damage"))
2782 actionstream<<player->getName()<<" damaged by "
2783 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2786 srp->setHP(srp->getHP() - damage);
2788 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2791 if(srp->m_hp_not_sent)
2792 SendPlayerHP(player);
2796 // Force send (to correct the client's predicted HP)
2797 SendPlayerHP(player);
2800 else if(command == TOSERVER_PASSWORD)
2803 [0] u16 TOSERVER_PASSWORD
2804 [2] u8[28] old password
2805 [30] u8[28] new password
2808 if(datasize != 2+PASSWORD_SIZE*2)
2810 /*char password[PASSWORD_SIZE];
2811 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2812 password[i] = data[2+i];
2813 password[PASSWORD_SIZE-1] = 0;*/
2815 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2823 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2825 char c = data[2+PASSWORD_SIZE+i];
2831 infostream<<"Server: Client requests a password change from "
2832 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2834 std::string playername = player->getName();
2836 if(m_authmanager.exists(playername) == false)
2838 infostream<<"Server: playername not found in authmanager"<<std::endl;
2839 // Wrong old password supplied!!
2840 SendChatMessage(peer_id, L"playername not found in authmanager");
2844 std::string checkpwd = m_authmanager.getPassword(playername);
2846 if(oldpwd != checkpwd)
2848 infostream<<"Server: invalid old password"<<std::endl;
2849 // Wrong old password supplied!!
2850 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2854 actionstream<<player->getName()<<" changes password"<<std::endl;
2856 m_authmanager.setPassword(playername, newpwd);
2858 infostream<<"Server: password change successful for "<<playername
2860 SendChatMessage(peer_id, L"Password change successful");
2862 else if(command == TOSERVER_PLAYERITEM)
2867 u16 item = readU16(&data[2]);
2868 srp->setWieldIndex(item);
2869 SendWieldedItem(srp);
2871 else if(command == TOSERVER_RESPAWN)
2876 RespawnPlayer(player);
2878 actionstream<<player->getName()<<" respawns at "
2879 <<PP(player->getPosition()/BS)<<std::endl;
2881 // ActiveObject is added to environment in AsyncRunStep after
2882 // the previous addition has been succesfully removed
2884 else if(command == TOSERVER_REQUEST_MEDIA) {
2885 std::string datastring((char*)&data[2], datasize-2);
2886 std::istringstream is(datastring, std::ios_base::binary);
2888 core::list<MediaRequest> tosend;
2889 u16 numfiles = readU16(is);
2891 infostream<<"Sending "<<numfiles<<" files to "
2892 <<getPlayerName(peer_id)<<std::endl;
2893 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2895 for(int i = 0; i < numfiles; i++) {
2896 std::string name = deSerializeString(is);
2897 tosend.push_back(MediaRequest(name));
2898 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2902 sendRequestedMedia(peer_id, tosend);
2904 // Now the client should know about everything
2905 // (definitions and files)
2906 getClient(peer_id)->definitions_sent = true;
2908 else if(command == TOSERVER_INTERACT)
2910 std::string datastring((char*)&data[2], datasize-2);
2911 std::istringstream is(datastring, std::ios_base::binary);
2917 [5] u32 length of the next item
2918 [9] serialized PointedThing
2920 0: start digging (from undersurface) or use
2921 1: stop digging (all parameters ignored)
2922 2: digging completed
2923 3: place block or item (to abovesurface)
2926 u8 action = readU8(is);
2927 u16 item_i = readU16(is);
2928 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2929 PointedThing pointed;
2930 pointed.deSerialize(tmp_is);
2932 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2933 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2937 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2938 <<" tried to interact, but is dead!"<<std::endl;
2942 v3f player_pos = srp->m_last_good_position;
2944 // Update wielded item
2945 if(srp->getWieldIndex() != item_i)
2947 srp->setWieldIndex(item_i);
2948 SendWieldedItem(srp);
2951 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2952 v3s16 p_under = pointed.node_undersurface;
2953 v3s16 p_above = pointed.node_abovesurface;
2955 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2956 ServerActiveObject *pointed_object = NULL;
2957 if(pointed.type == POINTEDTHING_OBJECT)
2959 pointed_object = m_env->getActiveObject(pointed.object_id);
2960 if(pointed_object == NULL)
2962 verbosestream<<"TOSERVER_INTERACT: "
2963 "pointed object is NULL"<<std::endl;
2969 v3f pointed_pos_under = player_pos;
2970 v3f pointed_pos_above = player_pos;
2971 if(pointed.type == POINTEDTHING_NODE)
2973 pointed_pos_under = intToFloat(p_under, BS);
2974 pointed_pos_above = intToFloat(p_above, BS);
2976 else if(pointed.type == POINTEDTHING_OBJECT)
2978 pointed_pos_under = pointed_object->getBasePosition();
2979 pointed_pos_above = pointed_pos_under;
2983 Check that target is reasonably close
2984 (only when digging or placing things)
2986 if(action == 0 || action == 2 || action == 3)
2988 float d = player_pos.getDistanceFrom(pointed_pos_under);
2989 float max_d = BS * 14; // Just some large enough value
2991 actionstream<<"Player "<<player->getName()
2992 <<" tried to access "<<pointed.dump()
2994 <<"d="<<d<<", max_d="<<max_d
2995 <<". ignoring."<<std::endl;
2996 // Re-send block to revert change on client-side
2997 RemoteClient *client = getClient(peer_id);
2998 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2999 client->SetBlockNotSent(blockpos);
3006 Make sure the player is allowed to do it
3008 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
3010 infostream<<"Ignoring interaction from player "<<player->getName()
3011 <<" because privileges are "<<getPlayerPrivs(player)
3017 0: start digging or punch object
3021 if(pointed.type == POINTEDTHING_NODE)
3024 NOTE: This can be used in the future to check if
3025 somebody is cheating, by checking the timing.
3027 MapNode n(CONTENT_IGNORE);
3030 n = m_env->getMap().getNode(p_under);
3032 catch(InvalidPositionException &e)
3034 infostream<<"Server: Not punching: Node not found."
3035 <<" Adding block to emerge queue."
3037 m_emerge_queue.addBlock(peer_id,
3038 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3040 if(n.getContent() != CONTENT_IGNORE)
3041 scriptapi_node_on_punch(m_lua, p_under, n, srp);
3043 else if(pointed.type == POINTEDTHING_OBJECT)
3045 // Skip if object has been removed
3046 if(pointed_object->m_removed)
3049 actionstream<<player->getName()<<" punches object "
3050 <<pointed.object_id<<": "
3051 <<pointed_object->getDescription()<<std::endl;
3053 ItemStack punchitem = srp->getWieldedItem();
3054 ToolCapabilities toolcap =
3055 punchitem.getToolCapabilities(m_itemdef);
3056 v3f dir = (pointed_object->getBasePosition() -
3057 (srp->getPosition() + srp->getEyeOffset())
3059 pointed_object->punch(dir, &toolcap, srp,
3060 srp->m_time_from_last_punch);
3061 srp->m_time_from_last_punch = 0;
3069 else if(action == 1)
3074 2: Digging completed
3076 else if(action == 2)
3078 // Only complete digging of nodes
3079 if(pointed.type == POINTEDTHING_NODE)
3081 MapNode n(CONTENT_IGNORE);
3084 n = m_env->getMap().getNode(p_under);
3086 catch(InvalidPositionException &e)
3088 infostream<<"Server: Not finishing digging: Node not found."
3089 <<" Adding block to emerge queue."
3091 m_emerge_queue.addBlock(peer_id,
3092 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3094 if(n.getContent() != CONTENT_IGNORE)
3095 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3100 3: place block or right-click object
3102 else if(action == 3)
3104 ItemStack item = srp->getWieldedItem();
3106 // Reset build time counter
3107 if(pointed.type == POINTEDTHING_NODE &&
3108 item.getDefinition(m_itemdef).type == ITEM_NODE)
3109 getClient(peer_id)->m_time_from_building = 0.0;
3111 if(pointed.type == POINTEDTHING_OBJECT)
3113 // Right click object
3115 // Skip if object has been removed
3116 if(pointed_object->m_removed)
3119 actionstream<<player->getName()<<" right-clicks object "
3120 <<pointed.object_id<<": "
3121 <<pointed_object->getDescription()<<std::endl;
3124 pointed_object->rightClick(srp);
3126 else if(scriptapi_item_on_place(m_lua,
3127 item, srp, pointed))
3129 // Placement was handled in lua
3131 // Apply returned ItemStack
3132 if(g_settings->getBool("creative_mode") == false)
3133 srp->setWieldedItem(item);
3141 else if(action == 4)
3143 ItemStack item = srp->getWieldedItem();
3145 actionstream<<player->getName()<<" uses "<<item.name
3146 <<", pointing at "<<pointed.dump()<<std::endl;
3148 if(scriptapi_item_on_use(m_lua,
3149 item, srp, pointed))
3151 // Apply returned ItemStack
3152 if(g_settings->getBool("creative_mode") == false)
3153 srp->setWieldedItem(item);
3159 Catch invalid actions
3163 infostream<<"WARNING: Server: Invalid action "
3164 <<action<<std::endl;
3167 else if(command == TOSERVER_REMOVED_SOUNDS)
3169 std::string datastring((char*)&data[2], datasize-2);
3170 std::istringstream is(datastring, std::ios_base::binary);
3172 int num = readU16(is);
3173 for(int k=0; k<num; k++){
3174 s32 id = readS32(is);
3175 std::map<s32, ServerPlayingSound>::iterator i =
3176 m_playing_sounds.find(id);
3177 if(i == m_playing_sounds.end())
3179 ServerPlayingSound &psound = i->second;
3180 psound.clients.erase(peer_id);
3181 if(psound.clients.size() == 0)
3182 m_playing_sounds.erase(i++);
3187 infostream<<"Server::ProcessData(): Ignoring "
3188 "unknown command "<<command<<std::endl;
3192 catch(SendFailedException &e)
3194 errorstream<<"Server::ProcessData(): SendFailedException: "
3200 void Server::onMapEditEvent(MapEditEvent *event)
3202 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3203 if(m_ignore_map_edit_events)
3205 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3207 MapEditEvent *e = event->clone();
3208 m_unsent_map_edit_queue.push_back(e);
3211 Inventory* Server::getInventory(const InventoryLocation &loc)
3214 case InventoryLocation::UNDEFINED:
3217 case InventoryLocation::CURRENT_PLAYER:
3220 case InventoryLocation::PLAYER:
3222 Player *player = m_env->getPlayer(loc.name.c_str());
3225 return &player->inventory;
3228 case InventoryLocation::NODEMETA:
3230 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3233 return meta->getInventory();
3241 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3244 case InventoryLocation::UNDEFINED:
3247 case InventoryLocation::CURRENT_PLAYER:
3250 case InventoryLocation::PLAYER:
3255 case InventoryLocation::NODEMETA:
3257 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3260 return meta->getOwner();
3268 void Server::setInventoryModified(const InventoryLocation &loc)
3271 case InventoryLocation::UNDEFINED:
3274 case InventoryLocation::PLAYER:
3276 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3277 (m_env->getPlayer(loc.name.c_str()));
3280 srp->m_inventory_not_sent = true;
3283 case InventoryLocation::NODEMETA:
3285 v3s16 blockpos = getNodeBlockPos(loc.p);
3287 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3289 meta->inventoryModified();
3291 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3293 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3295 setBlockNotSent(blockpos);
3303 core::list<PlayerInfo> Server::getPlayerInfo()
3305 DSTACK(__FUNCTION_NAME);
3306 JMutexAutoLock envlock(m_env_mutex);
3307 JMutexAutoLock conlock(m_con_mutex);
3309 core::list<PlayerInfo> list;
3311 core::list<Player*> players = m_env->getPlayers();
3313 core::list<Player*>::Iterator i;
3314 for(i = players.begin();
3315 i != players.end(); i++)
3319 Player *player = *i;
3322 // Copy info from connection to info struct
3323 info.id = player->peer_id;
3324 info.address = m_con.GetPeerAddress(player->peer_id);
3325 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3327 catch(con::PeerNotFoundException &e)
3329 // Set dummy peer info
3331 info.address = Address(0,0,0,0,0);
3335 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3336 info.position = player->getPosition();
3338 list.push_back(info);
3345 void Server::peerAdded(con::Peer *peer)
3347 DSTACK(__FUNCTION_NAME);
3348 verbosestream<<"Server::peerAdded(): peer->id="
3349 <<peer->id<<std::endl;
3352 c.type = PEER_ADDED;
3353 c.peer_id = peer->id;
3355 m_peer_change_queue.push_back(c);
3358 void Server::deletingPeer(con::Peer *peer, bool timeout)
3360 DSTACK(__FUNCTION_NAME);
3361 verbosestream<<"Server::deletingPeer(): peer->id="
3362 <<peer->id<<", timeout="<<timeout<<std::endl;
3365 c.type = PEER_REMOVED;
3366 c.peer_id = peer->id;
3367 c.timeout = timeout;
3368 m_peer_change_queue.push_back(c);
3375 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3377 DSTACK(__FUNCTION_NAME);
3378 std::ostringstream os(std::ios_base::binary);
3380 writeU16(os, TOCLIENT_HP);
3384 std::string s = os.str();
3385 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3387 con.Send(peer_id, 0, data, true);
3390 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3391 const std::wstring &reason)
3393 DSTACK(__FUNCTION_NAME);
3394 std::ostringstream os(std::ios_base::binary);
3396 writeU16(os, TOCLIENT_ACCESS_DENIED);
3397 os<<serializeWideString(reason);
3400 std::string s = os.str();
3401 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3403 con.Send(peer_id, 0, data, true);
3406 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3407 bool set_camera_point_target, v3f camera_point_target)
3409 DSTACK(__FUNCTION_NAME);
3410 std::ostringstream os(std::ios_base::binary);
3412 writeU16(os, TOCLIENT_DEATHSCREEN);
3413 writeU8(os, set_camera_point_target);
3414 writeV3F1000(os, camera_point_target);
3417 std::string s = os.str();
3418 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3420 con.Send(peer_id, 0, data, true);
3423 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3424 IItemDefManager *itemdef)
3426 DSTACK(__FUNCTION_NAME);
3427 std::ostringstream os(std::ios_base::binary);
3431 u32 length of the next item
3432 zlib-compressed serialized ItemDefManager
3434 writeU16(os, TOCLIENT_ITEMDEF);
3435 std::ostringstream tmp_os(std::ios::binary);
3436 itemdef->serialize(tmp_os);
3437 std::ostringstream tmp_os2(std::ios::binary);
3438 compressZlib(tmp_os.str(), tmp_os2);
3439 os<<serializeLongString(tmp_os2.str());
3442 std::string s = os.str();
3443 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3444 <<"): size="<<s.size()<<std::endl;
3445 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3447 con.Send(peer_id, 0, data, true);
3450 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3451 INodeDefManager *nodedef)
3453 DSTACK(__FUNCTION_NAME);
3454 std::ostringstream os(std::ios_base::binary);
3458 u32 length of the next item
3459 zlib-compressed serialized NodeDefManager
3461 writeU16(os, TOCLIENT_NODEDEF);
3462 std::ostringstream tmp_os(std::ios::binary);
3463 nodedef->serialize(tmp_os);
3464 std::ostringstream tmp_os2(std::ios::binary);
3465 compressZlib(tmp_os.str(), tmp_os2);
3466 os<<serializeLongString(tmp_os2.str());
3469 std::string s = os.str();
3470 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3471 <<"): size="<<s.size()<<std::endl;
3472 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3474 con.Send(peer_id, 0, data, true);
3478 Non-static send methods
3481 void Server::SendInventory(u16 peer_id)
3483 DSTACK(__FUNCTION_NAME);
3485 ServerRemotePlayer* player =
3486 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3489 player->m_inventory_not_sent = false;
3495 std::ostringstream os;
3496 //os.imbue(std::locale("C"));
3498 player->inventory.serialize(os);
3500 std::string s = os.str();
3502 SharedBuffer<u8> data(s.size()+2);
3503 writeU16(&data[0], TOCLIENT_INVENTORY);
3504 memcpy(&data[2], s.c_str(), s.size());
3507 m_con.Send(peer_id, 0, data, true);
3510 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3512 DSTACK(__FUNCTION_NAME);
3516 std::ostringstream os(std::ios_base::binary);
3518 writeU16(os, TOCLIENT_PLAYERITEM);
3520 writeU16(os, srp->peer_id);
3521 os<<serializeString(srp->getWieldedItem().getItemString());
3524 std::string s = os.str();
3525 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3527 m_con.SendToAll(0, data, true);
3530 void Server::SendPlayerItems()
3532 DSTACK(__FUNCTION_NAME);
3534 std::ostringstream os(std::ios_base::binary);
3535 core::list<Player *> players = m_env->getPlayers(true);
3537 writeU16(os, TOCLIENT_PLAYERITEM);
3538 writeU16(os, players.size());
3539 core::list<Player *>::Iterator i;
3540 for(i = players.begin(); i != players.end(); ++i)
3543 ServerRemotePlayer *srp =
3544 static_cast<ServerRemotePlayer*>(p);
3545 writeU16(os, p->peer_id);
3546 os<<serializeString(srp->getWieldedItem().getItemString());
3550 std::string s = os.str();
3551 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3553 m_con.SendToAll(0, data, true);
3556 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3558 DSTACK(__FUNCTION_NAME);
3560 std::ostringstream os(std::ios_base::binary);
3564 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3565 os.write((char*)buf, 2);
3568 writeU16(buf, message.size());
3569 os.write((char*)buf, 2);
3572 for(u32 i=0; i<message.size(); i++)
3576 os.write((char*)buf, 2);
3580 std::string s = os.str();
3581 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3583 m_con.Send(peer_id, 0, data, true);
3586 void Server::BroadcastChatMessage(const std::wstring &message)
3588 for(core::map<u16, RemoteClient*>::Iterator
3589 i = m_clients.getIterator();
3590 i.atEnd() == false; i++)
3592 // Get client and check that it is valid
3593 RemoteClient *client = i.getNode()->getValue();
3594 assert(client->peer_id == i.getNode()->getKey());
3595 if(client->serialization_version == SER_FMT_VER_INVALID)
3598 SendChatMessage(client->peer_id, message);
3602 void Server::SendPlayerHP(Player *player)
3604 SendHP(m_con, player->peer_id, player->hp);
3605 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3608 void Server::SendMovePlayer(Player *player)
3610 DSTACK(__FUNCTION_NAME);
3611 std::ostringstream os(std::ios_base::binary);
3613 writeU16(os, TOCLIENT_MOVE_PLAYER);
3614 writeV3F1000(os, player->getPosition());
3615 writeF1000(os, player->getPitch());
3616 writeF1000(os, player->getYaw());
3619 v3f pos = player->getPosition();
3620 f32 pitch = player->getPitch();
3621 f32 yaw = player->getYaw();
3622 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3623 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3630 std::string s = os.str();
3631 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3633 m_con.Send(player->peer_id, 0, data, true);
3636 s32 Server::playSound(const SimpleSoundSpec &spec,
3637 const ServerSoundParams ¶ms)
3639 // Find out initial position of sound
3640 bool pos_exists = false;
3641 v3f pos = params.getPos(m_env, &pos_exists);
3642 // If position is not found while it should be, cancel sound
3643 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3645 // Filter destination clients
3646 std::set<RemoteClient*> dst_clients;
3647 if(params.to_player != "")
3649 Player *player = m_env->getPlayer(params.to_player.c_str());
3651 infostream<<"Server::playSound: Player \""<<params.to_player
3652 <<"\" not found"<<std::endl;
3655 if(player->peer_id == PEER_ID_INEXISTENT){
3656 infostream<<"Server::playSound: Player \""<<params.to_player
3657 <<"\" not connected"<<std::endl;
3660 RemoteClient *client = getClient(player->peer_id);
3661 dst_clients.insert(client);
3665 for(core::map<u16, RemoteClient*>::Iterator
3666 i = m_clients.getIterator(); i.atEnd() == false; i++)
3668 RemoteClient *client = i.getNode()->getValue();
3669 Player *player = m_env->getPlayer(client->peer_id);
3673 if(player->getPosition().getDistanceFrom(pos) >
3674 params.max_hear_distance)
3677 dst_clients.insert(client);
3680 if(dst_clients.size() == 0)
3683 s32 id = m_next_sound_id++;
3684 // The sound will exist as a reference in m_playing_sounds
3685 m_playing_sounds[id] = ServerPlayingSound();
3686 ServerPlayingSound &psound = m_playing_sounds[id];
3687 psound.params = params;
3688 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3689 i != dst_clients.end(); i++)
3690 psound.clients.insert((*i)->peer_id);
3692 std::ostringstream os(std::ios_base::binary);
3693 writeU16(os, TOCLIENT_PLAY_SOUND);
3695 os<<serializeString(spec.name);
3696 writeF1000(os, spec.gain * params.gain);
3697 writeU8(os, params.type);
3698 writeV3F1000(os, pos);
3699 writeU16(os, params.object);
3700 writeU8(os, params.loop);
3702 std::string s = os.str();
3703 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3705 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3706 i != dst_clients.end(); i++){
3708 m_con.Send((*i)->peer_id, 0, data, true);
3712 void Server::stopSound(s32 handle)
3714 // Get sound reference
3715 std::map<s32, ServerPlayingSound>::iterator i =
3716 m_playing_sounds.find(handle);
3717 if(i == m_playing_sounds.end())
3719 ServerPlayingSound &psound = i->second;
3721 std::ostringstream os(std::ios_base::binary);
3722 writeU16(os, TOCLIENT_STOP_SOUND);
3723 writeS32(os, handle);
3725 std::string s = os.str();
3726 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3728 for(std::set<u16>::iterator i = psound.clients.begin();
3729 i != psound.clients.end(); i++){
3731 m_con.Send(*i, 0, data, true);
3733 // Remove sound reference
3734 m_playing_sounds.erase(i);
3737 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3738 core::list<u16> *far_players, float far_d_nodes)
3740 float maxd = far_d_nodes*BS;
3741 v3f p_f = intToFloat(p, BS);
3745 SharedBuffer<u8> reply(replysize);
3746 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3747 writeS16(&reply[2], p.X);
3748 writeS16(&reply[4], p.Y);
3749 writeS16(&reply[6], p.Z);
3751 for(core::map<u16, RemoteClient*>::Iterator
3752 i = m_clients.getIterator();
3753 i.atEnd() == false; i++)
3755 // Get client and check that it is valid
3756 RemoteClient *client = i.getNode()->getValue();
3757 assert(client->peer_id == i.getNode()->getKey());
3758 if(client->serialization_version == SER_FMT_VER_INVALID)
3761 // Don't send if it's the same one
3762 if(client->peer_id == ignore_id)
3768 Player *player = m_env->getPlayer(client->peer_id);
3771 // If player is far away, only set modified blocks not sent
3772 v3f player_pos = player->getPosition();
3773 if(player_pos.getDistanceFrom(p_f) > maxd)
3775 far_players->push_back(client->peer_id);
3782 m_con.Send(client->peer_id, 0, reply, true);
3786 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3787 core::list<u16> *far_players, float far_d_nodes)
3789 float maxd = far_d_nodes*BS;
3790 v3f p_f = intToFloat(p, BS);
3792 for(core::map<u16, RemoteClient*>::Iterator
3793 i = m_clients.getIterator();
3794 i.atEnd() == false; i++)
3796 // Get client and check that it is valid
3797 RemoteClient *client = i.getNode()->getValue();
3798 assert(client->peer_id == i.getNode()->getKey());
3799 if(client->serialization_version == SER_FMT_VER_INVALID)
3802 // Don't send if it's the same one
3803 if(client->peer_id == ignore_id)
3809 Player *player = m_env->getPlayer(client->peer_id);
3812 // If player is far away, only set modified blocks not sent
3813 v3f player_pos = player->getPosition();
3814 if(player_pos.getDistanceFrom(p_f) > maxd)
3816 far_players->push_back(client->peer_id);
3823 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3824 SharedBuffer<u8> reply(replysize);
3825 writeU16(&reply[0], TOCLIENT_ADDNODE);
3826 writeS16(&reply[2], p.X);
3827 writeS16(&reply[4], p.Y);
3828 writeS16(&reply[6], p.Z);
3829 n.serialize(&reply[8], client->serialization_version);
3832 m_con.Send(client->peer_id, 0, reply, true);
3836 void Server::setBlockNotSent(v3s16 p)
3838 for(core::map<u16, RemoteClient*>::Iterator
3839 i = m_clients.getIterator();
3840 i.atEnd()==false; i++)
3842 RemoteClient *client = i.getNode()->getValue();
3843 client->SetBlockNotSent(p);
3847 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3849 DSTACK(__FUNCTION_NAME);
3851 v3s16 p = block->getPos();
3855 bool completely_air = true;
3856 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3857 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3858 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3860 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3862 completely_air = false;
3863 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3868 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3870 infostream<<"[completely air] ";
3871 infostream<<std::endl;
3875 Create a packet with the block in the right format
3878 std::ostringstream os(std::ios_base::binary);
3879 block->serialize(os, ver, false);
3880 std::string s = os.str();
3881 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3883 u32 replysize = 8 + blockdata.getSize();
3884 SharedBuffer<u8> reply(replysize);
3885 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3886 writeS16(&reply[2], p.X);
3887 writeS16(&reply[4], p.Y);
3888 writeS16(&reply[6], p.Z);
3889 memcpy(&reply[8], *blockdata, blockdata.getSize());
3891 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3892 <<": \tpacket size: "<<replysize<<std::endl;*/
3897 m_con.Send(peer_id, 1, reply, true);
3900 void Server::SendBlocks(float dtime)
3902 DSTACK(__FUNCTION_NAME);
3904 JMutexAutoLock envlock(m_env_mutex);
3905 JMutexAutoLock conlock(m_con_mutex);
3907 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3909 core::array<PrioritySortedBlockTransfer> queue;
3911 s32 total_sending = 0;
3914 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3916 for(core::map<u16, RemoteClient*>::Iterator
3917 i = m_clients.getIterator();
3918 i.atEnd() == false; i++)
3920 RemoteClient *client = i.getNode()->getValue();
3921 assert(client->peer_id == i.getNode()->getKey());
3923 // If definitions and textures have not been sent, don't
3924 // send MapBlocks either
3925 if(!client->definitions_sent)
3928 total_sending += client->SendingCount();
3930 if(client->serialization_version == SER_FMT_VER_INVALID)
3933 client->GetNextBlocks(this, dtime, queue);
3938 // Lowest priority number comes first.
3939 // Lowest is most important.
3942 for(u32 i=0; i<queue.size(); i++)
3944 //TODO: Calculate limit dynamically
3945 if(total_sending >= g_settings->getS32
3946 ("max_simultaneous_block_sends_server_total"))
3949 PrioritySortedBlockTransfer q = queue[i];
3951 MapBlock *block = NULL;
3954 block = m_env->getMap().getBlockNoCreate(q.pos);
3956 catch(InvalidPositionException &e)
3961 RemoteClient *client = getClient(q.peer_id);
3963 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3965 client->SentBlock(q.pos);
3971 void Server::fillMediaCache()
3973 DSTACK(__FUNCTION_NAME);
3975 infostream<<"Server: Calculating media file checksums"<<std::endl;
3977 // Collect all media file paths
3978 std::list<std::string> paths;
3979 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3980 i != m_mods.end(); i++){
3981 const ModSpec &mod = *i;
3982 paths.push_back(mod.path + DIR_DELIM + "textures");
3983 paths.push_back(mod.path + DIR_DELIM + "sounds");
3984 paths.push_back(mod.path + DIR_DELIM + "media");
3987 // Collect media file information from paths into cache
3988 for(std::list<std::string>::iterator i = paths.begin();
3989 i != paths.end(); i++)
3991 std::string mediapath = *i;
3992 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3993 for(u32 j=0; j<dirlist.size(); j++){
3994 if(dirlist[j].dir) // Ignode dirs
3996 std::string filename = dirlist[j].name;
3997 // if name contains illegal characters, ignore the file
3998 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3999 errorstream<<"Server: ignoring illegal file name: \""
4000 <<filename<<"\""<<std::endl;
4003 std::string filepath = mediapath + DIR_DELIM + filename;
4005 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4006 if(fis.good() == false){
4007 errorstream<<"Server::fillMediaCache(): Could not open \""
4008 <<filename<<"\" for reading"<<std::endl;
4011 std::ostringstream tmp_os(std::ios_base::binary);
4015 fis.read(buf, 1024);
4016 std::streamsize len = fis.gcount();
4017 tmp_os.write(buf, len);
4026 errorstream<<"Server::fillMediaCache(): Failed to read \""
4027 <<filename<<"\""<<std::endl;
4030 if(tmp_os.str().length() == 0){
4031 errorstream<<"Server::fillMediaCache(): Empty file \""
4032 <<filepath<<"\""<<std::endl;
4037 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4039 unsigned char *digest = sha1.getDigest();
4040 std::string sha1_base64 = base64_encode(digest, 20);
4041 std::string sha1_hex = hex_encode((char*)digest, 20);
4045 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4046 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4051 struct SendableMediaAnnouncement
4054 std::string sha1_digest;
4056 SendableMediaAnnouncement(const std::string name_="",
4057 const std::string sha1_digest_=""):
4059 sha1_digest(sha1_digest_)
4063 void Server::sendMediaAnnouncement(u16 peer_id)
4065 DSTACK(__FUNCTION_NAME);
4067 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4070 core::list<SendableMediaAnnouncement> file_announcements;
4072 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4073 i != m_media.end(); i++){
4075 file_announcements.push_back(
4076 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4080 std::ostringstream os(std::ios_base::binary);
4088 u16 length of sha1_digest
4093 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4094 writeU16(os, file_announcements.size());
4096 for(core::list<SendableMediaAnnouncement>::Iterator
4097 j = file_announcements.begin();
4098 j != file_announcements.end(); j++){
4099 os<<serializeString(j->name);
4100 os<<serializeString(j->sha1_digest);
4104 std::string s = os.str();
4105 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4108 m_con.Send(peer_id, 0, data, true);
4112 struct SendableMedia
4118 SendableMedia(const std::string &name_="", const std::string path_="",
4119 const std::string &data_=""):
4126 void Server::sendRequestedMedia(u16 peer_id,
4127 const core::list<MediaRequest> &tosend)
4129 DSTACK(__FUNCTION_NAME);
4131 verbosestream<<"Server::sendRequestedMedia(): "
4132 <<"Sending files to client"<<std::endl;
4136 // Put 5kB in one bunch (this is not accurate)
4137 u32 bytes_per_bunch = 5000;
4139 core::array< core::list<SendableMedia> > file_bunches;
4140 file_bunches.push_back(core::list<SendableMedia>());
4142 u32 file_size_bunch_total = 0;
4144 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4145 i != tosend.end(); i++)
4147 if(m_media.find(i->name) == m_media.end()){
4148 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4149 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4153 //TODO get path + name
4154 std::string tpath = m_media[(*i).name].path;
4157 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4158 if(fis.good() == false){
4159 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4160 <<tpath<<"\" for reading"<<std::endl;
4163 std::ostringstream tmp_os(std::ios_base::binary);
4167 fis.read(buf, 1024);
4168 std::streamsize len = fis.gcount();
4169 tmp_os.write(buf, len);
4170 file_size_bunch_total += len;
4179 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4180 <<(*i).name<<"\""<<std::endl;
4183 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4184 <<tname<<"\""<<std::endl;*/
4186 file_bunches[file_bunches.size()-1].push_back(
4187 SendableMedia((*i).name, tpath, tmp_os.str()));
4189 // Start next bunch if got enough data
4190 if(file_size_bunch_total >= bytes_per_bunch){
4191 file_bunches.push_back(core::list<SendableMedia>());
4192 file_size_bunch_total = 0;
4197 /* Create and send packets */
4199 u32 num_bunches = file_bunches.size();
4200 for(u32 i=0; i<num_bunches; i++)
4202 std::ostringstream os(std::ios_base::binary);
4206 u16 total number of texture bunches
4207 u16 index of this bunch
4208 u32 number of files in this bunch
4217 writeU16(os, TOCLIENT_MEDIA);
4218 writeU16(os, num_bunches);
4220 writeU32(os, file_bunches[i].size());
4222 for(core::list<SendableMedia>::Iterator
4223 j = file_bunches[i].begin();
4224 j != file_bunches[i].end(); j++){
4225 os<<serializeString(j->name);
4226 os<<serializeLongString(j->data);
4230 std::string s = os.str();
4231 verbosestream<<"Server::sendRequestedMedia(): bunch "
4232 <<i<<"/"<<num_bunches
4233 <<" files="<<file_bunches[i].size()
4234 <<" size=" <<s.size()<<std::endl;
4235 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4237 m_con.Send(peer_id, 0, data, true);
4245 void Server::DiePlayer(Player *player)
4247 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4249 infostream<<"Server::DiePlayer(): Player "
4250 <<player->getName()<<" dies"<<std::endl;
4254 // Trigger scripted stuff
4255 scriptapi_on_dieplayer(m_lua, srp);
4257 // Handle players that are not connected
4258 if(player->peer_id == PEER_ID_INEXISTENT){
4259 RespawnPlayer(player);
4263 SendPlayerHP(player);
4264 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4267 void Server::RespawnPlayer(Player *player)
4269 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4271 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4273 v3f pos = findSpawnPos(m_env->getServerMap());
4274 player->setPosition(pos);
4275 srp->m_last_good_position = pos;
4276 srp->m_last_good_position_age = 0;
4278 SendMovePlayer(player);
4279 SendPlayerHP(player);
4282 void Server::UpdateCrafting(u16 peer_id)
4284 DSTACK(__FUNCTION_NAME);
4286 Player* player = m_env->getPlayer(peer_id);
4289 // Get a preview for crafting
4291 // No crafting in creative mode
4292 if(g_settings->getBool("creative_mode") == false)
4293 getCraftingResult(&player->inventory, preview, false, this);
4295 // Put the new preview in
4296 InventoryList *plist = player->inventory.getList("craftpreview");
4298 assert(plist->getSize() >= 1);
4299 plist->changeItem(0, preview);
4302 RemoteClient* Server::getClient(u16 peer_id)
4304 DSTACK(__FUNCTION_NAME);
4305 //JMutexAutoLock lock(m_con_mutex);
4306 core::map<u16, RemoteClient*>::Node *n;
4307 n = m_clients.find(peer_id);
4308 // A client should exist for all peers
4310 return n->getValue();
4313 std::wstring Server::getStatusString()
4315 std::wostringstream os(std::ios_base::binary);
4318 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4320 os<<L", uptime="<<m_uptime.get();
4321 // Information about clients
4323 for(core::map<u16, RemoteClient*>::Iterator
4324 i = m_clients.getIterator();
4325 i.atEnd() == false; i++)
4327 // Get client and check that it is valid
4328 RemoteClient *client = i.getNode()->getValue();
4329 assert(client->peer_id == i.getNode()->getKey());
4330 if(client->serialization_version == SER_FMT_VER_INVALID)
4333 Player *player = m_env->getPlayer(client->peer_id);
4334 // Get name of player
4335 std::wstring name = L"unknown";
4337 name = narrow_to_wide(player->getName());
4338 // Add name to information string
4342 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4343 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4344 if(g_settings->get("motd") != "")
4345 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4349 u64 Server::getPlayerAuthPrivs(const std::string &name)
4352 return m_authmanager.getPrivs(name);
4354 catch(AuthNotFoundException &e)
4356 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4361 void Server::setPlayerAuthPrivs(const std::string &name, u64 privs)
4364 return m_authmanager.setPrivs(name, privs);
4366 catch(AuthNotFoundException &e)
4368 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4372 u64 Server::getPlayerEffectivePrivs(const std::string &name)
4374 // Local player gets all privileges regardless of
4375 // what's set on their account.
4376 if(m_simple_singleplayer_mode)
4378 if(name == g_settings->get("name"))
4380 return getPlayerAuthPrivs(name);
4383 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4385 // Add player to auth manager
4386 if(m_authmanager.exists(name) == false)
4388 infostream<<"Server: adding player "<<name
4389 <<" to auth manager"<<std::endl;
4390 m_authmanager.add(name);
4391 m_authmanager.setPrivs(name,
4392 stringToPrivs(g_settings->get("default_privs")));
4394 // Change password and save
4395 m_authmanager.setPassword(name, translatePassword(name, password));
4396 m_authmanager.save();
4399 // Saves g_settings to configpath given at initialization
4400 void Server::saveConfig()
4402 if(m_path_config != "")
4403 g_settings->updateConfigFile(m_path_config.c_str());
4406 void Server::notifyPlayer(const char *name, const std::wstring msg)
4408 Player *player = m_env->getPlayer(name);
4411 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4414 void Server::notifyPlayers(const std::wstring msg)
4416 BroadcastChatMessage(msg);
4419 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4423 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4424 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4427 // IGameDef interface
4429 IItemDefManager* Server::getItemDefManager()
4433 INodeDefManager* Server::getNodeDefManager()
4437 ICraftDefManager* Server::getCraftDefManager()
4441 ITextureSource* Server::getTextureSource()
4445 u16 Server::allocateUnknownNodeId(const std::string &name)
4447 return m_nodedef->allocateDummy(name);
4449 ISoundManager* Server::getSoundManager()
4451 return &dummySoundManager;
4453 MtEventManager* Server::getEventManager()
4458 IWritableItemDefManager* Server::getWritableItemDefManager()
4462 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4466 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4471 const ModSpec* Server::getModSpec(const std::string &modname)
4473 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4474 i != m_mods.end(); i++){
4475 const ModSpec &mod = *i;
4476 if(mod.name == modname)
4482 v3f findSpawnPos(ServerMap &map)
4484 //return v3f(50,50,50)*BS;
4489 nodepos = v2s16(0,0);
4494 // Try to find a good place a few times
4495 for(s32 i=0; i<1000; i++)
4498 // We're going to try to throw the player to this position
4499 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4500 -range + (myrand()%(range*2)));
4501 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4502 // Get ground height at point (fallbacks to heightmap function)
4503 s16 groundheight = map.findGroundLevel(nodepos2d);
4504 // Don't go underwater
4505 if(groundheight < WATER_LEVEL)
4507 //infostream<<"-> Underwater"<<std::endl;
4510 // Don't go to high places
4511 if(groundheight > WATER_LEVEL + 4)
4513 //infostream<<"-> Underwater"<<std::endl;
4517 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4518 bool is_good = false;
4520 for(s32 i=0; i<10; i++){
4521 v3s16 blockpos = getNodeBlockPos(nodepos);
4522 map.emergeBlock(blockpos, true);
4523 MapNode n = map.getNodeNoEx(nodepos);
4524 if(n.getContent() == CONTENT_AIR){
4535 // Found a good place
4536 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4542 return intToFloat(nodepos, BS);
4545 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4548 Try to get an existing player
4550 ServerRemotePlayer *player =
4551 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4554 // If player is already connected, cancel
4555 if(player->peer_id != 0)
4557 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4562 player->peer_id = peer_id;
4564 // Re-add player to environment
4565 if(player->m_removed)
4567 player->m_removed = false;
4569 m_env->addActiveObject(player);
4572 // Reset inventory to creative if in creative mode
4573 if(g_settings->getBool("creative_mode"))
4575 // Warning: double code below
4576 // Backup actual inventory
4577 player->inventory_backup = new Inventory(m_itemdef);
4578 *(player->inventory_backup) = player->inventory;
4579 // Set creative inventory
4580 player->resetInventory();
4581 scriptapi_get_creative_inventory(m_lua, player);
4588 If player with the wanted peer_id already exists, cancel.
4590 if(m_env->getPlayer(peer_id) != NULL)
4592 infostream<<"emergePlayer(): Player with wrong name but same"
4593 " peer_id already exists"<<std::endl;
4601 /* Set player position */
4603 infostream<<"Server: Finding spawn place for player \""
4604 <<name<<"\""<<std::endl;
4606 v3f pos = findSpawnPos(m_env->getServerMap());
4608 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4609 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4611 /* Add player to environment */
4612 m_env->addPlayer(player);
4613 m_env->addActiveObject(srp);
4616 scriptapi_on_newplayer(m_lua, srp);
4618 /* Add stuff to inventory */
4619 if(g_settings->getBool("creative_mode"))
4621 // Warning: double code above
4622 // Backup actual inventory
4623 player->inventory_backup = new Inventory(m_itemdef);
4624 *(player->inventory_backup) = player->inventory;
4625 // Set creative inventory
4626 player->resetInventory();
4627 scriptapi_get_creative_inventory(m_lua, player);
4632 } // create new player
4635 void Server::handlePeerChange(PeerChange &c)
4637 JMutexAutoLock envlock(m_env_mutex);
4638 JMutexAutoLock conlock(m_con_mutex);
4640 if(c.type == PEER_ADDED)
4647 core::map<u16, RemoteClient*>::Node *n;
4648 n = m_clients.find(c.peer_id);
4649 // The client shouldn't already exist
4653 RemoteClient *client = new RemoteClient();
4654 client->peer_id = c.peer_id;
4655 m_clients.insert(client->peer_id, client);
4658 else if(c.type == PEER_REMOVED)
4665 core::map<u16, RemoteClient*>::Node *n;
4666 n = m_clients.find(c.peer_id);
4667 // The client should exist
4671 Mark objects to be not known by the client
4673 RemoteClient *client = n->getValue();
4675 for(core::map<u16, bool>::Iterator
4676 i = client->m_known_objects.getIterator();
4677 i.atEnd()==false; i++)
4680 u16 id = i.getNode()->getKey();
4681 ServerActiveObject* obj = m_env->getActiveObject(id);
4683 if(obj && obj->m_known_by_count > 0)
4684 obj->m_known_by_count--;
4688 Clear references to playing sounds
4690 for(std::map<s32, ServerPlayingSound>::iterator
4691 i = m_playing_sounds.begin();
4692 i != m_playing_sounds.end();)
4694 ServerPlayingSound &psound = i->second;
4695 psound.clients.erase(c.peer_id);
4696 if(psound.clients.size() == 0)
4697 m_playing_sounds.erase(i++);
4702 ServerRemotePlayer* player =
4703 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4705 // Collect information about leaving in chat
4706 std::wstring message;
4710 std::wstring name = narrow_to_wide(player->getName());
4713 message += L" left game";
4715 message += L" (timed out)";
4719 // Remove from environment
4721 player->m_removed = true;
4723 // Set player client disconnected
4725 player->peer_id = 0;
4733 std::ostringstream os(std::ios_base::binary);
4734 for(core::map<u16, RemoteClient*>::Iterator
4735 i = m_clients.getIterator();
4736 i.atEnd() == false; i++)
4738 RemoteClient *client = i.getNode()->getValue();
4739 assert(client->peer_id == i.getNode()->getKey());
4740 if(client->serialization_version == SER_FMT_VER_INVALID)
4743 Player *player = m_env->getPlayer(client->peer_id);
4746 // Get name of player
4747 os<<player->getName()<<" ";
4750 actionstream<<player->getName()<<" "
4751 <<(c.timeout?"times out.":"leaves game.")
4752 <<" List of players: "
4753 <<os.str()<<std::endl;
4758 delete m_clients[c.peer_id];
4759 m_clients.remove(c.peer_id);
4761 // Send player info to all remaining clients
4762 //SendPlayerInfos();
4764 // Send leave chat message to all remaining clients
4765 if(message.length() != 0)
4766 BroadcastChatMessage(message);
4775 void Server::handlePeerChanges()
4777 while(m_peer_change_queue.size() > 0)
4779 PeerChange c = m_peer_change_queue.pop_front();
4781 verbosestream<<"Server: Handling peer change: "
4782 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4785 handlePeerChange(c);
4789 u64 Server::getPlayerPrivs(Player *player)
4793 std::string playername = player->getName();
4794 return getPlayerEffectivePrivs(playername);
4797 void dedicated_server_loop(Server &server, bool &kill)
4799 DSTACK(__FUNCTION_NAME);
4801 verbosestream<<"dedicated_server_loop()"<<std::endl;
4803 IntervalLimiter m_profiler_interval;
4807 float steplen = g_settings->getFloat("dedicated_server_step");
4808 // This is kind of a hack but can be done like this
4809 // because server.step() is very light
4811 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4812 sleep_ms((int)(steplen*1000.0));
4814 server.step(steplen);
4816 if(server.getShutdownRequested() || kill)
4818 infostream<<"Dedicated server quitting"<<std::endl;
4825 float profiler_print_interval =
4826 g_settings->getFloat("profiler_print_interval");
4827 if(profiler_print_interval != 0)
4829 if(m_profiler_interval.step(steplen, profiler_print_interval))
4831 infostream<<"Profiler:"<<std::endl;
4832 g_profiler->print(infostream);
4833 g_profiler->clear();