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)
447 Player *player = server->m_env->getPlayer(peer_id);
448 // This can happen sometimes; clients and players are not in perfect sync.
452 // Won't send anything if already sending
453 if(m_blocks_sending.size() >= g_settings->getU16
454 ("max_simultaneous_block_sends_per_client"))
456 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
460 //TimeTaker timer("RemoteClient::GetNextBlocks");
462 v3f playerpos = player->getPosition();
463 v3f playerspeed = player->getSpeed();
464 v3f playerspeeddir(0,0,0);
465 if(playerspeed.getLength() > 1.0*BS)
466 playerspeeddir = playerspeed / playerspeed.getLength();
467 // Predict to next block
468 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
470 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
472 v3s16 center = getNodeBlockPos(center_nodepos);
474 // Camera position and direction
475 v3f camera_pos = player->getEyePosition();
476 v3f camera_dir = v3f(0,0,1);
477 camera_dir.rotateYZBy(player->getPitch());
478 camera_dir.rotateXZBy(player->getYaw());
480 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
481 <<camera_dir.Z<<")"<<std::endl;*/
484 Get the starting value of the block finder radius.
487 if(m_last_center != center)
489 m_nearest_unsent_d = 0;
490 m_last_center = center;
493 /*infostream<<"m_nearest_unsent_reset_timer="
494 <<m_nearest_unsent_reset_timer<<std::endl;*/
496 // Reset periodically to workaround for some bugs or stuff
497 if(m_nearest_unsent_reset_timer > 20.0)
499 m_nearest_unsent_reset_timer = 0;
500 m_nearest_unsent_d = 0;
501 //infostream<<"Resetting m_nearest_unsent_d for "
502 // <<server->getPlayerName(peer_id)<<std::endl;
505 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
506 s16 d_start = m_nearest_unsent_d;
508 //infostream<<"d_start="<<d_start<<std::endl;
510 u16 max_simul_sends_setting = g_settings->getU16
511 ("max_simultaneous_block_sends_per_client");
512 u16 max_simul_sends_usually = max_simul_sends_setting;
515 Check the time from last addNode/removeNode.
517 Decrease send rate if player is building stuff.
519 m_time_from_building += dtime;
520 if(m_time_from_building < g_settings->getFloat(
521 "full_block_send_enable_min_time_from_building"))
523 max_simul_sends_usually
524 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
528 Number of blocks sending + number of blocks selected for sending
530 u32 num_blocks_selected = m_blocks_sending.size();
533 next time d will be continued from the d from which the nearest
534 unsent block was found this time.
536 This is because not necessarily any of the blocks found this
537 time are actually sent.
539 s32 new_nearest_unsent_d = -1;
541 s16 d_max = g_settings->getS16("max_block_send_distance");
542 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
544 // Don't loop very much at a time
545 s16 max_d_increment_at_time = 2;
546 if(d_max > d_start + max_d_increment_at_time)
547 d_max = d_start + max_d_increment_at_time;
548 /*if(d_max_gen > d_start+2)
549 d_max_gen = d_start+2;*/
551 //infostream<<"Starting from "<<d_start<<std::endl;
553 s32 nearest_emerged_d = -1;
554 s32 nearest_emergefull_d = -1;
555 s32 nearest_sent_d = -1;
556 bool queue_is_full = false;
559 for(d = d_start; d <= d_max; d++)
561 /*errorstream<<"checking d="<<d<<" for "
562 <<server->getPlayerName(peer_id)<<std::endl;*/
563 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
566 If m_nearest_unsent_d was changed by the EmergeThread
567 (it can change it to 0 through SetBlockNotSent),
569 Else update m_nearest_unsent_d
571 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
573 d = m_nearest_unsent_d;
574 last_nearest_unsent_d = m_nearest_unsent_d;
578 Get the border/face dot coordinates of a "d-radiused"
581 core::list<v3s16> list;
582 getFacePositions(list, d);
584 core::list<v3s16>::Iterator li;
585 for(li=list.begin(); li!=list.end(); li++)
587 v3s16 p = *li + center;
591 - Don't allow too many simultaneous transfers
592 - EXCEPT when the blocks are very close
594 Also, don't send blocks that are already flying.
597 // Start with the usual maximum
598 u16 max_simul_dynamic = max_simul_sends_usually;
600 // If block is very close, allow full maximum
601 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
602 max_simul_dynamic = max_simul_sends_setting;
604 // Don't select too many blocks for sending
605 if(num_blocks_selected >= max_simul_dynamic)
607 queue_is_full = true;
608 goto queue_full_break;
611 // Don't send blocks that are currently being transferred
612 if(m_blocks_sending.find(p) != NULL)
618 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
619 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
620 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
621 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
622 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
623 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
626 // If this is true, inexistent block will be made from scratch
627 bool generate = d <= d_max_gen;
630 /*// Limit the generating area vertically to 2/3
631 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
634 // Limit the send area vertically to 1/2
635 if(abs(p.Y - center.Y) > d_max / 2)
641 If block is far away, don't generate it unless it is
647 // Block center y in nodes
648 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
649 // Don't generate if it's very high or very low
650 if(y < -64 || y > 64)
654 v2s16 p2d_nodes_center(
658 // Get ground height in nodes
659 s16 gh = server->m_env->getServerMap().findGroundLevel(
662 // If differs a lot, don't generate
663 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
665 // Actually, don't even send it
671 //infostream<<"d="<<d<<std::endl;
674 Don't generate or send if not in sight
675 FIXME This only works if the client uses a small enough
676 FOV setting. The default of 72 degrees is fine.
679 float camera_fov = (72.0*M_PI/180) * 4./3.;
680 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
686 Don't send already sent blocks
689 if(m_blocks_sent.find(p) != NULL)
696 Check if map has this block
698 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
700 bool surely_not_found_on_disk = false;
701 bool block_is_invalid = false;
704 // Reset usage timer, this block will be of use in the future.
705 block->resetUsageTimer();
707 // Block is dummy if data doesn't exist.
708 // It means it has been not found from disk and not generated
711 surely_not_found_on_disk = true;
714 // Block is valid if lighting is up-to-date and data exists
715 if(block->isValid() == false)
717 block_is_invalid = true;
720 /*if(block->isFullyGenerated() == false)
722 block_is_invalid = true;
727 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
728 v2s16 chunkpos = map->sector_to_chunk(p2d);
729 if(map->chunkNonVolatile(chunkpos) == false)
730 block_is_invalid = true;
732 if(block->isGenerated() == false)
733 block_is_invalid = true;
736 If block is not close, don't send it unless it is near
739 Block is near ground level if night-time mesh
740 differs from day-time mesh.
744 if(block->getDayNightDiff() == false)
751 If block has been marked to not exist on disk (dummy)
752 and generating new ones is not wanted, skip block.
754 if(generate == false && surely_not_found_on_disk == true)
761 Add inexistent block to emerge queue.
763 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
765 //TODO: Get value from somewhere
766 // Allow only one block in emerge queue
767 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
768 // Allow two blocks in queue per client
769 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
771 // Make it more responsive when needing to generate stuff
772 if(surely_not_found_on_disk)
774 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
776 //infostream<<"Adding block to emerge queue"<<std::endl;
778 // Add it to the emerge queue and trigger the thread
781 if(generate == false)
782 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
784 server->m_emerge_queue.addBlock(peer_id, p, flags);
785 server->m_emergethread.trigger();
787 if(nearest_emerged_d == -1)
788 nearest_emerged_d = d;
790 if(nearest_emergefull_d == -1)
791 nearest_emergefull_d = d;
798 if(nearest_sent_d == -1)
802 Add block to send queue
805 /*errorstream<<"sending from d="<<d<<" to "
806 <<server->getPlayerName(peer_id)<<std::endl;*/
808 PrioritySortedBlockTransfer q((float)d, p, peer_id);
812 num_blocks_selected += 1;
817 //infostream<<"Stopped at "<<d<<std::endl;
819 // If nothing was found for sending and nothing was queued for
820 // emerging, continue next time browsing from here
821 if(nearest_emerged_d != -1){
822 new_nearest_unsent_d = nearest_emerged_d;
823 } else if(nearest_emergefull_d != -1){
824 new_nearest_unsent_d = nearest_emergefull_d;
826 if(d > g_settings->getS16("max_block_send_distance")){
827 new_nearest_unsent_d = 0;
828 m_nothing_to_send_pause_timer = 2.0;
829 /*infostream<<"GetNextBlocks(): d wrapped around for "
830 <<server->getPlayerName(peer_id)
831 <<"; setting to 0 and pausing"<<std::endl;*/
833 if(nearest_sent_d != -1)
834 new_nearest_unsent_d = nearest_sent_d;
836 new_nearest_unsent_d = d;
840 if(new_nearest_unsent_d != -1)
841 m_nearest_unsent_d = new_nearest_unsent_d;
843 /*timer_result = timer.stop(true);
844 if(timer_result != 0)
845 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
848 void RemoteClient::GotBlock(v3s16 p)
850 if(m_blocks_sending.find(p) != NULL)
851 m_blocks_sending.remove(p);
854 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
855 " m_blocks_sending"<<std::endl;*/
856 m_excess_gotblocks++;
858 m_blocks_sent.insert(p, true);
861 void RemoteClient::SentBlock(v3s16 p)
863 if(m_blocks_sending.find(p) == NULL)
864 m_blocks_sending.insert(p, 0.0);
866 infostream<<"RemoteClient::SentBlock(): Sent block"
867 " already in m_blocks_sending"<<std::endl;
870 void RemoteClient::SetBlockNotSent(v3s16 p)
872 m_nearest_unsent_d = 0;
874 if(m_blocks_sending.find(p) != NULL)
875 m_blocks_sending.remove(p);
876 if(m_blocks_sent.find(p) != NULL)
877 m_blocks_sent.remove(p);
880 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
882 m_nearest_unsent_d = 0;
884 for(core::map<v3s16, MapBlock*>::Iterator
885 i = blocks.getIterator();
886 i.atEnd()==false; i++)
888 v3s16 p = i.getNode()->getKey();
890 if(m_blocks_sending.find(p) != NULL)
891 m_blocks_sending.remove(p);
892 if(m_blocks_sent.find(p) != NULL)
893 m_blocks_sent.remove(p);
901 PlayerInfo::PlayerInfo()
907 void PlayerInfo::PrintLine(std::ostream *s)
910 (*s)<<"\""<<name<<"\" ("
911 <<(position.X/10)<<","<<(position.Y/10)
912 <<","<<(position.Z/10)<<") ";
914 (*s)<<" avg_rtt="<<avg_rtt;
923 const std::string &path_world,
924 const std::string &path_config,
925 const SubgameSpec &gamespec,
926 bool simple_singleplayer_mode
928 m_path_world(path_world),
929 m_path_config(path_config),
930 m_gamespec(gamespec),
931 m_simple_singleplayer_mode(simple_singleplayer_mode),
932 m_async_fatal_error(""),
934 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
935 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
937 m_rollback_sink_enabled(true),
938 m_enable_rollback_recording(false),
940 m_itemdef(createItemDefManager()),
941 m_nodedef(createNodeDefManager()),
942 m_craftdef(createCraftDefManager()),
943 m_event(new EventManager()),
945 m_emergethread(this),
946 m_time_of_day_send_timer(0),
948 m_shutdown_requested(false),
949 m_ignore_map_edit_events(false),
950 m_ignore_map_edit_events_peer_id(0)
952 m_liquid_transform_timer = 0.0;
953 m_print_info_timer = 0.0;
954 m_objectdata_timer = 0.0;
955 m_emergethread_trigger_timer = 0.0;
956 m_savemap_timer = 0.0;
960 m_step_dtime_mutex.Init();
964 throw ServerError("Supplied empty world path");
966 if(!gamespec.isValid())
967 throw ServerError("Supplied invalid gamespec");
969 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
970 if(m_simple_singleplayer_mode)
971 infostream<<" in simple singleplayer mode"<<std::endl;
973 infostream<<std::endl;
974 infostream<<"- world: "<<m_path_world<<std::endl;
975 infostream<<"- config: "<<m_path_config<<std::endl;
976 infostream<<"- game: "<<m_gamespec.path<<std::endl;
978 // Create rollback manager
979 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
980 m_rollback = createRollbackManager(rollback_path, this);
982 // Add world mod search path
983 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
984 // Add addon mod search path
985 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
986 i != m_gamespec.mods_paths.end(); i++)
987 m_modspaths.push_front((*i));
989 // Print out mod search paths
990 for(core::list<std::string>::Iterator i = m_modspaths.begin();
991 i != m_modspaths.end(); i++){
992 std::string modspath = *i;
993 infostream<<"- mods: "<<modspath<<std::endl;
996 // Path to builtin.lua
997 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
999 // Create world if it doesn't exist
1000 if(!initializeWorld(m_path_world, m_gamespec.id))
1001 throw ServerError("Failed to initialize world");
1004 JMutexAutoLock envlock(m_env_mutex);
1005 JMutexAutoLock conlock(m_con_mutex);
1007 // Initialize scripting
1009 infostream<<"Server: Initializing Lua"<<std::endl;
1010 m_lua = script_init();
1013 scriptapi_export(m_lua, this);
1014 // Load and run builtin.lua
1015 infostream<<"Server: Loading builtin.lua [\""
1016 <<builtinpath<<"\"]"<<std::endl;
1017 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1019 errorstream<<"Server: Failed to load and run "
1020 <<builtinpath<<std::endl;
1021 throw ModError("Failed to load and run "+builtinpath);
1023 // Find mods in mod search paths
1024 m_mods = getMods(m_modspaths);
1026 infostream<<"Server: Loading mods: ";
1027 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1028 i != m_mods.end(); i++){
1029 const ModSpec &mod = *i;
1030 infostream<<mod.name<<" ";
1032 infostream<<std::endl;
1033 // Load and run "mod" scripts
1034 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1035 i != m_mods.end(); i++){
1036 const ModSpec &mod = *i;
1037 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1038 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1039 <<scriptpath<<"\"]"<<std::endl;
1040 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1042 errorstream<<"Server: Failed to load and run "
1043 <<scriptpath<<std::endl;
1044 throw ModError("Failed to load and run "+scriptpath);
1048 // Read Textures and calculate sha1 sums
1051 // Apply item aliases in the node definition manager
1052 m_nodedef->updateAliases(m_itemdef);
1054 // Initialize Environment
1056 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
1059 // Give environment reference to scripting api
1060 scriptapi_add_environment(m_lua, m_env);
1062 // Register us to receive map edit events
1063 m_env->getMap().addEventReceiver(this);
1065 // If file exists, load environment metadata
1066 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1068 infostream<<"Server: Loading environment metadata"<<std::endl;
1069 m_env->loadMeta(m_path_world);
1073 infostream<<"Server: Loading players"<<std::endl;
1074 m_env->deSerializePlayers(m_path_world);
1077 Add some test ActiveBlockModifiers to environment
1079 add_legacy_abms(m_env, m_nodedef);
1084 infostream<<"Server destructing"<<std::endl;
1087 Send shutdown message
1090 JMutexAutoLock conlock(m_con_mutex);
1092 std::wstring line = L"*** Server shutting down";
1095 Send the message to clients
1097 for(core::map<u16, RemoteClient*>::Iterator
1098 i = m_clients.getIterator();
1099 i.atEnd() == false; i++)
1101 // Get client and check that it is valid
1102 RemoteClient *client = i.getNode()->getValue();
1103 assert(client->peer_id == i.getNode()->getKey());
1104 if(client->serialization_version == SER_FMT_VER_INVALID)
1108 SendChatMessage(client->peer_id, line);
1110 catch(con::PeerNotFoundException &e)
1116 JMutexAutoLock envlock(m_env_mutex);
1121 infostream<<"Server: Saving players"<<std::endl;
1122 m_env->serializePlayers(m_path_world);
1125 Save environment metadata
1127 infostream<<"Server: Saving environment metadata"<<std::endl;
1128 m_env->saveMeta(m_path_world);
1140 JMutexAutoLock clientslock(m_con_mutex);
1142 for(core::map<u16, RemoteClient*>::Iterator
1143 i = m_clients.getIterator();
1144 i.atEnd() == false; i++)
1147 // NOTE: These are removed by env destructor
1149 u16 peer_id = i.getNode()->getKey();
1150 JMutexAutoLock envlock(m_env_mutex);
1151 m_env->removePlayer(peer_id);
1155 delete i.getNode()->getValue();
1159 // Delete things in the reverse order of creation
1167 // Deinitialize scripting
1168 infostream<<"Server: Deinitializing scripting"<<std::endl;
1169 script_deinit(m_lua);
1171 // Delete detached inventories
1173 for(std::map<std::string, Inventory*>::iterator
1174 i = m_detached_inventories.begin();
1175 i != m_detached_inventories.end(); i++){
1181 void Server::start(unsigned short port)
1183 DSTACK(__FUNCTION_NAME);
1184 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1186 // Stop thread if already running
1189 // Initialize connection
1190 m_con.SetTimeoutMs(30);
1194 m_thread.setRun(true);
1197 // ASCII art for the win!
1199 <<" .__ __ __ "<<std::endl
1200 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1201 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1202 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1203 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1204 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1205 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1206 actionstream<<"Server for gameid=\""<<m_gamespec.id
1207 <<"\" listening on port "<<port<<"."<<std::endl;
1212 DSTACK(__FUNCTION_NAME);
1214 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1216 // Stop threads (set run=false first so both start stopping)
1217 m_thread.setRun(false);
1218 m_emergethread.setRun(false);
1220 m_emergethread.stop();
1222 infostream<<"Server: Threads stopped"<<std::endl;
1225 void Server::step(float dtime)
1227 DSTACK(__FUNCTION_NAME);
1232 JMutexAutoLock lock(m_step_dtime_mutex);
1233 m_step_dtime += dtime;
1235 // Throw if fatal error occurred in thread
1236 std::string async_err = m_async_fatal_error.get();
1237 if(async_err != ""){
1238 throw ServerError(async_err);
1242 void Server::AsyncRunStep()
1244 DSTACK(__FUNCTION_NAME);
1246 g_profiler->add("Server::AsyncRunStep (num)", 1);
1250 JMutexAutoLock lock1(m_step_dtime_mutex);
1251 dtime = m_step_dtime;
1255 // Send blocks to clients
1262 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1264 //infostream<<"Server steps "<<dtime<<std::endl;
1265 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1268 JMutexAutoLock lock1(m_step_dtime_mutex);
1269 m_step_dtime -= dtime;
1276 m_uptime.set(m_uptime.get() + dtime);
1280 // Process connection's timeouts
1281 JMutexAutoLock lock2(m_con_mutex);
1282 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1283 m_con.RunTimeouts(dtime);
1287 // This has to be called so that the client list gets synced
1288 // with the peer list of the connection
1289 handlePeerChanges();
1293 Update time of day and overall game time
1296 JMutexAutoLock envlock(m_env_mutex);
1298 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1301 Send to clients at constant intervals
1304 m_time_of_day_send_timer -= dtime;
1305 if(m_time_of_day_send_timer < 0.0)
1307 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1309 //JMutexAutoLock envlock(m_env_mutex);
1310 JMutexAutoLock conlock(m_con_mutex);
1312 for(core::map<u16, RemoteClient*>::Iterator
1313 i = m_clients.getIterator();
1314 i.atEnd() == false; i++)
1316 RemoteClient *client = i.getNode()->getValue();
1317 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1318 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1320 m_con.Send(client->peer_id, 0, data, true);
1326 JMutexAutoLock lock(m_env_mutex);
1328 ScopeProfiler sp(g_profiler, "SEnv step");
1329 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1333 const float map_timer_and_unload_dtime = 2.92;
1334 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1336 JMutexAutoLock lock(m_env_mutex);
1337 // Run Map's timers and unload unused data
1338 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1339 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1340 g_settings->getFloat("server_unload_unused_data_timeout"));
1351 JMutexAutoLock lock(m_env_mutex);
1352 JMutexAutoLock lock2(m_con_mutex);
1354 ScopeProfiler sp(g_profiler, "Server: handle players");
1356 for(core::map<u16, RemoteClient*>::Iterator
1357 i = m_clients.getIterator();
1358 i.atEnd() == false; i++)
1360 RemoteClient *client = i.getNode()->getValue();
1361 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1362 if(playersao == NULL)
1366 Handle player HPs (die if hp=0)
1368 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
1369 DiePlayer(client->peer_id);
1372 Send player inventories and HPs if necessary
1374 if(playersao->m_teleported){
1375 SendMovePlayer(client->peer_id);
1376 playersao->m_teleported = false;
1378 if(playersao->m_inventory_not_sent){
1379 UpdateCrafting(client->peer_id);
1380 SendInventory(client->peer_id);
1382 if(playersao->m_hp_not_sent){
1383 SendPlayerHP(client->peer_id);
1388 /* Transform liquids */
1389 m_liquid_transform_timer += dtime;
1390 if(m_liquid_transform_timer >= 1.00)
1392 m_liquid_transform_timer -= 1.00;
1394 JMutexAutoLock lock(m_env_mutex);
1396 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1398 core::map<v3s16, MapBlock*> modified_blocks;
1399 m_env->getMap().transformLiquids(modified_blocks);
1404 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1405 ServerMap &map = ((ServerMap&)m_env->getMap());
1406 map.updateLighting(modified_blocks, lighting_modified_blocks);
1408 // Add blocks modified by lighting to modified_blocks
1409 for(core::map<v3s16, MapBlock*>::Iterator
1410 i = lighting_modified_blocks.getIterator();
1411 i.atEnd() == false; i++)
1413 MapBlock *block = i.getNode()->getValue();
1414 modified_blocks.insert(block->getPos(), block);
1418 Set the modified blocks unsent for all the clients
1421 JMutexAutoLock lock2(m_con_mutex);
1423 for(core::map<u16, RemoteClient*>::Iterator
1424 i = m_clients.getIterator();
1425 i.atEnd() == false; i++)
1427 RemoteClient *client = i.getNode()->getValue();
1429 if(modified_blocks.size() > 0)
1431 // Remove block from sent history
1432 client->SetBlocksNotSent(modified_blocks);
1437 // Periodically print some info
1439 float &counter = m_print_info_timer;
1445 JMutexAutoLock lock2(m_con_mutex);
1447 if(m_clients.size() != 0)
1448 infostream<<"Players:"<<std::endl;
1449 for(core::map<u16, RemoteClient*>::Iterator
1450 i = m_clients.getIterator();
1451 i.atEnd() == false; i++)
1453 //u16 peer_id = i.getNode()->getKey();
1454 RemoteClient *client = i.getNode()->getValue();
1455 Player *player = m_env->getPlayer(client->peer_id);
1458 infostream<<"* "<<player->getName()<<"\t";
1459 client->PrintInfo(infostream);
1464 //if(g_settings->getBool("enable_experimental"))
1468 Check added and deleted active objects
1471 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1472 JMutexAutoLock envlock(m_env_mutex);
1473 JMutexAutoLock conlock(m_con_mutex);
1475 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1477 // Radius inside which objects are active
1478 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1479 radius *= MAP_BLOCKSIZE;
1481 for(core::map<u16, RemoteClient*>::Iterator
1482 i = m_clients.getIterator();
1483 i.atEnd() == false; i++)
1485 RemoteClient *client = i.getNode()->getValue();
1487 // If definitions and textures have not been sent, don't
1488 // send objects either
1489 if(!client->definitions_sent)
1492 Player *player = m_env->getPlayer(client->peer_id);
1495 // This can happen if the client timeouts somehow
1496 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1498 <<" has no associated player"<<std::endl;*/
1501 v3s16 pos = floatToInt(player->getPosition(), BS);
1503 core::map<u16, bool> removed_objects;
1504 core::map<u16, bool> added_objects;
1505 m_env->getRemovedActiveObjects(pos, radius,
1506 client->m_known_objects, removed_objects);
1507 m_env->getAddedActiveObjects(pos, radius,
1508 client->m_known_objects, added_objects);
1510 // Ignore if nothing happened
1511 if(removed_objects.size() == 0 && added_objects.size() == 0)
1513 //infostream<<"active objects: none changed"<<std::endl;
1517 std::string data_buffer;
1521 // Handle removed objects
1522 writeU16((u8*)buf, removed_objects.size());
1523 data_buffer.append(buf, 2);
1524 for(core::map<u16, bool>::Iterator
1525 i = removed_objects.getIterator();
1526 i.atEnd()==false; i++)
1529 u16 id = i.getNode()->getKey();
1530 ServerActiveObject* obj = m_env->getActiveObject(id);
1532 // Add to data buffer for sending
1533 writeU16((u8*)buf, i.getNode()->getKey());
1534 data_buffer.append(buf, 2);
1536 // Remove from known objects
1537 client->m_known_objects.remove(i.getNode()->getKey());
1539 if(obj && obj->m_known_by_count > 0)
1540 obj->m_known_by_count--;
1543 // Handle added objects
1544 writeU16((u8*)buf, added_objects.size());
1545 data_buffer.append(buf, 2);
1546 for(core::map<u16, bool>::Iterator
1547 i = added_objects.getIterator();
1548 i.atEnd()==false; i++)
1551 u16 id = i.getNode()->getKey();
1552 ServerActiveObject* obj = m_env->getActiveObject(id);
1555 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1557 infostream<<"WARNING: "<<__FUNCTION_NAME
1558 <<": NULL object"<<std::endl;
1560 type = obj->getSendType();
1562 // Add to data buffer for sending
1563 writeU16((u8*)buf, id);
1564 data_buffer.append(buf, 2);
1565 writeU8((u8*)buf, type);
1566 data_buffer.append(buf, 1);
1569 data_buffer.append(serializeLongString(
1570 obj->getClientInitializationData()));
1572 data_buffer.append(serializeLongString(""));
1574 // Add to known objects
1575 client->m_known_objects.insert(i.getNode()->getKey(), false);
1578 obj->m_known_by_count++;
1582 SharedBuffer<u8> reply(2 + data_buffer.size());
1583 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1584 memcpy((char*)&reply[2], data_buffer.c_str(),
1585 data_buffer.size());
1587 m_con.Send(client->peer_id, 0, reply, true);
1589 verbosestream<<"Server: Sent object remove/add: "
1590 <<removed_objects.size()<<" removed, "
1591 <<added_objects.size()<<" added, "
1592 <<"packet size is "<<reply.getSize()<<std::endl;
1597 Collect a list of all the objects known by the clients
1598 and report it back to the environment.
1601 core::map<u16, bool> all_known_objects;
1603 for(core::map<u16, RemoteClient*>::Iterator
1604 i = m_clients.getIterator();
1605 i.atEnd() == false; i++)
1607 RemoteClient *client = i.getNode()->getValue();
1608 // Go through all known objects of client
1609 for(core::map<u16, bool>::Iterator
1610 i = client->m_known_objects.getIterator();
1611 i.atEnd()==false; i++)
1613 u16 id = i.getNode()->getKey();
1614 all_known_objects[id] = true;
1618 m_env->setKnownActiveObjects(whatever);
1624 Send object messages
1627 JMutexAutoLock envlock(m_env_mutex);
1628 JMutexAutoLock conlock(m_con_mutex);
1630 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1633 // Value = data sent by object
1634 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1636 // Get active object messages from environment
1639 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1643 core::list<ActiveObjectMessage>* message_list = NULL;
1644 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1645 n = buffered_messages.find(aom.id);
1648 message_list = new core::list<ActiveObjectMessage>;
1649 buffered_messages.insert(aom.id, message_list);
1653 message_list = n->getValue();
1655 message_list->push_back(aom);
1658 // Route data to every client
1659 for(core::map<u16, RemoteClient*>::Iterator
1660 i = m_clients.getIterator();
1661 i.atEnd()==false; i++)
1663 RemoteClient *client = i.getNode()->getValue();
1664 std::string reliable_data;
1665 std::string unreliable_data;
1666 // Go through all objects in message buffer
1667 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1668 j = buffered_messages.getIterator();
1669 j.atEnd()==false; j++)
1671 // If object is not known by client, skip it
1672 u16 id = j.getNode()->getKey();
1673 if(client->m_known_objects.find(id) == NULL)
1675 // Get message list of object
1676 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1677 // Go through every message
1678 for(core::list<ActiveObjectMessage>::Iterator
1679 k = list->begin(); k != list->end(); k++)
1681 // Compose the full new data with header
1682 ActiveObjectMessage aom = *k;
1683 std::string new_data;
1686 writeU16((u8*)&buf[0], aom.id);
1687 new_data.append(buf, 2);
1689 new_data += serializeString(aom.datastring);
1690 // Add data to buffer
1692 reliable_data += new_data;
1694 unreliable_data += new_data;
1698 reliable_data and unreliable_data are now ready.
1701 if(reliable_data.size() > 0)
1703 SharedBuffer<u8> reply(2 + reliable_data.size());
1704 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1705 memcpy((char*)&reply[2], reliable_data.c_str(),
1706 reliable_data.size());
1708 m_con.Send(client->peer_id, 0, reply, true);
1710 if(unreliable_data.size() > 0)
1712 SharedBuffer<u8> reply(2 + unreliable_data.size());
1713 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1714 memcpy((char*)&reply[2], unreliable_data.c_str(),
1715 unreliable_data.size());
1716 // Send as unreliable
1717 m_con.Send(client->peer_id, 0, reply, false);
1720 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1722 infostream<<"Server: Size of object message data: "
1723 <<"reliable: "<<reliable_data.size()
1724 <<", unreliable: "<<unreliable_data.size()
1729 // Clear buffered_messages
1730 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1731 i = buffered_messages.getIterator();
1732 i.atEnd()==false; i++)
1734 delete i.getNode()->getValue();
1738 } // enable_experimental
1741 Send queued-for-sending map edit events.
1744 // We will be accessing the environment and the connection
1745 JMutexAutoLock lock(m_env_mutex);
1746 JMutexAutoLock conlock(m_con_mutex);
1748 // Don't send too many at a time
1751 // Single change sending is disabled if queue size is not small
1752 bool disable_single_change_sending = false;
1753 if(m_unsent_map_edit_queue.size() >= 4)
1754 disable_single_change_sending = true;
1756 int event_count = m_unsent_map_edit_queue.size();
1758 // We'll log the amount of each
1761 while(m_unsent_map_edit_queue.size() != 0)
1763 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1765 // Players far away from the change are stored here.
1766 // Instead of sending the changes, MapBlocks are set not sent
1768 core::list<u16> far_players;
1770 if(event->type == MEET_ADDNODE)
1772 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1773 prof.add("MEET_ADDNODE", 1);
1774 if(disable_single_change_sending)
1775 sendAddNode(event->p, event->n, event->already_known_by_peer,
1778 sendAddNode(event->p, event->n, event->already_known_by_peer,
1781 else if(event->type == MEET_REMOVENODE)
1783 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1784 prof.add("MEET_REMOVENODE", 1);
1785 if(disable_single_change_sending)
1786 sendRemoveNode(event->p, event->already_known_by_peer,
1789 sendRemoveNode(event->p, event->already_known_by_peer,
1792 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1794 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1795 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1796 setBlockNotSent(event->p);
1798 else if(event->type == MEET_OTHER)
1800 infostream<<"Server: MEET_OTHER"<<std::endl;
1801 prof.add("MEET_OTHER", 1);
1802 for(core::map<v3s16, bool>::Iterator
1803 i = event->modified_blocks.getIterator();
1804 i.atEnd()==false; i++)
1806 v3s16 p = i.getNode()->getKey();
1812 prof.add("unknown", 1);
1813 infostream<<"WARNING: Server: Unknown MapEditEvent "
1814 <<((u32)event->type)<<std::endl;
1818 Set blocks not sent to far players
1820 if(far_players.size() > 0)
1822 // Convert list format to that wanted by SetBlocksNotSent
1823 core::map<v3s16, MapBlock*> modified_blocks2;
1824 for(core::map<v3s16, bool>::Iterator
1825 i = event->modified_blocks.getIterator();
1826 i.atEnd()==false; i++)
1828 v3s16 p = i.getNode()->getKey();
1829 modified_blocks2.insert(p,
1830 m_env->getMap().getBlockNoCreateNoEx(p));
1832 // Set blocks not sent
1833 for(core::list<u16>::Iterator
1834 i = far_players.begin();
1835 i != far_players.end(); i++)
1838 RemoteClient *client = getClient(peer_id);
1841 client->SetBlocksNotSent(modified_blocks2);
1847 /*// Don't send too many at a time
1849 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1853 if(event_count >= 5){
1854 infostream<<"Server: MapEditEvents:"<<std::endl;
1855 prof.print(infostream);
1856 } else if(event_count != 0){
1857 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1858 prof.print(verbosestream);
1864 Trigger emergethread (it somehow gets to a non-triggered but
1865 bysy state sometimes)
1868 float &counter = m_emergethread_trigger_timer;
1874 m_emergethread.trigger();
1876 // Update m_enable_rollback_recording here too
1877 m_enable_rollback_recording =
1878 g_settings->getBool("enable_rollback_recording");
1882 // Save map, players and auth stuff
1884 float &counter = m_savemap_timer;
1886 if(counter >= g_settings->getFloat("server_map_save_interval"))
1889 JMutexAutoLock lock(m_env_mutex);
1891 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1894 if(m_banmanager.isModified())
1895 m_banmanager.save();
1897 // Save changed parts of map
1898 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1901 m_env->serializePlayers(m_path_world);
1903 // Save environment metadata
1904 m_env->saveMeta(m_path_world);
1909 void Server::Receive()
1911 DSTACK(__FUNCTION_NAME);
1912 SharedBuffer<u8> data;
1917 JMutexAutoLock conlock(m_con_mutex);
1918 datasize = m_con.Receive(peer_id, data);
1921 // This has to be called so that the client list gets synced
1922 // with the peer list of the connection
1923 handlePeerChanges();
1925 ProcessData(*data, datasize, peer_id);
1927 catch(con::InvalidIncomingDataException &e)
1929 infostream<<"Server::Receive(): "
1930 "InvalidIncomingDataException: what()="
1931 <<e.what()<<std::endl;
1933 catch(con::PeerNotFoundException &e)
1935 //NOTE: This is not needed anymore
1937 // The peer has been disconnected.
1938 // Find the associated player and remove it.
1940 /*JMutexAutoLock envlock(m_env_mutex);
1942 infostream<<"ServerThread: peer_id="<<peer_id
1943 <<" has apparently closed connection. "
1944 <<"Removing player."<<std::endl;
1946 m_env->removePlayer(peer_id);*/
1950 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1952 DSTACK(__FUNCTION_NAME);
1953 // Environment is locked first.
1954 JMutexAutoLock envlock(m_env_mutex);
1955 JMutexAutoLock conlock(m_con_mutex);
1957 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1960 Address address = m_con.GetPeerAddress(peer_id);
1961 std::string addr_s = address.serializeString();
1963 // drop player if is ip is banned
1964 if(m_banmanager.isIpBanned(addr_s)){
1965 infostream<<"Server: A banned client tried to connect from "
1966 <<addr_s<<"; banned name was "
1967 <<m_banmanager.getBanName(addr_s)<<std::endl;
1968 // This actually doesn't seem to transfer to the client
1969 SendAccessDenied(m_con, peer_id,
1970 L"Your ip is banned. Banned name was "
1971 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1972 m_con.DeletePeer(peer_id);
1976 catch(con::PeerNotFoundException &e)
1978 infostream<<"Server::ProcessData(): Cancelling: peer "
1979 <<peer_id<<" not found"<<std::endl;
1983 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1985 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1993 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1995 if(command == TOSERVER_INIT)
1997 // [0] u16 TOSERVER_INIT
1998 // [2] u8 SER_FMT_VER_HIGHEST
1999 // [3] u8[20] player_name
2000 // [23] u8[28] password <--- can be sent without this, from old versions
2002 if(datasize < 2+1+PLAYERNAME_SIZE)
2005 verbosestream<<"Server: Got TOSERVER_INIT from "
2006 <<peer_id<<std::endl;
2008 // First byte after command is maximum supported
2009 // serialization version
2010 u8 client_max = data[2];
2011 u8 our_max = SER_FMT_VER_HIGHEST;
2012 // Use the highest version supported by both
2013 u8 deployed = core::min_(client_max, our_max);
2014 // If it's lower than the lowest supported, give up.
2015 if(deployed < SER_FMT_VER_LOWEST)
2016 deployed = SER_FMT_VER_INVALID;
2018 //peer->serialization_version = deployed;
2019 getClient(peer_id)->pending_serialization_version = deployed;
2021 if(deployed == SER_FMT_VER_INVALID)
2023 actionstream<<"Server: A mismatched client tried to connect from "
2024 <<addr_s<<std::endl;
2025 infostream<<"Server: Cannot negotiate "
2026 "serialization version with peer "
2027 <<peer_id<<std::endl;
2028 SendAccessDenied(m_con, peer_id, std::wstring(
2029 L"Your client's version is not supported.\n"
2030 L"Server version is ")
2031 + narrow_to_wide(VERSION_STRING) + L"."
2037 Read and check network protocol version
2040 u16 net_proto_version = 0;
2041 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2043 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2046 getClient(peer_id)->net_proto_version = net_proto_version;
2048 if(net_proto_version == 0)
2050 actionstream<<"Server: An old tried to connect from "<<addr_s
2052 SendAccessDenied(m_con, peer_id, std::wstring(
2053 L"Your client's version is not supported.\n"
2054 L"Server version is ")
2055 + narrow_to_wide(VERSION_STRING) + L"."
2060 if(g_settings->getBool("strict_protocol_version_checking"))
2062 if(net_proto_version != PROTOCOL_VERSION)
2064 actionstream<<"Server: A mismatched client tried to connect"
2065 <<" from "<<addr_s<<std::endl;
2066 SendAccessDenied(m_con, peer_id, std::wstring(
2067 L"Your client's version is not supported.\n"
2068 L"Server version is ")
2069 + narrow_to_wide(VERSION_STRING) + L",\n"
2070 + L"server's PROTOCOL_VERSION is "
2071 + narrow_to_wide(itos(PROTOCOL_VERSION))
2072 + L", client's PROTOCOL_VERSION is "
2073 + narrow_to_wide(itos(net_proto_version))
2084 char playername[PLAYERNAME_SIZE];
2085 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2087 playername[i] = data[3+i];
2089 playername[PLAYERNAME_SIZE-1] = 0;
2091 if(playername[0]=='\0')
2093 actionstream<<"Server: Player with an empty name "
2094 <<"tried to connect from "<<addr_s<<std::endl;
2095 SendAccessDenied(m_con, peer_id,
2100 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2102 actionstream<<"Server: Player with an invalid name "
2103 <<"tried to connect from "<<addr_s<<std::endl;
2104 SendAccessDenied(m_con, peer_id,
2105 L"Name contains unallowed characters");
2109 infostream<<"Server: New connection: \""<<playername<<"\" from "
2110 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2113 char given_password[PASSWORD_SIZE];
2114 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2116 // old version - assume blank password
2117 given_password[0] = 0;
2121 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2123 given_password[i] = data[23+i];
2125 given_password[PASSWORD_SIZE-1] = 0;
2128 if(!base64_is_valid(given_password)){
2129 infostream<<"Server: "<<playername
2130 <<" supplied invalid password hash"<<std::endl;
2131 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2135 std::string checkpwd; // Password hash to check against
2136 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2138 // If no authentication info exists for user, create it
2140 if(!isSingleplayer() &&
2141 g_settings->getBool("disallow_empty_password") &&
2142 std::string(given_password) == ""){
2143 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2144 L"disallowed. Set a password and try again.");
2147 std::wstring raw_default_password =
2148 narrow_to_wide(g_settings->get("default_password"));
2149 std::string initial_password =
2150 translatePassword(playername, raw_default_password);
2152 // If default_password is empty, allow any initial password
2153 if (raw_default_password.length() == 0)
2154 initial_password = given_password;
2156 scriptapi_create_auth(m_lua, playername, initial_password);
2159 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2162 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2166 if(given_password != checkpwd){
2167 infostream<<"Server: peer_id="<<peer_id
2168 <<": supplied invalid password for "
2169 <<playername<<std::endl;
2170 SendAccessDenied(m_con, peer_id, L"Invalid password");
2174 // Do not allow multiple players in simple singleplayer mode.
2175 // This isn't a perfect way to do it, but will suffice for now.
2176 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2177 infostream<<"Server: Not allowing another client to connect in"
2178 <<" simple singleplayer mode"<<std::endl;
2179 SendAccessDenied(m_con, peer_id,
2180 L"Running in simple singleplayer mode.");
2184 // Enforce user limit.
2185 // Don't enforce for users that have some admin right
2186 if(m_clients.size() >= g_settings->getU16("max_users") &&
2187 !checkPriv(playername, "server") &&
2188 !checkPriv(playername, "ban") &&
2189 !checkPriv(playername, "privs") &&
2190 !checkPriv(playername, "password") &&
2191 playername != g_settings->get("name"))
2193 actionstream<<"Server: "<<playername<<" tried to join, but there"
2194 <<" are already max_users="
2195 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2196 SendAccessDenied(m_con, peer_id, L"Too many users.");
2201 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2203 // If failed, cancel
2204 if(playersao == NULL)
2206 errorstream<<"Server: peer_id="<<peer_id
2207 <<": failed to emerge player"<<std::endl;
2212 Answer with a TOCLIENT_INIT
2215 SharedBuffer<u8> reply(2+1+6+8);
2216 writeU16(&reply[0], TOCLIENT_INIT);
2217 writeU8(&reply[2], deployed);
2218 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2219 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2222 m_con.Send(peer_id, 0, reply, true);
2226 Send complete position information
2228 SendMovePlayer(peer_id);
2233 if(command == TOSERVER_INIT2)
2235 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2236 <<peer_id<<std::endl;
2238 Player *player = m_env->getPlayer(peer_id);
2240 verbosestream<<"Server: TOSERVER_INIT2: "
2241 <<"Player not found; ignoring."<<std::endl;
2245 getClient(peer_id)->serialization_version
2246 = getClient(peer_id)->pending_serialization_version;
2249 Send some initialization data
2252 infostream<<"Server: Sending content to "
2253 <<getPlayerName(peer_id)<<std::endl;
2255 // Send item definitions
2256 SendItemDef(m_con, peer_id, m_itemdef);
2258 // Send node definitions
2259 SendNodeDef(m_con, peer_id, m_nodedef);
2261 // Send media announcement
2262 sendMediaAnnouncement(peer_id);
2265 SendPlayerPrivileges(peer_id);
2267 // Send inventory formspec
2268 SendPlayerInventoryFormspec(peer_id);
2271 UpdateCrafting(peer_id);
2272 SendInventory(peer_id);
2275 SendPlayerHP(peer_id);
2277 // Send detached inventories
2278 sendDetachedInventories(peer_id);
2280 // Show death screen if necessary
2282 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2286 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2287 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2288 m_con.Send(peer_id, 0, data, true);
2291 // Note things in chat if not in simple singleplayer mode
2292 if(!m_simple_singleplayer_mode)
2294 // Send information about server to player in chat
2295 SendChatMessage(peer_id, getStatusString());
2297 // Send information about joining in chat
2299 std::wstring name = L"unknown";
2300 Player *player = m_env->getPlayer(peer_id);
2302 name = narrow_to_wide(player->getName());
2304 std::wstring message;
2307 message += L" joined the game.";
2308 BroadcastChatMessage(message);
2312 // Warnings about protocol version can be issued here
2313 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2315 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER!");
2322 std::ostringstream os(std::ios_base::binary);
2323 for(core::map<u16, RemoteClient*>::Iterator
2324 i = m_clients.getIterator();
2325 i.atEnd() == false; i++)
2327 RemoteClient *client = i.getNode()->getValue();
2328 assert(client->peer_id == i.getNode()->getKey());
2329 if(client->serialization_version == SER_FMT_VER_INVALID)
2332 Player *player = m_env->getPlayer(client->peer_id);
2335 // Get name of player
2336 os<<player->getName()<<" ";
2339 actionstream<<player->getName()<<" joins game. List of players: "
2340 <<os.str()<<std::endl;
2346 if(peer_ser_ver == SER_FMT_VER_INVALID)
2348 infostream<<"Server::ProcessData(): Cancelling: Peer"
2349 " serialization format invalid or not initialized."
2350 " Skipping incoming command="<<command<<std::endl;
2354 Player *player = m_env->getPlayer(peer_id);
2356 infostream<<"Server::ProcessData(): Cancelling: "
2357 "No player for peer_id="<<peer_id
2362 PlayerSAO *playersao = player->getPlayerSAO();
2363 if(playersao == NULL){
2364 infostream<<"Server::ProcessData(): Cancelling: "
2365 "No player object for peer_id="<<peer_id
2370 if(command == TOSERVER_PLAYERPOS)
2372 if(datasize < 2+12+12+4+4)
2376 v3s32 ps = readV3S32(&data[start+2]);
2377 v3s32 ss = readV3S32(&data[start+2+12]);
2378 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2379 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2380 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2381 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2382 pitch = wrapDegrees(pitch);
2383 yaw = wrapDegrees(yaw);
2385 player->setPosition(position);
2386 player->setSpeed(speed);
2387 player->setPitch(pitch);
2388 player->setYaw(yaw);
2390 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2391 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2392 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2394 else if(command == TOSERVER_GOTBLOCKS)
2407 u16 count = data[2];
2408 for(u16 i=0; i<count; i++)
2410 if((s16)datasize < 2+1+(i+1)*6)
2411 throw con::InvalidIncomingDataException
2412 ("GOTBLOCKS length is too short");
2413 v3s16 p = readV3S16(&data[2+1+i*6]);
2414 /*infostream<<"Server: GOTBLOCKS ("
2415 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2416 RemoteClient *client = getClient(peer_id);
2417 client->GotBlock(p);
2420 else if(command == TOSERVER_DELETEDBLOCKS)
2433 u16 count = data[2];
2434 for(u16 i=0; i<count; i++)
2436 if((s16)datasize < 2+1+(i+1)*6)
2437 throw con::InvalidIncomingDataException
2438 ("DELETEDBLOCKS length is too short");
2439 v3s16 p = readV3S16(&data[2+1+i*6]);
2440 /*infostream<<"Server: DELETEDBLOCKS ("
2441 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2442 RemoteClient *client = getClient(peer_id);
2443 client->SetBlockNotSent(p);
2446 else if(command == TOSERVER_CLICK_OBJECT)
2448 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2451 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2453 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2456 else if(command == TOSERVER_GROUND_ACTION)
2458 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2462 else if(command == TOSERVER_RELEASE)
2464 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2467 else if(command == TOSERVER_SIGNTEXT)
2469 infostream<<"Server: SIGNTEXT not supported anymore"
2473 else if(command == TOSERVER_SIGNNODETEXT)
2475 infostream<<"Server: SIGNNODETEXT not supported anymore"
2479 else if(command == TOSERVER_INVENTORY_ACTION)
2481 // Strip command and create a stream
2482 std::string datastring((char*)&data[2], datasize-2);
2483 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2484 std::istringstream is(datastring, std::ios_base::binary);
2486 InventoryAction *a = InventoryAction::deSerialize(is);
2489 infostream<<"TOSERVER_INVENTORY_ACTION: "
2490 <<"InventoryAction::deSerialize() returned NULL"
2495 // If something goes wrong, this player is to blame
2496 RollbackScopeActor rollback_scope(m_rollback,
2497 std::string("player:")+player->getName());
2500 Note: Always set inventory not sent, to repair cases
2501 where the client made a bad prediction.
2505 Handle restrictions and special cases of the move action
2507 if(a->getType() == IACTION_MOVE)
2509 IMoveAction *ma = (IMoveAction*)a;
2511 ma->from_inv.applyCurrentPlayer(player->getName());
2512 ma->to_inv.applyCurrentPlayer(player->getName());
2514 setInventoryModified(ma->from_inv);
2515 setInventoryModified(ma->to_inv);
2517 bool from_inv_is_current_player =
2518 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2519 (ma->from_inv.name == player->getName());
2521 bool to_inv_is_current_player =
2522 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2523 (ma->to_inv.name == player->getName());
2526 Disable moving items out of craftpreview
2528 if(ma->from_list == "craftpreview")
2530 infostream<<"Ignoring IMoveAction from "
2531 <<(ma->from_inv.dump())<<":"<<ma->from_list
2532 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2533 <<" because src is "<<ma->from_list<<std::endl;
2539 Disable moving items into craftresult and craftpreview
2541 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2543 infostream<<"Ignoring IMoveAction from "
2544 <<(ma->from_inv.dump())<<":"<<ma->from_list
2545 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2546 <<" because dst is "<<ma->to_list<<std::endl;
2551 // Disallow moving items in elsewhere than player's inventory
2552 // if not allowed to interact
2553 if(!checkPriv(player->getName(), "interact") &&
2554 (!from_inv_is_current_player ||
2555 !to_inv_is_current_player))
2557 infostream<<"Cannot move outside of player's inventory: "
2558 <<"No interact privilege"<<std::endl;
2564 Handle restrictions and special cases of the drop action
2566 else if(a->getType() == IACTION_DROP)
2568 IDropAction *da = (IDropAction*)a;
2570 da->from_inv.applyCurrentPlayer(player->getName());
2572 setInventoryModified(da->from_inv);
2574 // Disallow dropping items if not allowed to interact
2575 if(!checkPriv(player->getName(), "interact"))
2582 Handle restrictions and special cases of the craft action
2584 else if(a->getType() == IACTION_CRAFT)
2586 ICraftAction *ca = (ICraftAction*)a;
2588 ca->craft_inv.applyCurrentPlayer(player->getName());
2590 setInventoryModified(ca->craft_inv);
2592 //bool craft_inv_is_current_player =
2593 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2594 // (ca->craft_inv.name == player->getName());
2596 // Disallow crafting if not allowed to interact
2597 if(!checkPriv(player->getName(), "interact"))
2599 infostream<<"Cannot craft: "
2600 <<"No interact privilege"<<std::endl;
2607 a->apply(this, playersao, this);
2611 else if(command == TOSERVER_CHAT_MESSAGE)
2619 std::string datastring((char*)&data[2], datasize-2);
2620 std::istringstream is(datastring, std::ios_base::binary);
2623 is.read((char*)buf, 2);
2624 u16 len = readU16(buf);
2626 std::wstring message;
2627 for(u16 i=0; i<len; i++)
2629 is.read((char*)buf, 2);
2630 message += (wchar_t)readU16(buf);
2633 // If something goes wrong, this player is to blame
2634 RollbackScopeActor rollback_scope(m_rollback,
2635 std::string("player:")+player->getName());
2637 // Get player name of this client
2638 std::wstring name = narrow_to_wide(player->getName());
2641 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2642 wide_to_narrow(message));
2643 // If script ate the message, don't proceed
2647 // Line to send to players
2649 // Whether to send to the player that sent the line
2650 bool send_to_sender = false;
2651 // Whether to send to other players
2652 bool send_to_others = false;
2654 // Commands are implemented in Lua, so only catch invalid
2655 // commands that were not "eaten" and send an error back
2656 if(message[0] == L'/')
2658 message = message.substr(1);
2659 send_to_sender = true;
2660 if(message.length() == 0)
2661 line += L"-!- Empty command";
2663 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2667 if(checkPriv(player->getName(), "shout")){
2672 send_to_others = true;
2674 line += L"-!- You don't have permission to shout.";
2675 send_to_sender = true;
2682 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2685 Send the message to clients
2687 for(core::map<u16, RemoteClient*>::Iterator
2688 i = m_clients.getIterator();
2689 i.atEnd() == false; i++)
2691 // Get client and check that it is valid
2692 RemoteClient *client = i.getNode()->getValue();
2693 assert(client->peer_id == i.getNode()->getKey());
2694 if(client->serialization_version == SER_FMT_VER_INVALID)
2698 bool sender_selected = (peer_id == client->peer_id);
2699 if(sender_selected == true && send_to_sender == false)
2701 if(sender_selected == false && send_to_others == false)
2704 SendChatMessage(client->peer_id, line);
2708 else if(command == TOSERVER_DAMAGE)
2710 std::string datastring((char*)&data[2], datasize-2);
2711 std::istringstream is(datastring, std::ios_base::binary);
2712 u8 damage = readU8(is);
2714 actionstream<<player->getName()<<" damaged by "
2715 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2718 playersao->setHP(playersao->getHP() - damage);
2720 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2723 if(playersao->m_hp_not_sent)
2724 SendPlayerHP(peer_id);
2726 else if(command == TOSERVER_PASSWORD)
2729 [0] u16 TOSERVER_PASSWORD
2730 [2] u8[28] old password
2731 [30] u8[28] new password
2734 if(datasize != 2+PASSWORD_SIZE*2)
2736 /*char password[PASSWORD_SIZE];
2737 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2738 password[i] = data[2+i];
2739 password[PASSWORD_SIZE-1] = 0;*/
2741 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2749 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2751 char c = data[2+PASSWORD_SIZE+i];
2757 if(!base64_is_valid(newpwd)){
2758 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2759 // Wrong old password supplied!!
2760 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2764 infostream<<"Server: Client requests a password change from "
2765 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2767 std::string playername = player->getName();
2769 std::string checkpwd;
2770 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2772 if(oldpwd != checkpwd)
2774 infostream<<"Server: invalid old password"<<std::endl;
2775 // Wrong old password supplied!!
2776 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2780 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2782 actionstream<<player->getName()<<" changes password"<<std::endl;
2783 SendChatMessage(peer_id, L"Password change successful.");
2785 actionstream<<player->getName()<<" tries to change password but "
2786 <<"it fails"<<std::endl;
2787 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2790 else if(command == TOSERVER_PLAYERITEM)
2795 u16 item = readU16(&data[2]);
2796 playersao->setWieldIndex(item);
2798 else if(command == TOSERVER_RESPAWN)
2803 RespawnPlayer(peer_id);
2805 actionstream<<player->getName()<<" respawns at "
2806 <<PP(player->getPosition()/BS)<<std::endl;
2808 // ActiveObject is added to environment in AsyncRunStep after
2809 // the previous addition has been succesfully removed
2811 else if(command == TOSERVER_REQUEST_MEDIA) {
2812 std::string datastring((char*)&data[2], datasize-2);
2813 std::istringstream is(datastring, std::ios_base::binary);
2815 core::list<MediaRequest> tosend;
2816 u16 numfiles = readU16(is);
2818 infostream<<"Sending "<<numfiles<<" files to "
2819 <<getPlayerName(peer_id)<<std::endl;
2820 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2822 for(int i = 0; i < numfiles; i++) {
2823 std::string name = deSerializeString(is);
2824 tosend.push_back(MediaRequest(name));
2825 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2829 sendRequestedMedia(peer_id, tosend);
2831 // Now the client should know about everything
2832 // (definitions and files)
2833 getClient(peer_id)->definitions_sent = true;
2835 else if(command == TOSERVER_INTERACT)
2837 std::string datastring((char*)&data[2], datasize-2);
2838 std::istringstream is(datastring, std::ios_base::binary);
2844 [5] u32 length of the next item
2845 [9] serialized PointedThing
2847 0: start digging (from undersurface) or use
2848 1: stop digging (all parameters ignored)
2849 2: digging completed
2850 3: place block or item (to abovesurface)
2853 u8 action = readU8(is);
2854 u16 item_i = readU16(is);
2855 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2856 PointedThing pointed;
2857 pointed.deSerialize(tmp_is);
2859 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2860 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2864 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2865 <<" tried to interact, but is dead!"<<std::endl;
2869 v3f player_pos = playersao->getLastGoodPosition();
2871 // Update wielded item
2872 playersao->setWieldIndex(item_i);
2874 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2875 v3s16 p_under = pointed.node_undersurface;
2876 v3s16 p_above = pointed.node_abovesurface;
2878 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2879 ServerActiveObject *pointed_object = NULL;
2880 if(pointed.type == POINTEDTHING_OBJECT)
2882 pointed_object = m_env->getActiveObject(pointed.object_id);
2883 if(pointed_object == NULL)
2885 verbosestream<<"TOSERVER_INTERACT: "
2886 "pointed object is NULL"<<std::endl;
2892 v3f pointed_pos_under = player_pos;
2893 v3f pointed_pos_above = player_pos;
2894 if(pointed.type == POINTEDTHING_NODE)
2896 pointed_pos_under = intToFloat(p_under, BS);
2897 pointed_pos_above = intToFloat(p_above, BS);
2899 else if(pointed.type == POINTEDTHING_OBJECT)
2901 pointed_pos_under = pointed_object->getBasePosition();
2902 pointed_pos_above = pointed_pos_under;
2906 Check that target is reasonably close
2907 (only when digging or placing things)
2909 if(action == 0 || action == 2 || action == 3)
2911 float d = player_pos.getDistanceFrom(pointed_pos_under);
2912 float max_d = BS * 14; // Just some large enough value
2914 actionstream<<"Player "<<player->getName()
2915 <<" tried to access "<<pointed.dump()
2917 <<"d="<<d<<", max_d="<<max_d
2918 <<". ignoring."<<std::endl;
2919 // Re-send block to revert change on client-side
2920 RemoteClient *client = getClient(peer_id);
2921 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2922 client->SetBlockNotSent(blockpos);
2929 Make sure the player is allowed to do it
2931 if(!checkPriv(player->getName(), "interact"))
2933 actionstream<<player->getName()<<" attempted to interact with "
2934 <<pointed.dump()<<" without 'interact' privilege"
2936 // Re-send block to revert change on client-side
2937 RemoteClient *client = getClient(peer_id);
2938 // Digging completed -> under
2940 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2941 client->SetBlockNotSent(blockpos);
2943 // Placement -> above
2945 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2946 client->SetBlockNotSent(blockpos);
2952 If something goes wrong, this player is to blame
2954 RollbackScopeActor rollback_scope(m_rollback,
2955 std::string("player:")+player->getName());
2958 0: start digging or punch object
2962 if(pointed.type == POINTEDTHING_NODE)
2965 NOTE: This can be used in the future to check if
2966 somebody is cheating, by checking the timing.
2968 MapNode n(CONTENT_IGNORE);
2971 n = m_env->getMap().getNode(p_under);
2973 catch(InvalidPositionException &e)
2975 infostream<<"Server: Not punching: Node not found."
2976 <<" Adding block to emerge queue."
2978 m_emerge_queue.addBlock(peer_id,
2979 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2981 if(n.getContent() != CONTENT_IGNORE)
2982 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
2984 playersao->noCheatDigStart(p_under);
2986 else if(pointed.type == POINTEDTHING_OBJECT)
2988 // Skip if object has been removed
2989 if(pointed_object->m_removed)
2992 actionstream<<player->getName()<<" punches object "
2993 <<pointed.object_id<<": "
2994 <<pointed_object->getDescription()<<std::endl;
2996 ItemStack punchitem = playersao->getWieldedItem();
2997 ToolCapabilities toolcap =
2998 punchitem.getToolCapabilities(m_itemdef);
2999 v3f dir = (pointed_object->getBasePosition() -
3000 (player->getPosition() + player->getEyeOffset())
3002 float time_from_last_punch =
3003 playersao->resetTimeFromLastPunch();
3004 pointed_object->punch(dir, &toolcap, playersao,
3005 time_from_last_punch);
3013 else if(action == 1)
3018 2: Digging completed
3020 else if(action == 2)
3022 // Only digging of nodes
3023 if(pointed.type == POINTEDTHING_NODE)
3025 MapNode n(CONTENT_IGNORE);
3028 n = m_env->getMap().getNode(p_under);
3030 catch(InvalidPositionException &e)
3032 infostream<<"Server: Not finishing digging: Node not found."
3033 <<" Adding block to emerge queue."
3035 m_emerge_queue.addBlock(peer_id,
3036 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3039 /* Cheat prevention */
3040 bool is_valid_dig = true;
3041 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3043 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3044 float nocheat_t = playersao->getNoCheatDigTime();
3045 playersao->noCheatDigEnd();
3046 // If player didn't start digging this, ignore dig
3047 if(nocheat_p != p_under){
3048 infostream<<"Server: NoCheat: "<<player->getName()
3049 <<" started digging "
3050 <<PP(nocheat_p)<<" and completed digging "
3051 <<PP(p_under)<<"; not digging."<<std::endl;
3052 is_valid_dig = false;
3054 // Get player's wielded item
3055 ItemStack playeritem;
3056 InventoryList *mlist = playersao->getInventory()->getList("main");
3058 playeritem = mlist->getItem(playersao->getWieldIndex());
3059 ToolCapabilities playeritem_toolcap =
3060 playeritem.getToolCapabilities(m_itemdef);
3061 // Get diggability and expected digging time
3062 DigParams params = getDigParams(m_nodedef->get(n).groups,
3063 &playeritem_toolcap);
3064 // If can't dig, try hand
3065 if(!params.diggable){
3066 const ItemDefinition &hand = m_itemdef->get("");
3067 const ToolCapabilities *tp = hand.tool_capabilities;
3069 params = getDigParams(m_nodedef->get(n).groups, tp);
3071 // If can't dig, ignore dig
3072 if(!params.diggable){
3073 infostream<<"Server: NoCheat: "<<player->getName()
3074 <<" completed digging "<<PP(p_under)
3075 <<", which is not diggable with tool. not digging."
3077 is_valid_dig = false;
3079 // If time is considerably too short, ignore dig
3080 // Check time only for medium and slow timed digs
3081 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3082 infostream<<"Server: NoCheat: "<<player->getName()
3083 <<" completed digging "
3084 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3085 <<params.time<<"s; not digging."<<std::endl;
3086 is_valid_dig = false;
3090 /* Actually dig node */
3092 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3093 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3095 // Send unusual result (that is, node not being removed)
3096 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3098 // Re-send block to revert change on client-side
3099 RemoteClient *client = getClient(peer_id);
3100 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3101 client->SetBlockNotSent(blockpos);
3107 3: place block or right-click object
3109 else if(action == 3)
3111 ItemStack item = playersao->getWieldedItem();
3113 // Reset build time counter
3114 if(pointed.type == POINTEDTHING_NODE &&
3115 item.getDefinition(m_itemdef).type == ITEM_NODE)
3116 getClient(peer_id)->m_time_from_building = 0.0;
3118 if(pointed.type == POINTEDTHING_OBJECT)
3120 // Right click object
3122 // Skip if object has been removed
3123 if(pointed_object->m_removed)
3126 actionstream<<player->getName()<<" right-clicks object "
3127 <<pointed.object_id<<": "
3128 <<pointed_object->getDescription()<<std::endl;
3131 pointed_object->rightClick(playersao);
3133 else if(scriptapi_item_on_place(m_lua,
3134 item, playersao, pointed))
3136 // Placement was handled in lua
3138 // Apply returned ItemStack
3139 playersao->setWieldedItem(item);
3142 // If item has node placement prediction, always send the above
3143 // node to make sure the client knows what exactly happened
3144 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3145 RemoteClient *client = getClient(peer_id);
3146 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3147 client->SetBlockNotSent(blockpos);
3154 else if(action == 4)
3156 ItemStack item = playersao->getWieldedItem();
3158 actionstream<<player->getName()<<" uses "<<item.name
3159 <<", pointing at "<<pointed.dump()<<std::endl;
3161 if(scriptapi_item_on_use(m_lua,
3162 item, playersao, pointed))
3164 // Apply returned ItemStack
3165 playersao->setWieldedItem(item);
3171 Catch invalid actions
3175 infostream<<"WARNING: Server: Invalid action "
3176 <<action<<std::endl;
3179 else if(command == TOSERVER_REMOVED_SOUNDS)
3181 std::string datastring((char*)&data[2], datasize-2);
3182 std::istringstream is(datastring, std::ios_base::binary);
3184 int num = readU16(is);
3185 for(int k=0; k<num; k++){
3186 s32 id = readS32(is);
3187 std::map<s32, ServerPlayingSound>::iterator i =
3188 m_playing_sounds.find(id);
3189 if(i == m_playing_sounds.end())
3191 ServerPlayingSound &psound = i->second;
3192 psound.clients.erase(peer_id);
3193 if(psound.clients.size() == 0)
3194 m_playing_sounds.erase(i++);
3197 else if(command == TOSERVER_NODEMETA_FIELDS)
3199 std::string datastring((char*)&data[2], datasize-2);
3200 std::istringstream is(datastring, std::ios_base::binary);
3202 v3s16 p = readV3S16(is);
3203 std::string formname = deSerializeString(is);
3204 int num = readU16(is);
3205 std::map<std::string, std::string> fields;
3206 for(int k=0; k<num; k++){
3207 std::string fieldname = deSerializeString(is);
3208 std::string fieldvalue = deSerializeLongString(is);
3209 fields[fieldname] = fieldvalue;
3212 // If something goes wrong, this player is to blame
3213 RollbackScopeActor rollback_scope(m_rollback,
3214 std::string("player:")+player->getName());
3216 // Check the target node for rollback data; leave others unnoticed
3217 RollbackNode rn_old(&m_env->getMap(), p, this);
3219 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3222 // Report rollback data
3223 RollbackNode rn_new(&m_env->getMap(), p, this);
3224 if(rollback() && rn_new != rn_old){
3225 RollbackAction action;
3226 action.setSetNode(p, rn_old, rn_new);
3227 rollback()->reportAction(action);
3230 else if(command == TOSERVER_INVENTORY_FIELDS)
3232 std::string datastring((char*)&data[2], datasize-2);
3233 std::istringstream is(datastring, std::ios_base::binary);
3235 std::string formname = deSerializeString(is);
3236 int num = readU16(is);
3237 std::map<std::string, std::string> fields;
3238 for(int k=0; k<num; k++){
3239 std::string fieldname = deSerializeString(is);
3240 std::string fieldvalue = deSerializeLongString(is);
3241 fields[fieldname] = fieldvalue;
3244 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3248 infostream<<"Server::ProcessData(): Ignoring "
3249 "unknown command "<<command<<std::endl;
3253 catch(SendFailedException &e)
3255 errorstream<<"Server::ProcessData(): SendFailedException: "
3261 void Server::onMapEditEvent(MapEditEvent *event)
3263 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3264 if(m_ignore_map_edit_events)
3266 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3268 MapEditEvent *e = event->clone();
3269 m_unsent_map_edit_queue.push_back(e);
3272 Inventory* Server::getInventory(const InventoryLocation &loc)
3275 case InventoryLocation::UNDEFINED:
3278 case InventoryLocation::CURRENT_PLAYER:
3281 case InventoryLocation::PLAYER:
3283 Player *player = m_env->getPlayer(loc.name.c_str());
3286 PlayerSAO *playersao = player->getPlayerSAO();
3289 return playersao->getInventory();
3292 case InventoryLocation::NODEMETA:
3294 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3297 return meta->getInventory();
3300 case InventoryLocation::DETACHED:
3302 if(m_detached_inventories.count(loc.name) == 0)
3304 return m_detached_inventories[loc.name];
3312 void Server::setInventoryModified(const InventoryLocation &loc)
3315 case InventoryLocation::UNDEFINED:
3318 case InventoryLocation::PLAYER:
3320 Player *player = m_env->getPlayer(loc.name.c_str());
3323 PlayerSAO *playersao = player->getPlayerSAO();
3326 playersao->m_inventory_not_sent = true;
3327 playersao->m_wielded_item_not_sent = true;
3330 case InventoryLocation::NODEMETA:
3332 v3s16 blockpos = getNodeBlockPos(loc.p);
3334 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3336 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3338 setBlockNotSent(blockpos);
3341 case InventoryLocation::DETACHED:
3343 sendDetachedInventoryToAll(loc.name);
3351 core::list<PlayerInfo> Server::getPlayerInfo()
3353 DSTACK(__FUNCTION_NAME);
3354 JMutexAutoLock envlock(m_env_mutex);
3355 JMutexAutoLock conlock(m_con_mutex);
3357 core::list<PlayerInfo> list;
3359 core::list<Player*> players = m_env->getPlayers();
3361 core::list<Player*>::Iterator i;
3362 for(i = players.begin();
3363 i != players.end(); i++)
3367 Player *player = *i;
3370 // Copy info from connection to info struct
3371 info.id = player->peer_id;
3372 info.address = m_con.GetPeerAddress(player->peer_id);
3373 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3375 catch(con::PeerNotFoundException &e)
3377 // Set dummy peer info
3379 info.address = Address(0,0,0,0,0);
3383 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3384 info.position = player->getPosition();
3386 list.push_back(info);
3393 void Server::peerAdded(con::Peer *peer)
3395 DSTACK(__FUNCTION_NAME);
3396 verbosestream<<"Server::peerAdded(): peer->id="
3397 <<peer->id<<std::endl;
3400 c.type = PEER_ADDED;
3401 c.peer_id = peer->id;
3403 m_peer_change_queue.push_back(c);
3406 void Server::deletingPeer(con::Peer *peer, bool timeout)
3408 DSTACK(__FUNCTION_NAME);
3409 verbosestream<<"Server::deletingPeer(): peer->id="
3410 <<peer->id<<", timeout="<<timeout<<std::endl;
3413 c.type = PEER_REMOVED;
3414 c.peer_id = peer->id;
3415 c.timeout = timeout;
3416 m_peer_change_queue.push_back(c);
3423 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3425 DSTACK(__FUNCTION_NAME);
3426 std::ostringstream os(std::ios_base::binary);
3428 writeU16(os, TOCLIENT_HP);
3432 std::string s = os.str();
3433 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3435 con.Send(peer_id, 0, data, true);
3438 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3439 const std::wstring &reason)
3441 DSTACK(__FUNCTION_NAME);
3442 std::ostringstream os(std::ios_base::binary);
3444 writeU16(os, TOCLIENT_ACCESS_DENIED);
3445 os<<serializeWideString(reason);
3448 std::string s = os.str();
3449 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3451 con.Send(peer_id, 0, data, true);
3454 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3455 bool set_camera_point_target, v3f camera_point_target)
3457 DSTACK(__FUNCTION_NAME);
3458 std::ostringstream os(std::ios_base::binary);
3460 writeU16(os, TOCLIENT_DEATHSCREEN);
3461 writeU8(os, set_camera_point_target);
3462 writeV3F1000(os, camera_point_target);
3465 std::string s = os.str();
3466 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3468 con.Send(peer_id, 0, data, true);
3471 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3472 IItemDefManager *itemdef)
3474 DSTACK(__FUNCTION_NAME);
3475 std::ostringstream os(std::ios_base::binary);
3479 u32 length of the next item
3480 zlib-compressed serialized ItemDefManager
3482 writeU16(os, TOCLIENT_ITEMDEF);
3483 std::ostringstream tmp_os(std::ios::binary);
3484 itemdef->serialize(tmp_os);
3485 std::ostringstream tmp_os2(std::ios::binary);
3486 compressZlib(tmp_os.str(), tmp_os2);
3487 os<<serializeLongString(tmp_os2.str());
3490 std::string s = os.str();
3491 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3492 <<"): size="<<s.size()<<std::endl;
3493 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3495 con.Send(peer_id, 0, data, true);
3498 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3499 INodeDefManager *nodedef)
3501 DSTACK(__FUNCTION_NAME);
3502 std::ostringstream os(std::ios_base::binary);
3506 u32 length of the next item
3507 zlib-compressed serialized NodeDefManager
3509 writeU16(os, TOCLIENT_NODEDEF);
3510 std::ostringstream tmp_os(std::ios::binary);
3511 nodedef->serialize(tmp_os);
3512 std::ostringstream tmp_os2(std::ios::binary);
3513 compressZlib(tmp_os.str(), tmp_os2);
3514 os<<serializeLongString(tmp_os2.str());
3517 std::string s = os.str();
3518 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3519 <<"): size="<<s.size()<<std::endl;
3520 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3522 con.Send(peer_id, 0, data, true);
3526 Non-static send methods
3529 void Server::SendInventory(u16 peer_id)
3531 DSTACK(__FUNCTION_NAME);
3533 PlayerSAO *playersao = getPlayerSAO(peer_id);
3536 playersao->m_inventory_not_sent = false;
3542 std::ostringstream os;
3543 playersao->getInventory()->serialize(os);
3545 std::string s = os.str();
3547 SharedBuffer<u8> data(s.size()+2);
3548 writeU16(&data[0], TOCLIENT_INVENTORY);
3549 memcpy(&data[2], s.c_str(), s.size());
3552 m_con.Send(peer_id, 0, data, true);
3555 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3557 DSTACK(__FUNCTION_NAME);
3559 std::ostringstream os(std::ios_base::binary);
3563 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3564 os.write((char*)buf, 2);
3567 writeU16(buf, message.size());
3568 os.write((char*)buf, 2);
3571 for(u32 i=0; i<message.size(); i++)
3575 os.write((char*)buf, 2);
3579 std::string s = os.str();
3580 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3582 m_con.Send(peer_id, 0, data, true);
3585 void Server::BroadcastChatMessage(const std::wstring &message)
3587 for(core::map<u16, RemoteClient*>::Iterator
3588 i = m_clients.getIterator();
3589 i.atEnd() == false; i++)
3591 // Get client and check that it is valid
3592 RemoteClient *client = i.getNode()->getValue();
3593 assert(client->peer_id == i.getNode()->getKey());
3594 if(client->serialization_version == SER_FMT_VER_INVALID)
3597 SendChatMessage(client->peer_id, message);
3601 void Server::SendPlayerHP(u16 peer_id)
3603 DSTACK(__FUNCTION_NAME);
3604 PlayerSAO *playersao = getPlayerSAO(peer_id);
3606 playersao->m_hp_not_sent = false;
3607 SendHP(m_con, peer_id, playersao->getHP());
3610 void Server::SendMovePlayer(u16 peer_id)
3612 DSTACK(__FUNCTION_NAME);
3613 Player *player = m_env->getPlayer(peer_id);
3616 std::ostringstream os(std::ios_base::binary);
3617 writeU16(os, TOCLIENT_MOVE_PLAYER);
3618 writeV3F1000(os, player->getPosition());
3619 writeF1000(os, player->getPitch());
3620 writeF1000(os, player->getYaw());
3623 v3f pos = player->getPosition();
3624 f32 pitch = player->getPitch();
3625 f32 yaw = player->getYaw();
3626 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3627 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3634 std::string s = os.str();
3635 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3637 m_con.Send(peer_id, 0, data, true);
3640 void Server::SendPlayerPrivileges(u16 peer_id)
3642 Player *player = m_env->getPlayer(peer_id);
3644 if(player->peer_id == PEER_ID_INEXISTENT)
3647 std::set<std::string> privs;
3648 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3650 std::ostringstream os(std::ios_base::binary);
3651 writeU16(os, TOCLIENT_PRIVILEGES);
3652 writeU16(os, privs.size());
3653 for(std::set<std::string>::const_iterator i = privs.begin();
3654 i != privs.end(); i++){
3655 os<<serializeString(*i);
3659 std::string s = os.str();
3660 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3662 m_con.Send(peer_id, 0, data, true);
3665 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3667 Player *player = m_env->getPlayer(peer_id);
3669 if(player->peer_id == PEER_ID_INEXISTENT)
3672 std::ostringstream os(std::ios_base::binary);
3673 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3674 os<<serializeLongString(player->inventory_formspec);
3677 std::string s = os.str();
3678 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3680 m_con.Send(peer_id, 0, data, true);
3683 s32 Server::playSound(const SimpleSoundSpec &spec,
3684 const ServerSoundParams ¶ms)
3686 // Find out initial position of sound
3687 bool pos_exists = false;
3688 v3f pos = params.getPos(m_env, &pos_exists);
3689 // If position is not found while it should be, cancel sound
3690 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3692 // Filter destination clients
3693 std::set<RemoteClient*> dst_clients;
3694 if(params.to_player != "")
3696 Player *player = m_env->getPlayer(params.to_player.c_str());
3698 infostream<<"Server::playSound: Player \""<<params.to_player
3699 <<"\" not found"<<std::endl;
3702 if(player->peer_id == PEER_ID_INEXISTENT){
3703 infostream<<"Server::playSound: Player \""<<params.to_player
3704 <<"\" not connected"<<std::endl;
3707 RemoteClient *client = getClient(player->peer_id);
3708 dst_clients.insert(client);
3712 for(core::map<u16, RemoteClient*>::Iterator
3713 i = m_clients.getIterator(); i.atEnd() == false; i++)
3715 RemoteClient *client = i.getNode()->getValue();
3716 Player *player = m_env->getPlayer(client->peer_id);
3720 if(player->getPosition().getDistanceFrom(pos) >
3721 params.max_hear_distance)
3724 dst_clients.insert(client);
3727 if(dst_clients.size() == 0)
3730 s32 id = m_next_sound_id++;
3731 // The sound will exist as a reference in m_playing_sounds
3732 m_playing_sounds[id] = ServerPlayingSound();
3733 ServerPlayingSound &psound = m_playing_sounds[id];
3734 psound.params = params;
3735 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3736 i != dst_clients.end(); i++)
3737 psound.clients.insert((*i)->peer_id);
3739 std::ostringstream os(std::ios_base::binary);
3740 writeU16(os, TOCLIENT_PLAY_SOUND);
3742 os<<serializeString(spec.name);
3743 writeF1000(os, spec.gain * params.gain);
3744 writeU8(os, params.type);
3745 writeV3F1000(os, pos);
3746 writeU16(os, params.object);
3747 writeU8(os, params.loop);
3749 std::string s = os.str();
3750 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3752 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3753 i != dst_clients.end(); i++){
3755 m_con.Send((*i)->peer_id, 0, data, true);
3759 void Server::stopSound(s32 handle)
3761 // Get sound reference
3762 std::map<s32, ServerPlayingSound>::iterator i =
3763 m_playing_sounds.find(handle);
3764 if(i == m_playing_sounds.end())
3766 ServerPlayingSound &psound = i->second;
3768 std::ostringstream os(std::ios_base::binary);
3769 writeU16(os, TOCLIENT_STOP_SOUND);
3770 writeS32(os, handle);
3772 std::string s = os.str();
3773 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3775 for(std::set<u16>::iterator i = psound.clients.begin();
3776 i != psound.clients.end(); i++){
3778 m_con.Send(*i, 0, data, true);
3780 // Remove sound reference
3781 m_playing_sounds.erase(i);
3784 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3785 core::list<u16> *far_players, float far_d_nodes)
3787 float maxd = far_d_nodes*BS;
3788 v3f p_f = intToFloat(p, BS);
3792 SharedBuffer<u8> reply(replysize);
3793 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3794 writeS16(&reply[2], p.X);
3795 writeS16(&reply[4], p.Y);
3796 writeS16(&reply[6], p.Z);
3798 for(core::map<u16, RemoteClient*>::Iterator
3799 i = m_clients.getIterator();
3800 i.atEnd() == false; i++)
3802 // Get client and check that it is valid
3803 RemoteClient *client = i.getNode()->getValue();
3804 assert(client->peer_id == i.getNode()->getKey());
3805 if(client->serialization_version == SER_FMT_VER_INVALID)
3808 // Don't send if it's the same one
3809 if(client->peer_id == ignore_id)
3815 Player *player = m_env->getPlayer(client->peer_id);
3818 // If player is far away, only set modified blocks not sent
3819 v3f player_pos = player->getPosition();
3820 if(player_pos.getDistanceFrom(p_f) > maxd)
3822 far_players->push_back(client->peer_id);
3829 m_con.Send(client->peer_id, 0, reply, true);
3833 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3834 core::list<u16> *far_players, float far_d_nodes)
3836 float maxd = far_d_nodes*BS;
3837 v3f p_f = intToFloat(p, BS);
3839 for(core::map<u16, RemoteClient*>::Iterator
3840 i = m_clients.getIterator();
3841 i.atEnd() == false; i++)
3843 // Get client and check that it is valid
3844 RemoteClient *client = i.getNode()->getValue();
3845 assert(client->peer_id == i.getNode()->getKey());
3846 if(client->serialization_version == SER_FMT_VER_INVALID)
3849 // Don't send if it's the same one
3850 if(client->peer_id == ignore_id)
3856 Player *player = m_env->getPlayer(client->peer_id);
3859 // If player is far away, only set modified blocks not sent
3860 v3f player_pos = player->getPosition();
3861 if(player_pos.getDistanceFrom(p_f) > maxd)
3863 far_players->push_back(client->peer_id);
3870 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3871 SharedBuffer<u8> reply(replysize);
3872 writeU16(&reply[0], TOCLIENT_ADDNODE);
3873 writeS16(&reply[2], p.X);
3874 writeS16(&reply[4], p.Y);
3875 writeS16(&reply[6], p.Z);
3876 n.serialize(&reply[8], client->serialization_version);
3879 m_con.Send(client->peer_id, 0, reply, true);
3883 void Server::setBlockNotSent(v3s16 p)
3885 for(core::map<u16, RemoteClient*>::Iterator
3886 i = m_clients.getIterator();
3887 i.atEnd()==false; i++)
3889 RemoteClient *client = i.getNode()->getValue();
3890 client->SetBlockNotSent(p);
3894 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3896 DSTACK(__FUNCTION_NAME);
3898 v3s16 p = block->getPos();
3902 bool completely_air = true;
3903 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3904 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3905 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3907 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3909 completely_air = false;
3910 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3915 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3917 infostream<<"[completely air] ";
3918 infostream<<std::endl;
3922 Create a packet with the block in the right format
3925 std::ostringstream os(std::ios_base::binary);
3926 block->serialize(os, ver, false);
3927 std::string s = os.str();
3928 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3930 u32 replysize = 8 + blockdata.getSize();
3931 SharedBuffer<u8> reply(replysize);
3932 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3933 writeS16(&reply[2], p.X);
3934 writeS16(&reply[4], p.Y);
3935 writeS16(&reply[6], p.Z);
3936 memcpy(&reply[8], *blockdata, blockdata.getSize());
3938 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3939 <<": \tpacket size: "<<replysize<<std::endl;*/
3944 m_con.Send(peer_id, 1, reply, true);
3947 void Server::SendBlocks(float dtime)
3949 DSTACK(__FUNCTION_NAME);
3951 JMutexAutoLock envlock(m_env_mutex);
3952 JMutexAutoLock conlock(m_con_mutex);
3954 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3956 core::array<PrioritySortedBlockTransfer> queue;
3958 s32 total_sending = 0;
3961 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3963 for(core::map<u16, RemoteClient*>::Iterator
3964 i = m_clients.getIterator();
3965 i.atEnd() == false; i++)
3967 RemoteClient *client = i.getNode()->getValue();
3968 assert(client->peer_id == i.getNode()->getKey());
3970 // If definitions and textures have not been sent, don't
3971 // send MapBlocks either
3972 if(!client->definitions_sent)
3975 total_sending += client->SendingCount();
3977 if(client->serialization_version == SER_FMT_VER_INVALID)
3980 client->GetNextBlocks(this, dtime, queue);
3985 // Lowest priority number comes first.
3986 // Lowest is most important.
3989 for(u32 i=0; i<queue.size(); i++)
3991 //TODO: Calculate limit dynamically
3992 if(total_sending >= g_settings->getS32
3993 ("max_simultaneous_block_sends_server_total"))
3996 PrioritySortedBlockTransfer q = queue[i];
3998 MapBlock *block = NULL;
4001 block = m_env->getMap().getBlockNoCreate(q.pos);
4003 catch(InvalidPositionException &e)
4008 RemoteClient *client = getClient(q.peer_id);
4010 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4012 client->SentBlock(q.pos);
4018 void Server::fillMediaCache()
4020 DSTACK(__FUNCTION_NAME);
4022 infostream<<"Server: Calculating media file checksums"<<std::endl;
4024 // Collect all media file paths
4025 std::list<std::string> paths;
4026 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4027 i != m_mods.end(); i++){
4028 const ModSpec &mod = *i;
4029 paths.push_back(mod.path + DIR_DELIM + "textures");
4030 paths.push_back(mod.path + DIR_DELIM + "sounds");
4031 paths.push_back(mod.path + DIR_DELIM + "media");
4033 std::string path_all = "textures";
4034 paths.push_back(path_all + DIR_DELIM + "all");
4036 // Collect media file information from paths into cache
4037 for(std::list<std::string>::iterator i = paths.begin();
4038 i != paths.end(); i++)
4040 std::string mediapath = *i;
4041 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4042 for(u32 j=0; j<dirlist.size(); j++){
4043 if(dirlist[j].dir) // Ignode dirs
4045 std::string filename = dirlist[j].name;
4046 // If name contains illegal characters, ignore the file
4047 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4048 infostream<<"Server: ignoring illegal file name: \""
4049 <<filename<<"\""<<std::endl;
4052 // If name is not in a supported format, ignore it
4053 const char *supported_ext[] = {
4054 ".png", ".jpg", ".bmp", ".tga",
4055 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4059 if(removeStringEnd(filename, supported_ext) == ""){
4060 infostream<<"Server: ignoring unsupported file extension: \""
4061 <<filename<<"\""<<std::endl;
4064 // Ok, attempt to load the file and add to cache
4065 std::string filepath = mediapath + DIR_DELIM + filename;
4067 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4068 if(fis.good() == false){
4069 errorstream<<"Server::fillMediaCache(): Could not open \""
4070 <<filename<<"\" for reading"<<std::endl;
4073 std::ostringstream tmp_os(std::ios_base::binary);
4077 fis.read(buf, 1024);
4078 std::streamsize len = fis.gcount();
4079 tmp_os.write(buf, len);
4088 errorstream<<"Server::fillMediaCache(): Failed to read \""
4089 <<filename<<"\""<<std::endl;
4092 if(tmp_os.str().length() == 0){
4093 errorstream<<"Server::fillMediaCache(): Empty file \""
4094 <<filepath<<"\""<<std::endl;
4099 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4101 unsigned char *digest = sha1.getDigest();
4102 std::string sha1_base64 = base64_encode(digest, 20);
4103 std::string sha1_hex = hex_encode((char*)digest, 20);
4107 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4108 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4113 struct SendableMediaAnnouncement
4116 std::string sha1_digest;
4118 SendableMediaAnnouncement(const std::string name_="",
4119 const std::string sha1_digest_=""):
4121 sha1_digest(sha1_digest_)
4125 void Server::sendMediaAnnouncement(u16 peer_id)
4127 DSTACK(__FUNCTION_NAME);
4129 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4132 core::list<SendableMediaAnnouncement> file_announcements;
4134 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4135 i != m_media.end(); i++){
4137 file_announcements.push_back(
4138 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4142 std::ostringstream os(std::ios_base::binary);
4150 u16 length of sha1_digest
4155 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4156 writeU16(os, file_announcements.size());
4158 for(core::list<SendableMediaAnnouncement>::Iterator
4159 j = file_announcements.begin();
4160 j != file_announcements.end(); j++){
4161 os<<serializeString(j->name);
4162 os<<serializeString(j->sha1_digest);
4166 std::string s = os.str();
4167 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4170 m_con.Send(peer_id, 0, data, true);
4174 struct SendableMedia
4180 SendableMedia(const std::string &name_="", const std::string path_="",
4181 const std::string &data_=""):
4188 void Server::sendRequestedMedia(u16 peer_id,
4189 const core::list<MediaRequest> &tosend)
4191 DSTACK(__FUNCTION_NAME);
4193 verbosestream<<"Server::sendRequestedMedia(): "
4194 <<"Sending files to client"<<std::endl;
4198 // Put 5kB in one bunch (this is not accurate)
4199 u32 bytes_per_bunch = 5000;
4201 core::array< core::list<SendableMedia> > file_bunches;
4202 file_bunches.push_back(core::list<SendableMedia>());
4204 u32 file_size_bunch_total = 0;
4206 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4207 i != tosend.end(); i++)
4209 if(m_media.find(i->name) == m_media.end()){
4210 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4211 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4215 //TODO get path + name
4216 std::string tpath = m_media[(*i).name].path;
4219 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4220 if(fis.good() == false){
4221 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4222 <<tpath<<"\" for reading"<<std::endl;
4225 std::ostringstream tmp_os(std::ios_base::binary);
4229 fis.read(buf, 1024);
4230 std::streamsize len = fis.gcount();
4231 tmp_os.write(buf, len);
4232 file_size_bunch_total += len;
4241 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4242 <<(*i).name<<"\""<<std::endl;
4245 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4246 <<tname<<"\""<<std::endl;*/
4248 file_bunches[file_bunches.size()-1].push_back(
4249 SendableMedia((*i).name, tpath, tmp_os.str()));
4251 // Start next bunch if got enough data
4252 if(file_size_bunch_total >= bytes_per_bunch){
4253 file_bunches.push_back(core::list<SendableMedia>());
4254 file_size_bunch_total = 0;
4259 /* Create and send packets */
4261 u32 num_bunches = file_bunches.size();
4262 for(u32 i=0; i<num_bunches; i++)
4264 std::ostringstream os(std::ios_base::binary);
4268 u16 total number of texture bunches
4269 u16 index of this bunch
4270 u32 number of files in this bunch
4279 writeU16(os, TOCLIENT_MEDIA);
4280 writeU16(os, num_bunches);
4282 writeU32(os, file_bunches[i].size());
4284 for(core::list<SendableMedia>::Iterator
4285 j = file_bunches[i].begin();
4286 j != file_bunches[i].end(); j++){
4287 os<<serializeString(j->name);
4288 os<<serializeLongString(j->data);
4292 std::string s = os.str();
4293 verbosestream<<"Server::sendRequestedMedia(): bunch "
4294 <<i<<"/"<<num_bunches
4295 <<" files="<<file_bunches[i].size()
4296 <<" size=" <<s.size()<<std::endl;
4297 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4299 m_con.Send(peer_id, 0, data, true);
4303 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4305 if(m_detached_inventories.count(name) == 0){
4306 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4309 Inventory *inv = m_detached_inventories[name];
4311 std::ostringstream os(std::ios_base::binary);
4312 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4313 os<<serializeString(name);
4317 std::string s = os.str();
4318 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4320 m_con.Send(peer_id, 0, data, true);
4323 void Server::sendDetachedInventoryToAll(const std::string &name)
4325 DSTACK(__FUNCTION_NAME);
4327 for(core::map<u16, RemoteClient*>::Iterator
4328 i = m_clients.getIterator();
4329 i.atEnd() == false; i++){
4330 RemoteClient *client = i.getNode()->getValue();
4331 sendDetachedInventory(name, client->peer_id);
4335 void Server::sendDetachedInventories(u16 peer_id)
4337 DSTACK(__FUNCTION_NAME);
4339 for(std::map<std::string, Inventory*>::iterator
4340 i = m_detached_inventories.begin();
4341 i != m_detached_inventories.end(); i++){
4342 const std::string &name = i->first;
4343 //Inventory *inv = i->second;
4344 sendDetachedInventory(name, peer_id);
4352 void Server::DiePlayer(u16 peer_id)
4354 DSTACK(__FUNCTION_NAME);
4356 PlayerSAO *playersao = getPlayerSAO(peer_id);
4359 infostream<<"Server::DiePlayer(): Player "
4360 <<playersao->getPlayer()->getName()
4361 <<" dies"<<std::endl;
4363 playersao->setHP(0);
4365 // Trigger scripted stuff
4366 scriptapi_on_dieplayer(m_lua, playersao);
4368 SendPlayerHP(peer_id);
4369 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4372 void Server::RespawnPlayer(u16 peer_id)
4374 DSTACK(__FUNCTION_NAME);
4376 PlayerSAO *playersao = getPlayerSAO(peer_id);
4379 infostream<<"Server::RespawnPlayer(): Player "
4380 <<playersao->getPlayer()->getName()
4381 <<" respawns"<<std::endl;
4383 playersao->setHP(PLAYER_MAX_HP);
4385 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4387 v3f pos = findSpawnPos(m_env->getServerMap());
4388 playersao->setPos(pos);
4392 void Server::UpdateCrafting(u16 peer_id)
4394 DSTACK(__FUNCTION_NAME);
4396 Player* player = m_env->getPlayer(peer_id);
4399 // Get a preview for crafting
4401 getCraftingResult(&player->inventory, preview, false, this);
4403 // Put the new preview in
4404 InventoryList *plist = player->inventory.getList("craftpreview");
4406 assert(plist->getSize() >= 1);
4407 plist->changeItem(0, preview);
4410 RemoteClient* Server::getClient(u16 peer_id)
4412 DSTACK(__FUNCTION_NAME);
4413 //JMutexAutoLock lock(m_con_mutex);
4414 core::map<u16, RemoteClient*>::Node *n;
4415 n = m_clients.find(peer_id);
4416 // A client should exist for all peers
4418 return n->getValue();
4421 std::wstring Server::getStatusString()
4423 std::wostringstream os(std::ios_base::binary);
4426 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4428 os<<L", uptime="<<m_uptime.get();
4429 // Information about clients
4430 core::map<u16, RemoteClient*>::Iterator i;
4433 for(i = m_clients.getIterator(), first = true;
4434 i.atEnd() == false; i++)
4436 // Get client and check that it is valid
4437 RemoteClient *client = i.getNode()->getValue();
4438 assert(client->peer_id == i.getNode()->getKey());
4439 if(client->serialization_version == SER_FMT_VER_INVALID)
4442 Player *player = m_env->getPlayer(client->peer_id);
4443 // Get name of player
4444 std::wstring name = L"unknown";
4446 name = narrow_to_wide(player->getName());
4447 // Add name to information string
4455 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4456 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4457 if(g_settings->get("motd") != "")
4458 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4462 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4464 std::set<std::string> privs;
4465 scriptapi_get_auth(m_lua, name, NULL, &privs);
4469 bool Server::checkPriv(const std::string &name, const std::string &priv)
4471 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4472 return (privs.count(priv) != 0);
4475 void Server::reportPrivsModified(const std::string &name)
4478 for(core::map<u16, RemoteClient*>::Iterator
4479 i = m_clients.getIterator();
4480 i.atEnd() == false; i++){
4481 RemoteClient *client = i.getNode()->getValue();
4482 Player *player = m_env->getPlayer(client->peer_id);
4483 reportPrivsModified(player->getName());
4486 Player *player = m_env->getPlayer(name.c_str());
4489 SendPlayerPrivileges(player->peer_id);
4490 PlayerSAO *sao = player->getPlayerSAO();
4493 sao->updatePrivileges(
4494 getPlayerEffectivePrivs(name),
4499 void Server::reportInventoryFormspecModified(const std::string &name)
4501 Player *player = m_env->getPlayer(name.c_str());
4504 SendPlayerInventoryFormspec(player->peer_id);
4507 // Saves g_settings to configpath given at initialization
4508 void Server::saveConfig()
4510 if(m_path_config != "")
4511 g_settings->updateConfigFile(m_path_config.c_str());
4514 void Server::notifyPlayer(const char *name, const std::wstring msg)
4516 Player *player = m_env->getPlayer(name);
4519 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4522 void Server::notifyPlayers(const std::wstring msg)
4524 BroadcastChatMessage(msg);
4527 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4531 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4532 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4535 Inventory* Server::createDetachedInventory(const std::string &name)
4537 if(m_detached_inventories.count(name) > 0){
4538 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4539 delete m_detached_inventories[name];
4541 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4543 Inventory *inv = new Inventory(m_itemdef);
4545 m_detached_inventories[name] = inv;
4546 sendDetachedInventoryToAll(name);
4553 BoolScopeSet(bool *dst, bool val):
4556 m_orig_state = *m_dst;
4561 *m_dst = m_orig_state;
4568 // actions: time-reversed list
4569 // Return value: success/failure
4570 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4571 std::list<std::string> *log)
4573 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4574 ServerMap *map = (ServerMap*)(&m_env->getMap());
4575 // Disable rollback report sink while reverting
4576 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4578 // Fail if no actions to handle
4579 if(actions.empty()){
4580 log->push_back("Nothing to do.");
4587 for(std::list<RollbackAction>::const_iterator
4588 i = actions.begin();
4589 i != actions.end(); i++)
4591 const RollbackAction &action = *i;
4593 bool success = action.applyRevert(map, this, this);
4596 std::ostringstream os;
4597 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4598 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4600 log->push_back(os.str());
4602 std::ostringstream os;
4603 os<<"Succesfully reverted step ("<<num_tried<<") "<<action.toString();
4604 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4606 log->push_back(os.str());
4610 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4611 <<" failed"<<std::endl;
4613 // Call it done if less than half failed
4614 return num_failed <= num_tried/2;
4617 // IGameDef interface
4619 IItemDefManager* Server::getItemDefManager()
4623 INodeDefManager* Server::getNodeDefManager()
4627 ICraftDefManager* Server::getCraftDefManager()
4631 ITextureSource* Server::getTextureSource()
4635 u16 Server::allocateUnknownNodeId(const std::string &name)
4637 return m_nodedef->allocateDummy(name);
4639 ISoundManager* Server::getSoundManager()
4641 return &dummySoundManager;
4643 MtEventManager* Server::getEventManager()
4647 IRollbackReportSink* Server::getRollbackReportSink()
4649 if(!m_enable_rollback_recording)
4651 if(!m_rollback_sink_enabled)
4656 IWritableItemDefManager* Server::getWritableItemDefManager()
4660 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4664 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4669 const ModSpec* Server::getModSpec(const std::string &modname)
4671 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4672 i != m_mods.end(); i++){
4673 const ModSpec &mod = *i;
4674 if(mod.name == modname)
4679 void Server::getModNames(core::list<std::string> &modlist)
4681 for(core::list<ModSpec>::Iterator i = m_mods.begin(); i != m_mods.end(); i++)
4683 modlist.push_back((*i).name);
4686 std::string Server::getBuiltinLuaPath()
4688 return porting::path_share + DIR_DELIM + "builtin";
4691 v3f findSpawnPos(ServerMap &map)
4693 //return v3f(50,50,50)*BS;
4698 nodepos = v2s16(0,0);
4703 // Try to find a good place a few times
4704 for(s32 i=0; i<1000; i++)
4707 // We're going to try to throw the player to this position
4708 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4709 -range + (myrand()%(range*2)));
4710 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4711 // Get ground height at point (fallbacks to heightmap function)
4712 s16 groundheight = map.findGroundLevel(nodepos2d);
4713 // Don't go underwater
4714 if(groundheight < WATER_LEVEL)
4716 //infostream<<"-> Underwater"<<std::endl;
4719 // Don't go to high places
4720 if(groundheight > WATER_LEVEL + 4)
4722 //infostream<<"-> Underwater"<<std::endl;
4726 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4727 bool is_good = false;
4729 for(s32 i=0; i<10; i++){
4730 v3s16 blockpos = getNodeBlockPos(nodepos);
4731 map.emergeBlock(blockpos, true);
4732 MapNode n = map.getNodeNoEx(nodepos);
4733 if(n.getContent() == CONTENT_AIR){
4744 // Found a good place
4745 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4751 return intToFloat(nodepos, BS);
4754 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4756 RemotePlayer *player = NULL;
4757 bool newplayer = false;
4760 Try to get an existing player
4762 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4764 // If player is already connected, cancel
4765 if(player != NULL && player->peer_id != 0)
4767 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4772 If player with the wanted peer_id already exists, cancel.
4774 if(m_env->getPlayer(peer_id) != NULL)
4776 infostream<<"emergePlayer(): Player with wrong name but same"
4777 " peer_id already exists"<<std::endl;
4782 Create a new player if it doesn't exist yet
4787 player = new RemotePlayer(this);
4788 player->updateName(name);
4790 /* Set player position */
4791 infostream<<"Server: Finding spawn place for player \""
4792 <<name<<"\""<<std::endl;
4793 v3f pos = findSpawnPos(m_env->getServerMap());
4794 player->setPosition(pos);
4796 /* Add player to environment */
4797 m_env->addPlayer(player);
4801 Create a new player active object
4803 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4804 getPlayerEffectivePrivs(player->getName()),
4807 /* Add object to environment */
4808 m_env->addActiveObject(playersao);
4812 scriptapi_on_newplayer(m_lua, playersao);
4814 scriptapi_on_joinplayer(m_lua, playersao);
4819 void Server::handlePeerChange(PeerChange &c)
4821 JMutexAutoLock envlock(m_env_mutex);
4822 JMutexAutoLock conlock(m_con_mutex);
4824 if(c.type == PEER_ADDED)
4831 core::map<u16, RemoteClient*>::Node *n;
4832 n = m_clients.find(c.peer_id);
4833 // The client shouldn't already exist
4837 RemoteClient *client = new RemoteClient();
4838 client->peer_id = c.peer_id;
4839 m_clients.insert(client->peer_id, client);
4842 else if(c.type == PEER_REMOVED)
4849 core::map<u16, RemoteClient*>::Node *n;
4850 n = m_clients.find(c.peer_id);
4851 // The client should exist
4855 Mark objects to be not known by the client
4857 RemoteClient *client = n->getValue();
4859 for(core::map<u16, bool>::Iterator
4860 i = client->m_known_objects.getIterator();
4861 i.atEnd()==false; i++)
4864 u16 id = i.getNode()->getKey();
4865 ServerActiveObject* obj = m_env->getActiveObject(id);
4867 if(obj && obj->m_known_by_count > 0)
4868 obj->m_known_by_count--;
4872 Clear references to playing sounds
4874 for(std::map<s32, ServerPlayingSound>::iterator
4875 i = m_playing_sounds.begin();
4876 i != m_playing_sounds.end();)
4878 ServerPlayingSound &psound = i->second;
4879 psound.clients.erase(c.peer_id);
4880 if(psound.clients.size() == 0)
4881 m_playing_sounds.erase(i++);
4886 Player *player = m_env->getPlayer(c.peer_id);
4888 // Collect information about leaving in chat
4889 std::wstring message;
4893 std::wstring name = narrow_to_wide(player->getName());
4896 message += L" left the game.";
4898 message += L" (timed out)";
4902 /* Run scripts and remove from environment */
4906 PlayerSAO *playersao = player->getPlayerSAO();
4909 scriptapi_on_leaveplayer(m_lua, playersao);
4911 playersao->disconnected();
4921 std::ostringstream os(std::ios_base::binary);
4922 for(core::map<u16, RemoteClient*>::Iterator
4923 i = m_clients.getIterator();
4924 i.atEnd() == false; i++)
4926 RemoteClient *client = i.getNode()->getValue();
4927 assert(client->peer_id == i.getNode()->getKey());
4928 if(client->serialization_version == SER_FMT_VER_INVALID)
4931 Player *player = m_env->getPlayer(client->peer_id);
4934 // Get name of player
4935 os<<player->getName()<<" ";
4938 actionstream<<player->getName()<<" "
4939 <<(c.timeout?"times out.":"leaves game.")
4940 <<" List of players: "
4941 <<os.str()<<std::endl;
4946 delete m_clients[c.peer_id];
4947 m_clients.remove(c.peer_id);
4949 // Send player info to all remaining clients
4950 //SendPlayerInfos();
4952 // Send leave chat message to all remaining clients
4953 if(message.length() != 0)
4954 BroadcastChatMessage(message);
4963 void Server::handlePeerChanges()
4965 while(m_peer_change_queue.size() > 0)
4967 PeerChange c = m_peer_change_queue.pop_front();
4969 verbosestream<<"Server: Handling peer change: "
4970 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4973 handlePeerChange(c);
4977 void dedicated_server_loop(Server &server, bool &kill)
4979 DSTACK(__FUNCTION_NAME);
4981 verbosestream<<"dedicated_server_loop()"<<std::endl;
4983 IntervalLimiter m_profiler_interval;
4987 float steplen = g_settings->getFloat("dedicated_server_step");
4988 // This is kind of a hack but can be done like this
4989 // because server.step() is very light
4991 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4992 sleep_ms((int)(steplen*1000.0));
4994 server.step(steplen);
4996 if(server.getShutdownRequested() || kill)
4998 infostream<<"Dedicated server quitting"<<std::endl;
5005 float profiler_print_interval =
5006 g_settings->getFloat("profiler_print_interval");
5007 if(profiler_print_interval != 0)
5009 if(m_profiler_interval.step(steplen, profiler_print_interval))
5011 infostream<<"Profiler:"<<std::endl;
5012 g_profiler->print(infostream);
5013 g_profiler->clear();