3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "clientserver.h"
25 #include "jmutexautolock.h"
27 #include "constants.h"
32 #include "serverobject.h"
37 #include "scriptapi.h"
42 #include "content_mapnode.h"
43 #include "content_nodemeta.h"
44 #include "content_abm.h"
45 #include "content_sao.h"
50 #include "sound.h" // dummySoundManager
51 #include "event_manager.h"
53 #include "util/string.h"
54 #include "util/pointedthing.h"
55 #include "util/mathconstants.h"
58 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
60 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
62 class MapEditEventIgnorer
65 MapEditEventIgnorer(bool *flag):
74 ~MapEditEventIgnorer()
87 class MapEditEventAreaIgnorer
90 MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
91 m_ignorevariable(ignorevariable)
93 if(m_ignorevariable->getVolume() == 0)
94 *m_ignorevariable = a;
96 m_ignorevariable = NULL;
99 ~MapEditEventAreaIgnorer()
103 assert(m_ignorevariable->getVolume() != 0);
104 *m_ignorevariable = VoxelArea();
109 VoxelArea *m_ignorevariable;
112 void * ServerThread::Thread()
116 log_register_thread("ServerThread");
118 DSTACK(__FUNCTION_NAME);
120 BEGIN_DEBUG_EXCEPTION_HANDLER
125 //TimeTaker timer("AsyncRunStep() + Receive()");
128 //TimeTaker timer("AsyncRunStep()");
129 m_server->AsyncRunStep();
132 //infostream<<"Running m_server->Receive()"<<std::endl;
135 catch(con::NoIncomingDataException &e)
138 catch(con::PeerNotFoundException &e)
140 infostream<<"Server: PeerNotFoundException"<<std::endl;
142 catch(con::ConnectionBindFailed &e)
144 m_server->setAsyncFatalError(e.what());
148 m_server->setAsyncFatalError(e.what());
152 END_DEBUG_EXCEPTION_HANDLER(errorstream)
157 void * EmergeThread::Thread()
161 log_register_thread("EmergeThread");
163 DSTACK(__FUNCTION_NAME);
165 BEGIN_DEBUG_EXCEPTION_HANDLER
167 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
169 v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
172 Get block info from queue, emerge them and send them
175 After queue is empty, exit.
179 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
183 SharedPtr<QueuedBlockEmerge> q(qptr);
191 Do not generate over-limit
193 if(blockpos_over_limit(p))
196 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
198 //TimeTaker timer("block emerge");
201 Try to emerge it from somewhere.
203 If it is only wanted as optional, only loading from disk
208 Check if any peer wants it as non-optional. In that case it
211 Also decrement the emerge queue count in clients.
214 bool only_from_disk = true;
217 core::map<u16, u8>::Iterator i;
218 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
220 //u16 peer_id = i.getNode()->getKey();
223 u8 flags = i.getNode()->getValue();
224 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
225 only_from_disk = false;
230 if(enable_mapgen_debug_info)
231 infostream<<"EmergeThread: p="
232 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
233 <<"only_from_disk="<<only_from_disk<<std::endl;
235 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
237 MapBlock *block = NULL;
238 bool got_block = true;
239 core::map<v3s16, MapBlock*> modified_blocks;
242 Try to fetch block from memory or disk.
243 If not found and asked to generate, initialize generator.
246 bool started_generate = false;
247 mapgen::BlockMakeData data;
250 JMutexAutoLock envlock(m_server->m_env_mutex);
252 // Load sector if it isn't loaded
253 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
254 map.loadSectorMeta(p2d);
256 // Attempt to load block
257 block = map.getBlockNoCreateNoEx(p);
258 if(!block || block->isDummy() || !block->isGenerated())
260 if(enable_mapgen_debug_info)
261 infostream<<"EmergeThread: not in memory, "
262 <<"attempting to load from disk"<<std::endl;
264 block = map.loadBlock(p);
267 // If could not load and allowed to generate, start generation
268 // inside this same envlock
269 if(only_from_disk == false &&
270 (block == NULL || block->isGenerated() == false)){
271 if(enable_mapgen_debug_info)
272 infostream<<"EmergeThread: generating"<<std::endl;
273 started_generate = true;
275 map.initBlockMake(&data, p);
280 If generator was initialized, generate now when envlock is free.
285 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
287 TimeTaker t("mapgen::make_block()");
289 mapgen::make_block(&data);
291 if(enable_mapgen_debug_info == false)
292 t.stop(true); // Hide output
296 // Lock environment again to access the map
297 JMutexAutoLock envlock(m_server->m_env_mutex);
299 ScopeProfiler sp(g_profiler, "EmergeThread: after "
300 "mapgen::make_block (envlock)", SPT_AVG);
302 // Blit data back on map, update lighting, add mobs and
303 // whatever this does
304 map.finishBlockMake(&data, modified_blocks);
307 block = map.getBlockNoCreateNoEx(p);
309 // If block doesn't exist, don't try doing anything with it
310 // This happens if the block is not in generation boundaries
315 Do some post-generate stuff
318 v3s16 minp = data.blockpos_min*MAP_BLOCKSIZE;
319 v3s16 maxp = data.blockpos_max*MAP_BLOCKSIZE +
320 v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
323 Ignore map edit events, they will not need to be
324 sent to anybody because the block hasn't been sent
327 //MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
328 MapEditEventAreaIgnorer ign(
329 &m_server->m_ignore_map_edit_events_area,
330 VoxelArea(minp, maxp));
332 TimeTaker timer("on_generated");
333 scriptapi_environment_on_generated(m_server->m_lua,
334 minp, maxp, mapgen::get_blockseed(data.seed, minp));
335 /*int t = timer.stop(true);
336 dstream<<"on_generated took "<<t<<"ms"<<std::endl;*/
339 if(enable_mapgen_debug_info)
340 infostream<<"EmergeThread: ended up with: "
341 <<analyze_block(block)<<std::endl;
343 // Activate objects and stuff
344 m_server->m_env->activateBlock(block, 0);
352 Set sent status of modified blocks on clients
355 // NOTE: Server's clients are also behind the connection mutex
356 JMutexAutoLock lock(m_server->m_con_mutex);
359 Add the originally fetched block to the modified list
363 modified_blocks.insert(p, block);
367 Set the modified blocks unsent for all the clients
370 for(core::map<u16, RemoteClient*>::Iterator
371 i = m_server->m_clients.getIterator();
372 i.atEnd() == false; i++)
374 RemoteClient *client = i.getNode()->getValue();
376 if(modified_blocks.size() > 0)
378 // Remove block from sent history
379 client->SetBlocksNotSent(modified_blocks);
383 catch(VersionMismatchException &e)
385 std::ostringstream err;
386 err<<"World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl;
387 err<<"----"<<std::endl;
388 err<<"\""<<e.what()<<"\""<<std::endl;
389 err<<"See debug.txt."<<std::endl;
390 err<<"World probably saved by a newer version of Minetest."<<std::endl;
391 m_server->setAsyncFatalError(err.str());
393 catch(SerializationError &e)
395 std::ostringstream err;
396 err<<"Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl;
397 err<<"----"<<std::endl;
398 err<<"\""<<e.what()<<"\""<<std::endl;
399 err<<"See debug.txt."<<std::endl;
400 err<<"You can ignore this using [ignore_world_load_errors = true]."<<std::endl;
401 m_server->setAsyncFatalError(err.str());
404 END_DEBUG_EXCEPTION_HANDLER(errorstream)
406 log_deregister_thread();
411 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
413 if(pos_exists) *pos_exists = false;
418 if(pos_exists) *pos_exists = true;
423 ServerActiveObject *sao = env->getActiveObject(object);
426 if(pos_exists) *pos_exists = true;
427 return sao->getBasePosition(); }
432 void RemoteClient::GetNextBlocks(Server *server, float dtime,
433 core::array<PrioritySortedBlockTransfer> &dest)
435 DSTACK(__FUNCTION_NAME);
438 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
441 m_nothing_to_send_pause_timer -= dtime;
442 m_nearest_unsent_reset_timer += dtime;
444 if(m_nothing_to_send_pause_timer >= 0)
449 // Won't send anything if already sending
450 if(m_blocks_sending.size() >= g_settings->getU16
451 ("max_simultaneous_block_sends_per_client"))
453 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
457 //TimeTaker timer("RemoteClient::GetNextBlocks");
459 Player *player = server->m_env->getPlayer(peer_id);
461 assert(player != NULL);
463 v3f playerpos = player->getPosition();
464 v3f playerspeed = player->getSpeed();
465 v3f playerspeeddir(0,0,0);
466 if(playerspeed.getLength() > 1.0*BS)
467 playerspeeddir = playerspeed / playerspeed.getLength();
468 // Predict to next block
469 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
471 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
473 v3s16 center = getNodeBlockPos(center_nodepos);
475 // Camera position and direction
476 v3f camera_pos = player->getEyePosition();
477 v3f camera_dir = v3f(0,0,1);
478 camera_dir.rotateYZBy(player->getPitch());
479 camera_dir.rotateXZBy(player->getYaw());
481 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
482 <<camera_dir.Z<<")"<<std::endl;*/
485 Get the starting value of the block finder radius.
488 if(m_last_center != center)
490 m_nearest_unsent_d = 0;
491 m_last_center = center;
494 /*infostream<<"m_nearest_unsent_reset_timer="
495 <<m_nearest_unsent_reset_timer<<std::endl;*/
497 // Reset periodically to workaround for some bugs or stuff
498 if(m_nearest_unsent_reset_timer > 20.0)
500 m_nearest_unsent_reset_timer = 0;
501 m_nearest_unsent_d = 0;
502 //infostream<<"Resetting m_nearest_unsent_d for "
503 // <<server->getPlayerName(peer_id)<<std::endl;
506 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
507 s16 d_start = m_nearest_unsent_d;
509 //infostream<<"d_start="<<d_start<<std::endl;
511 u16 max_simul_sends_setting = g_settings->getU16
512 ("max_simultaneous_block_sends_per_client");
513 u16 max_simul_sends_usually = max_simul_sends_setting;
516 Check the time from last addNode/removeNode.
518 Decrease send rate if player is building stuff.
520 m_time_from_building += dtime;
521 if(m_time_from_building < g_settings->getFloat(
522 "full_block_send_enable_min_time_from_building"))
524 max_simul_sends_usually
525 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
529 Number of blocks sending + number of blocks selected for sending
531 u32 num_blocks_selected = m_blocks_sending.size();
534 next time d will be continued from the d from which the nearest
535 unsent block was found this time.
537 This is because not necessarily any of the blocks found this
538 time are actually sent.
540 s32 new_nearest_unsent_d = -1;
542 s16 d_max = g_settings->getS16("max_block_send_distance");
543 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
545 // Don't loop very much at a time
546 s16 max_d_increment_at_time = 2;
547 if(d_max > d_start + max_d_increment_at_time)
548 d_max = d_start + max_d_increment_at_time;
549 /*if(d_max_gen > d_start+2)
550 d_max_gen = d_start+2;*/
552 //infostream<<"Starting from "<<d_start<<std::endl;
554 s32 nearest_emerged_d = -1;
555 s32 nearest_emergefull_d = -1;
556 s32 nearest_sent_d = -1;
557 bool queue_is_full = false;
560 for(d = d_start; d <= d_max; d++)
562 /*errorstream<<"checking d="<<d<<" for "
563 <<server->getPlayerName(peer_id)<<std::endl;*/
564 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
567 If m_nearest_unsent_d was changed by the EmergeThread
568 (it can change it to 0 through SetBlockNotSent),
570 Else update m_nearest_unsent_d
572 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
574 d = m_nearest_unsent_d;
575 last_nearest_unsent_d = m_nearest_unsent_d;
579 Get the border/face dot coordinates of a "d-radiused"
582 core::list<v3s16> list;
583 getFacePositions(list, d);
585 core::list<v3s16>::Iterator li;
586 for(li=list.begin(); li!=list.end(); li++)
588 v3s16 p = *li + center;
592 - Don't allow too many simultaneous transfers
593 - EXCEPT when the blocks are very close
595 Also, don't send blocks that are already flying.
598 // Start with the usual maximum
599 u16 max_simul_dynamic = max_simul_sends_usually;
601 // If block is very close, allow full maximum
602 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
603 max_simul_dynamic = max_simul_sends_setting;
605 // Don't select too many blocks for sending
606 if(num_blocks_selected >= max_simul_dynamic)
608 queue_is_full = true;
609 goto queue_full_break;
612 // Don't send blocks that are currently being transferred
613 if(m_blocks_sending.find(p) != NULL)
619 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
620 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
621 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
622 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
623 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
624 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
627 // If this is true, inexistent block will be made from scratch
628 bool generate = d <= d_max_gen;
631 /*// Limit the generating area vertically to 2/3
632 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
635 // Limit the send area vertically to 1/2
636 if(abs(p.Y - center.Y) > d_max / 2)
642 If block is far away, don't generate it unless it is
648 // Block center y in nodes
649 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
650 // Don't generate if it's very high or very low
651 if(y < -64 || y > 64)
655 v2s16 p2d_nodes_center(
659 // Get ground height in nodes
660 s16 gh = server->m_env->getServerMap().findGroundLevel(
663 // If differs a lot, don't generate
664 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
666 // Actually, don't even send it
672 //infostream<<"d="<<d<<std::endl;
675 Don't generate or send if not in sight
676 FIXME This only works if the client uses a small enough
677 FOV setting. The default of 72 degrees is fine.
680 float camera_fov = (72.0*M_PI/180) * 4./3.;
681 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
687 Don't send already sent blocks
690 if(m_blocks_sent.find(p) != NULL)
697 Check if map has this block
699 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
701 bool surely_not_found_on_disk = false;
702 bool block_is_invalid = false;
705 // Reset usage timer, this block will be of use in the future.
706 block->resetUsageTimer();
708 // Block is dummy if data doesn't exist.
709 // It means it has been not found from disk and not generated
712 surely_not_found_on_disk = true;
715 // Block is valid if lighting is up-to-date and data exists
716 if(block->isValid() == false)
718 block_is_invalid = true;
721 /*if(block->isFullyGenerated() == false)
723 block_is_invalid = true;
728 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
729 v2s16 chunkpos = map->sector_to_chunk(p2d);
730 if(map->chunkNonVolatile(chunkpos) == false)
731 block_is_invalid = true;
733 if(block->isGenerated() == false)
734 block_is_invalid = true;
737 If block is not close, don't send it unless it is near
740 Block is near ground level if night-time mesh
741 differs from day-time mesh.
745 if(block->getDayNightDiff() == false)
752 If block has been marked to not exist on disk (dummy)
753 and generating new ones is not wanted, skip block.
755 if(generate == false && surely_not_found_on_disk == true)
762 Add inexistent block to emerge queue.
764 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
766 //TODO: Get value from somewhere
767 // Allow only one block in emerge queue
768 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
769 // Allow two blocks in queue per client
770 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
772 // Make it more responsive when needing to generate stuff
773 if(surely_not_found_on_disk)
775 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
777 //infostream<<"Adding block to emerge queue"<<std::endl;
779 // Add it to the emerge queue and trigger the thread
782 if(generate == false)
783 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
785 server->m_emerge_queue.addBlock(peer_id, p, flags);
786 server->m_emergethread.trigger();
788 if(nearest_emerged_d == -1)
789 nearest_emerged_d = d;
791 if(nearest_emergefull_d == -1)
792 nearest_emergefull_d = d;
799 if(nearest_sent_d == -1)
803 Add block to send queue
806 /*errorstream<<"sending from d="<<d<<" to "
807 <<server->getPlayerName(peer_id)<<std::endl;*/
809 PrioritySortedBlockTransfer q((float)d, p, peer_id);
813 num_blocks_selected += 1;
818 //infostream<<"Stopped at "<<d<<std::endl;
820 // If nothing was found for sending and nothing was queued for
821 // emerging, continue next time browsing from here
822 if(nearest_emerged_d != -1){
823 new_nearest_unsent_d = nearest_emerged_d;
824 } else if(nearest_emergefull_d != -1){
825 new_nearest_unsent_d = nearest_emergefull_d;
827 if(d > g_settings->getS16("max_block_send_distance")){
828 new_nearest_unsent_d = 0;
829 m_nothing_to_send_pause_timer = 2.0;
830 /*infostream<<"GetNextBlocks(): d wrapped around for "
831 <<server->getPlayerName(peer_id)
832 <<"; setting to 0 and pausing"<<std::endl;*/
834 if(nearest_sent_d != -1)
835 new_nearest_unsent_d = nearest_sent_d;
837 new_nearest_unsent_d = d;
841 if(new_nearest_unsent_d != -1)
842 m_nearest_unsent_d = new_nearest_unsent_d;
844 /*timer_result = timer.stop(true);
845 if(timer_result != 0)
846 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
849 void RemoteClient::GotBlock(v3s16 p)
851 if(m_blocks_sending.find(p) != NULL)
852 m_blocks_sending.remove(p);
855 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
856 " m_blocks_sending"<<std::endl;*/
857 m_excess_gotblocks++;
859 m_blocks_sent.insert(p, true);
862 void RemoteClient::SentBlock(v3s16 p)
864 if(m_blocks_sending.find(p) == NULL)
865 m_blocks_sending.insert(p, 0.0);
867 infostream<<"RemoteClient::SentBlock(): Sent block"
868 " already in m_blocks_sending"<<std::endl;
871 void RemoteClient::SetBlockNotSent(v3s16 p)
873 m_nearest_unsent_d = 0;
875 if(m_blocks_sending.find(p) != NULL)
876 m_blocks_sending.remove(p);
877 if(m_blocks_sent.find(p) != NULL)
878 m_blocks_sent.remove(p);
881 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
883 m_nearest_unsent_d = 0;
885 for(core::map<v3s16, MapBlock*>::Iterator
886 i = blocks.getIterator();
887 i.atEnd()==false; i++)
889 v3s16 p = i.getNode()->getKey();
891 if(m_blocks_sending.find(p) != NULL)
892 m_blocks_sending.remove(p);
893 if(m_blocks_sent.find(p) != NULL)
894 m_blocks_sent.remove(p);
902 PlayerInfo::PlayerInfo()
908 void PlayerInfo::PrintLine(std::ostream *s)
911 (*s)<<"\""<<name<<"\" ("
912 <<(position.X/10)<<","<<(position.Y/10)
913 <<","<<(position.Z/10)<<") ";
915 (*s)<<" avg_rtt="<<avg_rtt;
924 const std::string &path_world,
925 const std::string &path_config,
926 const SubgameSpec &gamespec,
927 bool simple_singleplayer_mode
929 m_path_world(path_world),
930 m_path_config(path_config),
931 m_gamespec(gamespec),
932 m_simple_singleplayer_mode(simple_singleplayer_mode),
933 m_async_fatal_error(""),
935 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
936 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
938 m_rollback_sink_enabled(true),
939 m_enable_rollback_recording(false),
941 m_itemdef(createItemDefManager()),
942 m_nodedef(createNodeDefManager()),
943 m_craftdef(createCraftDefManager()),
944 m_event(new EventManager()),
946 m_emergethread(this),
947 m_time_of_day_send_timer(0),
949 m_shutdown_requested(false),
950 m_ignore_map_edit_events(false),
951 m_ignore_map_edit_events_peer_id(0)
953 m_liquid_transform_timer = 0.0;
954 m_print_info_timer = 0.0;
955 m_objectdata_timer = 0.0;
956 m_emergethread_trigger_timer = 0.0;
957 m_savemap_timer = 0.0;
961 m_step_dtime_mutex.Init();
965 throw ServerError("Supplied empty world path");
967 if(!gamespec.isValid())
968 throw ServerError("Supplied invalid gamespec");
970 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
971 if(m_simple_singleplayer_mode)
972 infostream<<" in simple singleplayer mode"<<std::endl;
974 infostream<<std::endl;
975 infostream<<"- world: "<<m_path_world<<std::endl;
976 infostream<<"- config: "<<m_path_config<<std::endl;
977 infostream<<"- game: "<<m_gamespec.path<<std::endl;
979 // Create rollback manager
980 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
981 m_rollback = createRollbackManager(rollback_path, this);
983 // Add world mod search path
984 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
985 // Add addon mod search path
986 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
987 i != m_gamespec.mods_paths.end(); i++)
988 m_modspaths.push_front((*i));
990 // Print out mod search paths
991 for(core::list<std::string>::Iterator i = m_modspaths.begin();
992 i != m_modspaths.end(); i++){
993 std::string modspath = *i;
994 infostream<<"- mods: "<<modspath<<std::endl;
997 // Path to builtin.lua
998 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
1000 // Create world if it doesn't exist
1001 if(!initializeWorld(m_path_world, m_gamespec.id))
1002 throw ServerError("Failed to initialize world");
1005 JMutexAutoLock envlock(m_env_mutex);
1006 JMutexAutoLock conlock(m_con_mutex);
1008 // Initialize scripting
1010 infostream<<"Server: Initializing Lua"<<std::endl;
1011 m_lua = script_init();
1014 scriptapi_export(m_lua, this);
1015 // Load and run builtin.lua
1016 infostream<<"Server: Loading builtin.lua [\""
1017 <<builtinpath<<"\"]"<<std::endl;
1018 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1020 errorstream<<"Server: Failed to load and run "
1021 <<builtinpath<<std::endl;
1022 throw ModError("Failed to load and run "+builtinpath);
1024 // Find mods in mod search paths
1025 m_mods = getMods(m_modspaths);
1027 infostream<<"Server: Loading mods: ";
1028 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1029 i != m_mods.end(); i++){
1030 const ModSpec &mod = *i;
1031 infostream<<mod.name<<" ";
1033 infostream<<std::endl;
1034 // Load and run "mod" scripts
1035 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1036 i != m_mods.end(); i++){
1037 const ModSpec &mod = *i;
1038 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1039 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1040 <<scriptpath<<"\"]"<<std::endl;
1041 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1043 errorstream<<"Server: Failed to load and run "
1044 <<scriptpath<<std::endl;
1045 throw ModError("Failed to load and run "+scriptpath);
1049 // Read Textures and calculate sha1 sums
1052 // Apply item aliases in the node definition manager
1053 m_nodedef->updateAliases(m_itemdef);
1055 // Initialize Environment
1057 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
1060 // Give environment reference to scripting api
1061 scriptapi_add_environment(m_lua, m_env);
1063 // Register us to receive map edit events
1064 m_env->getMap().addEventReceiver(this);
1066 // If file exists, load environment metadata
1067 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1069 infostream<<"Server: Loading environment metadata"<<std::endl;
1070 m_env->loadMeta(m_path_world);
1074 infostream<<"Server: Loading players"<<std::endl;
1075 m_env->deSerializePlayers(m_path_world);
1078 Add some test ActiveBlockModifiers to environment
1080 add_legacy_abms(m_env, m_nodedef);
1085 infostream<<"Server destructing"<<std::endl;
1088 Send shutdown message
1091 JMutexAutoLock conlock(m_con_mutex);
1093 std::wstring line = L"*** Server shutting down";
1096 Send the message to clients
1098 for(core::map<u16, RemoteClient*>::Iterator
1099 i = m_clients.getIterator();
1100 i.atEnd() == false; i++)
1102 // Get client and check that it is valid
1103 RemoteClient *client = i.getNode()->getValue();
1104 assert(client->peer_id == i.getNode()->getKey());
1105 if(client->serialization_version == SER_FMT_VER_INVALID)
1109 SendChatMessage(client->peer_id, line);
1111 catch(con::PeerNotFoundException &e)
1117 JMutexAutoLock envlock(m_env_mutex);
1122 infostream<<"Server: Saving players"<<std::endl;
1123 m_env->serializePlayers(m_path_world);
1126 Save environment metadata
1128 infostream<<"Server: Saving environment metadata"<<std::endl;
1129 m_env->saveMeta(m_path_world);
1141 JMutexAutoLock clientslock(m_con_mutex);
1143 for(core::map<u16, RemoteClient*>::Iterator
1144 i = m_clients.getIterator();
1145 i.atEnd() == false; i++)
1148 // NOTE: These are removed by env destructor
1150 u16 peer_id = i.getNode()->getKey();
1151 JMutexAutoLock envlock(m_env_mutex);
1152 m_env->removePlayer(peer_id);
1156 delete i.getNode()->getValue();
1160 // Delete things in the reverse order of creation
1168 // Deinitialize scripting
1169 infostream<<"Server: Deinitializing scripting"<<std::endl;
1170 script_deinit(m_lua);
1172 // Delete detached inventories
1174 for(std::map<std::string, Inventory*>::iterator
1175 i = m_detached_inventories.begin();
1176 i != m_detached_inventories.end(); i++){
1182 void Server::start(unsigned short port)
1184 DSTACK(__FUNCTION_NAME);
1185 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1187 // Stop thread if already running
1190 // Initialize connection
1191 m_con.SetTimeoutMs(30);
1195 m_thread.setRun(true);
1198 // ASCII art for the win!
1200 <<" .__ __ __ "<<std::endl
1201 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1202 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1203 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1204 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1205 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1206 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1207 actionstream<<"Server for gameid=\""<<m_gamespec.id
1208 <<"\" listening on port "<<port<<"."<<std::endl;
1213 DSTACK(__FUNCTION_NAME);
1215 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1217 // Stop threads (set run=false first so both start stopping)
1218 m_thread.setRun(false);
1219 m_emergethread.setRun(false);
1221 m_emergethread.stop();
1223 infostream<<"Server: Threads stopped"<<std::endl;
1226 void Server::step(float dtime)
1228 DSTACK(__FUNCTION_NAME);
1233 JMutexAutoLock lock(m_step_dtime_mutex);
1234 m_step_dtime += dtime;
1236 // Throw if fatal error occurred in thread
1237 std::string async_err = m_async_fatal_error.get();
1238 if(async_err != ""){
1239 throw ServerError(async_err);
1243 void Server::AsyncRunStep()
1245 DSTACK(__FUNCTION_NAME);
1247 g_profiler->add("Server::AsyncRunStep (num)", 1);
1251 JMutexAutoLock lock1(m_step_dtime_mutex);
1252 dtime = m_step_dtime;
1256 // Send blocks to clients
1263 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1265 //infostream<<"Server steps "<<dtime<<std::endl;
1266 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1269 JMutexAutoLock lock1(m_step_dtime_mutex);
1270 m_step_dtime -= dtime;
1277 m_uptime.set(m_uptime.get() + dtime);
1281 // Process connection's timeouts
1282 JMutexAutoLock lock2(m_con_mutex);
1283 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1284 m_con.RunTimeouts(dtime);
1288 // This has to be called so that the client list gets synced
1289 // with the peer list of the connection
1290 handlePeerChanges();
1294 Update time of day and overall game time
1297 JMutexAutoLock envlock(m_env_mutex);
1299 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1302 Send to clients at constant intervals
1305 m_time_of_day_send_timer -= dtime;
1306 if(m_time_of_day_send_timer < 0.0)
1308 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1310 //JMutexAutoLock envlock(m_env_mutex);
1311 JMutexAutoLock conlock(m_con_mutex);
1313 for(core::map<u16, RemoteClient*>::Iterator
1314 i = m_clients.getIterator();
1315 i.atEnd() == false; i++)
1317 RemoteClient *client = i.getNode()->getValue();
1318 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1319 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1321 m_con.Send(client->peer_id, 0, data, true);
1327 JMutexAutoLock lock(m_env_mutex);
1329 ScopeProfiler sp(g_profiler, "SEnv step");
1330 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1334 const float map_timer_and_unload_dtime = 2.92;
1335 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1337 JMutexAutoLock lock(m_env_mutex);
1338 // Run Map's timers and unload unused data
1339 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1340 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1341 g_settings->getFloat("server_unload_unused_data_timeout"));
1352 JMutexAutoLock lock(m_env_mutex);
1353 JMutexAutoLock lock2(m_con_mutex);
1355 ScopeProfiler sp(g_profiler, "Server: handle players");
1357 for(core::map<u16, RemoteClient*>::Iterator
1358 i = m_clients.getIterator();
1359 i.atEnd() == false; i++)
1361 RemoteClient *client = i.getNode()->getValue();
1362 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1363 if(playersao == NULL)
1367 Handle player HPs (die if hp=0)
1369 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
1370 DiePlayer(client->peer_id);
1373 Send player inventories and HPs if necessary
1375 if(playersao->m_teleported){
1376 SendMovePlayer(client->peer_id);
1377 playersao->m_teleported = false;
1379 if(playersao->m_inventory_not_sent){
1380 UpdateCrafting(client->peer_id);
1381 SendInventory(client->peer_id);
1383 if(playersao->m_hp_not_sent){
1384 SendPlayerHP(client->peer_id);
1389 /* Transform liquids */
1390 m_liquid_transform_timer += dtime;
1391 if(m_liquid_transform_timer >= 1.00)
1393 m_liquid_transform_timer -= 1.00;
1395 JMutexAutoLock lock(m_env_mutex);
1397 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1399 core::map<v3s16, MapBlock*> modified_blocks;
1400 m_env->getMap().transformLiquids(modified_blocks);
1405 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1406 ServerMap &map = ((ServerMap&)m_env->getMap());
1407 map.updateLighting(modified_blocks, lighting_modified_blocks);
1409 // Add blocks modified by lighting to modified_blocks
1410 for(core::map<v3s16, MapBlock*>::Iterator
1411 i = lighting_modified_blocks.getIterator();
1412 i.atEnd() == false; i++)
1414 MapBlock *block = i.getNode()->getValue();
1415 modified_blocks.insert(block->getPos(), block);
1419 Set the modified blocks unsent for all the clients
1422 JMutexAutoLock lock2(m_con_mutex);
1424 for(core::map<u16, RemoteClient*>::Iterator
1425 i = m_clients.getIterator();
1426 i.atEnd() == false; i++)
1428 RemoteClient *client = i.getNode()->getValue();
1430 if(modified_blocks.size() > 0)
1432 // Remove block from sent history
1433 client->SetBlocksNotSent(modified_blocks);
1438 // Periodically print some info
1440 float &counter = m_print_info_timer;
1446 JMutexAutoLock lock2(m_con_mutex);
1448 if(m_clients.size() != 0)
1449 infostream<<"Players:"<<std::endl;
1450 for(core::map<u16, RemoteClient*>::Iterator
1451 i = m_clients.getIterator();
1452 i.atEnd() == false; i++)
1454 //u16 peer_id = i.getNode()->getKey();
1455 RemoteClient *client = i.getNode()->getValue();
1456 Player *player = m_env->getPlayer(client->peer_id);
1459 infostream<<"* "<<player->getName()<<"\t";
1460 client->PrintInfo(infostream);
1465 //if(g_settings->getBool("enable_experimental"))
1469 Check added and deleted active objects
1472 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1473 JMutexAutoLock envlock(m_env_mutex);
1474 JMutexAutoLock conlock(m_con_mutex);
1476 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1478 // Radius inside which objects are active
1479 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1480 radius *= MAP_BLOCKSIZE;
1482 for(core::map<u16, RemoteClient*>::Iterator
1483 i = m_clients.getIterator();
1484 i.atEnd() == false; i++)
1486 RemoteClient *client = i.getNode()->getValue();
1488 // If definitions and textures have not been sent, don't
1489 // send objects either
1490 if(!client->definitions_sent)
1493 Player *player = m_env->getPlayer(client->peer_id);
1496 // This can happen if the client timeouts somehow
1497 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1499 <<" has no associated player"<<std::endl;*/
1502 v3s16 pos = floatToInt(player->getPosition(), BS);
1504 core::map<u16, bool> removed_objects;
1505 core::map<u16, bool> added_objects;
1506 m_env->getRemovedActiveObjects(pos, radius,
1507 client->m_known_objects, removed_objects);
1508 m_env->getAddedActiveObjects(pos, radius,
1509 client->m_known_objects, added_objects);
1511 // Ignore if nothing happened
1512 if(removed_objects.size() == 0 && added_objects.size() == 0)
1514 //infostream<<"active objects: none changed"<<std::endl;
1518 std::string data_buffer;
1522 // Handle removed objects
1523 writeU16((u8*)buf, removed_objects.size());
1524 data_buffer.append(buf, 2);
1525 for(core::map<u16, bool>::Iterator
1526 i = removed_objects.getIterator();
1527 i.atEnd()==false; i++)
1530 u16 id = i.getNode()->getKey();
1531 ServerActiveObject* obj = m_env->getActiveObject(id);
1533 // Add to data buffer for sending
1534 writeU16((u8*)buf, i.getNode()->getKey());
1535 data_buffer.append(buf, 2);
1537 // Remove from known objects
1538 client->m_known_objects.remove(i.getNode()->getKey());
1540 if(obj && obj->m_known_by_count > 0)
1541 obj->m_known_by_count--;
1544 // Handle added objects
1545 writeU16((u8*)buf, added_objects.size());
1546 data_buffer.append(buf, 2);
1547 for(core::map<u16, bool>::Iterator
1548 i = added_objects.getIterator();
1549 i.atEnd()==false; i++)
1552 u16 id = i.getNode()->getKey();
1553 ServerActiveObject* obj = m_env->getActiveObject(id);
1556 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1558 infostream<<"WARNING: "<<__FUNCTION_NAME
1559 <<": NULL object"<<std::endl;
1561 type = obj->getSendType();
1563 // Add to data buffer for sending
1564 writeU16((u8*)buf, id);
1565 data_buffer.append(buf, 2);
1566 writeU8((u8*)buf, type);
1567 data_buffer.append(buf, 1);
1570 data_buffer.append(serializeLongString(
1571 obj->getClientInitializationData()));
1573 data_buffer.append(serializeLongString(""));
1575 // Add to known objects
1576 client->m_known_objects.insert(i.getNode()->getKey(), false);
1579 obj->m_known_by_count++;
1583 SharedBuffer<u8> reply(2 + data_buffer.size());
1584 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1585 memcpy((char*)&reply[2], data_buffer.c_str(),
1586 data_buffer.size());
1588 m_con.Send(client->peer_id, 0, reply, true);
1590 verbosestream<<"Server: Sent object remove/add: "
1591 <<removed_objects.size()<<" removed, "
1592 <<added_objects.size()<<" added, "
1593 <<"packet size is "<<reply.getSize()<<std::endl;
1598 Collect a list of all the objects known by the clients
1599 and report it back to the environment.
1602 core::map<u16, bool> all_known_objects;
1604 for(core::map<u16, RemoteClient*>::Iterator
1605 i = m_clients.getIterator();
1606 i.atEnd() == false; i++)
1608 RemoteClient *client = i.getNode()->getValue();
1609 // Go through all known objects of client
1610 for(core::map<u16, bool>::Iterator
1611 i = client->m_known_objects.getIterator();
1612 i.atEnd()==false; i++)
1614 u16 id = i.getNode()->getKey();
1615 all_known_objects[id] = true;
1619 m_env->setKnownActiveObjects(whatever);
1625 Send object messages
1628 JMutexAutoLock envlock(m_env_mutex);
1629 JMutexAutoLock conlock(m_con_mutex);
1631 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1634 // Value = data sent by object
1635 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1637 // Get active object messages from environment
1640 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1644 core::list<ActiveObjectMessage>* message_list = NULL;
1645 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1646 n = buffered_messages.find(aom.id);
1649 message_list = new core::list<ActiveObjectMessage>;
1650 buffered_messages.insert(aom.id, message_list);
1654 message_list = n->getValue();
1656 message_list->push_back(aom);
1659 // Route data to every client
1660 for(core::map<u16, RemoteClient*>::Iterator
1661 i = m_clients.getIterator();
1662 i.atEnd()==false; i++)
1664 RemoteClient *client = i.getNode()->getValue();
1665 std::string reliable_data;
1666 std::string unreliable_data;
1667 // Go through all objects in message buffer
1668 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1669 j = buffered_messages.getIterator();
1670 j.atEnd()==false; j++)
1672 // If object is not known by client, skip it
1673 u16 id = j.getNode()->getKey();
1674 if(client->m_known_objects.find(id) == NULL)
1676 // Get message list of object
1677 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1678 // Go through every message
1679 for(core::list<ActiveObjectMessage>::Iterator
1680 k = list->begin(); k != list->end(); k++)
1682 // Compose the full new data with header
1683 ActiveObjectMessage aom = *k;
1684 std::string new_data;
1687 writeU16((u8*)&buf[0], aom.id);
1688 new_data.append(buf, 2);
1690 new_data += serializeString(aom.datastring);
1691 // Add data to buffer
1693 reliable_data += new_data;
1695 unreliable_data += new_data;
1699 reliable_data and unreliable_data are now ready.
1702 if(reliable_data.size() > 0)
1704 SharedBuffer<u8> reply(2 + reliable_data.size());
1705 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1706 memcpy((char*)&reply[2], reliable_data.c_str(),
1707 reliable_data.size());
1709 m_con.Send(client->peer_id, 0, reply, true);
1711 if(unreliable_data.size() > 0)
1713 SharedBuffer<u8> reply(2 + unreliable_data.size());
1714 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1715 memcpy((char*)&reply[2], unreliable_data.c_str(),
1716 unreliable_data.size());
1717 // Send as unreliable
1718 m_con.Send(client->peer_id, 0, reply, false);
1721 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1723 infostream<<"Server: Size of object message data: "
1724 <<"reliable: "<<reliable_data.size()
1725 <<", unreliable: "<<unreliable_data.size()
1730 // Clear buffered_messages
1731 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1732 i = buffered_messages.getIterator();
1733 i.atEnd()==false; i++)
1735 delete i.getNode()->getValue();
1739 } // enable_experimental
1742 Send queued-for-sending map edit events.
1745 // We will be accessing the environment and the connection
1746 JMutexAutoLock lock(m_env_mutex);
1747 JMutexAutoLock conlock(m_con_mutex);
1749 // Don't send too many at a time
1752 // Single change sending is disabled if queue size is not small
1753 bool disable_single_change_sending = false;
1754 if(m_unsent_map_edit_queue.size() >= 4)
1755 disable_single_change_sending = true;
1757 int event_count = m_unsent_map_edit_queue.size();
1759 // We'll log the amount of each
1762 while(m_unsent_map_edit_queue.size() != 0)
1764 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1766 // Players far away from the change are stored here.
1767 // Instead of sending the changes, MapBlocks are set not sent
1769 core::list<u16> far_players;
1771 if(event->type == MEET_ADDNODE)
1773 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1774 prof.add("MEET_ADDNODE", 1);
1775 if(disable_single_change_sending)
1776 sendAddNode(event->p, event->n, event->already_known_by_peer,
1779 sendAddNode(event->p, event->n, event->already_known_by_peer,
1782 else if(event->type == MEET_REMOVENODE)
1784 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1785 prof.add("MEET_REMOVENODE", 1);
1786 if(disable_single_change_sending)
1787 sendRemoveNode(event->p, event->already_known_by_peer,
1790 sendRemoveNode(event->p, event->already_known_by_peer,
1793 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1795 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1796 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1797 setBlockNotSent(event->p);
1799 else if(event->type == MEET_OTHER)
1801 infostream<<"Server: MEET_OTHER"<<std::endl;
1802 prof.add("MEET_OTHER", 1);
1803 for(core::map<v3s16, bool>::Iterator
1804 i = event->modified_blocks.getIterator();
1805 i.atEnd()==false; i++)
1807 v3s16 p = i.getNode()->getKey();
1813 prof.add("unknown", 1);
1814 infostream<<"WARNING: Server: Unknown MapEditEvent "
1815 <<((u32)event->type)<<std::endl;
1819 Set blocks not sent to far players
1821 if(far_players.size() > 0)
1823 // Convert list format to that wanted by SetBlocksNotSent
1824 core::map<v3s16, MapBlock*> modified_blocks2;
1825 for(core::map<v3s16, bool>::Iterator
1826 i = event->modified_blocks.getIterator();
1827 i.atEnd()==false; i++)
1829 v3s16 p = i.getNode()->getKey();
1830 modified_blocks2.insert(p,
1831 m_env->getMap().getBlockNoCreateNoEx(p));
1833 // Set blocks not sent
1834 for(core::list<u16>::Iterator
1835 i = far_players.begin();
1836 i != far_players.end(); i++)
1839 RemoteClient *client = getClient(peer_id);
1842 client->SetBlocksNotSent(modified_blocks2);
1848 /*// Don't send too many at a time
1850 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1854 if(event_count >= 5){
1855 infostream<<"Server: MapEditEvents:"<<std::endl;
1856 prof.print(infostream);
1857 } else if(event_count != 0){
1858 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1859 prof.print(verbosestream);
1865 Trigger emergethread (it somehow gets to a non-triggered but
1866 bysy state sometimes)
1869 float &counter = m_emergethread_trigger_timer;
1875 m_emergethread.trigger();
1877 // Update m_enable_rollback_recording here too
1878 m_enable_rollback_recording =
1879 g_settings->getBool("enable_rollback_recording");
1883 // Save map, players and auth stuff
1885 float &counter = m_savemap_timer;
1887 if(counter >= g_settings->getFloat("server_map_save_interval"))
1890 JMutexAutoLock lock(m_env_mutex);
1892 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1895 if(m_banmanager.isModified())
1896 m_banmanager.save();
1898 // Save changed parts of map
1899 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1902 m_env->serializePlayers(m_path_world);
1904 // Save environment metadata
1905 m_env->saveMeta(m_path_world);
1910 void Server::Receive()
1912 DSTACK(__FUNCTION_NAME);
1913 SharedBuffer<u8> data;
1918 JMutexAutoLock conlock(m_con_mutex);
1919 datasize = m_con.Receive(peer_id, data);
1922 // This has to be called so that the client list gets synced
1923 // with the peer list of the connection
1924 handlePeerChanges();
1926 ProcessData(*data, datasize, peer_id);
1928 catch(con::InvalidIncomingDataException &e)
1930 infostream<<"Server::Receive(): "
1931 "InvalidIncomingDataException: what()="
1932 <<e.what()<<std::endl;
1934 catch(con::PeerNotFoundException &e)
1936 //NOTE: This is not needed anymore
1938 // The peer has been disconnected.
1939 // Find the associated player and remove it.
1941 /*JMutexAutoLock envlock(m_env_mutex);
1943 infostream<<"ServerThread: peer_id="<<peer_id
1944 <<" has apparently closed connection. "
1945 <<"Removing player."<<std::endl;
1947 m_env->removePlayer(peer_id);*/
1951 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1953 DSTACK(__FUNCTION_NAME);
1954 // Environment is locked first.
1955 JMutexAutoLock envlock(m_env_mutex);
1956 JMutexAutoLock conlock(m_con_mutex);
1958 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1961 Address address = m_con.GetPeerAddress(peer_id);
1962 std::string addr_s = address.serializeString();
1964 // drop player if is ip is banned
1965 if(m_banmanager.isIpBanned(addr_s)){
1966 infostream<<"Server: A banned client tried to connect from "
1967 <<addr_s<<"; banned name was "
1968 <<m_banmanager.getBanName(addr_s)<<std::endl;
1969 // This actually doesn't seem to transfer to the client
1970 SendAccessDenied(m_con, peer_id,
1971 L"Your ip is banned. Banned name was "
1972 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1973 m_con.DeletePeer(peer_id);
1977 catch(con::PeerNotFoundException &e)
1979 infostream<<"Server::ProcessData(): Cancelling: peer "
1980 <<peer_id<<" not found"<<std::endl;
1984 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1986 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1994 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1996 if(command == TOSERVER_INIT)
1998 // [0] u16 TOSERVER_INIT
1999 // [2] u8 SER_FMT_VER_HIGHEST
2000 // [3] u8[20] player_name
2001 // [23] u8[28] password <--- can be sent without this, from old versions
2003 if(datasize < 2+1+PLAYERNAME_SIZE)
2006 verbosestream<<"Server: Got TOSERVER_INIT from "
2007 <<peer_id<<std::endl;
2009 // First byte after command is maximum supported
2010 // serialization version
2011 u8 client_max = data[2];
2012 u8 our_max = SER_FMT_VER_HIGHEST;
2013 // Use the highest version supported by both
2014 u8 deployed = core::min_(client_max, our_max);
2015 // If it's lower than the lowest supported, give up.
2016 if(deployed < SER_FMT_VER_LOWEST)
2017 deployed = SER_FMT_VER_INVALID;
2019 //peer->serialization_version = deployed;
2020 getClient(peer_id)->pending_serialization_version = deployed;
2022 if(deployed == SER_FMT_VER_INVALID)
2024 actionstream<<"Server: A mismatched client tried to connect from "
2025 <<addr_s<<std::endl;
2026 infostream<<"Server: Cannot negotiate "
2027 "serialization version with peer "
2028 <<peer_id<<std::endl;
2029 SendAccessDenied(m_con, peer_id, std::wstring(
2030 L"Your client's version is not supported.\n"
2031 L"Server version is ")
2032 + narrow_to_wide(VERSION_STRING) + L"."
2038 Read and check network protocol version
2041 u16 net_proto_version = 0;
2042 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2044 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2047 getClient(peer_id)->net_proto_version = net_proto_version;
2049 if(net_proto_version == 0)
2051 actionstream<<"Server: An old tried to connect from "<<addr_s
2053 SendAccessDenied(m_con, peer_id, std::wstring(
2054 L"Your client's version is not supported.\n"
2055 L"Server version is ")
2056 + narrow_to_wide(VERSION_STRING) + L"."
2061 if(g_settings->getBool("strict_protocol_version_checking"))
2063 if(net_proto_version != PROTOCOL_VERSION)
2065 actionstream<<"Server: A mismatched client tried to connect"
2066 <<" from "<<addr_s<<std::endl;
2067 SendAccessDenied(m_con, peer_id, std::wstring(
2068 L"Your client's version is not supported.\n"
2069 L"Server version is ")
2070 + narrow_to_wide(VERSION_STRING) + L",\n"
2071 + L"server's PROTOCOL_VERSION is "
2072 + narrow_to_wide(itos(PROTOCOL_VERSION))
2073 + L", client's PROTOCOL_VERSION is "
2074 + narrow_to_wide(itos(net_proto_version))
2085 char playername[PLAYERNAME_SIZE];
2086 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2088 playername[i] = data[3+i];
2090 playername[PLAYERNAME_SIZE-1] = 0;
2092 if(playername[0]=='\0')
2094 actionstream<<"Server: Player with an empty name "
2095 <<"tried to connect from "<<addr_s<<std::endl;
2096 SendAccessDenied(m_con, peer_id,
2101 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2103 actionstream<<"Server: Player with an invalid name "
2104 <<"tried to connect from "<<addr_s<<std::endl;
2105 SendAccessDenied(m_con, peer_id,
2106 L"Name contains unallowed characters");
2110 infostream<<"Server: New connection: \""<<playername<<"\" from "
2111 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2114 char given_password[PASSWORD_SIZE];
2115 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2117 // old version - assume blank password
2118 given_password[0] = 0;
2122 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2124 given_password[i] = data[23+i];
2126 given_password[PASSWORD_SIZE-1] = 0;
2129 if(!base64_is_valid(given_password)){
2130 infostream<<"Server: "<<playername
2131 <<" supplied invalid password hash"<<std::endl;
2132 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2136 std::string checkpwd; // Password hash to check against
2137 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2139 // If no authentication info exists for user, create it
2141 if(!isSingleplayer() &&
2142 g_settings->getBool("disallow_empty_password") &&
2143 std::string(given_password) == ""){
2144 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2145 L"disallowed. Set a password and try again.");
2148 std::wstring raw_default_password =
2149 narrow_to_wide(g_settings->get("default_password"));
2150 std::string initial_password =
2151 translatePassword(playername, raw_default_password);
2153 // If default_password is empty, allow any initial password
2154 if (raw_default_password.length() == 0)
2155 initial_password = given_password;
2157 scriptapi_create_auth(m_lua, playername, initial_password);
2160 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2163 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2167 if(given_password != checkpwd){
2168 infostream<<"Server: peer_id="<<peer_id
2169 <<": supplied invalid password for "
2170 <<playername<<std::endl;
2171 SendAccessDenied(m_con, peer_id, L"Invalid password");
2175 // Do not allow multiple players in simple singleplayer mode.
2176 // This isn't a perfect way to do it, but will suffice for now.
2177 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2178 infostream<<"Server: Not allowing another client to connect in"
2179 <<" simple singleplayer mode"<<std::endl;
2180 SendAccessDenied(m_con, peer_id,
2181 L"Running in simple singleplayer mode.");
2185 // Enforce user limit.
2186 // Don't enforce for users that have some admin right
2187 if(m_clients.size() >= g_settings->getU16("max_users") &&
2188 !checkPriv(playername, "server") &&
2189 !checkPriv(playername, "ban") &&
2190 !checkPriv(playername, "privs") &&
2191 !checkPriv(playername, "password") &&
2192 playername != g_settings->get("name"))
2194 actionstream<<"Server: "<<playername<<" tried to join, but there"
2195 <<" are already max_users="
2196 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2197 SendAccessDenied(m_con, peer_id, L"Too many users.");
2202 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2204 // If failed, cancel
2205 if(playersao == NULL)
2207 errorstream<<"Server: peer_id="<<peer_id
2208 <<": failed to emerge player"<<std::endl;
2213 Answer with a TOCLIENT_INIT
2216 SharedBuffer<u8> reply(2+1+6+8);
2217 writeU16(&reply[0], TOCLIENT_INIT);
2218 writeU8(&reply[2], deployed);
2219 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2220 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2223 m_con.Send(peer_id, 0, reply, true);
2227 Send complete position information
2229 SendMovePlayer(peer_id);
2234 if(command == TOSERVER_INIT2)
2236 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2237 <<peer_id<<std::endl;
2239 Player *player = m_env->getPlayer(peer_id);
2241 verbosestream<<"Server: TOSERVER_INIT2: "
2242 <<"Player not found; ignoring."<<std::endl;
2246 getClient(peer_id)->serialization_version
2247 = getClient(peer_id)->pending_serialization_version;
2250 Send some initialization data
2253 infostream<<"Server: Sending content to "
2254 <<getPlayerName(peer_id)<<std::endl;
2256 // Send item definitions
2257 SendItemDef(m_con, peer_id, m_itemdef);
2259 // Send node definitions
2260 SendNodeDef(m_con, peer_id, m_nodedef);
2262 // Send media announcement
2263 sendMediaAnnouncement(peer_id);
2266 SendPlayerPrivileges(peer_id);
2268 // Send inventory formspec
2269 SendPlayerInventoryFormspec(peer_id);
2272 UpdateCrafting(peer_id);
2273 SendInventory(peer_id);
2276 SendPlayerHP(peer_id);
2278 // Send detached inventories
2279 sendDetachedInventories(peer_id);
2281 // Show death screen if necessary
2283 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2287 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2288 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2289 m_con.Send(peer_id, 0, data, true);
2292 // Note things in chat if not in simple singleplayer mode
2293 if(!m_simple_singleplayer_mode)
2295 // Send information about server to player in chat
2296 SendChatMessage(peer_id, getStatusString());
2298 // Send information about joining in chat
2300 std::wstring name = L"unknown";
2301 Player *player = m_env->getPlayer(peer_id);
2303 name = narrow_to_wide(player->getName());
2305 std::wstring message;
2308 message += L" joined the game.";
2309 BroadcastChatMessage(message);
2313 // Warnings about protocol version can be issued here
2314 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2316 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER!");
2323 std::ostringstream os(std::ios_base::binary);
2324 for(core::map<u16, RemoteClient*>::Iterator
2325 i = m_clients.getIterator();
2326 i.atEnd() == false; i++)
2328 RemoteClient *client = i.getNode()->getValue();
2329 assert(client->peer_id == i.getNode()->getKey());
2330 if(client->serialization_version == SER_FMT_VER_INVALID)
2333 Player *player = m_env->getPlayer(client->peer_id);
2336 // Get name of player
2337 os<<player->getName()<<" ";
2340 actionstream<<player->getName()<<" joins game. List of players: "
2341 <<os.str()<<std::endl;
2347 if(peer_ser_ver == SER_FMT_VER_INVALID)
2349 infostream<<"Server::ProcessData(): Cancelling: Peer"
2350 " serialization format invalid or not initialized."
2351 " Skipping incoming command="<<command<<std::endl;
2355 Player *player = m_env->getPlayer(peer_id);
2357 infostream<<"Server::ProcessData(): Cancelling: "
2358 "No player for peer_id="<<peer_id
2363 PlayerSAO *playersao = player->getPlayerSAO();
2364 if(playersao == NULL){
2365 infostream<<"Server::ProcessData(): Cancelling: "
2366 "No player object for peer_id="<<peer_id
2371 if(command == TOSERVER_PLAYERPOS)
2373 if(datasize < 2+12+12+4+4)
2377 v3s32 ps = readV3S32(&data[start+2]);
2378 v3s32 ss = readV3S32(&data[start+2+12]);
2379 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2380 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2381 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2382 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2383 pitch = wrapDegrees(pitch);
2384 yaw = wrapDegrees(yaw);
2386 player->setPosition(position);
2387 player->setSpeed(speed);
2388 player->setPitch(pitch);
2389 player->setYaw(yaw);
2391 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2392 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2393 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2395 else if(command == TOSERVER_GOTBLOCKS)
2408 u16 count = data[2];
2409 for(u16 i=0; i<count; i++)
2411 if((s16)datasize < 2+1+(i+1)*6)
2412 throw con::InvalidIncomingDataException
2413 ("GOTBLOCKS length is too short");
2414 v3s16 p = readV3S16(&data[2+1+i*6]);
2415 /*infostream<<"Server: GOTBLOCKS ("
2416 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2417 RemoteClient *client = getClient(peer_id);
2418 client->GotBlock(p);
2421 else if(command == TOSERVER_DELETEDBLOCKS)
2434 u16 count = data[2];
2435 for(u16 i=0; i<count; i++)
2437 if((s16)datasize < 2+1+(i+1)*6)
2438 throw con::InvalidIncomingDataException
2439 ("DELETEDBLOCKS length is too short");
2440 v3s16 p = readV3S16(&data[2+1+i*6]);
2441 /*infostream<<"Server: DELETEDBLOCKS ("
2442 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2443 RemoteClient *client = getClient(peer_id);
2444 client->SetBlockNotSent(p);
2447 else if(command == TOSERVER_CLICK_OBJECT)
2449 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2452 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2454 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2457 else if(command == TOSERVER_GROUND_ACTION)
2459 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2463 else if(command == TOSERVER_RELEASE)
2465 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2468 else if(command == TOSERVER_SIGNTEXT)
2470 infostream<<"Server: SIGNTEXT not supported anymore"
2474 else if(command == TOSERVER_SIGNNODETEXT)
2476 infostream<<"Server: SIGNNODETEXT not supported anymore"
2480 else if(command == TOSERVER_INVENTORY_ACTION)
2482 // Strip command and create a stream
2483 std::string datastring((char*)&data[2], datasize-2);
2484 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2485 std::istringstream is(datastring, std::ios_base::binary);
2487 InventoryAction *a = InventoryAction::deSerialize(is);
2490 infostream<<"TOSERVER_INVENTORY_ACTION: "
2491 <<"InventoryAction::deSerialize() returned NULL"
2496 // If something goes wrong, this player is to blame
2497 RollbackScopeActor rollback_scope(m_rollback,
2498 std::string("player:")+player->getName());
2501 Note: Always set inventory not sent, to repair cases
2502 where the client made a bad prediction.
2506 Handle restrictions and special cases of the move action
2508 if(a->getType() == IACTION_MOVE)
2510 IMoveAction *ma = (IMoveAction*)a;
2512 ma->from_inv.applyCurrentPlayer(player->getName());
2513 ma->to_inv.applyCurrentPlayer(player->getName());
2515 setInventoryModified(ma->from_inv);
2516 setInventoryModified(ma->to_inv);
2518 bool from_inv_is_current_player =
2519 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2520 (ma->from_inv.name == player->getName());
2522 bool to_inv_is_current_player =
2523 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2524 (ma->to_inv.name == player->getName());
2527 Disable moving items out of craftpreview
2529 if(ma->from_list == "craftpreview")
2531 infostream<<"Ignoring IMoveAction from "
2532 <<(ma->from_inv.dump())<<":"<<ma->from_list
2533 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2534 <<" because src is "<<ma->from_list<<std::endl;
2540 Disable moving items into craftresult and craftpreview
2542 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2544 infostream<<"Ignoring IMoveAction from "
2545 <<(ma->from_inv.dump())<<":"<<ma->from_list
2546 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2547 <<" because dst is "<<ma->to_list<<std::endl;
2552 // Disallow moving items in elsewhere than player's inventory
2553 // if not allowed to interact
2554 if(!checkPriv(player->getName(), "interact") &&
2555 (!from_inv_is_current_player ||
2556 !to_inv_is_current_player))
2558 infostream<<"Cannot move outside of player's inventory: "
2559 <<"No interact privilege"<<std::endl;
2565 Handle restrictions and special cases of the drop action
2567 else if(a->getType() == IACTION_DROP)
2569 IDropAction *da = (IDropAction*)a;
2571 da->from_inv.applyCurrentPlayer(player->getName());
2573 setInventoryModified(da->from_inv);
2575 // Disallow dropping items if not allowed to interact
2576 if(!checkPriv(player->getName(), "interact"))
2583 Handle restrictions and special cases of the craft action
2585 else if(a->getType() == IACTION_CRAFT)
2587 ICraftAction *ca = (ICraftAction*)a;
2589 ca->craft_inv.applyCurrentPlayer(player->getName());
2591 setInventoryModified(ca->craft_inv);
2593 //bool craft_inv_is_current_player =
2594 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2595 // (ca->craft_inv.name == player->getName());
2597 // Disallow crafting if not allowed to interact
2598 if(!checkPriv(player->getName(), "interact"))
2600 infostream<<"Cannot craft: "
2601 <<"No interact privilege"<<std::endl;
2608 a->apply(this, playersao, this);
2612 else if(command == TOSERVER_CHAT_MESSAGE)
2620 std::string datastring((char*)&data[2], datasize-2);
2621 std::istringstream is(datastring, std::ios_base::binary);
2624 is.read((char*)buf, 2);
2625 u16 len = readU16(buf);
2627 std::wstring message;
2628 for(u16 i=0; i<len; i++)
2630 is.read((char*)buf, 2);
2631 message += (wchar_t)readU16(buf);
2634 // If something goes wrong, this player is to blame
2635 RollbackScopeActor rollback_scope(m_rollback,
2636 std::string("player:")+player->getName());
2638 // Get player name of this client
2639 std::wstring name = narrow_to_wide(player->getName());
2642 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2643 wide_to_narrow(message));
2644 // If script ate the message, don't proceed
2648 // Line to send to players
2650 // Whether to send to the player that sent the line
2651 bool send_to_sender = false;
2652 // Whether to send to other players
2653 bool send_to_others = false;
2655 // Commands are implemented in Lua, so only catch invalid
2656 // commands that were not "eaten" and send an error back
2657 if(message[0] == L'/')
2659 message = message.substr(1);
2660 send_to_sender = true;
2661 if(message.length() == 0)
2662 line += L"-!- Empty command";
2664 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2668 if(checkPriv(player->getName(), "shout")){
2673 send_to_others = true;
2675 line += L"-!- You don't have permission to shout.";
2676 send_to_sender = true;
2683 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2686 Send the message to clients
2688 for(core::map<u16, RemoteClient*>::Iterator
2689 i = m_clients.getIterator();
2690 i.atEnd() == false; i++)
2692 // Get client and check that it is valid
2693 RemoteClient *client = i.getNode()->getValue();
2694 assert(client->peer_id == i.getNode()->getKey());
2695 if(client->serialization_version == SER_FMT_VER_INVALID)
2699 bool sender_selected = (peer_id == client->peer_id);
2700 if(sender_selected == true && send_to_sender == false)
2702 if(sender_selected == false && send_to_others == false)
2705 SendChatMessage(client->peer_id, line);
2709 else if(command == TOSERVER_DAMAGE)
2711 std::string datastring((char*)&data[2], datasize-2);
2712 std::istringstream is(datastring, std::ios_base::binary);
2713 u8 damage = readU8(is);
2715 actionstream<<player->getName()<<" damaged by "
2716 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2719 playersao->setHP(playersao->getHP() - damage);
2721 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2724 if(playersao->m_hp_not_sent)
2725 SendPlayerHP(peer_id);
2727 else if(command == TOSERVER_PASSWORD)
2730 [0] u16 TOSERVER_PASSWORD
2731 [2] u8[28] old password
2732 [30] u8[28] new password
2735 if(datasize != 2+PASSWORD_SIZE*2)
2737 /*char password[PASSWORD_SIZE];
2738 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2739 password[i] = data[2+i];
2740 password[PASSWORD_SIZE-1] = 0;*/
2742 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2750 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2752 char c = data[2+PASSWORD_SIZE+i];
2758 if(!base64_is_valid(newpwd)){
2759 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2760 // Wrong old password supplied!!
2761 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2765 infostream<<"Server: Client requests a password change from "
2766 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2768 std::string playername = player->getName();
2770 std::string checkpwd;
2771 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2773 if(oldpwd != checkpwd)
2775 infostream<<"Server: invalid old password"<<std::endl;
2776 // Wrong old password supplied!!
2777 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2781 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2783 actionstream<<player->getName()<<" changes password"<<std::endl;
2784 SendChatMessage(peer_id, L"Password change successful.");
2786 actionstream<<player->getName()<<" tries to change password but "
2787 <<"it fails"<<std::endl;
2788 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2791 else if(command == TOSERVER_PLAYERITEM)
2796 u16 item = readU16(&data[2]);
2797 playersao->setWieldIndex(item);
2799 else if(command == TOSERVER_RESPAWN)
2804 RespawnPlayer(peer_id);
2806 actionstream<<player->getName()<<" respawns at "
2807 <<PP(player->getPosition()/BS)<<std::endl;
2809 // ActiveObject is added to environment in AsyncRunStep after
2810 // the previous addition has been succesfully removed
2812 else if(command == TOSERVER_REQUEST_MEDIA) {
2813 std::string datastring((char*)&data[2], datasize-2);
2814 std::istringstream is(datastring, std::ios_base::binary);
2816 core::list<MediaRequest> tosend;
2817 u16 numfiles = readU16(is);
2819 infostream<<"Sending "<<numfiles<<" files to "
2820 <<getPlayerName(peer_id)<<std::endl;
2821 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2823 for(int i = 0; i < numfiles; i++) {
2824 std::string name = deSerializeString(is);
2825 tosend.push_back(MediaRequest(name));
2826 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2830 sendRequestedMedia(peer_id, tosend);
2832 // Now the client should know about everything
2833 // (definitions and files)
2834 getClient(peer_id)->definitions_sent = true;
2836 else if(command == TOSERVER_INTERACT)
2838 std::string datastring((char*)&data[2], datasize-2);
2839 std::istringstream is(datastring, std::ios_base::binary);
2845 [5] u32 length of the next item
2846 [9] serialized PointedThing
2848 0: start digging (from undersurface) or use
2849 1: stop digging (all parameters ignored)
2850 2: digging completed
2851 3: place block or item (to abovesurface)
2854 u8 action = readU8(is);
2855 u16 item_i = readU16(is);
2856 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2857 PointedThing pointed;
2858 pointed.deSerialize(tmp_is);
2860 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2861 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2865 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2866 <<" tried to interact, but is dead!"<<std::endl;
2870 v3f player_pos = playersao->getLastGoodPosition();
2872 // Update wielded item
2873 playersao->setWieldIndex(item_i);
2875 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2876 v3s16 p_under = pointed.node_undersurface;
2877 v3s16 p_above = pointed.node_abovesurface;
2879 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2880 ServerActiveObject *pointed_object = NULL;
2881 if(pointed.type == POINTEDTHING_OBJECT)
2883 pointed_object = m_env->getActiveObject(pointed.object_id);
2884 if(pointed_object == NULL)
2886 verbosestream<<"TOSERVER_INTERACT: "
2887 "pointed object is NULL"<<std::endl;
2893 v3f pointed_pos_under = player_pos;
2894 v3f pointed_pos_above = player_pos;
2895 if(pointed.type == POINTEDTHING_NODE)
2897 pointed_pos_under = intToFloat(p_under, BS);
2898 pointed_pos_above = intToFloat(p_above, BS);
2900 else if(pointed.type == POINTEDTHING_OBJECT)
2902 pointed_pos_under = pointed_object->getBasePosition();
2903 pointed_pos_above = pointed_pos_under;
2907 Check that target is reasonably close
2908 (only when digging or placing things)
2910 if(action == 0 || action == 2 || action == 3)
2912 float d = player_pos.getDistanceFrom(pointed_pos_under);
2913 float max_d = BS * 14; // Just some large enough value
2915 actionstream<<"Player "<<player->getName()
2916 <<" tried to access "<<pointed.dump()
2918 <<"d="<<d<<", max_d="<<max_d
2919 <<". ignoring."<<std::endl;
2920 // Re-send block to revert change on client-side
2921 RemoteClient *client = getClient(peer_id);
2922 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2923 client->SetBlockNotSent(blockpos);
2930 Make sure the player is allowed to do it
2932 if(!checkPriv(player->getName(), "interact"))
2934 actionstream<<player->getName()<<" attempted to interact with "
2935 <<pointed.dump()<<" without 'interact' privilege"
2937 // Re-send block to revert change on client-side
2938 RemoteClient *client = getClient(peer_id);
2939 // Digging completed -> under
2941 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2942 client->SetBlockNotSent(blockpos);
2944 // Placement -> above
2946 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2947 client->SetBlockNotSent(blockpos);
2953 If something goes wrong, this player is to blame
2955 RollbackScopeActor rollback_scope(m_rollback,
2956 std::string("player:")+player->getName());
2959 0: start digging or punch object
2963 if(pointed.type == POINTEDTHING_NODE)
2966 NOTE: This can be used in the future to check if
2967 somebody is cheating, by checking the timing.
2969 MapNode n(CONTENT_IGNORE);
2972 n = m_env->getMap().getNode(p_under);
2974 catch(InvalidPositionException &e)
2976 infostream<<"Server: Not punching: Node not found."
2977 <<" Adding block to emerge queue."
2979 m_emerge_queue.addBlock(peer_id,
2980 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2982 if(n.getContent() != CONTENT_IGNORE)
2983 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
2985 playersao->noCheatDigStart(p_under);
2987 else if(pointed.type == POINTEDTHING_OBJECT)
2989 // Skip if object has been removed
2990 if(pointed_object->m_removed)
2993 actionstream<<player->getName()<<" punches object "
2994 <<pointed.object_id<<": "
2995 <<pointed_object->getDescription()<<std::endl;
2997 ItemStack punchitem = playersao->getWieldedItem();
2998 ToolCapabilities toolcap =
2999 punchitem.getToolCapabilities(m_itemdef);
3000 v3f dir = (pointed_object->getBasePosition() -
3001 (player->getPosition() + player->getEyeOffset())
3003 float time_from_last_punch =
3004 playersao->resetTimeFromLastPunch();
3005 pointed_object->punch(dir, &toolcap, playersao,
3006 time_from_last_punch);
3014 else if(action == 1)
3019 2: Digging completed
3021 else if(action == 2)
3023 // Only digging of nodes
3024 if(pointed.type == POINTEDTHING_NODE)
3026 MapNode n(CONTENT_IGNORE);
3029 n = m_env->getMap().getNode(p_under);
3031 catch(InvalidPositionException &e)
3033 infostream<<"Server: Not finishing digging: Node not found."
3034 <<" Adding block to emerge queue."
3036 m_emerge_queue.addBlock(peer_id,
3037 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3040 /* Cheat prevention */
3041 bool is_valid_dig = true;
3042 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3044 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3045 float nocheat_t = playersao->getNoCheatDigTime();
3046 playersao->noCheatDigEnd();
3047 // If player didn't start digging this, ignore dig
3048 if(nocheat_p != p_under){
3049 infostream<<"Server: NoCheat: "<<player->getName()
3050 <<" started digging "
3051 <<PP(nocheat_p)<<" and completed digging "
3052 <<PP(p_under)<<"; not digging."<<std::endl;
3053 is_valid_dig = false;
3055 // Get player's wielded item
3056 ItemStack playeritem;
3057 InventoryList *mlist = playersao->getInventory()->getList("main");
3059 playeritem = mlist->getItem(playersao->getWieldIndex());
3060 ToolCapabilities playeritem_toolcap =
3061 playeritem.getToolCapabilities(m_itemdef);
3062 // Get diggability and expected digging time
3063 DigParams params = getDigParams(m_nodedef->get(n).groups,
3064 &playeritem_toolcap);
3065 // If can't dig, try hand
3066 if(!params.diggable){
3067 const ItemDefinition &hand = m_itemdef->get("");
3068 const ToolCapabilities *tp = hand.tool_capabilities;
3070 params = getDigParams(m_nodedef->get(n).groups, tp);
3072 // If can't dig, ignore dig
3073 if(!params.diggable){
3074 infostream<<"Server: NoCheat: "<<player->getName()
3075 <<" completed digging "<<PP(p_under)
3076 <<", which is not diggable with tool. not digging."
3078 is_valid_dig = false;
3080 // If time is considerably too short, ignore dig
3081 // Check time only for medium and slow timed digs
3082 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3083 infostream<<"Server: NoCheat: "<<player->getName()
3084 <<" completed digging "
3085 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3086 <<params.time<<"s; not digging."<<std::endl;
3087 is_valid_dig = false;
3091 /* Actually dig node */
3093 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3094 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3096 // Send unusual result (that is, node not being removed)
3097 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3099 // Re-send block to revert change on client-side
3100 RemoteClient *client = getClient(peer_id);
3101 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3102 client->SetBlockNotSent(blockpos);
3108 3: place block or right-click object
3110 else if(action == 3)
3112 ItemStack item = playersao->getWieldedItem();
3114 // Reset build time counter
3115 if(pointed.type == POINTEDTHING_NODE &&
3116 item.getDefinition(m_itemdef).type == ITEM_NODE)
3117 getClient(peer_id)->m_time_from_building = 0.0;
3119 if(pointed.type == POINTEDTHING_OBJECT)
3121 // Right click object
3123 // Skip if object has been removed
3124 if(pointed_object->m_removed)
3127 actionstream<<player->getName()<<" right-clicks object "
3128 <<pointed.object_id<<": "
3129 <<pointed_object->getDescription()<<std::endl;
3132 pointed_object->rightClick(playersao);
3134 else if(scriptapi_item_on_place(m_lua,
3135 item, playersao, pointed))
3137 // Placement was handled in lua
3139 // Apply returned ItemStack
3140 playersao->setWieldedItem(item);
3143 // If item has node placement prediction, always send the above
3144 // node to make sure the client knows what exactly happened
3145 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3146 RemoteClient *client = getClient(peer_id);
3147 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3148 client->SetBlockNotSent(blockpos);
3155 else if(action == 4)
3157 ItemStack item = playersao->getWieldedItem();
3159 actionstream<<player->getName()<<" uses "<<item.name
3160 <<", pointing at "<<pointed.dump()<<std::endl;
3162 if(scriptapi_item_on_use(m_lua,
3163 item, playersao, pointed))
3165 // Apply returned ItemStack
3166 playersao->setWieldedItem(item);
3172 Catch invalid actions
3176 infostream<<"WARNING: Server: Invalid action "
3177 <<action<<std::endl;
3180 else if(command == TOSERVER_REMOVED_SOUNDS)
3182 std::string datastring((char*)&data[2], datasize-2);
3183 std::istringstream is(datastring, std::ios_base::binary);
3185 int num = readU16(is);
3186 for(int k=0; k<num; k++){
3187 s32 id = readS32(is);
3188 std::map<s32, ServerPlayingSound>::iterator i =
3189 m_playing_sounds.find(id);
3190 if(i == m_playing_sounds.end())
3192 ServerPlayingSound &psound = i->second;
3193 psound.clients.erase(peer_id);
3194 if(psound.clients.size() == 0)
3195 m_playing_sounds.erase(i++);
3198 else if(command == TOSERVER_NODEMETA_FIELDS)
3200 std::string datastring((char*)&data[2], datasize-2);
3201 std::istringstream is(datastring, std::ios_base::binary);
3203 v3s16 p = readV3S16(is);
3204 std::string formname = deSerializeString(is);
3205 int num = readU16(is);
3206 std::map<std::string, std::string> fields;
3207 for(int k=0; k<num; k++){
3208 std::string fieldname = deSerializeString(is);
3209 std::string fieldvalue = deSerializeLongString(is);
3210 fields[fieldname] = fieldvalue;
3213 // If something goes wrong, this player is to blame
3214 RollbackScopeActor rollback_scope(m_rollback,
3215 std::string("player:")+player->getName());
3217 // Check the target node for rollback data; leave others unnoticed
3218 RollbackNode rn_old(&m_env->getMap(), p, this);
3220 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3223 // Report rollback data
3224 RollbackNode rn_new(&m_env->getMap(), p, this);
3225 if(rollback() && rn_new != rn_old){
3226 RollbackAction action;
3227 action.setSetNode(p, rn_old, rn_new);
3228 rollback()->reportAction(action);
3231 else if(command == TOSERVER_INVENTORY_FIELDS)
3233 std::string datastring((char*)&data[2], datasize-2);
3234 std::istringstream is(datastring, std::ios_base::binary);
3236 std::string formname = deSerializeString(is);
3237 int num = readU16(is);
3238 std::map<std::string, std::string> fields;
3239 for(int k=0; k<num; k++){
3240 std::string fieldname = deSerializeString(is);
3241 std::string fieldvalue = deSerializeLongString(is);
3242 fields[fieldname] = fieldvalue;
3245 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3249 infostream<<"Server::ProcessData(): Ignoring "
3250 "unknown command "<<command<<std::endl;
3254 catch(SendFailedException &e)
3256 errorstream<<"Server::ProcessData(): SendFailedException: "
3262 void Server::onMapEditEvent(MapEditEvent *event)
3264 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3265 if(m_ignore_map_edit_events)
3267 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3269 MapEditEvent *e = event->clone();
3270 m_unsent_map_edit_queue.push_back(e);
3273 Inventory* Server::getInventory(const InventoryLocation &loc)
3276 case InventoryLocation::UNDEFINED:
3279 case InventoryLocation::CURRENT_PLAYER:
3282 case InventoryLocation::PLAYER:
3284 Player *player = m_env->getPlayer(loc.name.c_str());
3287 PlayerSAO *playersao = player->getPlayerSAO();
3290 return playersao->getInventory();
3293 case InventoryLocation::NODEMETA:
3295 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3298 return meta->getInventory();
3301 case InventoryLocation::DETACHED:
3303 if(m_detached_inventories.count(loc.name) == 0)
3305 return m_detached_inventories[loc.name];
3313 void Server::setInventoryModified(const InventoryLocation &loc)
3316 case InventoryLocation::UNDEFINED:
3319 case InventoryLocation::PLAYER:
3321 Player *player = m_env->getPlayer(loc.name.c_str());
3324 PlayerSAO *playersao = player->getPlayerSAO();
3327 playersao->m_inventory_not_sent = true;
3328 playersao->m_wielded_item_not_sent = true;
3331 case InventoryLocation::NODEMETA:
3333 v3s16 blockpos = getNodeBlockPos(loc.p);
3335 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3337 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3339 setBlockNotSent(blockpos);
3342 case InventoryLocation::DETACHED:
3344 sendDetachedInventoryToAll(loc.name);
3352 core::list<PlayerInfo> Server::getPlayerInfo()
3354 DSTACK(__FUNCTION_NAME);
3355 JMutexAutoLock envlock(m_env_mutex);
3356 JMutexAutoLock conlock(m_con_mutex);
3358 core::list<PlayerInfo> list;
3360 core::list<Player*> players = m_env->getPlayers();
3362 core::list<Player*>::Iterator i;
3363 for(i = players.begin();
3364 i != players.end(); i++)
3368 Player *player = *i;
3371 // Copy info from connection to info struct
3372 info.id = player->peer_id;
3373 info.address = m_con.GetPeerAddress(player->peer_id);
3374 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3376 catch(con::PeerNotFoundException &e)
3378 // Set dummy peer info
3380 info.address = Address(0,0,0,0,0);
3384 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3385 info.position = player->getPosition();
3387 list.push_back(info);
3394 void Server::peerAdded(con::Peer *peer)
3396 DSTACK(__FUNCTION_NAME);
3397 verbosestream<<"Server::peerAdded(): peer->id="
3398 <<peer->id<<std::endl;
3401 c.type = PEER_ADDED;
3402 c.peer_id = peer->id;
3404 m_peer_change_queue.push_back(c);
3407 void Server::deletingPeer(con::Peer *peer, bool timeout)
3409 DSTACK(__FUNCTION_NAME);
3410 verbosestream<<"Server::deletingPeer(): peer->id="
3411 <<peer->id<<", timeout="<<timeout<<std::endl;
3414 c.type = PEER_REMOVED;
3415 c.peer_id = peer->id;
3416 c.timeout = timeout;
3417 m_peer_change_queue.push_back(c);
3424 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3426 DSTACK(__FUNCTION_NAME);
3427 std::ostringstream os(std::ios_base::binary);
3429 writeU16(os, TOCLIENT_HP);
3433 std::string s = os.str();
3434 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3436 con.Send(peer_id, 0, data, true);
3439 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3440 const std::wstring &reason)
3442 DSTACK(__FUNCTION_NAME);
3443 std::ostringstream os(std::ios_base::binary);
3445 writeU16(os, TOCLIENT_ACCESS_DENIED);
3446 os<<serializeWideString(reason);
3449 std::string s = os.str();
3450 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3452 con.Send(peer_id, 0, data, true);
3455 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3456 bool set_camera_point_target, v3f camera_point_target)
3458 DSTACK(__FUNCTION_NAME);
3459 std::ostringstream os(std::ios_base::binary);
3461 writeU16(os, TOCLIENT_DEATHSCREEN);
3462 writeU8(os, set_camera_point_target);
3463 writeV3F1000(os, camera_point_target);
3466 std::string s = os.str();
3467 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3469 con.Send(peer_id, 0, data, true);
3472 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3473 IItemDefManager *itemdef)
3475 DSTACK(__FUNCTION_NAME);
3476 std::ostringstream os(std::ios_base::binary);
3480 u32 length of the next item
3481 zlib-compressed serialized ItemDefManager
3483 writeU16(os, TOCLIENT_ITEMDEF);
3484 std::ostringstream tmp_os(std::ios::binary);
3485 itemdef->serialize(tmp_os);
3486 std::ostringstream tmp_os2(std::ios::binary);
3487 compressZlib(tmp_os.str(), tmp_os2);
3488 os<<serializeLongString(tmp_os2.str());
3491 std::string s = os.str();
3492 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3493 <<"): size="<<s.size()<<std::endl;
3494 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3496 con.Send(peer_id, 0, data, true);
3499 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3500 INodeDefManager *nodedef)
3502 DSTACK(__FUNCTION_NAME);
3503 std::ostringstream os(std::ios_base::binary);
3507 u32 length of the next item
3508 zlib-compressed serialized NodeDefManager
3510 writeU16(os, TOCLIENT_NODEDEF);
3511 std::ostringstream tmp_os(std::ios::binary);
3512 nodedef->serialize(tmp_os);
3513 std::ostringstream tmp_os2(std::ios::binary);
3514 compressZlib(tmp_os.str(), tmp_os2);
3515 os<<serializeLongString(tmp_os2.str());
3518 std::string s = os.str();
3519 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3520 <<"): size="<<s.size()<<std::endl;
3521 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3523 con.Send(peer_id, 0, data, true);
3527 Non-static send methods
3530 void Server::SendInventory(u16 peer_id)
3532 DSTACK(__FUNCTION_NAME);
3534 PlayerSAO *playersao = getPlayerSAO(peer_id);
3537 playersao->m_inventory_not_sent = false;
3543 std::ostringstream os;
3544 playersao->getInventory()->serialize(os);
3546 std::string s = os.str();
3548 SharedBuffer<u8> data(s.size()+2);
3549 writeU16(&data[0], TOCLIENT_INVENTORY);
3550 memcpy(&data[2], s.c_str(), s.size());
3553 m_con.Send(peer_id, 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(u16 peer_id)
3604 DSTACK(__FUNCTION_NAME);
3605 PlayerSAO *playersao = getPlayerSAO(peer_id);
3607 playersao->m_hp_not_sent = false;
3608 SendHP(m_con, peer_id, playersao->getHP());
3611 void Server::SendMovePlayer(u16 peer_id)
3613 DSTACK(__FUNCTION_NAME);
3614 Player *player = m_env->getPlayer(peer_id);
3617 std::ostringstream os(std::ios_base::binary);
3618 writeU16(os, TOCLIENT_MOVE_PLAYER);
3619 writeV3F1000(os, player->getPosition());
3620 writeF1000(os, player->getPitch());
3621 writeF1000(os, player->getYaw());
3624 v3f pos = player->getPosition();
3625 f32 pitch = player->getPitch();
3626 f32 yaw = player->getYaw();
3627 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3628 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3635 std::string s = os.str();
3636 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3638 m_con.Send(peer_id, 0, data, true);
3641 void Server::SendPlayerPrivileges(u16 peer_id)
3643 Player *player = m_env->getPlayer(peer_id);
3645 if(player->peer_id == PEER_ID_INEXISTENT)
3648 std::set<std::string> privs;
3649 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3651 std::ostringstream os(std::ios_base::binary);
3652 writeU16(os, TOCLIENT_PRIVILEGES);
3653 writeU16(os, privs.size());
3654 for(std::set<std::string>::const_iterator i = privs.begin();
3655 i != privs.end(); i++){
3656 os<<serializeString(*i);
3660 std::string s = os.str();
3661 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3663 m_con.Send(peer_id, 0, data, true);
3666 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3668 Player *player = m_env->getPlayer(peer_id);
3670 if(player->peer_id == PEER_ID_INEXISTENT)
3673 std::ostringstream os(std::ios_base::binary);
3674 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3675 os<<serializeLongString(player->inventory_formspec);
3678 std::string s = os.str();
3679 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3681 m_con.Send(peer_id, 0, data, true);
3684 s32 Server::playSound(const SimpleSoundSpec &spec,
3685 const ServerSoundParams ¶ms)
3687 // Find out initial position of sound
3688 bool pos_exists = false;
3689 v3f pos = params.getPos(m_env, &pos_exists);
3690 // If position is not found while it should be, cancel sound
3691 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3693 // Filter destination clients
3694 std::set<RemoteClient*> dst_clients;
3695 if(params.to_player != "")
3697 Player *player = m_env->getPlayer(params.to_player.c_str());
3699 infostream<<"Server::playSound: Player \""<<params.to_player
3700 <<"\" not found"<<std::endl;
3703 if(player->peer_id == PEER_ID_INEXISTENT){
3704 infostream<<"Server::playSound: Player \""<<params.to_player
3705 <<"\" not connected"<<std::endl;
3708 RemoteClient *client = getClient(player->peer_id);
3709 dst_clients.insert(client);
3713 for(core::map<u16, RemoteClient*>::Iterator
3714 i = m_clients.getIterator(); i.atEnd() == false; i++)
3716 RemoteClient *client = i.getNode()->getValue();
3717 Player *player = m_env->getPlayer(client->peer_id);
3721 if(player->getPosition().getDistanceFrom(pos) >
3722 params.max_hear_distance)
3725 dst_clients.insert(client);
3728 if(dst_clients.size() == 0)
3731 s32 id = m_next_sound_id++;
3732 // The sound will exist as a reference in m_playing_sounds
3733 m_playing_sounds[id] = ServerPlayingSound();
3734 ServerPlayingSound &psound = m_playing_sounds[id];
3735 psound.params = params;
3736 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3737 i != dst_clients.end(); i++)
3738 psound.clients.insert((*i)->peer_id);
3740 std::ostringstream os(std::ios_base::binary);
3741 writeU16(os, TOCLIENT_PLAY_SOUND);
3743 os<<serializeString(spec.name);
3744 writeF1000(os, spec.gain * params.gain);
3745 writeU8(os, params.type);
3746 writeV3F1000(os, pos);
3747 writeU16(os, params.object);
3748 writeU8(os, params.loop);
3750 std::string s = os.str();
3751 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3753 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3754 i != dst_clients.end(); i++){
3756 m_con.Send((*i)->peer_id, 0, data, true);
3760 void Server::stopSound(s32 handle)
3762 // Get sound reference
3763 std::map<s32, ServerPlayingSound>::iterator i =
3764 m_playing_sounds.find(handle);
3765 if(i == m_playing_sounds.end())
3767 ServerPlayingSound &psound = i->second;
3769 std::ostringstream os(std::ios_base::binary);
3770 writeU16(os, TOCLIENT_STOP_SOUND);
3771 writeS32(os, handle);
3773 std::string s = os.str();
3774 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3776 for(std::set<u16>::iterator i = psound.clients.begin();
3777 i != psound.clients.end(); i++){
3779 m_con.Send(*i, 0, data, true);
3781 // Remove sound reference
3782 m_playing_sounds.erase(i);
3785 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3786 core::list<u16> *far_players, float far_d_nodes)
3788 float maxd = far_d_nodes*BS;
3789 v3f p_f = intToFloat(p, BS);
3793 SharedBuffer<u8> reply(replysize);
3794 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3795 writeS16(&reply[2], p.X);
3796 writeS16(&reply[4], p.Y);
3797 writeS16(&reply[6], p.Z);
3799 for(core::map<u16, RemoteClient*>::Iterator
3800 i = m_clients.getIterator();
3801 i.atEnd() == false; i++)
3803 // Get client and check that it is valid
3804 RemoteClient *client = i.getNode()->getValue();
3805 assert(client->peer_id == i.getNode()->getKey());
3806 if(client->serialization_version == SER_FMT_VER_INVALID)
3809 // Don't send if it's the same one
3810 if(client->peer_id == ignore_id)
3816 Player *player = m_env->getPlayer(client->peer_id);
3819 // If player is far away, only set modified blocks not sent
3820 v3f player_pos = player->getPosition();
3821 if(player_pos.getDistanceFrom(p_f) > maxd)
3823 far_players->push_back(client->peer_id);
3830 m_con.Send(client->peer_id, 0, reply, true);
3834 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3835 core::list<u16> *far_players, float far_d_nodes)
3837 float maxd = far_d_nodes*BS;
3838 v3f p_f = intToFloat(p, BS);
3840 for(core::map<u16, RemoteClient*>::Iterator
3841 i = m_clients.getIterator();
3842 i.atEnd() == false; i++)
3844 // Get client and check that it is valid
3845 RemoteClient *client = i.getNode()->getValue();
3846 assert(client->peer_id == i.getNode()->getKey());
3847 if(client->serialization_version == SER_FMT_VER_INVALID)
3850 // Don't send if it's the same one
3851 if(client->peer_id == ignore_id)
3857 Player *player = m_env->getPlayer(client->peer_id);
3860 // If player is far away, only set modified blocks not sent
3861 v3f player_pos = player->getPosition();
3862 if(player_pos.getDistanceFrom(p_f) > maxd)
3864 far_players->push_back(client->peer_id);
3871 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3872 SharedBuffer<u8> reply(replysize);
3873 writeU16(&reply[0], TOCLIENT_ADDNODE);
3874 writeS16(&reply[2], p.X);
3875 writeS16(&reply[4], p.Y);
3876 writeS16(&reply[6], p.Z);
3877 n.serialize(&reply[8], client->serialization_version);
3880 m_con.Send(client->peer_id, 0, reply, true);
3884 void Server::setBlockNotSent(v3s16 p)
3886 for(core::map<u16, RemoteClient*>::Iterator
3887 i = m_clients.getIterator();
3888 i.atEnd()==false; i++)
3890 RemoteClient *client = i.getNode()->getValue();
3891 client->SetBlockNotSent(p);
3895 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3897 DSTACK(__FUNCTION_NAME);
3899 v3s16 p = block->getPos();
3903 bool completely_air = true;
3904 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3905 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3906 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3908 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3910 completely_air = false;
3911 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3916 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3918 infostream<<"[completely air] ";
3919 infostream<<std::endl;
3923 Create a packet with the block in the right format
3926 std::ostringstream os(std::ios_base::binary);
3927 block->serialize(os, ver, false);
3928 std::string s = os.str();
3929 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3931 u32 replysize = 8 + blockdata.getSize();
3932 SharedBuffer<u8> reply(replysize);
3933 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3934 writeS16(&reply[2], p.X);
3935 writeS16(&reply[4], p.Y);
3936 writeS16(&reply[6], p.Z);
3937 memcpy(&reply[8], *blockdata, blockdata.getSize());
3939 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3940 <<": \tpacket size: "<<replysize<<std::endl;*/
3945 m_con.Send(peer_id, 1, reply, true);
3948 void Server::SendBlocks(float dtime)
3950 DSTACK(__FUNCTION_NAME);
3952 JMutexAutoLock envlock(m_env_mutex);
3953 JMutexAutoLock conlock(m_con_mutex);
3955 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3957 core::array<PrioritySortedBlockTransfer> queue;
3959 s32 total_sending = 0;
3962 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3964 for(core::map<u16, RemoteClient*>::Iterator
3965 i = m_clients.getIterator();
3966 i.atEnd() == false; i++)
3968 RemoteClient *client = i.getNode()->getValue();
3969 assert(client->peer_id == i.getNode()->getKey());
3971 // If definitions and textures have not been sent, don't
3972 // send MapBlocks either
3973 if(!client->definitions_sent)
3976 total_sending += client->SendingCount();
3978 if(client->serialization_version == SER_FMT_VER_INVALID)
3981 client->GetNextBlocks(this, dtime, queue);
3986 // Lowest priority number comes first.
3987 // Lowest is most important.
3990 for(u32 i=0; i<queue.size(); i++)
3992 //TODO: Calculate limit dynamically
3993 if(total_sending >= g_settings->getS32
3994 ("max_simultaneous_block_sends_server_total"))
3997 PrioritySortedBlockTransfer q = queue[i];
3999 MapBlock *block = NULL;
4002 block = m_env->getMap().getBlockNoCreate(q.pos);
4004 catch(InvalidPositionException &e)
4009 RemoteClient *client = getClient(q.peer_id);
4011 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4013 client->SentBlock(q.pos);
4019 void Server::fillMediaCache()
4021 DSTACK(__FUNCTION_NAME);
4023 infostream<<"Server: Calculating media file checksums"<<std::endl;
4025 // Collect all media file paths
4026 std::list<std::string> paths;
4027 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4028 i != m_mods.end(); i++){
4029 const ModSpec &mod = *i;
4030 paths.push_back(mod.path + DIR_DELIM + "textures");
4031 paths.push_back(mod.path + DIR_DELIM + "sounds");
4032 paths.push_back(mod.path + DIR_DELIM + "media");
4034 std::string path_all = "textures";
4035 paths.push_back(path_all + DIR_DELIM + "all");
4037 // Collect media file information from paths into cache
4038 for(std::list<std::string>::iterator i = paths.begin();
4039 i != paths.end(); i++)
4041 std::string mediapath = *i;
4042 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4043 for(u32 j=0; j<dirlist.size(); j++){
4044 if(dirlist[j].dir) // Ignode dirs
4046 std::string filename = dirlist[j].name;
4047 // If name contains illegal characters, ignore the file
4048 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4049 infostream<<"Server: ignoring illegal file name: \""
4050 <<filename<<"\""<<std::endl;
4053 // If name is not in a supported format, ignore it
4054 const char *supported_ext[] = {
4055 ".png", ".jpg", ".bmp", ".tga",
4056 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4060 if(removeStringEnd(filename, supported_ext) == ""){
4061 infostream<<"Server: ignoring unsupported file extension: \""
4062 <<filename<<"\""<<std::endl;
4065 // Ok, attempt to load the file and add to cache
4066 std::string filepath = mediapath + DIR_DELIM + filename;
4068 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4069 if(fis.good() == false){
4070 errorstream<<"Server::fillMediaCache(): Could not open \""
4071 <<filename<<"\" for reading"<<std::endl;
4074 std::ostringstream tmp_os(std::ios_base::binary);
4078 fis.read(buf, 1024);
4079 std::streamsize len = fis.gcount();
4080 tmp_os.write(buf, len);
4089 errorstream<<"Server::fillMediaCache(): Failed to read \""
4090 <<filename<<"\""<<std::endl;
4093 if(tmp_os.str().length() == 0){
4094 errorstream<<"Server::fillMediaCache(): Empty file \""
4095 <<filepath<<"\""<<std::endl;
4100 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4102 unsigned char *digest = sha1.getDigest();
4103 std::string sha1_base64 = base64_encode(digest, 20);
4104 std::string sha1_hex = hex_encode((char*)digest, 20);
4108 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4109 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4114 struct SendableMediaAnnouncement
4117 std::string sha1_digest;
4119 SendableMediaAnnouncement(const std::string name_="",
4120 const std::string sha1_digest_=""):
4122 sha1_digest(sha1_digest_)
4126 void Server::sendMediaAnnouncement(u16 peer_id)
4128 DSTACK(__FUNCTION_NAME);
4130 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4133 core::list<SendableMediaAnnouncement> file_announcements;
4135 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4136 i != m_media.end(); i++){
4138 file_announcements.push_back(
4139 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4143 std::ostringstream os(std::ios_base::binary);
4151 u16 length of sha1_digest
4156 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4157 writeU16(os, file_announcements.size());
4159 for(core::list<SendableMediaAnnouncement>::Iterator
4160 j = file_announcements.begin();
4161 j != file_announcements.end(); j++){
4162 os<<serializeString(j->name);
4163 os<<serializeString(j->sha1_digest);
4167 std::string s = os.str();
4168 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4171 m_con.Send(peer_id, 0, data, true);
4175 struct SendableMedia
4181 SendableMedia(const std::string &name_="", const std::string path_="",
4182 const std::string &data_=""):
4189 void Server::sendRequestedMedia(u16 peer_id,
4190 const core::list<MediaRequest> &tosend)
4192 DSTACK(__FUNCTION_NAME);
4194 verbosestream<<"Server::sendRequestedMedia(): "
4195 <<"Sending files to client"<<std::endl;
4199 // Put 5kB in one bunch (this is not accurate)
4200 u32 bytes_per_bunch = 5000;
4202 core::array< core::list<SendableMedia> > file_bunches;
4203 file_bunches.push_back(core::list<SendableMedia>());
4205 u32 file_size_bunch_total = 0;
4207 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4208 i != tosend.end(); i++)
4210 if(m_media.find(i->name) == m_media.end()){
4211 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4212 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4216 //TODO get path + name
4217 std::string tpath = m_media[(*i).name].path;
4220 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4221 if(fis.good() == false){
4222 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4223 <<tpath<<"\" for reading"<<std::endl;
4226 std::ostringstream tmp_os(std::ios_base::binary);
4230 fis.read(buf, 1024);
4231 std::streamsize len = fis.gcount();
4232 tmp_os.write(buf, len);
4233 file_size_bunch_total += len;
4242 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4243 <<(*i).name<<"\""<<std::endl;
4246 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4247 <<tname<<"\""<<std::endl;*/
4249 file_bunches[file_bunches.size()-1].push_back(
4250 SendableMedia((*i).name, tpath, tmp_os.str()));
4252 // Start next bunch if got enough data
4253 if(file_size_bunch_total >= bytes_per_bunch){
4254 file_bunches.push_back(core::list<SendableMedia>());
4255 file_size_bunch_total = 0;
4260 /* Create and send packets */
4262 u32 num_bunches = file_bunches.size();
4263 for(u32 i=0; i<num_bunches; i++)
4265 std::ostringstream os(std::ios_base::binary);
4269 u16 total number of texture bunches
4270 u16 index of this bunch
4271 u32 number of files in this bunch
4280 writeU16(os, TOCLIENT_MEDIA);
4281 writeU16(os, num_bunches);
4283 writeU32(os, file_bunches[i].size());
4285 for(core::list<SendableMedia>::Iterator
4286 j = file_bunches[i].begin();
4287 j != file_bunches[i].end(); j++){
4288 os<<serializeString(j->name);
4289 os<<serializeLongString(j->data);
4293 std::string s = os.str();
4294 verbosestream<<"Server::sendRequestedMedia(): bunch "
4295 <<i<<"/"<<num_bunches
4296 <<" files="<<file_bunches[i].size()
4297 <<" size=" <<s.size()<<std::endl;
4298 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4300 m_con.Send(peer_id, 0, data, true);
4304 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4306 if(m_detached_inventories.count(name) == 0){
4307 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4310 Inventory *inv = m_detached_inventories[name];
4312 std::ostringstream os(std::ios_base::binary);
4313 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4314 os<<serializeString(name);
4318 std::string s = os.str();
4319 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4321 m_con.Send(peer_id, 0, data, true);
4324 void Server::sendDetachedInventoryToAll(const std::string &name)
4326 DSTACK(__FUNCTION_NAME);
4328 for(core::map<u16, RemoteClient*>::Iterator
4329 i = m_clients.getIterator();
4330 i.atEnd() == false; i++){
4331 RemoteClient *client = i.getNode()->getValue();
4332 sendDetachedInventory(name, client->peer_id);
4336 void Server::sendDetachedInventories(u16 peer_id)
4338 DSTACK(__FUNCTION_NAME);
4340 for(std::map<std::string, Inventory*>::iterator
4341 i = m_detached_inventories.begin();
4342 i != m_detached_inventories.end(); i++){
4343 const std::string &name = i->first;
4344 //Inventory *inv = i->second;
4345 sendDetachedInventory(name, peer_id);
4353 void Server::DiePlayer(u16 peer_id)
4355 DSTACK(__FUNCTION_NAME);
4357 PlayerSAO *playersao = getPlayerSAO(peer_id);
4360 infostream<<"Server::DiePlayer(): Player "
4361 <<playersao->getPlayer()->getName()
4362 <<" dies"<<std::endl;
4364 playersao->setHP(0);
4366 // Trigger scripted stuff
4367 scriptapi_on_dieplayer(m_lua, playersao);
4369 SendPlayerHP(peer_id);
4370 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4373 void Server::RespawnPlayer(u16 peer_id)
4375 DSTACK(__FUNCTION_NAME);
4377 PlayerSAO *playersao = getPlayerSAO(peer_id);
4380 infostream<<"Server::RespawnPlayer(): Player "
4381 <<playersao->getPlayer()->getName()
4382 <<" respawns"<<std::endl;
4384 playersao->setHP(PLAYER_MAX_HP);
4386 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4388 v3f pos = findSpawnPos(m_env->getServerMap());
4389 playersao->setPos(pos);
4393 void Server::UpdateCrafting(u16 peer_id)
4395 DSTACK(__FUNCTION_NAME);
4397 Player* player = m_env->getPlayer(peer_id);
4400 // Get a preview for crafting
4402 getCraftingResult(&player->inventory, preview, false, this);
4404 // Put the new preview in
4405 InventoryList *plist = player->inventory.getList("craftpreview");
4407 assert(plist->getSize() >= 1);
4408 plist->changeItem(0, preview);
4411 RemoteClient* Server::getClient(u16 peer_id)
4413 DSTACK(__FUNCTION_NAME);
4414 //JMutexAutoLock lock(m_con_mutex);
4415 core::map<u16, RemoteClient*>::Node *n;
4416 n = m_clients.find(peer_id);
4417 // A client should exist for all peers
4419 return n->getValue();
4422 std::wstring Server::getStatusString()
4424 std::wostringstream os(std::ios_base::binary);
4427 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4429 os<<L", uptime="<<m_uptime.get();
4430 // Information about clients
4431 core::map<u16, RemoteClient*>::Iterator i;
4434 for(i = m_clients.getIterator(), first = true;
4435 i.atEnd() == false; i++)
4437 // Get client and check that it is valid
4438 RemoteClient *client = i.getNode()->getValue();
4439 assert(client->peer_id == i.getNode()->getKey());
4440 if(client->serialization_version == SER_FMT_VER_INVALID)
4443 Player *player = m_env->getPlayer(client->peer_id);
4444 // Get name of player
4445 std::wstring name = L"unknown";
4447 name = narrow_to_wide(player->getName());
4448 // Add name to information string
4456 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4457 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4458 if(g_settings->get("motd") != "")
4459 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4463 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4465 std::set<std::string> privs;
4466 scriptapi_get_auth(m_lua, name, NULL, &privs);
4470 bool Server::checkPriv(const std::string &name, const std::string &priv)
4472 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4473 return (privs.count(priv) != 0);
4476 void Server::reportPrivsModified(const std::string &name)
4479 for(core::map<u16, RemoteClient*>::Iterator
4480 i = m_clients.getIterator();
4481 i.atEnd() == false; i++){
4482 RemoteClient *client = i.getNode()->getValue();
4483 Player *player = m_env->getPlayer(client->peer_id);
4484 reportPrivsModified(player->getName());
4487 Player *player = m_env->getPlayer(name.c_str());
4490 SendPlayerPrivileges(player->peer_id);
4491 PlayerSAO *sao = player->getPlayerSAO();
4494 sao->updatePrivileges(
4495 getPlayerEffectivePrivs(name),
4500 void Server::reportInventoryFormspecModified(const std::string &name)
4502 Player *player = m_env->getPlayer(name.c_str());
4505 SendPlayerInventoryFormspec(player->peer_id);
4508 // Saves g_settings to configpath given at initialization
4509 void Server::saveConfig()
4511 if(m_path_config != "")
4512 g_settings->updateConfigFile(m_path_config.c_str());
4515 void Server::notifyPlayer(const char *name, const std::wstring msg)
4517 Player *player = m_env->getPlayer(name);
4520 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4523 void Server::notifyPlayers(const std::wstring msg)
4525 BroadcastChatMessage(msg);
4528 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4532 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4533 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4536 Inventory* Server::createDetachedInventory(const std::string &name)
4538 if(m_detached_inventories.count(name) > 0){
4539 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4540 delete m_detached_inventories[name];
4542 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4544 Inventory *inv = new Inventory(m_itemdef);
4546 m_detached_inventories[name] = inv;
4547 sendDetachedInventoryToAll(name);
4554 BoolScopeSet(bool *dst, bool val):
4557 m_orig_state = *m_dst;
4562 *m_dst = m_orig_state;
4569 // actions: time-reversed list
4570 // Return value: success/failure
4571 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4572 std::list<std::string> *log)
4574 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4575 ServerMap *map = (ServerMap*)(&m_env->getMap());
4576 // Disable rollback report sink while reverting
4577 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4579 // Fail if no actions to handle
4580 if(actions.empty()){
4581 log->push_back("Nothing to do.");
4588 for(std::list<RollbackAction>::const_iterator
4589 i = actions.begin();
4590 i != actions.end(); i++)
4592 const RollbackAction &action = *i;
4594 bool success = action.applyRevert(map, this, this);
4597 std::ostringstream os;
4598 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4599 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4601 log->push_back(os.str());
4603 std::ostringstream os;
4604 os<<"Succesfully reverted step ("<<num_tried<<") "<<action.toString();
4605 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4607 log->push_back(os.str());
4611 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4612 <<" failed"<<std::endl;
4614 // Call it done if less than half failed
4615 return num_failed <= num_tried/2;
4618 // IGameDef interface
4620 IItemDefManager* Server::getItemDefManager()
4624 INodeDefManager* Server::getNodeDefManager()
4628 ICraftDefManager* Server::getCraftDefManager()
4632 ITextureSource* Server::getTextureSource()
4636 u16 Server::allocateUnknownNodeId(const std::string &name)
4638 return m_nodedef->allocateDummy(name);
4640 ISoundManager* Server::getSoundManager()
4642 return &dummySoundManager;
4644 MtEventManager* Server::getEventManager()
4648 IRollbackReportSink* Server::getRollbackReportSink()
4650 if(!m_enable_rollback_recording)
4652 if(!m_rollback_sink_enabled)
4657 IWritableItemDefManager* Server::getWritableItemDefManager()
4661 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4665 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4670 const ModSpec* Server::getModSpec(const std::string &modname)
4672 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4673 i != m_mods.end(); i++){
4674 const ModSpec &mod = *i;
4675 if(mod.name == modname)
4680 void Server::getModNames(core::list<std::string> &modlist)
4682 for(core::list<ModSpec>::Iterator i = m_mods.begin(); i != m_mods.end(); i++)
4684 modlist.push_back((*i).name);
4687 std::string Server::getBuiltinLuaPath()
4689 return porting::path_share + DIR_DELIM + "builtin";
4692 v3f findSpawnPos(ServerMap &map)
4694 //return v3f(50,50,50)*BS;
4699 nodepos = v2s16(0,0);
4704 // Try to find a good place a few times
4705 for(s32 i=0; i<1000; i++)
4708 // We're going to try to throw the player to this position
4709 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4710 -range + (myrand()%(range*2)));
4711 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4712 // Get ground height at point (fallbacks to heightmap function)
4713 s16 groundheight = map.findGroundLevel(nodepos2d);
4714 // Don't go underwater
4715 if(groundheight < WATER_LEVEL)
4717 //infostream<<"-> Underwater"<<std::endl;
4720 // Don't go to high places
4721 if(groundheight > WATER_LEVEL + 4)
4723 //infostream<<"-> Underwater"<<std::endl;
4727 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4728 bool is_good = false;
4730 for(s32 i=0; i<10; i++){
4731 v3s16 blockpos = getNodeBlockPos(nodepos);
4732 map.emergeBlock(blockpos, true);
4733 MapNode n = map.getNodeNoEx(nodepos);
4734 if(n.getContent() == CONTENT_AIR){
4745 // Found a good place
4746 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4752 return intToFloat(nodepos, BS);
4755 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4757 RemotePlayer *player = NULL;
4758 bool newplayer = false;
4761 Try to get an existing player
4763 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4765 // If player is already connected, cancel
4766 if(player != NULL && player->peer_id != 0)
4768 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4773 If player with the wanted peer_id already exists, cancel.
4775 if(m_env->getPlayer(peer_id) != NULL)
4777 infostream<<"emergePlayer(): Player with wrong name but same"
4778 " peer_id already exists"<<std::endl;
4783 Create a new player if it doesn't exist yet
4788 player = new RemotePlayer(this);
4789 player->updateName(name);
4791 /* Set player position */
4792 infostream<<"Server: Finding spawn place for player \""
4793 <<name<<"\""<<std::endl;
4794 v3f pos = findSpawnPos(m_env->getServerMap());
4795 player->setPosition(pos);
4797 /* Add player to environment */
4798 m_env->addPlayer(player);
4802 Create a new player active object
4804 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4805 getPlayerEffectivePrivs(player->getName()),
4808 /* Add object to environment */
4809 m_env->addActiveObject(playersao);
4813 scriptapi_on_newplayer(m_lua, playersao);
4815 scriptapi_on_joinplayer(m_lua, playersao);
4820 void Server::handlePeerChange(PeerChange &c)
4822 JMutexAutoLock envlock(m_env_mutex);
4823 JMutexAutoLock conlock(m_con_mutex);
4825 if(c.type == PEER_ADDED)
4832 core::map<u16, RemoteClient*>::Node *n;
4833 n = m_clients.find(c.peer_id);
4834 // The client shouldn't already exist
4838 RemoteClient *client = new RemoteClient();
4839 client->peer_id = c.peer_id;
4840 m_clients.insert(client->peer_id, client);
4843 else if(c.type == PEER_REMOVED)
4850 core::map<u16, RemoteClient*>::Node *n;
4851 n = m_clients.find(c.peer_id);
4852 // The client should exist
4856 Mark objects to be not known by the client
4858 RemoteClient *client = n->getValue();
4860 for(core::map<u16, bool>::Iterator
4861 i = client->m_known_objects.getIterator();
4862 i.atEnd()==false; i++)
4865 u16 id = i.getNode()->getKey();
4866 ServerActiveObject* obj = m_env->getActiveObject(id);
4868 if(obj && obj->m_known_by_count > 0)
4869 obj->m_known_by_count--;
4873 Clear references to playing sounds
4875 for(std::map<s32, ServerPlayingSound>::iterator
4876 i = m_playing_sounds.begin();
4877 i != m_playing_sounds.end();)
4879 ServerPlayingSound &psound = i->second;
4880 psound.clients.erase(c.peer_id);
4881 if(psound.clients.size() == 0)
4882 m_playing_sounds.erase(i++);
4887 Player *player = m_env->getPlayer(c.peer_id);
4889 // Collect information about leaving in chat
4890 std::wstring message;
4894 std::wstring name = narrow_to_wide(player->getName());
4897 message += L" left the game.";
4899 message += L" (timed out)";
4903 /* Run scripts and remove from environment */
4907 PlayerSAO *playersao = player->getPlayerSAO();
4910 scriptapi_on_leaveplayer(m_lua, playersao);
4912 playersao->disconnected();
4922 std::ostringstream os(std::ios_base::binary);
4923 for(core::map<u16, RemoteClient*>::Iterator
4924 i = m_clients.getIterator();
4925 i.atEnd() == false; i++)
4927 RemoteClient *client = i.getNode()->getValue();
4928 assert(client->peer_id == i.getNode()->getKey());
4929 if(client->serialization_version == SER_FMT_VER_INVALID)
4932 Player *player = m_env->getPlayer(client->peer_id);
4935 // Get name of player
4936 os<<player->getName()<<" ";
4939 actionstream<<player->getName()<<" "
4940 <<(c.timeout?"times out.":"leaves game.")
4941 <<" List of players: "
4942 <<os.str()<<std::endl;
4947 delete m_clients[c.peer_id];
4948 m_clients.remove(c.peer_id);
4950 // Send player info to all remaining clients
4951 //SendPlayerInfos();
4953 // Send leave chat message to all remaining clients
4954 if(message.length() != 0)
4955 BroadcastChatMessage(message);
4964 void Server::handlePeerChanges()
4966 while(m_peer_change_queue.size() > 0)
4968 PeerChange c = m_peer_change_queue.pop_front();
4970 verbosestream<<"Server: Handling peer change: "
4971 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4974 handlePeerChange(c);
4978 void dedicated_server_loop(Server &server, bool &kill)
4980 DSTACK(__FUNCTION_NAME);
4982 verbosestream<<"dedicated_server_loop()"<<std::endl;
4984 IntervalLimiter m_profiler_interval;
4988 float steplen = g_settings->getFloat("dedicated_server_step");
4989 // This is kind of a hack but can be done like this
4990 // because server.step() is very light
4992 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4993 sleep_ms((int)(steplen*1000.0));
4995 server.step(steplen);
4997 if(server.getShutdownRequested() || kill)
4999 infostream<<"Dedicated server quitting"<<std::endl;
5006 float profiler_print_interval =
5007 g_settings->getFloat("profiler_print_interval");
5008 if(profiler_print_interval != 0)
5010 if(m_profiler_interval.step(steplen, profiler_print_interval))
5012 infostream<<"Profiler:"<<std::endl;
5013 g_profiler->print(infostream);
5014 g_profiler->clear();