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"
30 #include "servercommand.h"
33 #include "serverobject.h"
38 #include "scriptapi.h"
43 #include "content_mapnode.h"
44 #include "content_nodemeta.h"
45 #include "content_abm.h"
46 #include "content_sao.h"
51 #include "sound.h" // dummySoundManager
52 #include "event_manager.h"
54 #include "util/string.h"
55 #include "util/pointedthing.h"
56 #include "util/mathconstants.h"
59 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
61 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
63 class MapEditEventIgnorer
66 MapEditEventIgnorer(bool *flag):
75 ~MapEditEventIgnorer()
88 class MapEditEventAreaIgnorer
91 MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
92 m_ignorevariable(ignorevariable)
94 if(m_ignorevariable->getVolume() == 0)
95 *m_ignorevariable = a;
97 m_ignorevariable = NULL;
100 ~MapEditEventAreaIgnorer()
104 assert(m_ignorevariable->getVolume() != 0);
105 *m_ignorevariable = VoxelArea();
110 VoxelArea *m_ignorevariable;
113 void * ServerThread::Thread()
117 log_register_thread("ServerThread");
119 DSTACK(__FUNCTION_NAME);
121 BEGIN_DEBUG_EXCEPTION_HANDLER
126 //TimeTaker timer("AsyncRunStep() + Receive()");
129 //TimeTaker timer("AsyncRunStep()");
130 m_server->AsyncRunStep();
133 //infostream<<"Running m_server->Receive()"<<std::endl;
136 catch(con::NoIncomingDataException &e)
139 catch(con::PeerNotFoundException &e)
141 infostream<<"Server: PeerNotFoundException"<<std::endl;
143 catch(con::ConnectionBindFailed &e)
145 m_server->setAsyncFatalError(e.what());
149 m_server->setAsyncFatalError(e.what());
153 END_DEBUG_EXCEPTION_HANDLER(errorstream)
158 void * EmergeThread::Thread()
162 log_register_thread("EmergeThread");
164 DSTACK(__FUNCTION_NAME);
166 BEGIN_DEBUG_EXCEPTION_HANDLER
168 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
170 v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
173 Get block info from queue, emerge them and send them
176 After queue is empty, exit.
180 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
184 SharedPtr<QueuedBlockEmerge> q(qptr);
192 Do not generate over-limit
194 if(blockpos_over_limit(p))
197 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
199 //TimeTaker timer("block emerge");
202 Try to emerge it from somewhere.
204 If it is only wanted as optional, only loading from disk
209 Check if any peer wants it as non-optional. In that case it
212 Also decrement the emerge queue count in clients.
215 bool only_from_disk = true;
218 core::map<u16, u8>::Iterator i;
219 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
221 //u16 peer_id = i.getNode()->getKey();
224 u8 flags = i.getNode()->getValue();
225 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
226 only_from_disk = false;
231 if(enable_mapgen_debug_info)
232 infostream<<"EmergeThread: p="
233 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
234 <<"only_from_disk="<<only_from_disk<<std::endl;
236 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
238 MapBlock *block = NULL;
239 bool got_block = true;
240 core::map<v3s16, MapBlock*> modified_blocks;
243 Try to fetch block from memory or disk.
244 If not found and asked to generate, initialize generator.
247 bool started_generate = false;
248 mapgen::BlockMakeData data;
251 JMutexAutoLock envlock(m_server->m_env_mutex);
253 // Load sector if it isn't loaded
254 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
255 map.loadSectorMeta(p2d);
257 // Attempt to load block
258 block = map.getBlockNoCreateNoEx(p);
259 if(!block || block->isDummy() || !block->isGenerated())
261 if(enable_mapgen_debug_info)
262 infostream<<"EmergeThread: not in memory, "
263 <<"attempting to load from disk"<<std::endl;
265 block = map.loadBlock(p);
268 // If could not load and allowed to generate, start generation
269 // inside this same envlock
270 if(only_from_disk == false &&
271 (block == NULL || block->isGenerated() == false)){
272 if(enable_mapgen_debug_info)
273 infostream<<"EmergeThread: generating"<<std::endl;
274 started_generate = true;
276 map.initBlockMake(&data, p);
281 If generator was initialized, generate now when envlock is free.
286 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
288 TimeTaker t("mapgen::make_block()");
290 mapgen::make_block(&data);
292 if(enable_mapgen_debug_info == false)
293 t.stop(true); // Hide output
297 // Lock environment again to access the map
298 JMutexAutoLock envlock(m_server->m_env_mutex);
300 ScopeProfiler sp(g_profiler, "EmergeThread: after "
301 "mapgen::make_block (envlock)", SPT_AVG);
303 // Blit data back on map, update lighting, add mobs and
304 // whatever this does
305 map.finishBlockMake(&data, modified_blocks);
308 block = map.getBlockNoCreateNoEx(p);
310 // If block doesn't exist, don't try doing anything with it
311 // This happens if the block is not in generation boundaries
316 Do some post-generate stuff
319 v3s16 minp = data.blockpos_min*MAP_BLOCKSIZE;
320 v3s16 maxp = data.blockpos_max*MAP_BLOCKSIZE +
321 v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
324 Ignore map edit events, they will not need to be
325 sent to anybody because the block hasn't been sent
328 //MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
329 MapEditEventAreaIgnorer ign(
330 &m_server->m_ignore_map_edit_events_area,
331 VoxelArea(minp, maxp));
333 TimeTaker timer("on_generated");
334 scriptapi_environment_on_generated(m_server->m_lua,
335 minp, maxp, mapgen::get_blockseed(data.seed, minp));
336 /*int t = timer.stop(true);
337 dstream<<"on_generated took "<<t<<"ms"<<std::endl;*/
340 if(enable_mapgen_debug_info)
341 infostream<<"EmergeThread: ended up with: "
342 <<analyze_block(block)<<std::endl;
344 // Activate objects and stuff
345 m_server->m_env->activateBlock(block, 0);
353 Set sent status of modified blocks on clients
356 // NOTE: Server's clients are also behind the connection mutex
357 JMutexAutoLock lock(m_server->m_con_mutex);
360 Add the originally fetched block to the modified list
364 modified_blocks.insert(p, block);
368 Set the modified blocks unsent for all the clients
371 for(core::map<u16, RemoteClient*>::Iterator
372 i = m_server->m_clients.getIterator();
373 i.atEnd() == false; i++)
375 RemoteClient *client = i.getNode()->getValue();
377 if(modified_blocks.size() > 0)
379 // Remove block from sent history
380 client->SetBlocksNotSent(modified_blocks);
384 catch(VersionMismatchException &e)
386 std::ostringstream err;
387 err<<"World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl;
388 err<<"----"<<std::endl;
389 err<<"\""<<e.what()<<"\""<<std::endl;
390 err<<"See debug.txt."<<std::endl;
391 err<<"World probably saved by a newer version of Minetest."<<std::endl;
392 m_server->setAsyncFatalError(err.str());
394 catch(SerializationError &e)
396 std::ostringstream err;
397 err<<"Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl;
398 err<<"----"<<std::endl;
399 err<<"\""<<e.what()<<"\""<<std::endl;
400 err<<"See debug.txt."<<std::endl;
401 err<<"You can ignore this using [ignore_world_load_errors = true]."<<std::endl;
402 m_server->setAsyncFatalError(err.str());
405 END_DEBUG_EXCEPTION_HANDLER(errorstream)
407 log_deregister_thread();
412 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
414 if(pos_exists) *pos_exists = false;
419 if(pos_exists) *pos_exists = true;
424 ServerActiveObject *sao = env->getActiveObject(object);
427 if(pos_exists) *pos_exists = true;
428 return sao->getBasePosition(); }
433 void RemoteClient::GetNextBlocks(Server *server, float dtime,
434 core::array<PrioritySortedBlockTransfer> &dest)
436 DSTACK(__FUNCTION_NAME);
439 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
442 m_nothing_to_send_pause_timer -= dtime;
443 m_nearest_unsent_reset_timer += dtime;
445 if(m_nothing_to_send_pause_timer >= 0)
450 // Won't send anything if already sending
451 if(m_blocks_sending.size() >= g_settings->getU16
452 ("max_simultaneous_block_sends_per_client"))
454 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
458 //TimeTaker timer("RemoteClient::GetNextBlocks");
460 Player *player = server->m_env->getPlayer(peer_id);
462 assert(player != NULL);
464 v3f playerpos = player->getPosition();
465 v3f playerspeed = player->getSpeed();
466 v3f playerspeeddir(0,0,0);
467 if(playerspeed.getLength() > 1.0*BS)
468 playerspeeddir = playerspeed / playerspeed.getLength();
469 // Predict to next block
470 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
472 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
474 v3s16 center = getNodeBlockPos(center_nodepos);
476 // Camera position and direction
477 v3f camera_pos = player->getEyePosition();
478 v3f camera_dir = v3f(0,0,1);
479 camera_dir.rotateYZBy(player->getPitch());
480 camera_dir.rotateXZBy(player->getYaw());
482 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
483 <<camera_dir.Z<<")"<<std::endl;*/
486 Get the starting value of the block finder radius.
489 if(m_last_center != center)
491 m_nearest_unsent_d = 0;
492 m_last_center = center;
495 /*infostream<<"m_nearest_unsent_reset_timer="
496 <<m_nearest_unsent_reset_timer<<std::endl;*/
498 // Reset periodically to workaround for some bugs or stuff
499 if(m_nearest_unsent_reset_timer > 20.0)
501 m_nearest_unsent_reset_timer = 0;
502 m_nearest_unsent_d = 0;
503 //infostream<<"Resetting m_nearest_unsent_d for "
504 // <<server->getPlayerName(peer_id)<<std::endl;
507 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
508 s16 d_start = m_nearest_unsent_d;
510 //infostream<<"d_start="<<d_start<<std::endl;
512 u16 max_simul_sends_setting = g_settings->getU16
513 ("max_simultaneous_block_sends_per_client");
514 u16 max_simul_sends_usually = max_simul_sends_setting;
517 Check the time from last addNode/removeNode.
519 Decrease send rate if player is building stuff.
521 m_time_from_building += dtime;
522 if(m_time_from_building < g_settings->getFloat(
523 "full_block_send_enable_min_time_from_building"))
525 max_simul_sends_usually
526 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
530 Number of blocks sending + number of blocks selected for sending
532 u32 num_blocks_selected = m_blocks_sending.size();
535 next time d will be continued from the d from which the nearest
536 unsent block was found this time.
538 This is because not necessarily any of the blocks found this
539 time are actually sent.
541 s32 new_nearest_unsent_d = -1;
543 s16 d_max = g_settings->getS16("max_block_send_distance");
544 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
546 // Don't loop very much at a time
547 s16 max_d_increment_at_time = 2;
548 if(d_max > d_start + max_d_increment_at_time)
549 d_max = d_start + max_d_increment_at_time;
550 /*if(d_max_gen > d_start+2)
551 d_max_gen = d_start+2;*/
553 //infostream<<"Starting from "<<d_start<<std::endl;
555 s32 nearest_emerged_d = -1;
556 s32 nearest_emergefull_d = -1;
557 s32 nearest_sent_d = -1;
558 bool queue_is_full = false;
561 for(d = d_start; d <= d_max; d++)
563 /*errorstream<<"checking d="<<d<<" for "
564 <<server->getPlayerName(peer_id)<<std::endl;*/
565 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
568 If m_nearest_unsent_d was changed by the EmergeThread
569 (it can change it to 0 through SetBlockNotSent),
571 Else update m_nearest_unsent_d
573 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
575 d = m_nearest_unsent_d;
576 last_nearest_unsent_d = m_nearest_unsent_d;
580 Get the border/face dot coordinates of a "d-radiused"
583 core::list<v3s16> list;
584 getFacePositions(list, d);
586 core::list<v3s16>::Iterator li;
587 for(li=list.begin(); li!=list.end(); li++)
589 v3s16 p = *li + center;
593 - Don't allow too many simultaneous transfers
594 - EXCEPT when the blocks are very close
596 Also, don't send blocks that are already flying.
599 // Start with the usual maximum
600 u16 max_simul_dynamic = max_simul_sends_usually;
602 // If block is very close, allow full maximum
603 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
604 max_simul_dynamic = max_simul_sends_setting;
606 // Don't select too many blocks for sending
607 if(num_blocks_selected >= max_simul_dynamic)
609 queue_is_full = true;
610 goto queue_full_break;
613 // Don't send blocks that are currently being transferred
614 if(m_blocks_sending.find(p) != NULL)
620 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
621 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
622 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
623 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
624 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
625 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
628 // If this is true, inexistent block will be made from scratch
629 bool generate = d <= d_max_gen;
632 /*// Limit the generating area vertically to 2/3
633 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
636 // Limit the send area vertically to 1/2
637 if(abs(p.Y - center.Y) > d_max / 2)
643 If block is far away, don't generate it unless it is
649 // Block center y in nodes
650 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
651 // Don't generate if it's very high or very low
652 if(y < -64 || y > 64)
656 v2s16 p2d_nodes_center(
660 // Get ground height in nodes
661 s16 gh = server->m_env->getServerMap().findGroundLevel(
664 // If differs a lot, don't generate
665 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
667 // Actually, don't even send it
673 //infostream<<"d="<<d<<std::endl;
676 Don't generate or send if not in sight
677 FIXME This only works if the client uses a small enough
678 FOV setting. The default of 72 degrees is fine.
681 float camera_fov = (72.0*M_PI/180) * 4./3.;
682 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
688 Don't send already sent blocks
691 if(m_blocks_sent.find(p) != NULL)
698 Check if map has this block
700 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
702 bool surely_not_found_on_disk = false;
703 bool block_is_invalid = false;
706 // Reset usage timer, this block will be of use in the future.
707 block->resetUsageTimer();
709 // Block is dummy if data doesn't exist.
710 // It means it has been not found from disk and not generated
713 surely_not_found_on_disk = true;
716 // Block is valid if lighting is up-to-date and data exists
717 if(block->isValid() == false)
719 block_is_invalid = true;
722 /*if(block->isFullyGenerated() == false)
724 block_is_invalid = true;
729 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
730 v2s16 chunkpos = map->sector_to_chunk(p2d);
731 if(map->chunkNonVolatile(chunkpos) == false)
732 block_is_invalid = true;
734 if(block->isGenerated() == false)
735 block_is_invalid = true;
738 If block is not close, don't send it unless it is near
741 Block is near ground level if night-time mesh
742 differs from day-time mesh.
746 if(block->getDayNightDiff() == false)
753 If block has been marked to not exist on disk (dummy)
754 and generating new ones is not wanted, skip block.
756 if(generate == false && surely_not_found_on_disk == true)
763 Add inexistent block to emerge queue.
765 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
767 //TODO: Get value from somewhere
768 // Allow only one block in emerge queue
769 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
770 // Allow two blocks in queue per client
771 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
773 // Make it more responsive when needing to generate stuff
774 if(surely_not_found_on_disk)
776 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
778 //infostream<<"Adding block to emerge queue"<<std::endl;
780 // Add it to the emerge queue and trigger the thread
783 if(generate == false)
784 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
786 server->m_emerge_queue.addBlock(peer_id, p, flags);
787 server->m_emergethread.trigger();
789 if(nearest_emerged_d == -1)
790 nearest_emerged_d = d;
792 if(nearest_emergefull_d == -1)
793 nearest_emergefull_d = d;
800 if(nearest_sent_d == -1)
804 Add block to send queue
807 /*errorstream<<"sending from d="<<d<<" to "
808 <<server->getPlayerName(peer_id)<<std::endl;*/
810 PrioritySortedBlockTransfer q((float)d, p, peer_id);
814 num_blocks_selected += 1;
819 //infostream<<"Stopped at "<<d<<std::endl;
821 // If nothing was found for sending and nothing was queued for
822 // emerging, continue next time browsing from here
823 if(nearest_emerged_d != -1){
824 new_nearest_unsent_d = nearest_emerged_d;
825 } else if(nearest_emergefull_d != -1){
826 new_nearest_unsent_d = nearest_emergefull_d;
828 if(d > g_settings->getS16("max_block_send_distance")){
829 new_nearest_unsent_d = 0;
830 m_nothing_to_send_pause_timer = 2.0;
831 /*infostream<<"GetNextBlocks(): d wrapped around for "
832 <<server->getPlayerName(peer_id)
833 <<"; setting to 0 and pausing"<<std::endl;*/
835 if(nearest_sent_d != -1)
836 new_nearest_unsent_d = nearest_sent_d;
838 new_nearest_unsent_d = d;
842 if(new_nearest_unsent_d != -1)
843 m_nearest_unsent_d = new_nearest_unsent_d;
845 /*timer_result = timer.stop(true);
846 if(timer_result != 0)
847 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
850 void RemoteClient::GotBlock(v3s16 p)
852 if(m_blocks_sending.find(p) != NULL)
853 m_blocks_sending.remove(p);
856 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
857 " m_blocks_sending"<<std::endl;*/
858 m_excess_gotblocks++;
860 m_blocks_sent.insert(p, true);
863 void RemoteClient::SentBlock(v3s16 p)
865 if(m_blocks_sending.find(p) == NULL)
866 m_blocks_sending.insert(p, 0.0);
868 infostream<<"RemoteClient::SentBlock(): Sent block"
869 " already in m_blocks_sending"<<std::endl;
872 void RemoteClient::SetBlockNotSent(v3s16 p)
874 m_nearest_unsent_d = 0;
876 if(m_blocks_sending.find(p) != NULL)
877 m_blocks_sending.remove(p);
878 if(m_blocks_sent.find(p) != NULL)
879 m_blocks_sent.remove(p);
882 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
884 m_nearest_unsent_d = 0;
886 for(core::map<v3s16, MapBlock*>::Iterator
887 i = blocks.getIterator();
888 i.atEnd()==false; i++)
890 v3s16 p = i.getNode()->getKey();
892 if(m_blocks_sending.find(p) != NULL)
893 m_blocks_sending.remove(p);
894 if(m_blocks_sent.find(p) != NULL)
895 m_blocks_sent.remove(p);
903 PlayerInfo::PlayerInfo()
909 void PlayerInfo::PrintLine(std::ostream *s)
912 (*s)<<"\""<<name<<"\" ("
913 <<(position.X/10)<<","<<(position.Y/10)
914 <<","<<(position.Z/10)<<") ";
916 (*s)<<" avg_rtt="<<avg_rtt;
925 const std::string &path_world,
926 const std::string &path_config,
927 const SubgameSpec &gamespec,
928 bool simple_singleplayer_mode
930 m_path_world(path_world),
931 m_path_config(path_config),
932 m_gamespec(gamespec),
933 m_simple_singleplayer_mode(simple_singleplayer_mode),
934 m_async_fatal_error(""),
936 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
937 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
939 m_rollback_sink_enabled(true),
941 m_itemdef(createItemDefManager()),
942 m_nodedef(createNodeDefManager()),
943 m_craftdef(createCraftDefManager()),
944 m_event(new EventManager()),
946 m_emergethread(this),
947 m_time_of_day_send_timer(0),
949 m_shutdown_requested(false),
950 m_ignore_map_edit_events(false),
951 m_ignore_map_edit_events_peer_id(0)
953 m_liquid_transform_timer = 0.0;
954 m_print_info_timer = 0.0;
955 m_objectdata_timer = 0.0;
956 m_emergethread_trigger_timer = 0.0;
957 m_savemap_timer = 0.0;
961 m_step_dtime_mutex.Init();
965 throw ServerError("Supplied empty world path");
967 if(!gamespec.isValid())
968 throw ServerError("Supplied invalid gamespec");
970 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
971 if(m_simple_singleplayer_mode)
972 infostream<<" in simple singleplayer mode"<<std::endl;
974 infostream<<std::endl;
975 infostream<<"- world: "<<m_path_world<<std::endl;
976 infostream<<"- config: "<<m_path_config<<std::endl;
977 infostream<<"- game: "<<m_gamespec.path<<std::endl;
979 // Create rollback manager
980 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
981 m_rollback = createRollbackManager(rollback_path, this);
983 // Add world mod search path
984 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
985 // Add addon mod search path
986 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
987 i != m_gamespec.mods_paths.end(); i++)
988 m_modspaths.push_front((*i));
990 // Print out mod search paths
991 for(core::list<std::string>::Iterator i = m_modspaths.begin();
992 i != m_modspaths.end(); i++){
993 std::string modspath = *i;
994 infostream<<"- mods: "<<modspath<<std::endl;
997 // Path to builtin.lua
998 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
1000 // Create world if it doesn't exist
1001 if(!initializeWorld(m_path_world, m_gamespec.id))
1002 throw ServerError("Failed to initialize world");
1005 JMutexAutoLock envlock(m_env_mutex);
1006 JMutexAutoLock conlock(m_con_mutex);
1008 // Initialize scripting
1010 infostream<<"Server: Initializing Lua"<<std::endl;
1011 m_lua = script_init();
1014 scriptapi_export(m_lua, this);
1015 // Load and run builtin.lua
1016 infostream<<"Server: Loading builtin.lua [\""
1017 <<builtinpath<<"\"]"<<std::endl;
1018 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1020 errorstream<<"Server: Failed to load and run "
1021 <<builtinpath<<std::endl;
1022 throw ModError("Failed to load and run "+builtinpath);
1024 // Find mods in mod search paths
1025 m_mods = getMods(m_modspaths);
1027 infostream<<"Server: Loading mods: ";
1028 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1029 i != m_mods.end(); i++){
1030 const ModSpec &mod = *i;
1031 infostream<<mod.name<<" ";
1033 infostream<<std::endl;
1034 // Load and run "mod" scripts
1035 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1036 i != m_mods.end(); i++){
1037 const ModSpec &mod = *i;
1038 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1039 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1040 <<scriptpath<<"\"]"<<std::endl;
1041 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1043 errorstream<<"Server: Failed to load and run "
1044 <<scriptpath<<std::endl;
1045 throw ModError("Failed to load and run "+scriptpath);
1049 // Read Textures and calculate sha1 sums
1052 // Apply item aliases in the node definition manager
1053 m_nodedef->updateAliases(m_itemdef);
1055 // Initialize Environment
1057 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
1060 // Give environment reference to scripting api
1061 scriptapi_add_environment(m_lua, m_env);
1063 // Register us to receive map edit events
1064 m_env->getMap().addEventReceiver(this);
1066 // If file exists, load environment metadata
1067 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1069 infostream<<"Server: Loading environment metadata"<<std::endl;
1070 m_env->loadMeta(m_path_world);
1074 infostream<<"Server: Loading players"<<std::endl;
1075 m_env->deSerializePlayers(m_path_world);
1078 Add some test ActiveBlockModifiers to environment
1080 add_legacy_abms(m_env, m_nodedef);
1085 infostream<<"Server destructing"<<std::endl;
1088 Send shutdown message
1091 JMutexAutoLock conlock(m_con_mutex);
1093 std::wstring line = L"*** Server shutting down";
1096 Send the message to clients
1098 for(core::map<u16, RemoteClient*>::Iterator
1099 i = m_clients.getIterator();
1100 i.atEnd() == false; i++)
1102 // Get client and check that it is valid
1103 RemoteClient *client = i.getNode()->getValue();
1104 assert(client->peer_id == i.getNode()->getKey());
1105 if(client->serialization_version == SER_FMT_VER_INVALID)
1109 SendChatMessage(client->peer_id, line);
1111 catch(con::PeerNotFoundException &e)
1117 JMutexAutoLock envlock(m_env_mutex);
1122 infostream<<"Server: Saving players"<<std::endl;
1123 m_env->serializePlayers(m_path_world);
1126 Save environment metadata
1128 infostream<<"Server: Saving environment metadata"<<std::endl;
1129 m_env->saveMeta(m_path_world);
1141 JMutexAutoLock clientslock(m_con_mutex);
1143 for(core::map<u16, RemoteClient*>::Iterator
1144 i = m_clients.getIterator();
1145 i.atEnd() == false; i++)
1148 // NOTE: These are removed by env destructor
1150 u16 peer_id = i.getNode()->getKey();
1151 JMutexAutoLock envlock(m_env_mutex);
1152 m_env->removePlayer(peer_id);
1156 delete i.getNode()->getValue();
1160 // Delete things in the reverse order of creation
1168 // Deinitialize scripting
1169 infostream<<"Server: Deinitializing scripting"<<std::endl;
1170 script_deinit(m_lua);
1172 // Delete detached inventories
1174 for(std::map<std::string, Inventory*>::iterator
1175 i = m_detached_inventories.begin();
1176 i != m_detached_inventories.end(); i++){
1182 void Server::start(unsigned short port)
1184 DSTACK(__FUNCTION_NAME);
1185 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1187 // Stop thread if already running
1190 // Initialize connection
1191 m_con.SetTimeoutMs(30);
1195 m_thread.setRun(true);
1198 // ASCII art for the win!
1200 <<" .__ __ __ "<<std::endl
1201 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1202 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1203 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1204 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1205 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1206 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1207 actionstream<<"Server for gameid=\""<<m_gamespec.id
1208 <<"\" listening on port "<<port<<"."<<std::endl;
1213 DSTACK(__FUNCTION_NAME);
1215 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1217 // Stop threads (set run=false first so both start stopping)
1218 m_thread.setRun(false);
1219 m_emergethread.setRun(false);
1221 m_emergethread.stop();
1223 infostream<<"Server: Threads stopped"<<std::endl;
1226 void Server::step(float dtime)
1228 DSTACK(__FUNCTION_NAME);
1233 JMutexAutoLock lock(m_step_dtime_mutex);
1234 m_step_dtime += dtime;
1236 // Throw if fatal error occurred in thread
1237 std::string async_err = m_async_fatal_error.get();
1238 if(async_err != ""){
1239 throw ServerError(async_err);
1243 void Server::AsyncRunStep()
1245 DSTACK(__FUNCTION_NAME);
1247 g_profiler->add("Server::AsyncRunStep (num)", 1);
1251 JMutexAutoLock lock1(m_step_dtime_mutex);
1252 dtime = m_step_dtime;
1256 // Send blocks to clients
1263 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1265 //infostream<<"Server steps "<<dtime<<std::endl;
1266 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1269 JMutexAutoLock lock1(m_step_dtime_mutex);
1270 m_step_dtime -= dtime;
1277 m_uptime.set(m_uptime.get() + dtime);
1281 // Process connection's timeouts
1282 JMutexAutoLock lock2(m_con_mutex);
1283 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1284 m_con.RunTimeouts(dtime);
1288 // This has to be called so that the client list gets synced
1289 // with the peer list of the connection
1290 handlePeerChanges();
1294 Update time of day and overall game time
1297 JMutexAutoLock envlock(m_env_mutex);
1299 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1302 Send to clients at constant intervals
1305 m_time_of_day_send_timer -= dtime;
1306 if(m_time_of_day_send_timer < 0.0)
1308 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1310 //JMutexAutoLock envlock(m_env_mutex);
1311 JMutexAutoLock conlock(m_con_mutex);
1313 for(core::map<u16, RemoteClient*>::Iterator
1314 i = m_clients.getIterator();
1315 i.atEnd() == false; i++)
1317 RemoteClient *client = i.getNode()->getValue();
1318 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1319 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1321 m_con.Send(client->peer_id, 0, data, true);
1327 JMutexAutoLock lock(m_env_mutex);
1329 ScopeProfiler sp(g_profiler, "SEnv step");
1330 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1334 const float map_timer_and_unload_dtime = 2.92;
1335 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1337 JMutexAutoLock lock(m_env_mutex);
1338 // Run Map's timers and unload unused data
1339 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1340 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1341 g_settings->getFloat("server_unload_unused_data_timeout"));
1352 JMutexAutoLock lock(m_env_mutex);
1353 JMutexAutoLock lock2(m_con_mutex);
1355 ScopeProfiler sp(g_profiler, "Server: handle players");
1357 for(core::map<u16, RemoteClient*>::Iterator
1358 i = m_clients.getIterator();
1359 i.atEnd() == false; i++)
1361 RemoteClient *client = i.getNode()->getValue();
1362 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1363 if(playersao == NULL)
1367 Handle player HPs (die if hp=0)
1369 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
1370 DiePlayer(client->peer_id);
1373 Send player inventories and HPs if necessary
1375 if(playersao->m_teleported){
1376 SendMovePlayer(client->peer_id);
1377 playersao->m_teleported = false;
1379 if(playersao->m_inventory_not_sent){
1380 UpdateCrafting(client->peer_id);
1381 SendInventory(client->peer_id);
1383 if(playersao->m_hp_not_sent){
1384 SendPlayerHP(client->peer_id);
1389 /* Transform liquids */
1390 m_liquid_transform_timer += dtime;
1391 if(m_liquid_transform_timer >= 1.00)
1393 m_liquid_transform_timer -= 1.00;
1395 JMutexAutoLock lock(m_env_mutex);
1397 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1399 core::map<v3s16, MapBlock*> modified_blocks;
1400 m_env->getMap().transformLiquids(modified_blocks);
1405 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1406 ServerMap &map = ((ServerMap&)m_env->getMap());
1407 map.updateLighting(modified_blocks, lighting_modified_blocks);
1409 // Add blocks modified by lighting to modified_blocks
1410 for(core::map<v3s16, MapBlock*>::Iterator
1411 i = lighting_modified_blocks.getIterator();
1412 i.atEnd() == false; i++)
1414 MapBlock *block = i.getNode()->getValue();
1415 modified_blocks.insert(block->getPos(), block);
1419 Set the modified blocks unsent for all the clients
1422 JMutexAutoLock lock2(m_con_mutex);
1424 for(core::map<u16, RemoteClient*>::Iterator
1425 i = m_clients.getIterator();
1426 i.atEnd() == false; i++)
1428 RemoteClient *client = i.getNode()->getValue();
1430 if(modified_blocks.size() > 0)
1432 // Remove block from sent history
1433 client->SetBlocksNotSent(modified_blocks);
1438 // Periodically print some info
1440 float &counter = m_print_info_timer;
1446 JMutexAutoLock lock2(m_con_mutex);
1448 if(m_clients.size() != 0)
1449 infostream<<"Players:"<<std::endl;
1450 for(core::map<u16, RemoteClient*>::Iterator
1451 i = m_clients.getIterator();
1452 i.atEnd() == false; i++)
1454 //u16 peer_id = i.getNode()->getKey();
1455 RemoteClient *client = i.getNode()->getValue();
1456 Player *player = m_env->getPlayer(client->peer_id);
1459 infostream<<"* "<<player->getName()<<"\t";
1460 client->PrintInfo(infostream);
1465 //if(g_settings->getBool("enable_experimental"))
1469 Check added and deleted active objects
1472 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1473 JMutexAutoLock envlock(m_env_mutex);
1474 JMutexAutoLock conlock(m_con_mutex);
1476 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1478 // Radius inside which objects are active
1479 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1480 radius *= MAP_BLOCKSIZE;
1482 for(core::map<u16, RemoteClient*>::Iterator
1483 i = m_clients.getIterator();
1484 i.atEnd() == false; i++)
1486 RemoteClient *client = i.getNode()->getValue();
1488 // If definitions and textures have not been sent, don't
1489 // send objects either
1490 if(!client->definitions_sent)
1493 Player *player = m_env->getPlayer(client->peer_id);
1496 // This can happen if the client timeouts somehow
1497 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1499 <<" has no associated player"<<std::endl;*/
1502 v3s16 pos = floatToInt(player->getPosition(), BS);
1504 core::map<u16, bool> removed_objects;
1505 core::map<u16, bool> added_objects;
1506 m_env->getRemovedActiveObjects(pos, radius,
1507 client->m_known_objects, removed_objects);
1508 m_env->getAddedActiveObjects(pos, radius,
1509 client->m_known_objects, added_objects);
1511 // Ignore if nothing happened
1512 if(removed_objects.size() == 0 && added_objects.size() == 0)
1514 //infostream<<"active objects: none changed"<<std::endl;
1518 std::string data_buffer;
1522 // Handle removed objects
1523 writeU16((u8*)buf, removed_objects.size());
1524 data_buffer.append(buf, 2);
1525 for(core::map<u16, bool>::Iterator
1526 i = removed_objects.getIterator();
1527 i.atEnd()==false; i++)
1530 u16 id = i.getNode()->getKey();
1531 ServerActiveObject* obj = m_env->getActiveObject(id);
1533 // Add to data buffer for sending
1534 writeU16((u8*)buf, i.getNode()->getKey());
1535 data_buffer.append(buf, 2);
1537 // Remove from known objects
1538 client->m_known_objects.remove(i.getNode()->getKey());
1540 if(obj && obj->m_known_by_count > 0)
1541 obj->m_known_by_count--;
1544 // Handle added objects
1545 writeU16((u8*)buf, added_objects.size());
1546 data_buffer.append(buf, 2);
1547 for(core::map<u16, bool>::Iterator
1548 i = added_objects.getIterator();
1549 i.atEnd()==false; i++)
1552 u16 id = i.getNode()->getKey();
1553 ServerActiveObject* obj = m_env->getActiveObject(id);
1556 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1558 infostream<<"WARNING: "<<__FUNCTION_NAME
1559 <<": NULL object"<<std::endl;
1561 type = obj->getSendType();
1563 // Add to data buffer for sending
1564 writeU16((u8*)buf, id);
1565 data_buffer.append(buf, 2);
1566 writeU8((u8*)buf, type);
1567 data_buffer.append(buf, 1);
1570 data_buffer.append(serializeLongString(
1571 obj->getClientInitializationData()));
1573 data_buffer.append(serializeLongString(""));
1575 // Add to known objects
1576 client->m_known_objects.insert(i.getNode()->getKey(), false);
1579 obj->m_known_by_count++;
1583 SharedBuffer<u8> reply(2 + data_buffer.size());
1584 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1585 memcpy((char*)&reply[2], data_buffer.c_str(),
1586 data_buffer.size());
1588 m_con.Send(client->peer_id, 0, reply, true);
1590 verbosestream<<"Server: Sent object remove/add: "
1591 <<removed_objects.size()<<" removed, "
1592 <<added_objects.size()<<" added, "
1593 <<"packet size is "<<reply.getSize()<<std::endl;
1598 Collect a list of all the objects known by the clients
1599 and report it back to the environment.
1602 core::map<u16, bool> all_known_objects;
1604 for(core::map<u16, RemoteClient*>::Iterator
1605 i = m_clients.getIterator();
1606 i.atEnd() == false; i++)
1608 RemoteClient *client = i.getNode()->getValue();
1609 // Go through all known objects of client
1610 for(core::map<u16, bool>::Iterator
1611 i = client->m_known_objects.getIterator();
1612 i.atEnd()==false; i++)
1614 u16 id = i.getNode()->getKey();
1615 all_known_objects[id] = true;
1619 m_env->setKnownActiveObjects(whatever);
1625 Send object messages
1628 JMutexAutoLock envlock(m_env_mutex);
1629 JMutexAutoLock conlock(m_con_mutex);
1631 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1634 // Value = data sent by object
1635 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1637 // Get active object messages from environment
1640 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1644 core::list<ActiveObjectMessage>* message_list = NULL;
1645 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1646 n = buffered_messages.find(aom.id);
1649 message_list = new core::list<ActiveObjectMessage>;
1650 buffered_messages.insert(aom.id, message_list);
1654 message_list = n->getValue();
1656 message_list->push_back(aom);
1659 // Route data to every client
1660 for(core::map<u16, RemoteClient*>::Iterator
1661 i = m_clients.getIterator();
1662 i.atEnd()==false; i++)
1664 RemoteClient *client = i.getNode()->getValue();
1665 std::string reliable_data;
1666 std::string unreliable_data;
1667 // Go through all objects in message buffer
1668 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1669 j = buffered_messages.getIterator();
1670 j.atEnd()==false; j++)
1672 // If object is not known by client, skip it
1673 u16 id = j.getNode()->getKey();
1674 if(client->m_known_objects.find(id) == NULL)
1676 // Get message list of object
1677 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1678 // Go through every message
1679 for(core::list<ActiveObjectMessage>::Iterator
1680 k = list->begin(); k != list->end(); k++)
1682 // Compose the full new data with header
1683 ActiveObjectMessage aom = *k;
1684 std::string new_data;
1687 writeU16((u8*)&buf[0], aom.id);
1688 new_data.append(buf, 2);
1690 new_data += serializeString(aom.datastring);
1691 // Add data to buffer
1693 reliable_data += new_data;
1695 unreliable_data += new_data;
1699 reliable_data and unreliable_data are now ready.
1702 if(reliable_data.size() > 0)
1704 SharedBuffer<u8> reply(2 + reliable_data.size());
1705 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1706 memcpy((char*)&reply[2], reliable_data.c_str(),
1707 reliable_data.size());
1709 m_con.Send(client->peer_id, 0, reply, true);
1711 if(unreliable_data.size() > 0)
1713 SharedBuffer<u8> reply(2 + unreliable_data.size());
1714 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1715 memcpy((char*)&reply[2], unreliable_data.c_str(),
1716 unreliable_data.size());
1717 // Send as unreliable
1718 m_con.Send(client->peer_id, 0, reply, false);
1721 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1723 infostream<<"Server: Size of object message data: "
1724 <<"reliable: "<<reliable_data.size()
1725 <<", unreliable: "<<unreliable_data.size()
1730 // Clear buffered_messages
1731 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1732 i = buffered_messages.getIterator();
1733 i.atEnd()==false; i++)
1735 delete i.getNode()->getValue();
1739 } // enable_experimental
1742 Send queued-for-sending map edit events.
1745 // We will be accessing the environment and the connection
1746 JMutexAutoLock lock(m_env_mutex);
1747 JMutexAutoLock conlock(m_con_mutex);
1749 // Don't send too many at a time
1752 // Single change sending is disabled if queue size is not small
1753 bool disable_single_change_sending = false;
1754 if(m_unsent_map_edit_queue.size() >= 4)
1755 disable_single_change_sending = true;
1757 int event_count = m_unsent_map_edit_queue.size();
1759 // We'll log the amount of each
1762 while(m_unsent_map_edit_queue.size() != 0)
1764 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1766 // Players far away from the change are stored here.
1767 // Instead of sending the changes, MapBlocks are set not sent
1769 core::list<u16> far_players;
1771 if(event->type == MEET_ADDNODE)
1773 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1774 prof.add("MEET_ADDNODE", 1);
1775 if(disable_single_change_sending)
1776 sendAddNode(event->p, event->n, event->already_known_by_peer,
1779 sendAddNode(event->p, event->n, event->already_known_by_peer,
1782 else if(event->type == MEET_REMOVENODE)
1784 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1785 prof.add("MEET_REMOVENODE", 1);
1786 if(disable_single_change_sending)
1787 sendRemoveNode(event->p, event->already_known_by_peer,
1790 sendRemoveNode(event->p, event->already_known_by_peer,
1793 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1795 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1796 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1797 setBlockNotSent(event->p);
1799 else if(event->type == MEET_OTHER)
1801 infostream<<"Server: MEET_OTHER"<<std::endl;
1802 prof.add("MEET_OTHER", 1);
1803 for(core::map<v3s16, bool>::Iterator
1804 i = event->modified_blocks.getIterator();
1805 i.atEnd()==false; i++)
1807 v3s16 p = i.getNode()->getKey();
1813 prof.add("unknown", 1);
1814 infostream<<"WARNING: Server: Unknown MapEditEvent "
1815 <<((u32)event->type)<<std::endl;
1819 Set blocks not sent to far players
1821 if(far_players.size() > 0)
1823 // Convert list format to that wanted by SetBlocksNotSent
1824 core::map<v3s16, MapBlock*> modified_blocks2;
1825 for(core::map<v3s16, bool>::Iterator
1826 i = event->modified_blocks.getIterator();
1827 i.atEnd()==false; i++)
1829 v3s16 p = i.getNode()->getKey();
1830 modified_blocks2.insert(p,
1831 m_env->getMap().getBlockNoCreateNoEx(p));
1833 // Set blocks not sent
1834 for(core::list<u16>::Iterator
1835 i = far_players.begin();
1836 i != far_players.end(); i++)
1839 RemoteClient *client = getClient(peer_id);
1842 client->SetBlocksNotSent(modified_blocks2);
1848 /*// Don't send too many at a time
1850 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1854 if(event_count >= 5){
1855 infostream<<"Server: MapEditEvents:"<<std::endl;
1856 prof.print(infostream);
1857 } else if(event_count != 0){
1858 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1859 prof.print(verbosestream);
1865 Trigger emergethread (it somehow gets to a non-triggered but
1866 bysy state sometimes)
1869 float &counter = m_emergethread_trigger_timer;
1875 m_emergethread.trigger();
1879 // Save map, players and auth stuff
1881 float &counter = m_savemap_timer;
1883 if(counter >= g_settings->getFloat("server_map_save_interval"))
1886 JMutexAutoLock lock(m_env_mutex);
1888 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1891 if(m_banmanager.isModified())
1892 m_banmanager.save();
1894 // Save changed parts of map
1895 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1898 m_env->serializePlayers(m_path_world);
1900 // Save environment metadata
1901 m_env->saveMeta(m_path_world);
1906 void Server::Receive()
1908 DSTACK(__FUNCTION_NAME);
1909 SharedBuffer<u8> data;
1914 JMutexAutoLock conlock(m_con_mutex);
1915 datasize = m_con.Receive(peer_id, data);
1918 // This has to be called so that the client list gets synced
1919 // with the peer list of the connection
1920 handlePeerChanges();
1922 ProcessData(*data, datasize, peer_id);
1924 catch(con::InvalidIncomingDataException &e)
1926 infostream<<"Server::Receive(): "
1927 "InvalidIncomingDataException: what()="
1928 <<e.what()<<std::endl;
1930 catch(con::PeerNotFoundException &e)
1932 //NOTE: This is not needed anymore
1934 // The peer has been disconnected.
1935 // Find the associated player and remove it.
1937 /*JMutexAutoLock envlock(m_env_mutex);
1939 infostream<<"ServerThread: peer_id="<<peer_id
1940 <<" has apparently closed connection. "
1941 <<"Removing player."<<std::endl;
1943 m_env->removePlayer(peer_id);*/
1947 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1949 DSTACK(__FUNCTION_NAME);
1950 // Environment is locked first.
1951 JMutexAutoLock envlock(m_env_mutex);
1952 JMutexAutoLock conlock(m_con_mutex);
1954 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1957 Address address = m_con.GetPeerAddress(peer_id);
1958 std::string addr_s = address.serializeString();
1960 // drop player if is ip is banned
1961 if(m_banmanager.isIpBanned(addr_s)){
1962 infostream<<"Server: A banned client tried to connect from "
1963 <<addr_s<<"; banned name was "
1964 <<m_banmanager.getBanName(addr_s)<<std::endl;
1965 // This actually doesn't seem to transfer to the client
1966 SendAccessDenied(m_con, peer_id,
1967 L"Your ip is banned. Banned name was "
1968 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1969 m_con.DeletePeer(peer_id);
1973 catch(con::PeerNotFoundException &e)
1975 infostream<<"Server::ProcessData(): Cancelling: peer "
1976 <<peer_id<<" not found"<<std::endl;
1980 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1982 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1990 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1992 if(command == TOSERVER_INIT)
1994 // [0] u16 TOSERVER_INIT
1995 // [2] u8 SER_FMT_VER_HIGHEST
1996 // [3] u8[20] player_name
1997 // [23] u8[28] password <--- can be sent without this, from old versions
1999 if(datasize < 2+1+PLAYERNAME_SIZE)
2002 verbosestream<<"Server: Got TOSERVER_INIT from "
2003 <<peer_id<<std::endl;
2005 // First byte after command is maximum supported
2006 // serialization version
2007 u8 client_max = data[2];
2008 u8 our_max = SER_FMT_VER_HIGHEST;
2009 // Use the highest version supported by both
2010 u8 deployed = core::min_(client_max, our_max);
2011 // If it's lower than the lowest supported, give up.
2012 if(deployed < SER_FMT_VER_LOWEST)
2013 deployed = SER_FMT_VER_INVALID;
2015 //peer->serialization_version = deployed;
2016 getClient(peer_id)->pending_serialization_version = deployed;
2018 if(deployed == SER_FMT_VER_INVALID)
2020 actionstream<<"Server: A mismatched client tried to connect from "
2021 <<addr_s<<std::endl;
2022 infostream<<"Server: Cannot negotiate "
2023 "serialization version with peer "
2024 <<peer_id<<std::endl;
2025 SendAccessDenied(m_con, peer_id, std::wstring(
2026 L"Your client's version is not supported.\n"
2027 L"Server version is ")
2028 + narrow_to_wide(VERSION_STRING) + L"."
2034 Read and check network protocol version
2037 u16 net_proto_version = 0;
2038 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2040 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2043 getClient(peer_id)->net_proto_version = net_proto_version;
2045 if(net_proto_version == 0)
2047 actionstream<<"Server: An old tried to connect from "<<addr_s
2049 SendAccessDenied(m_con, peer_id, std::wstring(
2050 L"Your client's version is not supported.\n"
2051 L"Server version is ")
2052 + narrow_to_wide(VERSION_STRING) + L"."
2057 if(g_settings->getBool("strict_protocol_version_checking"))
2059 if(net_proto_version != PROTOCOL_VERSION)
2061 actionstream<<"Server: A mismatched client tried to connect"
2062 <<" from "<<addr_s<<std::endl;
2063 SendAccessDenied(m_con, peer_id, std::wstring(
2064 L"Your client's version is not supported.\n"
2065 L"Server version is ")
2066 + narrow_to_wide(VERSION_STRING) + L",\n"
2067 + L"server's PROTOCOL_VERSION is "
2068 + narrow_to_wide(itos(PROTOCOL_VERSION))
2069 + L", client's PROTOCOL_VERSION is "
2070 + narrow_to_wide(itos(net_proto_version))
2081 char playername[PLAYERNAME_SIZE];
2082 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2084 playername[i] = data[3+i];
2086 playername[PLAYERNAME_SIZE-1] = 0;
2088 if(playername[0]=='\0')
2090 actionstream<<"Server: Player with an empty name "
2091 <<"tried to connect from "<<addr_s<<std::endl;
2092 SendAccessDenied(m_con, peer_id,
2097 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2099 actionstream<<"Server: Player with an invalid name "
2100 <<"tried to connect from "<<addr_s<<std::endl;
2101 SendAccessDenied(m_con, peer_id,
2102 L"Name contains unallowed characters");
2106 infostream<<"Server: New connection: \""<<playername<<"\" from "
2107 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2110 char given_password[PASSWORD_SIZE];
2111 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2113 // old version - assume blank password
2114 given_password[0] = 0;
2118 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2120 given_password[i] = data[23+i];
2122 given_password[PASSWORD_SIZE-1] = 0;
2125 if(!base64_is_valid(given_password)){
2126 infostream<<"Server: "<<playername
2127 <<" supplied invalid password hash"<<std::endl;
2128 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2132 std::string checkpwd; // Password hash to check against
2133 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2135 // If no authentication info exists for user, create it
2137 if(!isSingleplayer() &&
2138 g_settings->getBool("disallow_empty_password") &&
2139 std::string(given_password) == ""){
2140 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2141 L"disallowed. Set a password and try again.");
2144 std::wstring raw_default_password =
2145 narrow_to_wide(g_settings->get("default_password"));
2146 std::string initial_password =
2147 translatePassword(playername, raw_default_password);
2149 // If default_password is empty, allow any initial password
2150 if (raw_default_password.length() == 0)
2151 initial_password = given_password;
2153 scriptapi_create_auth(m_lua, playername, initial_password);
2156 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2159 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2163 if(given_password != checkpwd){
2164 infostream<<"Server: peer_id="<<peer_id
2165 <<": supplied invalid password for "
2166 <<playername<<std::endl;
2167 SendAccessDenied(m_con, peer_id, L"Invalid password");
2171 // Do not allow multiple players in simple singleplayer mode.
2172 // This isn't a perfect way to do it, but will suffice for now.
2173 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2174 infostream<<"Server: Not allowing another client to connect in"
2175 <<" simple singleplayer mode"<<std::endl;
2176 SendAccessDenied(m_con, peer_id,
2177 L"Running in simple singleplayer mode.");
2181 // Enforce user limit.
2182 // Don't enforce for users that have some admin right
2183 if(m_clients.size() >= g_settings->getU16("max_users") &&
2184 !checkPriv(playername, "server") &&
2185 !checkPriv(playername, "ban") &&
2186 !checkPriv(playername, "privs") &&
2187 !checkPriv(playername, "password") &&
2188 playername != g_settings->get("name"))
2190 actionstream<<"Server: "<<playername<<" tried to join, but there"
2191 <<" are already max_users="
2192 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2193 SendAccessDenied(m_con, peer_id, L"Too many users.");
2198 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2200 // If failed, cancel
2201 if(playersao == NULL)
2203 errorstream<<"Server: peer_id="<<peer_id
2204 <<": failed to emerge player"<<std::endl;
2209 Answer with a TOCLIENT_INIT
2212 SharedBuffer<u8> reply(2+1+6+8);
2213 writeU16(&reply[0], TOCLIENT_INIT);
2214 writeU8(&reply[2], deployed);
2215 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2216 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2219 m_con.Send(peer_id, 0, reply, true);
2223 Send complete position information
2225 SendMovePlayer(peer_id);
2230 if(command == TOSERVER_INIT2)
2232 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2233 <<peer_id<<std::endl;
2235 Player *player = m_env->getPlayer(peer_id);
2237 verbosestream<<"Server: TOSERVER_INIT2: "
2238 <<"Player not found; ignoring."<<std::endl;
2242 getClient(peer_id)->serialization_version
2243 = getClient(peer_id)->pending_serialization_version;
2246 Send some initialization data
2249 infostream<<"Server: Sending content to "
2250 <<getPlayerName(peer_id)<<std::endl;
2252 // Send item definitions
2253 SendItemDef(m_con, peer_id, m_itemdef);
2255 // Send node definitions
2256 SendNodeDef(m_con, peer_id, m_nodedef);
2258 // Send media announcement
2259 sendMediaAnnouncement(peer_id);
2262 SendPlayerPrivileges(peer_id);
2264 // Send inventory formspec
2265 SendPlayerInventoryFormspec(peer_id);
2268 UpdateCrafting(peer_id);
2269 SendInventory(peer_id);
2272 SendPlayerHP(peer_id);
2274 // Send detached inventories
2275 sendDetachedInventories(peer_id);
2277 // Show death screen if necessary
2279 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2283 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2284 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2285 m_con.Send(peer_id, 0, data, true);
2288 // Note things in chat if not in simple singleplayer mode
2289 if(!m_simple_singleplayer_mode)
2291 // Send information about server to player in chat
2292 SendChatMessage(peer_id, getStatusString());
2294 // Send information about joining in chat
2296 std::wstring name = L"unknown";
2297 Player *player = m_env->getPlayer(peer_id);
2299 name = narrow_to_wide(player->getName());
2301 std::wstring message;
2304 message += L" joined the game.";
2305 BroadcastChatMessage(message);
2309 // Warnings about protocol version can be issued here
2310 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2312 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER!");
2319 std::ostringstream os(std::ios_base::binary);
2320 for(core::map<u16, RemoteClient*>::Iterator
2321 i = m_clients.getIterator();
2322 i.atEnd() == false; i++)
2324 RemoteClient *client = i.getNode()->getValue();
2325 assert(client->peer_id == i.getNode()->getKey());
2326 if(client->serialization_version == SER_FMT_VER_INVALID)
2329 Player *player = m_env->getPlayer(client->peer_id);
2332 // Get name of player
2333 os<<player->getName()<<" ";
2336 actionstream<<player->getName()<<" joins game. List of players: "
2337 <<os.str()<<std::endl;
2343 if(peer_ser_ver == SER_FMT_VER_INVALID)
2345 infostream<<"Server::ProcessData(): Cancelling: Peer"
2346 " serialization format invalid or not initialized."
2347 " Skipping incoming command="<<command<<std::endl;
2351 Player *player = m_env->getPlayer(peer_id);
2353 infostream<<"Server::ProcessData(): Cancelling: "
2354 "No player for peer_id="<<peer_id
2359 PlayerSAO *playersao = player->getPlayerSAO();
2360 if(playersao == NULL){
2361 infostream<<"Server::ProcessData(): Cancelling: "
2362 "No player object for peer_id="<<peer_id
2367 if(command == TOSERVER_PLAYERPOS)
2369 if(datasize < 2+12+12+4+4)
2373 v3s32 ps = readV3S32(&data[start+2]);
2374 v3s32 ss = readV3S32(&data[start+2+12]);
2375 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2376 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2377 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2378 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2379 pitch = wrapDegrees(pitch);
2380 yaw = wrapDegrees(yaw);
2382 player->setPosition(position);
2383 player->setSpeed(speed);
2384 player->setPitch(pitch);
2385 player->setYaw(yaw);
2387 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2388 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2389 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2391 else if(command == TOSERVER_GOTBLOCKS)
2404 u16 count = data[2];
2405 for(u16 i=0; i<count; i++)
2407 if((s16)datasize < 2+1+(i+1)*6)
2408 throw con::InvalidIncomingDataException
2409 ("GOTBLOCKS length is too short");
2410 v3s16 p = readV3S16(&data[2+1+i*6]);
2411 /*infostream<<"Server: GOTBLOCKS ("
2412 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2413 RemoteClient *client = getClient(peer_id);
2414 client->GotBlock(p);
2417 else if(command == TOSERVER_DELETEDBLOCKS)
2430 u16 count = data[2];
2431 for(u16 i=0; i<count; i++)
2433 if((s16)datasize < 2+1+(i+1)*6)
2434 throw con::InvalidIncomingDataException
2435 ("DELETEDBLOCKS length is too short");
2436 v3s16 p = readV3S16(&data[2+1+i*6]);
2437 /*infostream<<"Server: DELETEDBLOCKS ("
2438 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2439 RemoteClient *client = getClient(peer_id);
2440 client->SetBlockNotSent(p);
2443 else if(command == TOSERVER_CLICK_OBJECT)
2445 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2448 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2450 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2453 else if(command == TOSERVER_GROUND_ACTION)
2455 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2459 else if(command == TOSERVER_RELEASE)
2461 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2464 else if(command == TOSERVER_SIGNTEXT)
2466 infostream<<"Server: SIGNTEXT not supported anymore"
2470 else if(command == TOSERVER_SIGNNODETEXT)
2472 infostream<<"Server: SIGNNODETEXT not supported anymore"
2476 else if(command == TOSERVER_INVENTORY_ACTION)
2478 // Strip command and create a stream
2479 std::string datastring((char*)&data[2], datasize-2);
2480 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2481 std::istringstream is(datastring, std::ios_base::binary);
2483 InventoryAction *a = InventoryAction::deSerialize(is);
2486 infostream<<"TOSERVER_INVENTORY_ACTION: "
2487 <<"InventoryAction::deSerialize() returned NULL"
2492 // If something goes wrong, this player is to blame
2493 RollbackScopeActor rollback_scope(m_rollback,
2494 std::string("player:")+player->getName());
2497 Note: Always set inventory not sent, to repair cases
2498 where the client made a bad prediction.
2502 Handle restrictions and special cases of the move action
2504 if(a->getType() == IACTION_MOVE)
2506 IMoveAction *ma = (IMoveAction*)a;
2508 ma->from_inv.applyCurrentPlayer(player->getName());
2509 ma->to_inv.applyCurrentPlayer(player->getName());
2511 setInventoryModified(ma->from_inv);
2512 setInventoryModified(ma->to_inv);
2514 bool from_inv_is_current_player =
2515 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2516 (ma->from_inv.name == player->getName());
2518 bool to_inv_is_current_player =
2519 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2520 (ma->to_inv.name == player->getName());
2523 Disable moving items out of craftpreview
2525 if(ma->from_list == "craftpreview")
2527 infostream<<"Ignoring IMoveAction from "
2528 <<(ma->from_inv.dump())<<":"<<ma->from_list
2529 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2530 <<" because src is "<<ma->from_list<<std::endl;
2536 Disable moving items into craftresult and craftpreview
2538 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2540 infostream<<"Ignoring IMoveAction from "
2541 <<(ma->from_inv.dump())<<":"<<ma->from_list
2542 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2543 <<" because dst is "<<ma->to_list<<std::endl;
2548 // Disallow moving items in elsewhere than player's inventory
2549 // if not allowed to interact
2550 if(!checkPriv(player->getName(), "interact") &&
2551 (!from_inv_is_current_player ||
2552 !to_inv_is_current_player))
2554 infostream<<"Cannot move outside of player's inventory: "
2555 <<"No interact privilege"<<std::endl;
2561 Handle restrictions and special cases of the drop action
2563 else if(a->getType() == IACTION_DROP)
2565 IDropAction *da = (IDropAction*)a;
2567 da->from_inv.applyCurrentPlayer(player->getName());
2569 setInventoryModified(da->from_inv);
2571 // Disallow dropping items if not allowed to interact
2572 if(!checkPriv(player->getName(), "interact"))
2579 Handle restrictions and special cases of the craft action
2581 else if(a->getType() == IACTION_CRAFT)
2583 ICraftAction *ca = (ICraftAction*)a;
2585 ca->craft_inv.applyCurrentPlayer(player->getName());
2587 setInventoryModified(ca->craft_inv);
2589 //bool craft_inv_is_current_player =
2590 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2591 // (ca->craft_inv.name == player->getName());
2593 // Disallow crafting if not allowed to interact
2594 if(!checkPriv(player->getName(), "interact"))
2596 infostream<<"Cannot craft: "
2597 <<"No interact privilege"<<std::endl;
2604 a->apply(this, playersao, this);
2608 else if(command == TOSERVER_CHAT_MESSAGE)
2616 std::string datastring((char*)&data[2], datasize-2);
2617 std::istringstream is(datastring, std::ios_base::binary);
2620 is.read((char*)buf, 2);
2621 u16 len = readU16(buf);
2623 std::wstring message;
2624 for(u16 i=0; i<len; i++)
2626 is.read((char*)buf, 2);
2627 message += (wchar_t)readU16(buf);
2630 // Get player name of this client
2631 std::wstring name = narrow_to_wide(player->getName());
2634 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2635 wide_to_narrow(message));
2636 // If script ate the message, don't proceed
2640 // Line to send to players
2642 // Whether to send to the player that sent the line
2643 bool send_to_sender = false;
2644 // Whether to send to other players
2645 bool send_to_others = false;
2648 if(message[0] == L'/')
2650 size_t strip_size = 1;
2651 if (message[1] == L'#') // support old-style commans
2653 message = message.substr(strip_size);
2655 WStrfnd f1(message);
2656 f1.next(L" "); // Skip over /#whatever
2657 std::wstring paramstring = f1.next(L"");
2659 ServerCommandContext *ctx = new ServerCommandContext(
2660 str_split(message, L' '),
2666 std::wstring reply(processServerCommand(ctx));
2667 send_to_sender = ctx->flags & SEND_TO_SENDER;
2668 send_to_others = ctx->flags & SEND_TO_OTHERS;
2670 if (ctx->flags & SEND_NO_PREFIX)
2673 line += L"Server: " + reply;
2680 if(checkPriv(player->getName(), "shout")){
2685 send_to_others = true;
2687 line += L"-!- You don't have permission to shout.";
2688 send_to_sender = true;
2695 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2698 Send the message to clients
2700 for(core::map<u16, RemoteClient*>::Iterator
2701 i = m_clients.getIterator();
2702 i.atEnd() == false; i++)
2704 // Get client and check that it is valid
2705 RemoteClient *client = i.getNode()->getValue();
2706 assert(client->peer_id == i.getNode()->getKey());
2707 if(client->serialization_version == SER_FMT_VER_INVALID)
2711 bool sender_selected = (peer_id == client->peer_id);
2712 if(sender_selected == true && send_to_sender == false)
2714 if(sender_selected == false && send_to_others == false)
2717 SendChatMessage(client->peer_id, line);
2721 else if(command == TOSERVER_DAMAGE)
2723 std::string datastring((char*)&data[2], datasize-2);
2724 std::istringstream is(datastring, std::ios_base::binary);
2725 u8 damage = readU8(is);
2727 actionstream<<player->getName()<<" damaged by "
2728 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2731 playersao->setHP(playersao->getHP() - damage);
2733 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2736 if(playersao->m_hp_not_sent)
2737 SendPlayerHP(peer_id);
2739 else if(command == TOSERVER_PASSWORD)
2742 [0] u16 TOSERVER_PASSWORD
2743 [2] u8[28] old password
2744 [30] u8[28] new password
2747 if(datasize != 2+PASSWORD_SIZE*2)
2749 /*char password[PASSWORD_SIZE];
2750 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2751 password[i] = data[2+i];
2752 password[PASSWORD_SIZE-1] = 0;*/
2754 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2762 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2764 char c = data[2+PASSWORD_SIZE+i];
2770 if(!base64_is_valid(newpwd)){
2771 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2772 // Wrong old password supplied!!
2773 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2777 infostream<<"Server: Client requests a password change from "
2778 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2780 std::string playername = player->getName();
2782 std::string checkpwd;
2783 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2785 if(oldpwd != checkpwd)
2787 infostream<<"Server: invalid old password"<<std::endl;
2788 // Wrong old password supplied!!
2789 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2793 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2795 actionstream<<player->getName()<<" changes password"<<std::endl;
2796 SendChatMessage(peer_id, L"Password change successful.");
2798 actionstream<<player->getName()<<" tries to change password but "
2799 <<"it fails"<<std::endl;
2800 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2803 else if(command == TOSERVER_PLAYERITEM)
2808 u16 item = readU16(&data[2]);
2809 playersao->setWieldIndex(item);
2811 else if(command == TOSERVER_RESPAWN)
2816 RespawnPlayer(peer_id);
2818 actionstream<<player->getName()<<" respawns at "
2819 <<PP(player->getPosition()/BS)<<std::endl;
2821 // ActiveObject is added to environment in AsyncRunStep after
2822 // the previous addition has been succesfully removed
2824 else if(command == TOSERVER_REQUEST_MEDIA) {
2825 std::string datastring((char*)&data[2], datasize-2);
2826 std::istringstream is(datastring, std::ios_base::binary);
2828 core::list<MediaRequest> tosend;
2829 u16 numfiles = readU16(is);
2831 infostream<<"Sending "<<numfiles<<" files to "
2832 <<getPlayerName(peer_id)<<std::endl;
2833 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2835 for(int i = 0; i < numfiles; i++) {
2836 std::string name = deSerializeString(is);
2837 tosend.push_back(MediaRequest(name));
2838 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2842 sendRequestedMedia(peer_id, tosend);
2844 // Now the client should know about everything
2845 // (definitions and files)
2846 getClient(peer_id)->definitions_sent = true;
2848 else if(command == TOSERVER_INTERACT)
2850 std::string datastring((char*)&data[2], datasize-2);
2851 std::istringstream is(datastring, std::ios_base::binary);
2857 [5] u32 length of the next item
2858 [9] serialized PointedThing
2860 0: start digging (from undersurface) or use
2861 1: stop digging (all parameters ignored)
2862 2: digging completed
2863 3: place block or item (to abovesurface)
2866 u8 action = readU8(is);
2867 u16 item_i = readU16(is);
2868 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2869 PointedThing pointed;
2870 pointed.deSerialize(tmp_is);
2872 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2873 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2877 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2878 <<" tried to interact, but is dead!"<<std::endl;
2882 v3f player_pos = playersao->getLastGoodPosition();
2884 // Update wielded item
2885 playersao->setWieldIndex(item_i);
2887 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2888 v3s16 p_under = pointed.node_undersurface;
2889 v3s16 p_above = pointed.node_abovesurface;
2891 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2892 ServerActiveObject *pointed_object = NULL;
2893 if(pointed.type == POINTEDTHING_OBJECT)
2895 pointed_object = m_env->getActiveObject(pointed.object_id);
2896 if(pointed_object == NULL)
2898 verbosestream<<"TOSERVER_INTERACT: "
2899 "pointed object is NULL"<<std::endl;
2905 v3f pointed_pos_under = player_pos;
2906 v3f pointed_pos_above = player_pos;
2907 if(pointed.type == POINTEDTHING_NODE)
2909 pointed_pos_under = intToFloat(p_under, BS);
2910 pointed_pos_above = intToFloat(p_above, BS);
2912 else if(pointed.type == POINTEDTHING_OBJECT)
2914 pointed_pos_under = pointed_object->getBasePosition();
2915 pointed_pos_above = pointed_pos_under;
2919 Check that target is reasonably close
2920 (only when digging or placing things)
2922 if(action == 0 || action == 2 || action == 3)
2924 float d = player_pos.getDistanceFrom(pointed_pos_under);
2925 float max_d = BS * 14; // Just some large enough value
2927 actionstream<<"Player "<<player->getName()
2928 <<" tried to access "<<pointed.dump()
2930 <<"d="<<d<<", max_d="<<max_d
2931 <<". ignoring."<<std::endl;
2932 // Re-send block to revert change on client-side
2933 RemoteClient *client = getClient(peer_id);
2934 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2935 client->SetBlockNotSent(blockpos);
2942 Make sure the player is allowed to do it
2944 if(!checkPriv(player->getName(), "interact"))
2946 actionstream<<player->getName()<<" attempted to interact with "
2947 <<pointed.dump()<<" without 'interact' privilege"
2949 // Re-send block to revert change on client-side
2950 RemoteClient *client = getClient(peer_id);
2951 // Digging completed -> under
2953 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2954 client->SetBlockNotSent(blockpos);
2956 // Placement -> above
2958 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2959 client->SetBlockNotSent(blockpos);
2965 If something goes wrong, this player is to blame
2967 RollbackScopeActor rollback_scope(m_rollback,
2968 std::string("player:")+player->getName());
2971 0: start digging or punch object
2975 if(pointed.type == POINTEDTHING_NODE)
2978 NOTE: This can be used in the future to check if
2979 somebody is cheating, by checking the timing.
2981 MapNode n(CONTENT_IGNORE);
2984 n = m_env->getMap().getNode(p_under);
2986 catch(InvalidPositionException &e)
2988 infostream<<"Server: Not punching: Node not found."
2989 <<" Adding block to emerge queue."
2991 m_emerge_queue.addBlock(peer_id,
2992 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2994 if(n.getContent() != CONTENT_IGNORE)
2995 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
2997 playersao->noCheatDigStart(p_under);
2999 else if(pointed.type == POINTEDTHING_OBJECT)
3001 // Skip if object has been removed
3002 if(pointed_object->m_removed)
3005 actionstream<<player->getName()<<" punches object "
3006 <<pointed.object_id<<": "
3007 <<pointed_object->getDescription()<<std::endl;
3009 ItemStack punchitem = playersao->getWieldedItem();
3010 ToolCapabilities toolcap =
3011 punchitem.getToolCapabilities(m_itemdef);
3012 v3f dir = (pointed_object->getBasePosition() -
3013 (player->getPosition() + player->getEyeOffset())
3015 float time_from_last_punch =
3016 playersao->resetTimeFromLastPunch();
3017 pointed_object->punch(dir, &toolcap, playersao,
3018 time_from_last_punch);
3026 else if(action == 1)
3031 2: Digging completed
3033 else if(action == 2)
3035 // Only digging of nodes
3036 if(pointed.type == POINTEDTHING_NODE)
3038 MapNode n(CONTENT_IGNORE);
3041 n = m_env->getMap().getNode(p_under);
3043 catch(InvalidPositionException &e)
3045 infostream<<"Server: Not finishing digging: Node not found."
3046 <<" Adding block to emerge queue."
3048 m_emerge_queue.addBlock(peer_id,
3049 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3052 /* Cheat prevention */
3053 bool is_valid_dig = true;
3054 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3056 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3057 float nocheat_t = playersao->getNoCheatDigTime();
3058 playersao->noCheatDigEnd();
3059 // If player didn't start digging this, ignore dig
3060 if(nocheat_p != p_under){
3061 infostream<<"Server: NoCheat: "<<player->getName()
3062 <<" started digging "
3063 <<PP(nocheat_p)<<" and completed digging "
3064 <<PP(p_under)<<"; not digging."<<std::endl;
3065 is_valid_dig = false;
3067 // Get player's wielded item
3068 ItemStack playeritem;
3069 InventoryList *mlist = playersao->getInventory()->getList("main");
3071 playeritem = mlist->getItem(playersao->getWieldIndex());
3072 ToolCapabilities playeritem_toolcap =
3073 playeritem.getToolCapabilities(m_itemdef);
3074 // Get diggability and expected digging time
3075 DigParams params = getDigParams(m_nodedef->get(n).groups,
3076 &playeritem_toolcap);
3077 // If can't dig, try hand
3078 if(!params.diggable){
3079 const ItemDefinition &hand = m_itemdef->get("");
3080 const ToolCapabilities *tp = hand.tool_capabilities;
3082 params = getDigParams(m_nodedef->get(n).groups, tp);
3084 // If can't dig, ignore dig
3085 if(!params.diggable){
3086 infostream<<"Server: NoCheat: "<<player->getName()
3087 <<" completed digging "<<PP(p_under)
3088 <<", which is not diggable with tool. not digging."
3090 is_valid_dig = false;
3092 // If time is considerably too short, ignore dig
3093 // Check time only for medium and slow timed digs
3094 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3095 infostream<<"Server: NoCheat: "<<player->getName()
3096 <<" completed digging "
3097 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3098 <<params.time<<"s; not digging."<<std::endl;
3099 is_valid_dig = false;
3103 /* Actually dig node */
3105 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3106 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3108 // Send unusual result (that is, node not being removed)
3109 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3111 // Re-send block to revert change on client-side
3112 RemoteClient *client = getClient(peer_id);
3113 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3114 client->SetBlockNotSent(blockpos);
3120 3: place block or right-click object
3122 else if(action == 3)
3124 ItemStack item = playersao->getWieldedItem();
3126 // Reset build time counter
3127 if(pointed.type == POINTEDTHING_NODE &&
3128 item.getDefinition(m_itemdef).type == ITEM_NODE)
3129 getClient(peer_id)->m_time_from_building = 0.0;
3131 if(pointed.type == POINTEDTHING_OBJECT)
3133 // Right click object
3135 // Skip if object has been removed
3136 if(pointed_object->m_removed)
3139 actionstream<<player->getName()<<" right-clicks object "
3140 <<pointed.object_id<<": "
3141 <<pointed_object->getDescription()<<std::endl;
3144 pointed_object->rightClick(playersao);
3146 else if(scriptapi_item_on_place(m_lua,
3147 item, playersao, pointed))
3149 // Placement was handled in lua
3151 // Apply returned ItemStack
3152 playersao->setWieldedItem(item);
3155 // If item has node placement prediction, always send the above
3156 // node to make sure the client knows what exactly happened
3157 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3158 RemoteClient *client = getClient(peer_id);
3159 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3160 client->SetBlockNotSent(blockpos);
3167 else if(action == 4)
3169 ItemStack item = playersao->getWieldedItem();
3171 actionstream<<player->getName()<<" uses "<<item.name
3172 <<", pointing at "<<pointed.dump()<<std::endl;
3174 if(scriptapi_item_on_use(m_lua,
3175 item, playersao, pointed))
3177 // Apply returned ItemStack
3178 playersao->setWieldedItem(item);
3184 Catch invalid actions
3188 infostream<<"WARNING: Server: Invalid action "
3189 <<action<<std::endl;
3192 else if(command == TOSERVER_REMOVED_SOUNDS)
3194 std::string datastring((char*)&data[2], datasize-2);
3195 std::istringstream is(datastring, std::ios_base::binary);
3197 int num = readU16(is);
3198 for(int k=0; k<num; k++){
3199 s32 id = readS32(is);
3200 std::map<s32, ServerPlayingSound>::iterator i =
3201 m_playing_sounds.find(id);
3202 if(i == m_playing_sounds.end())
3204 ServerPlayingSound &psound = i->second;
3205 psound.clients.erase(peer_id);
3206 if(psound.clients.size() == 0)
3207 m_playing_sounds.erase(i++);
3210 else if(command == TOSERVER_NODEMETA_FIELDS)
3212 std::string datastring((char*)&data[2], datasize-2);
3213 std::istringstream is(datastring, std::ios_base::binary);
3215 v3s16 p = readV3S16(is);
3216 std::string formname = deSerializeString(is);
3217 int num = readU16(is);
3218 std::map<std::string, std::string> fields;
3219 for(int k=0; k<num; k++){
3220 std::string fieldname = deSerializeString(is);
3221 std::string fieldvalue = deSerializeLongString(is);
3222 fields[fieldname] = fieldvalue;
3225 // If something goes wrong, this player is to blame
3226 RollbackScopeActor rollback_scope(m_rollback,
3227 std::string("player:")+player->getName());
3229 // Check the target node for rollback data; leave others unnoticed
3230 RollbackNode rn_old(&m_env->getMap(), p, this);
3232 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3235 // Report rollback data
3236 RollbackNode rn_new(&m_env->getMap(), p, this);
3237 if(rollback() && rn_new != rn_old){
3238 RollbackAction action;
3239 action.setSetNode(p, rn_old, rn_new);
3240 rollback()->reportAction(action);
3243 else if(command == TOSERVER_INVENTORY_FIELDS)
3245 std::string datastring((char*)&data[2], datasize-2);
3246 std::istringstream is(datastring, std::ios_base::binary);
3248 std::string formname = deSerializeString(is);
3249 int num = readU16(is);
3250 std::map<std::string, std::string> fields;
3251 for(int k=0; k<num; k++){
3252 std::string fieldname = deSerializeString(is);
3253 std::string fieldvalue = deSerializeLongString(is);
3254 fields[fieldname] = fieldvalue;
3257 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3261 infostream<<"Server::ProcessData(): Ignoring "
3262 "unknown command "<<command<<std::endl;
3266 catch(SendFailedException &e)
3268 errorstream<<"Server::ProcessData(): SendFailedException: "
3274 void Server::onMapEditEvent(MapEditEvent *event)
3276 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3277 if(m_ignore_map_edit_events)
3279 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3281 MapEditEvent *e = event->clone();
3282 m_unsent_map_edit_queue.push_back(e);
3285 Inventory* Server::getInventory(const InventoryLocation &loc)
3288 case InventoryLocation::UNDEFINED:
3291 case InventoryLocation::CURRENT_PLAYER:
3294 case InventoryLocation::PLAYER:
3296 Player *player = m_env->getPlayer(loc.name.c_str());
3299 PlayerSAO *playersao = player->getPlayerSAO();
3302 return playersao->getInventory();
3305 case InventoryLocation::NODEMETA:
3307 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3310 return meta->getInventory();
3313 case InventoryLocation::DETACHED:
3315 if(m_detached_inventories.count(loc.name) == 0)
3317 return m_detached_inventories[loc.name];
3325 void Server::setInventoryModified(const InventoryLocation &loc)
3328 case InventoryLocation::UNDEFINED:
3331 case InventoryLocation::PLAYER:
3333 Player *player = m_env->getPlayer(loc.name.c_str());
3336 PlayerSAO *playersao = player->getPlayerSAO();
3339 playersao->m_inventory_not_sent = true;
3340 playersao->m_wielded_item_not_sent = true;
3343 case InventoryLocation::NODEMETA:
3345 v3s16 blockpos = getNodeBlockPos(loc.p);
3347 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3349 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3351 setBlockNotSent(blockpos);
3354 case InventoryLocation::DETACHED:
3356 sendDetachedInventoryToAll(loc.name);
3364 core::list<PlayerInfo> Server::getPlayerInfo()
3366 DSTACK(__FUNCTION_NAME);
3367 JMutexAutoLock envlock(m_env_mutex);
3368 JMutexAutoLock conlock(m_con_mutex);
3370 core::list<PlayerInfo> list;
3372 core::list<Player*> players = m_env->getPlayers();
3374 core::list<Player*>::Iterator i;
3375 for(i = players.begin();
3376 i != players.end(); i++)
3380 Player *player = *i;
3383 // Copy info from connection to info struct
3384 info.id = player->peer_id;
3385 info.address = m_con.GetPeerAddress(player->peer_id);
3386 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3388 catch(con::PeerNotFoundException &e)
3390 // Set dummy peer info
3392 info.address = Address(0,0,0,0,0);
3396 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3397 info.position = player->getPosition();
3399 list.push_back(info);
3406 void Server::peerAdded(con::Peer *peer)
3408 DSTACK(__FUNCTION_NAME);
3409 verbosestream<<"Server::peerAdded(): peer->id="
3410 <<peer->id<<std::endl;
3413 c.type = PEER_ADDED;
3414 c.peer_id = peer->id;
3416 m_peer_change_queue.push_back(c);
3419 void Server::deletingPeer(con::Peer *peer, bool timeout)
3421 DSTACK(__FUNCTION_NAME);
3422 verbosestream<<"Server::deletingPeer(): peer->id="
3423 <<peer->id<<", timeout="<<timeout<<std::endl;
3426 c.type = PEER_REMOVED;
3427 c.peer_id = peer->id;
3428 c.timeout = timeout;
3429 m_peer_change_queue.push_back(c);
3436 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3438 DSTACK(__FUNCTION_NAME);
3439 std::ostringstream os(std::ios_base::binary);
3441 writeU16(os, TOCLIENT_HP);
3445 std::string s = os.str();
3446 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3448 con.Send(peer_id, 0, data, true);
3451 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3452 const std::wstring &reason)
3454 DSTACK(__FUNCTION_NAME);
3455 std::ostringstream os(std::ios_base::binary);
3457 writeU16(os, TOCLIENT_ACCESS_DENIED);
3458 os<<serializeWideString(reason);
3461 std::string s = os.str();
3462 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3464 con.Send(peer_id, 0, data, true);
3467 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3468 bool set_camera_point_target, v3f camera_point_target)
3470 DSTACK(__FUNCTION_NAME);
3471 std::ostringstream os(std::ios_base::binary);
3473 writeU16(os, TOCLIENT_DEATHSCREEN);
3474 writeU8(os, set_camera_point_target);
3475 writeV3F1000(os, camera_point_target);
3478 std::string s = os.str();
3479 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3481 con.Send(peer_id, 0, data, true);
3484 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3485 IItemDefManager *itemdef)
3487 DSTACK(__FUNCTION_NAME);
3488 std::ostringstream os(std::ios_base::binary);
3492 u32 length of the next item
3493 zlib-compressed serialized ItemDefManager
3495 writeU16(os, TOCLIENT_ITEMDEF);
3496 std::ostringstream tmp_os(std::ios::binary);
3497 itemdef->serialize(tmp_os);
3498 std::ostringstream tmp_os2(std::ios::binary);
3499 compressZlib(tmp_os.str(), tmp_os2);
3500 os<<serializeLongString(tmp_os2.str());
3503 std::string s = os.str();
3504 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3505 <<"): size="<<s.size()<<std::endl;
3506 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3508 con.Send(peer_id, 0, data, true);
3511 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3512 INodeDefManager *nodedef)
3514 DSTACK(__FUNCTION_NAME);
3515 std::ostringstream os(std::ios_base::binary);
3519 u32 length of the next item
3520 zlib-compressed serialized NodeDefManager
3522 writeU16(os, TOCLIENT_NODEDEF);
3523 std::ostringstream tmp_os(std::ios::binary);
3524 nodedef->serialize(tmp_os);
3525 std::ostringstream tmp_os2(std::ios::binary);
3526 compressZlib(tmp_os.str(), tmp_os2);
3527 os<<serializeLongString(tmp_os2.str());
3530 std::string s = os.str();
3531 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3532 <<"): size="<<s.size()<<std::endl;
3533 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3535 con.Send(peer_id, 0, data, true);
3539 Non-static send methods
3542 void Server::SendInventory(u16 peer_id)
3544 DSTACK(__FUNCTION_NAME);
3546 PlayerSAO *playersao = getPlayerSAO(peer_id);
3549 playersao->m_inventory_not_sent = false;
3555 std::ostringstream os;
3556 playersao->getInventory()->serialize(os);
3558 std::string s = os.str();
3560 SharedBuffer<u8> data(s.size()+2);
3561 writeU16(&data[0], TOCLIENT_INVENTORY);
3562 memcpy(&data[2], s.c_str(), s.size());
3565 m_con.Send(peer_id, 0, data, true);
3568 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3570 DSTACK(__FUNCTION_NAME);
3572 std::ostringstream os(std::ios_base::binary);
3576 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3577 os.write((char*)buf, 2);
3580 writeU16(buf, message.size());
3581 os.write((char*)buf, 2);
3584 for(u32 i=0; i<message.size(); i++)
3588 os.write((char*)buf, 2);
3592 std::string s = os.str();
3593 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3595 m_con.Send(peer_id, 0, data, true);
3598 void Server::BroadcastChatMessage(const std::wstring &message)
3600 for(core::map<u16, RemoteClient*>::Iterator
3601 i = m_clients.getIterator();
3602 i.atEnd() == false; i++)
3604 // Get client and check that it is valid
3605 RemoteClient *client = i.getNode()->getValue();
3606 assert(client->peer_id == i.getNode()->getKey());
3607 if(client->serialization_version == SER_FMT_VER_INVALID)
3610 SendChatMessage(client->peer_id, message);
3614 void Server::SendPlayerHP(u16 peer_id)
3616 DSTACK(__FUNCTION_NAME);
3617 PlayerSAO *playersao = getPlayerSAO(peer_id);
3619 playersao->m_hp_not_sent = false;
3620 SendHP(m_con, peer_id, playersao->getHP());
3623 void Server::SendMovePlayer(u16 peer_id)
3625 DSTACK(__FUNCTION_NAME);
3626 Player *player = m_env->getPlayer(peer_id);
3629 std::ostringstream os(std::ios_base::binary);
3630 writeU16(os, TOCLIENT_MOVE_PLAYER);
3631 writeV3F1000(os, player->getPosition());
3632 writeF1000(os, player->getPitch());
3633 writeF1000(os, player->getYaw());
3636 v3f pos = player->getPosition();
3637 f32 pitch = player->getPitch();
3638 f32 yaw = player->getYaw();
3639 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3640 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3647 std::string s = os.str();
3648 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3650 m_con.Send(peer_id, 0, data, true);
3653 void Server::SendPlayerPrivileges(u16 peer_id)
3655 Player *player = m_env->getPlayer(peer_id);
3657 if(player->peer_id == PEER_ID_INEXISTENT)
3660 std::set<std::string> privs;
3661 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3663 std::ostringstream os(std::ios_base::binary);
3664 writeU16(os, TOCLIENT_PRIVILEGES);
3665 writeU16(os, privs.size());
3666 for(std::set<std::string>::const_iterator i = privs.begin();
3667 i != privs.end(); i++){
3668 os<<serializeString(*i);
3672 std::string s = os.str();
3673 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3675 m_con.Send(peer_id, 0, data, true);
3678 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3680 Player *player = m_env->getPlayer(peer_id);
3682 if(player->peer_id == PEER_ID_INEXISTENT)
3685 std::ostringstream os(std::ios_base::binary);
3686 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3687 os<<serializeLongString(player->inventory_formspec);
3690 std::string s = os.str();
3691 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3693 m_con.Send(peer_id, 0, data, true);
3696 s32 Server::playSound(const SimpleSoundSpec &spec,
3697 const ServerSoundParams ¶ms)
3699 // Find out initial position of sound
3700 bool pos_exists = false;
3701 v3f pos = params.getPos(m_env, &pos_exists);
3702 // If position is not found while it should be, cancel sound
3703 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3705 // Filter destination clients
3706 std::set<RemoteClient*> dst_clients;
3707 if(params.to_player != "")
3709 Player *player = m_env->getPlayer(params.to_player.c_str());
3711 infostream<<"Server::playSound: Player \""<<params.to_player
3712 <<"\" not found"<<std::endl;
3715 if(player->peer_id == PEER_ID_INEXISTENT){
3716 infostream<<"Server::playSound: Player \""<<params.to_player
3717 <<"\" not connected"<<std::endl;
3720 RemoteClient *client = getClient(player->peer_id);
3721 dst_clients.insert(client);
3725 for(core::map<u16, RemoteClient*>::Iterator
3726 i = m_clients.getIterator(); i.atEnd() == false; i++)
3728 RemoteClient *client = i.getNode()->getValue();
3729 Player *player = m_env->getPlayer(client->peer_id);
3733 if(player->getPosition().getDistanceFrom(pos) >
3734 params.max_hear_distance)
3737 dst_clients.insert(client);
3740 if(dst_clients.size() == 0)
3743 s32 id = m_next_sound_id++;
3744 // The sound will exist as a reference in m_playing_sounds
3745 m_playing_sounds[id] = ServerPlayingSound();
3746 ServerPlayingSound &psound = m_playing_sounds[id];
3747 psound.params = params;
3748 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3749 i != dst_clients.end(); i++)
3750 psound.clients.insert((*i)->peer_id);
3752 std::ostringstream os(std::ios_base::binary);
3753 writeU16(os, TOCLIENT_PLAY_SOUND);
3755 os<<serializeString(spec.name);
3756 writeF1000(os, spec.gain * params.gain);
3757 writeU8(os, params.type);
3758 writeV3F1000(os, pos);
3759 writeU16(os, params.object);
3760 writeU8(os, params.loop);
3762 std::string s = os.str();
3763 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3765 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3766 i != dst_clients.end(); i++){
3768 m_con.Send((*i)->peer_id, 0, data, true);
3772 void Server::stopSound(s32 handle)
3774 // Get sound reference
3775 std::map<s32, ServerPlayingSound>::iterator i =
3776 m_playing_sounds.find(handle);
3777 if(i == m_playing_sounds.end())
3779 ServerPlayingSound &psound = i->second;
3781 std::ostringstream os(std::ios_base::binary);
3782 writeU16(os, TOCLIENT_STOP_SOUND);
3783 writeS32(os, handle);
3785 std::string s = os.str();
3786 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3788 for(std::set<u16>::iterator i = psound.clients.begin();
3789 i != psound.clients.end(); i++){
3791 m_con.Send(*i, 0, data, true);
3793 // Remove sound reference
3794 m_playing_sounds.erase(i);
3797 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3798 core::list<u16> *far_players, float far_d_nodes)
3800 float maxd = far_d_nodes*BS;
3801 v3f p_f = intToFloat(p, BS);
3805 SharedBuffer<u8> reply(replysize);
3806 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3807 writeS16(&reply[2], p.X);
3808 writeS16(&reply[4], p.Y);
3809 writeS16(&reply[6], p.Z);
3811 for(core::map<u16, RemoteClient*>::Iterator
3812 i = m_clients.getIterator();
3813 i.atEnd() == false; i++)
3815 // Get client and check that it is valid
3816 RemoteClient *client = i.getNode()->getValue();
3817 assert(client->peer_id == i.getNode()->getKey());
3818 if(client->serialization_version == SER_FMT_VER_INVALID)
3821 // Don't send if it's the same one
3822 if(client->peer_id == ignore_id)
3828 Player *player = m_env->getPlayer(client->peer_id);
3831 // If player is far away, only set modified blocks not sent
3832 v3f player_pos = player->getPosition();
3833 if(player_pos.getDistanceFrom(p_f) > maxd)
3835 far_players->push_back(client->peer_id);
3842 m_con.Send(client->peer_id, 0, reply, true);
3846 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3847 core::list<u16> *far_players, float far_d_nodes)
3849 float maxd = far_d_nodes*BS;
3850 v3f p_f = intToFloat(p, BS);
3852 for(core::map<u16, RemoteClient*>::Iterator
3853 i = m_clients.getIterator();
3854 i.atEnd() == false; i++)
3856 // Get client and check that it is valid
3857 RemoteClient *client = i.getNode()->getValue();
3858 assert(client->peer_id == i.getNode()->getKey());
3859 if(client->serialization_version == SER_FMT_VER_INVALID)
3862 // Don't send if it's the same one
3863 if(client->peer_id == ignore_id)
3869 Player *player = m_env->getPlayer(client->peer_id);
3872 // If player is far away, only set modified blocks not sent
3873 v3f player_pos = player->getPosition();
3874 if(player_pos.getDistanceFrom(p_f) > maxd)
3876 far_players->push_back(client->peer_id);
3883 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3884 SharedBuffer<u8> reply(replysize);
3885 writeU16(&reply[0], TOCLIENT_ADDNODE);
3886 writeS16(&reply[2], p.X);
3887 writeS16(&reply[4], p.Y);
3888 writeS16(&reply[6], p.Z);
3889 n.serialize(&reply[8], client->serialization_version);
3892 m_con.Send(client->peer_id, 0, reply, true);
3896 void Server::setBlockNotSent(v3s16 p)
3898 for(core::map<u16, RemoteClient*>::Iterator
3899 i = m_clients.getIterator();
3900 i.atEnd()==false; i++)
3902 RemoteClient *client = i.getNode()->getValue();
3903 client->SetBlockNotSent(p);
3907 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3909 DSTACK(__FUNCTION_NAME);
3911 v3s16 p = block->getPos();
3915 bool completely_air = true;
3916 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3917 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3918 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3920 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3922 completely_air = false;
3923 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3928 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3930 infostream<<"[completely air] ";
3931 infostream<<std::endl;
3935 Create a packet with the block in the right format
3938 std::ostringstream os(std::ios_base::binary);
3939 block->serialize(os, ver, false);
3940 std::string s = os.str();
3941 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3943 u32 replysize = 8 + blockdata.getSize();
3944 SharedBuffer<u8> reply(replysize);
3945 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3946 writeS16(&reply[2], p.X);
3947 writeS16(&reply[4], p.Y);
3948 writeS16(&reply[6], p.Z);
3949 memcpy(&reply[8], *blockdata, blockdata.getSize());
3951 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3952 <<": \tpacket size: "<<replysize<<std::endl;*/
3957 m_con.Send(peer_id, 1, reply, true);
3960 void Server::SendBlocks(float dtime)
3962 DSTACK(__FUNCTION_NAME);
3964 JMutexAutoLock envlock(m_env_mutex);
3965 JMutexAutoLock conlock(m_con_mutex);
3967 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3969 core::array<PrioritySortedBlockTransfer> queue;
3971 s32 total_sending = 0;
3974 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3976 for(core::map<u16, RemoteClient*>::Iterator
3977 i = m_clients.getIterator();
3978 i.atEnd() == false; i++)
3980 RemoteClient *client = i.getNode()->getValue();
3981 assert(client->peer_id == i.getNode()->getKey());
3983 // If definitions and textures have not been sent, don't
3984 // send MapBlocks either
3985 if(!client->definitions_sent)
3988 total_sending += client->SendingCount();
3990 if(client->serialization_version == SER_FMT_VER_INVALID)
3993 client->GetNextBlocks(this, dtime, queue);
3998 // Lowest priority number comes first.
3999 // Lowest is most important.
4002 for(u32 i=0; i<queue.size(); i++)
4004 //TODO: Calculate limit dynamically
4005 if(total_sending >= g_settings->getS32
4006 ("max_simultaneous_block_sends_server_total"))
4009 PrioritySortedBlockTransfer q = queue[i];
4011 MapBlock *block = NULL;
4014 block = m_env->getMap().getBlockNoCreate(q.pos);
4016 catch(InvalidPositionException &e)
4021 RemoteClient *client = getClient(q.peer_id);
4023 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4025 client->SentBlock(q.pos);
4031 void Server::fillMediaCache()
4033 DSTACK(__FUNCTION_NAME);
4035 infostream<<"Server: Calculating media file checksums"<<std::endl;
4037 // Collect all media file paths
4038 std::list<std::string> paths;
4039 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4040 i != m_mods.end(); i++){
4041 const ModSpec &mod = *i;
4042 paths.push_back(mod.path + DIR_DELIM + "textures");
4043 paths.push_back(mod.path + DIR_DELIM + "sounds");
4044 paths.push_back(mod.path + DIR_DELIM + "media");
4046 std::string path_all = "textures";
4047 paths.push_back(path_all + DIR_DELIM + "all");
4049 // Collect media file information from paths into cache
4050 for(std::list<std::string>::iterator i = paths.begin();
4051 i != paths.end(); i++)
4053 std::string mediapath = *i;
4054 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4055 for(u32 j=0; j<dirlist.size(); j++){
4056 if(dirlist[j].dir) // Ignode dirs
4058 std::string filename = dirlist[j].name;
4059 // If name contains illegal characters, ignore the file
4060 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4061 infostream<<"Server: ignoring illegal file name: \""
4062 <<filename<<"\""<<std::endl;
4065 // If name is not in a supported format, ignore it
4066 const char *supported_ext[] = {
4067 ".png", ".jpg", ".bmp", ".tga",
4068 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4072 if(removeStringEnd(filename, supported_ext) == ""){
4073 infostream<<"Server: ignoring unsupported file extension: \""
4074 <<filename<<"\""<<std::endl;
4077 // Ok, attempt to load the file and add to cache
4078 std::string filepath = mediapath + DIR_DELIM + filename;
4080 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4081 if(fis.good() == false){
4082 errorstream<<"Server::fillMediaCache(): Could not open \""
4083 <<filename<<"\" for reading"<<std::endl;
4086 std::ostringstream tmp_os(std::ios_base::binary);
4090 fis.read(buf, 1024);
4091 std::streamsize len = fis.gcount();
4092 tmp_os.write(buf, len);
4101 errorstream<<"Server::fillMediaCache(): Failed to read \""
4102 <<filename<<"\""<<std::endl;
4105 if(tmp_os.str().length() == 0){
4106 errorstream<<"Server::fillMediaCache(): Empty file \""
4107 <<filepath<<"\""<<std::endl;
4112 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4114 unsigned char *digest = sha1.getDigest();
4115 std::string sha1_base64 = base64_encode(digest, 20);
4116 std::string sha1_hex = hex_encode((char*)digest, 20);
4120 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4121 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4126 struct SendableMediaAnnouncement
4129 std::string sha1_digest;
4131 SendableMediaAnnouncement(const std::string name_="",
4132 const std::string sha1_digest_=""):
4134 sha1_digest(sha1_digest_)
4138 void Server::sendMediaAnnouncement(u16 peer_id)
4140 DSTACK(__FUNCTION_NAME);
4142 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4145 core::list<SendableMediaAnnouncement> file_announcements;
4147 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4148 i != m_media.end(); i++){
4150 file_announcements.push_back(
4151 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4155 std::ostringstream os(std::ios_base::binary);
4163 u16 length of sha1_digest
4168 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4169 writeU16(os, file_announcements.size());
4171 for(core::list<SendableMediaAnnouncement>::Iterator
4172 j = file_announcements.begin();
4173 j != file_announcements.end(); j++){
4174 os<<serializeString(j->name);
4175 os<<serializeString(j->sha1_digest);
4179 std::string s = os.str();
4180 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4183 m_con.Send(peer_id, 0, data, true);
4187 struct SendableMedia
4193 SendableMedia(const std::string &name_="", const std::string path_="",
4194 const std::string &data_=""):
4201 void Server::sendRequestedMedia(u16 peer_id,
4202 const core::list<MediaRequest> &tosend)
4204 DSTACK(__FUNCTION_NAME);
4206 verbosestream<<"Server::sendRequestedMedia(): "
4207 <<"Sending files to client"<<std::endl;
4211 // Put 5kB in one bunch (this is not accurate)
4212 u32 bytes_per_bunch = 5000;
4214 core::array< core::list<SendableMedia> > file_bunches;
4215 file_bunches.push_back(core::list<SendableMedia>());
4217 u32 file_size_bunch_total = 0;
4219 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4220 i != tosend.end(); i++)
4222 if(m_media.find(i->name) == m_media.end()){
4223 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4224 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4228 //TODO get path + name
4229 std::string tpath = m_media[(*i).name].path;
4232 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4233 if(fis.good() == false){
4234 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4235 <<tpath<<"\" for reading"<<std::endl;
4238 std::ostringstream tmp_os(std::ios_base::binary);
4242 fis.read(buf, 1024);
4243 std::streamsize len = fis.gcount();
4244 tmp_os.write(buf, len);
4245 file_size_bunch_total += len;
4254 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4255 <<(*i).name<<"\""<<std::endl;
4258 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4259 <<tname<<"\""<<std::endl;*/
4261 file_bunches[file_bunches.size()-1].push_back(
4262 SendableMedia((*i).name, tpath, tmp_os.str()));
4264 // Start next bunch if got enough data
4265 if(file_size_bunch_total >= bytes_per_bunch){
4266 file_bunches.push_back(core::list<SendableMedia>());
4267 file_size_bunch_total = 0;
4272 /* Create and send packets */
4274 u32 num_bunches = file_bunches.size();
4275 for(u32 i=0; i<num_bunches; i++)
4277 std::ostringstream os(std::ios_base::binary);
4281 u16 total number of texture bunches
4282 u16 index of this bunch
4283 u32 number of files in this bunch
4292 writeU16(os, TOCLIENT_MEDIA);
4293 writeU16(os, num_bunches);
4295 writeU32(os, file_bunches[i].size());
4297 for(core::list<SendableMedia>::Iterator
4298 j = file_bunches[i].begin();
4299 j != file_bunches[i].end(); j++){
4300 os<<serializeString(j->name);
4301 os<<serializeLongString(j->data);
4305 std::string s = os.str();
4306 verbosestream<<"Server::sendRequestedMedia(): bunch "
4307 <<i<<"/"<<num_bunches
4308 <<" files="<<file_bunches[i].size()
4309 <<" size=" <<s.size()<<std::endl;
4310 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4312 m_con.Send(peer_id, 0, data, true);
4316 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4318 if(m_detached_inventories.count(name) == 0){
4319 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4322 Inventory *inv = m_detached_inventories[name];
4324 std::ostringstream os(std::ios_base::binary);
4325 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4326 os<<serializeString(name);
4330 std::string s = os.str();
4331 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4333 m_con.Send(peer_id, 0, data, true);
4336 void Server::sendDetachedInventoryToAll(const std::string &name)
4338 DSTACK(__FUNCTION_NAME);
4340 for(core::map<u16, RemoteClient*>::Iterator
4341 i = m_clients.getIterator();
4342 i.atEnd() == false; i++){
4343 RemoteClient *client = i.getNode()->getValue();
4344 sendDetachedInventory(name, client->peer_id);
4348 void Server::sendDetachedInventories(u16 peer_id)
4350 DSTACK(__FUNCTION_NAME);
4352 for(std::map<std::string, Inventory*>::iterator
4353 i = m_detached_inventories.begin();
4354 i != m_detached_inventories.end(); i++){
4355 const std::string &name = i->first;
4356 //Inventory *inv = i->second;
4357 sendDetachedInventory(name, peer_id);
4365 void Server::DiePlayer(u16 peer_id)
4367 DSTACK(__FUNCTION_NAME);
4369 PlayerSAO *playersao = getPlayerSAO(peer_id);
4372 infostream<<"Server::DiePlayer(): Player "
4373 <<playersao->getPlayer()->getName()
4374 <<" dies"<<std::endl;
4376 playersao->setHP(0);
4378 // Trigger scripted stuff
4379 scriptapi_on_dieplayer(m_lua, playersao);
4381 SendPlayerHP(peer_id);
4382 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4385 void Server::RespawnPlayer(u16 peer_id)
4387 DSTACK(__FUNCTION_NAME);
4389 PlayerSAO *playersao = getPlayerSAO(peer_id);
4392 infostream<<"Server::RespawnPlayer(): Player "
4393 <<playersao->getPlayer()->getName()
4394 <<" respawns"<<std::endl;
4396 playersao->setHP(PLAYER_MAX_HP);
4398 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4400 v3f pos = findSpawnPos(m_env->getServerMap());
4401 playersao->setPos(pos);
4405 void Server::UpdateCrafting(u16 peer_id)
4407 DSTACK(__FUNCTION_NAME);
4409 Player* player = m_env->getPlayer(peer_id);
4412 // Get a preview for crafting
4414 getCraftingResult(&player->inventory, preview, false, this);
4416 // Put the new preview in
4417 InventoryList *plist = player->inventory.getList("craftpreview");
4419 assert(plist->getSize() >= 1);
4420 plist->changeItem(0, preview);
4423 RemoteClient* Server::getClient(u16 peer_id)
4425 DSTACK(__FUNCTION_NAME);
4426 //JMutexAutoLock lock(m_con_mutex);
4427 core::map<u16, RemoteClient*>::Node *n;
4428 n = m_clients.find(peer_id);
4429 // A client should exist for all peers
4431 return n->getValue();
4434 std::wstring Server::getStatusString()
4436 std::wostringstream os(std::ios_base::binary);
4439 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4441 os<<L", uptime="<<m_uptime.get();
4442 // Information about clients
4444 for(core::map<u16, RemoteClient*>::Iterator
4445 i = m_clients.getIterator();
4446 i.atEnd() == false; i++)
4448 // Get client and check that it is valid
4449 RemoteClient *client = i.getNode()->getValue();
4450 assert(client->peer_id == i.getNode()->getKey());
4451 if(client->serialization_version == SER_FMT_VER_INVALID)
4454 Player *player = m_env->getPlayer(client->peer_id);
4455 // Get name of player
4456 std::wstring name = L"unknown";
4458 name = narrow_to_wide(player->getName());
4459 // Add name to information string
4463 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4464 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4465 if(g_settings->get("motd") != "")
4466 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4470 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4472 std::set<std::string> privs;
4473 scriptapi_get_auth(m_lua, name, NULL, &privs);
4477 bool Server::checkPriv(const std::string &name, const std::string &priv)
4479 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4480 return (privs.count(priv) != 0);
4483 void Server::reportPrivsModified(const std::string &name)
4486 for(core::map<u16, RemoteClient*>::Iterator
4487 i = m_clients.getIterator();
4488 i.atEnd() == false; i++){
4489 RemoteClient *client = i.getNode()->getValue();
4490 Player *player = m_env->getPlayer(client->peer_id);
4491 reportPrivsModified(player->getName());
4494 Player *player = m_env->getPlayer(name.c_str());
4497 SendPlayerPrivileges(player->peer_id);
4498 PlayerSAO *sao = player->getPlayerSAO();
4501 sao->updatePrivileges(
4502 getPlayerEffectivePrivs(name),
4507 void Server::reportInventoryFormspecModified(const std::string &name)
4509 Player *player = m_env->getPlayer(name.c_str());
4512 SendPlayerInventoryFormspec(player->peer_id);
4515 // Saves g_settings to configpath given at initialization
4516 void Server::saveConfig()
4518 if(m_path_config != "")
4519 g_settings->updateConfigFile(m_path_config.c_str());
4522 void Server::notifyPlayer(const char *name, const std::wstring msg)
4524 Player *player = m_env->getPlayer(name);
4527 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4530 void Server::notifyPlayers(const std::wstring msg)
4532 BroadcastChatMessage(msg);
4535 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4539 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4540 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4543 Inventory* Server::createDetachedInventory(const std::string &name)
4545 if(m_detached_inventories.count(name) > 0){
4546 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4547 delete m_detached_inventories[name];
4549 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4551 Inventory *inv = new Inventory(m_itemdef);
4553 m_detached_inventories[name] = inv;
4554 sendDetachedInventoryToAll(name);
4561 BoolScopeSet(bool *dst, bool val):
4564 m_orig_state = *m_dst;
4569 *m_dst = m_orig_state;
4576 // actions: time-reversed list
4577 // Return value: success/failure
4578 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4579 std::list<std::string> *log)
4581 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4582 ServerMap *map = (ServerMap*)(&m_env->getMap());
4583 // Disable rollback report sink while reverting
4584 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4586 // Fail if no actions to handle
4587 if(actions.empty()){
4588 log->push_back("Nothing to do.");
4595 for(std::list<RollbackAction>::const_iterator
4596 i = actions.begin();
4597 i != actions.end(); i++)
4599 const RollbackAction &action = *i;
4601 bool success = action.applyRevert(map, this, this);
4604 std::ostringstream os;
4605 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4606 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4608 log->push_back(os.str());
4610 std::ostringstream os;
4611 os<<"Succesfully reverted step ("<<num_tried<<") "<<action.toString();
4612 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4614 log->push_back(os.str());
4618 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4619 <<" failed"<<std::endl;
4621 // Call it done if less than half failed
4622 return num_failed <= num_tried/2;
4625 // IGameDef interface
4627 IItemDefManager* Server::getItemDefManager()
4631 INodeDefManager* Server::getNodeDefManager()
4635 ICraftDefManager* Server::getCraftDefManager()
4639 ITextureSource* Server::getTextureSource()
4643 u16 Server::allocateUnknownNodeId(const std::string &name)
4645 return m_nodedef->allocateDummy(name);
4647 ISoundManager* Server::getSoundManager()
4649 return &dummySoundManager;
4651 MtEventManager* Server::getEventManager()
4655 IRollbackReportSink* Server::getRollbackReportSink()
4657 if(!m_rollback_sink_enabled)
4662 IWritableItemDefManager* Server::getWritableItemDefManager()
4666 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4670 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4675 const ModSpec* Server::getModSpec(const std::string &modname)
4677 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4678 i != m_mods.end(); i++){
4679 const ModSpec &mod = *i;
4680 if(mod.name == modname)
4685 void Server::getModNames(core::list<std::string> &modlist)
4687 for(core::list<ModSpec>::Iterator i = m_mods.begin(); i != m_mods.end(); i++)
4689 modlist.push_back((*i).name);
4692 std::string Server::getBuiltinLuaPath()
4694 return porting::path_share + DIR_DELIM + "builtin";
4697 v3f findSpawnPos(ServerMap &map)
4699 //return v3f(50,50,50)*BS;
4704 nodepos = v2s16(0,0);
4709 // Try to find a good place a few times
4710 for(s32 i=0; i<1000; i++)
4713 // We're going to try to throw the player to this position
4714 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4715 -range + (myrand()%(range*2)));
4716 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4717 // Get ground height at point (fallbacks to heightmap function)
4718 s16 groundheight = map.findGroundLevel(nodepos2d);
4719 // Don't go underwater
4720 if(groundheight < WATER_LEVEL)
4722 //infostream<<"-> Underwater"<<std::endl;
4725 // Don't go to high places
4726 if(groundheight > WATER_LEVEL + 4)
4728 //infostream<<"-> Underwater"<<std::endl;
4732 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4733 bool is_good = false;
4735 for(s32 i=0; i<10; i++){
4736 v3s16 blockpos = getNodeBlockPos(nodepos);
4737 map.emergeBlock(blockpos, true);
4738 MapNode n = map.getNodeNoEx(nodepos);
4739 if(n.getContent() == CONTENT_AIR){
4750 // Found a good place
4751 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4757 return intToFloat(nodepos, BS);
4760 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4762 RemotePlayer *player = NULL;
4763 bool newplayer = false;
4766 Try to get an existing player
4768 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4770 // If player is already connected, cancel
4771 if(player != NULL && player->peer_id != 0)
4773 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4778 If player with the wanted peer_id already exists, cancel.
4780 if(m_env->getPlayer(peer_id) != NULL)
4782 infostream<<"emergePlayer(): Player with wrong name but same"
4783 " peer_id already exists"<<std::endl;
4788 Create a new player if it doesn't exist yet
4793 player = new RemotePlayer(this);
4794 player->updateName(name);
4796 /* Set player position */
4797 infostream<<"Server: Finding spawn place for player \""
4798 <<name<<"\""<<std::endl;
4799 v3f pos = findSpawnPos(m_env->getServerMap());
4800 player->setPosition(pos);
4802 /* Add player to environment */
4803 m_env->addPlayer(player);
4807 Create a new player active object
4809 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4810 getPlayerEffectivePrivs(player->getName()),
4813 /* Add object to environment */
4814 m_env->addActiveObject(playersao);
4818 scriptapi_on_newplayer(m_lua, playersao);
4820 scriptapi_on_joinplayer(m_lua, playersao);
4825 void Server::handlePeerChange(PeerChange &c)
4827 JMutexAutoLock envlock(m_env_mutex);
4828 JMutexAutoLock conlock(m_con_mutex);
4830 if(c.type == PEER_ADDED)
4837 core::map<u16, RemoteClient*>::Node *n;
4838 n = m_clients.find(c.peer_id);
4839 // The client shouldn't already exist
4843 RemoteClient *client = new RemoteClient();
4844 client->peer_id = c.peer_id;
4845 m_clients.insert(client->peer_id, client);
4848 else if(c.type == PEER_REMOVED)
4855 core::map<u16, RemoteClient*>::Node *n;
4856 n = m_clients.find(c.peer_id);
4857 // The client should exist
4861 Mark objects to be not known by the client
4863 RemoteClient *client = n->getValue();
4865 for(core::map<u16, bool>::Iterator
4866 i = client->m_known_objects.getIterator();
4867 i.atEnd()==false; i++)
4870 u16 id = i.getNode()->getKey();
4871 ServerActiveObject* obj = m_env->getActiveObject(id);
4873 if(obj && obj->m_known_by_count > 0)
4874 obj->m_known_by_count--;
4878 Clear references to playing sounds
4880 for(std::map<s32, ServerPlayingSound>::iterator
4881 i = m_playing_sounds.begin();
4882 i != m_playing_sounds.end();)
4884 ServerPlayingSound &psound = i->second;
4885 psound.clients.erase(c.peer_id);
4886 if(psound.clients.size() == 0)
4887 m_playing_sounds.erase(i++);
4892 Player *player = m_env->getPlayer(c.peer_id);
4894 // Collect information about leaving in chat
4895 std::wstring message;
4899 std::wstring name = narrow_to_wide(player->getName());
4902 message += L" left the game.";
4904 message += L" (timed out)";
4908 /* Run scripts and remove from environment */
4912 PlayerSAO *playersao = player->getPlayerSAO();
4915 scriptapi_on_leaveplayer(m_lua, playersao);
4917 playersao->disconnected();
4927 std::ostringstream os(std::ios_base::binary);
4928 for(core::map<u16, RemoteClient*>::Iterator
4929 i = m_clients.getIterator();
4930 i.atEnd() == false; i++)
4932 RemoteClient *client = i.getNode()->getValue();
4933 assert(client->peer_id == i.getNode()->getKey());
4934 if(client->serialization_version == SER_FMT_VER_INVALID)
4937 Player *player = m_env->getPlayer(client->peer_id);
4940 // Get name of player
4941 os<<player->getName()<<" ";
4944 actionstream<<player->getName()<<" "
4945 <<(c.timeout?"times out.":"leaves game.")
4946 <<" List of players: "
4947 <<os.str()<<std::endl;
4952 delete m_clients[c.peer_id];
4953 m_clients.remove(c.peer_id);
4955 // Send player info to all remaining clients
4956 //SendPlayerInfos();
4958 // Send leave chat message to all remaining clients
4959 if(message.length() != 0)
4960 BroadcastChatMessage(message);
4969 void Server::handlePeerChanges()
4971 while(m_peer_change_queue.size() > 0)
4973 PeerChange c = m_peer_change_queue.pop_front();
4975 verbosestream<<"Server: Handling peer change: "
4976 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4979 handlePeerChange(c);
4983 void dedicated_server_loop(Server &server, bool &kill)
4985 DSTACK(__FUNCTION_NAME);
4987 verbosestream<<"dedicated_server_loop()"<<std::endl;
4989 IntervalLimiter m_profiler_interval;
4993 float steplen = g_settings->getFloat("dedicated_server_step");
4994 // This is kind of a hack but can be done like this
4995 // because server.step() is very light
4997 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4998 sleep_ms((int)(steplen*1000.0));
5000 server.step(steplen);
5002 if(server.getShutdownRequested() || kill)
5004 infostream<<"Dedicated server quitting"<<std::endl;
5011 float profiler_print_interval =
5012 g_settings->getFloat("profiler_print_interval");
5013 if(profiler_print_interval != 0)
5015 if(m_profiler_interval.step(steplen, profiler_print_interval))
5017 infostream<<"Profiler:"<<std::endl;
5018 g_profiler->print(infostream);
5019 g_profiler->clear();