3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "clientserver.h"
25 #include "jmutexautolock.h"
27 #include "constants.h"
32 #include "serverobject.h"
37 #include "scriptapi.h"
42 #include "content_mapnode.h"
43 #include "content_nodemeta.h"
44 #include "content_abm.h"
45 #include "content_sao.h"
50 #include "sound.h" // dummySoundManager
51 #include "event_manager.h"
53 #include "util/string.h"
54 #include "util/pointedthing.h"
55 #include "util/mathconstants.h"
57 #include "util/serialize.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)
448 Player *player = server->m_env->getPlayer(peer_id);
449 // This can happen sometimes; clients and players are not in perfect sync.
453 // Won't send anything if already sending
454 if(m_blocks_sending.size() >= g_settings->getU16
455 ("max_simultaneous_block_sends_per_client"))
457 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
461 //TimeTaker timer("RemoteClient::GetNextBlocks");
463 v3f playerpos = player->getPosition();
464 v3f playerspeed = player->getSpeed();
465 v3f playerspeeddir(0,0,0);
466 if(playerspeed.getLength() > 1.0*BS)
467 playerspeeddir = playerspeed / playerspeed.getLength();
468 // Predict to next block
469 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
471 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
473 v3s16 center = getNodeBlockPos(center_nodepos);
475 // Camera position and direction
476 v3f camera_pos = player->getEyePosition();
477 v3f camera_dir = v3f(0,0,1);
478 camera_dir.rotateYZBy(player->getPitch());
479 camera_dir.rotateXZBy(player->getYaw());
481 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
482 <<camera_dir.Z<<")"<<std::endl;*/
485 Get the starting value of the block finder radius.
488 if(m_last_center != center)
490 m_nearest_unsent_d = 0;
491 m_last_center = center;
494 /*infostream<<"m_nearest_unsent_reset_timer="
495 <<m_nearest_unsent_reset_timer<<std::endl;*/
497 // Reset periodically to workaround for some bugs or stuff
498 if(m_nearest_unsent_reset_timer > 20.0)
500 m_nearest_unsent_reset_timer = 0;
501 m_nearest_unsent_d = 0;
502 //infostream<<"Resetting m_nearest_unsent_d for "
503 // <<server->getPlayerName(peer_id)<<std::endl;
506 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
507 s16 d_start = m_nearest_unsent_d;
509 //infostream<<"d_start="<<d_start<<std::endl;
511 u16 max_simul_sends_setting = g_settings->getU16
512 ("max_simultaneous_block_sends_per_client");
513 u16 max_simul_sends_usually = max_simul_sends_setting;
516 Check the time from last addNode/removeNode.
518 Decrease send rate if player is building stuff.
520 m_time_from_building += dtime;
521 if(m_time_from_building < g_settings->getFloat(
522 "full_block_send_enable_min_time_from_building"))
524 max_simul_sends_usually
525 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
529 Number of blocks sending + number of blocks selected for sending
531 u32 num_blocks_selected = m_blocks_sending.size();
534 next time d will be continued from the d from which the nearest
535 unsent block was found this time.
537 This is because not necessarily any of the blocks found this
538 time are actually sent.
540 s32 new_nearest_unsent_d = -1;
542 s16 d_max = g_settings->getS16("max_block_send_distance");
543 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
545 // Don't loop very much at a time
546 s16 max_d_increment_at_time = 2;
547 if(d_max > d_start + max_d_increment_at_time)
548 d_max = d_start + max_d_increment_at_time;
549 /*if(d_max_gen > d_start+2)
550 d_max_gen = d_start+2;*/
552 //infostream<<"Starting from "<<d_start<<std::endl;
554 s32 nearest_emerged_d = -1;
555 s32 nearest_emergefull_d = -1;
556 s32 nearest_sent_d = -1;
557 bool queue_is_full = false;
560 for(d = d_start; d <= d_max; d++)
562 /*errorstream<<"checking d="<<d<<" for "
563 <<server->getPlayerName(peer_id)<<std::endl;*/
564 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
567 If m_nearest_unsent_d was changed by the EmergeThread
568 (it can change it to 0 through SetBlockNotSent),
570 Else update m_nearest_unsent_d
572 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
574 d = m_nearest_unsent_d;
575 last_nearest_unsent_d = m_nearest_unsent_d;
579 Get the border/face dot coordinates of a "d-radiused"
582 core::list<v3s16> list;
583 getFacePositions(list, d);
585 core::list<v3s16>::Iterator li;
586 for(li=list.begin(); li!=list.end(); li++)
588 v3s16 p = *li + center;
592 - Don't allow too many simultaneous transfers
593 - EXCEPT when the blocks are very close
595 Also, don't send blocks that are already flying.
598 // Start with the usual maximum
599 u16 max_simul_dynamic = max_simul_sends_usually;
601 // If block is very close, allow full maximum
602 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
603 max_simul_dynamic = max_simul_sends_setting;
605 // Don't select too many blocks for sending
606 if(num_blocks_selected >= max_simul_dynamic)
608 queue_is_full = true;
609 goto queue_full_break;
612 // Don't send blocks that are currently being transferred
613 if(m_blocks_sending.find(p) != NULL)
619 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
620 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
621 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
622 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
623 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
624 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
627 // If this is true, inexistent block will be made from scratch
628 bool generate = d <= d_max_gen;
631 /*// Limit the generating area vertically to 2/3
632 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
635 // Limit the send area vertically to 1/2
636 if(abs(p.Y - center.Y) > d_max / 2)
642 If block is far away, don't generate it unless it is
648 // Block center y in nodes
649 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
650 // Don't generate if it's very high or very low
651 if(y < -64 || y > 64)
655 v2s16 p2d_nodes_center(
659 // Get ground height in nodes
660 s16 gh = server->m_env->getServerMap().findGroundLevel(
663 // If differs a lot, don't generate
664 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
666 // Actually, don't even send it
672 //infostream<<"d="<<d<<std::endl;
675 Don't generate or send if not in sight
676 FIXME This only works if the client uses a small enough
677 FOV setting. The default of 72 degrees is fine.
680 float camera_fov = (72.0*M_PI/180) * 4./3.;
681 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
687 Don't send already sent blocks
690 if(m_blocks_sent.find(p) != NULL)
697 Check if map has this block
699 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
701 bool surely_not_found_on_disk = false;
702 bool block_is_invalid = false;
705 // Reset usage timer, this block will be of use in the future.
706 block->resetUsageTimer();
708 // Block is dummy if data doesn't exist.
709 // It means it has been not found from disk and not generated
712 surely_not_found_on_disk = true;
715 // Block is valid if lighting is up-to-date and data exists
716 if(block->isValid() == false)
718 block_is_invalid = true;
721 /*if(block->isFullyGenerated() == false)
723 block_is_invalid = true;
728 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
729 v2s16 chunkpos = map->sector_to_chunk(p2d);
730 if(map->chunkNonVolatile(chunkpos) == false)
731 block_is_invalid = true;
733 if(block->isGenerated() == false)
734 block_is_invalid = true;
737 If block is not close, don't send it unless it is near
740 Block is near ground level if night-time mesh
741 differs from day-time mesh.
745 if(block->getDayNightDiff() == false)
752 If block has been marked to not exist on disk (dummy)
753 and generating new ones is not wanted, skip block.
755 if(generate == false && surely_not_found_on_disk == true)
762 Add inexistent block to emerge queue.
764 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
766 //TODO: Get value from somewhere
767 // Allow only one block in emerge queue
768 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
769 // Allow two blocks in queue per client
770 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
772 // Make it more responsive when needing to generate stuff
773 if(surely_not_found_on_disk)
775 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
777 //infostream<<"Adding block to emerge queue"<<std::endl;
779 // Add it to the emerge queue and trigger the thread
782 if(generate == false)
783 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
785 server->m_emerge_queue.addBlock(peer_id, p, flags);
786 server->m_emergethread.trigger();
788 if(nearest_emerged_d == -1)
789 nearest_emerged_d = d;
791 if(nearest_emergefull_d == -1)
792 nearest_emergefull_d = d;
799 if(nearest_sent_d == -1)
803 Add block to send queue
806 /*errorstream<<"sending from d="<<d<<" to "
807 <<server->getPlayerName(peer_id)<<std::endl;*/
809 PrioritySortedBlockTransfer q((float)d, p, peer_id);
813 num_blocks_selected += 1;
818 //infostream<<"Stopped at "<<d<<std::endl;
820 // If nothing was found for sending and nothing was queued for
821 // emerging, continue next time browsing from here
822 if(nearest_emerged_d != -1){
823 new_nearest_unsent_d = nearest_emerged_d;
824 } else if(nearest_emergefull_d != -1){
825 new_nearest_unsent_d = nearest_emergefull_d;
827 if(d > g_settings->getS16("max_block_send_distance")){
828 new_nearest_unsent_d = 0;
829 m_nothing_to_send_pause_timer = 2.0;
830 /*infostream<<"GetNextBlocks(): d wrapped around for "
831 <<server->getPlayerName(peer_id)
832 <<"; setting to 0 and pausing"<<std::endl;*/
834 if(nearest_sent_d != -1)
835 new_nearest_unsent_d = nearest_sent_d;
837 new_nearest_unsent_d = d;
841 if(new_nearest_unsent_d != -1)
842 m_nearest_unsent_d = new_nearest_unsent_d;
844 /*timer_result = timer.stop(true);
845 if(timer_result != 0)
846 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
849 void RemoteClient::GotBlock(v3s16 p)
851 if(m_blocks_sending.find(p) != NULL)
852 m_blocks_sending.remove(p);
855 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
856 " m_blocks_sending"<<std::endl;*/
857 m_excess_gotblocks++;
859 m_blocks_sent.insert(p, true);
862 void RemoteClient::SentBlock(v3s16 p)
864 if(m_blocks_sending.find(p) == NULL)
865 m_blocks_sending.insert(p, 0.0);
867 infostream<<"RemoteClient::SentBlock(): Sent block"
868 " already in m_blocks_sending"<<std::endl;
871 void RemoteClient::SetBlockNotSent(v3s16 p)
873 m_nearest_unsent_d = 0;
875 if(m_blocks_sending.find(p) != NULL)
876 m_blocks_sending.remove(p);
877 if(m_blocks_sent.find(p) != NULL)
878 m_blocks_sent.remove(p);
881 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
883 m_nearest_unsent_d = 0;
885 for(core::map<v3s16, MapBlock*>::Iterator
886 i = blocks.getIterator();
887 i.atEnd()==false; i++)
889 v3s16 p = i.getNode()->getKey();
891 if(m_blocks_sending.find(p) != NULL)
892 m_blocks_sending.remove(p);
893 if(m_blocks_sent.find(p) != NULL)
894 m_blocks_sent.remove(p);
902 PlayerInfo::PlayerInfo()
908 void PlayerInfo::PrintLine(std::ostream *s)
911 (*s)<<"\""<<name<<"\" ("
912 <<(position.X/10)<<","<<(position.Y/10)
913 <<","<<(position.Z/10)<<") ";
915 (*s)<<" avg_rtt="<<avg_rtt;
924 const std::string &path_world,
925 const std::string &path_config,
926 const SubgameSpec &gamespec,
927 bool simple_singleplayer_mode
929 m_path_world(path_world),
930 m_path_config(path_config),
931 m_gamespec(gamespec),
932 m_simple_singleplayer_mode(simple_singleplayer_mode),
933 m_async_fatal_error(""),
935 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
936 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
938 m_rollback_sink_enabled(true),
939 m_enable_rollback_recording(false),
941 m_itemdef(createItemDefManager()),
942 m_nodedef(createNodeDefManager()),
943 m_craftdef(createCraftDefManager()),
944 m_event(new EventManager()),
946 m_emergethread(this),
947 m_time_of_day_send_timer(0),
949 m_shutdown_requested(false),
950 m_ignore_map_edit_events(false),
951 m_ignore_map_edit_events_peer_id(0)
953 m_liquid_transform_timer = 0.0;
954 m_print_info_timer = 0.0;
955 m_objectdata_timer = 0.0;
956 m_emergethread_trigger_timer = 0.0;
957 m_savemap_timer = 0.0;
961 m_step_dtime_mutex.Init();
965 throw ServerError("Supplied empty world path");
967 if(!gamespec.isValid())
968 throw ServerError("Supplied invalid gamespec");
970 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
971 if(m_simple_singleplayer_mode)
972 infostream<<" in simple singleplayer mode"<<std::endl;
974 infostream<<std::endl;
975 infostream<<"- world: "<<m_path_world<<std::endl;
976 infostream<<"- config: "<<m_path_config<<std::endl;
977 infostream<<"- game: "<<m_gamespec.path<<std::endl;
979 // Create rollback manager
980 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
981 m_rollback = createRollbackManager(rollback_path, this);
983 // Add world mod search path
984 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
985 // Add addon mod search path
986 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
987 i != m_gamespec.mods_paths.end(); i++)
988 m_modspaths.push_front((*i));
990 // Print out mod search paths
991 for(core::list<std::string>::Iterator i = m_modspaths.begin();
992 i != m_modspaths.end(); i++){
993 std::string modspath = *i;
994 infostream<<"- mods: "<<modspath<<std::endl;
997 // Path to builtin.lua
998 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
1000 // Create world if it doesn't exist
1001 if(!initializeWorld(m_path_world, m_gamespec.id))
1002 throw ServerError("Failed to initialize world");
1005 JMutexAutoLock envlock(m_env_mutex);
1006 JMutexAutoLock conlock(m_con_mutex);
1008 // Initialize scripting
1010 infostream<<"Server: Initializing Lua"<<std::endl;
1011 m_lua = script_init();
1014 scriptapi_export(m_lua, this);
1015 // Load and run builtin.lua
1016 infostream<<"Server: Loading builtin.lua [\""
1017 <<builtinpath<<"\"]"<<std::endl;
1018 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1020 errorstream<<"Server: Failed to load and run "
1021 <<builtinpath<<std::endl;
1022 throw ModError("Failed to load and run "+builtinpath);
1024 // Find mods in mod search paths
1025 m_mods = getMods(m_modspaths);
1027 infostream<<"Server: Loading mods: ";
1028 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1029 i != m_mods.end(); i++){
1030 const ModSpec &mod = *i;
1031 infostream<<mod.name<<" ";
1033 infostream<<std::endl;
1034 // Load and run "mod" scripts
1035 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1036 i != m_mods.end(); i++){
1037 const ModSpec &mod = *i;
1038 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1039 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1040 <<scriptpath<<"\"]"<<std::endl;
1041 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1043 errorstream<<"Server: Failed to load and run "
1044 <<scriptpath<<std::endl;
1045 throw ModError("Failed to load and run "+scriptpath);
1049 // Read Textures and calculate sha1 sums
1052 // Apply item aliases in the node definition manager
1053 m_nodedef->updateAliases(m_itemdef);
1055 // Initialize Environment
1057 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
1060 // Give environment reference to scripting api
1061 scriptapi_add_environment(m_lua, m_env);
1063 // Register us to receive map edit events
1064 m_env->getMap().addEventReceiver(this);
1066 // If file exists, load environment metadata
1067 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1069 infostream<<"Server: Loading environment metadata"<<std::endl;
1070 m_env->loadMeta(m_path_world);
1074 infostream<<"Server: Loading players"<<std::endl;
1075 m_env->deSerializePlayers(m_path_world);
1078 Add some test ActiveBlockModifiers to environment
1080 add_legacy_abms(m_env, m_nodedef);
1085 infostream<<"Server destructing"<<std::endl;
1088 Send shutdown message
1091 JMutexAutoLock conlock(m_con_mutex);
1093 std::wstring line = L"*** Server shutting down";
1096 Send the message to clients
1098 for(core::map<u16, RemoteClient*>::Iterator
1099 i = m_clients.getIterator();
1100 i.atEnd() == false; i++)
1102 // Get client and check that it is valid
1103 RemoteClient *client = i.getNode()->getValue();
1104 assert(client->peer_id == i.getNode()->getKey());
1105 if(client->serialization_version == SER_FMT_VER_INVALID)
1109 SendChatMessage(client->peer_id, line);
1111 catch(con::PeerNotFoundException &e)
1117 Execute script shutdown hooks
1119 scriptapi_on_shutdown(m_lua);
1122 JMutexAutoLock envlock(m_env_mutex);
1127 infostream<<"Server: Saving players"<<std::endl;
1128 m_env->serializePlayers(m_path_world);
1131 Save environment metadata
1133 infostream<<"Server: Saving environment metadata"<<std::endl;
1134 m_env->saveMeta(m_path_world);
1146 JMutexAutoLock clientslock(m_con_mutex);
1148 for(core::map<u16, RemoteClient*>::Iterator
1149 i = m_clients.getIterator();
1150 i.atEnd() == false; i++)
1153 // NOTE: These are removed by env destructor
1155 u16 peer_id = i.getNode()->getKey();
1156 JMutexAutoLock envlock(m_env_mutex);
1157 m_env->removePlayer(peer_id);
1161 delete i.getNode()->getValue();
1165 // Delete things in the reverse order of creation
1173 // Deinitialize scripting
1174 infostream<<"Server: Deinitializing scripting"<<std::endl;
1175 script_deinit(m_lua);
1177 // Delete detached inventories
1179 for(std::map<std::string, Inventory*>::iterator
1180 i = m_detached_inventories.begin();
1181 i != m_detached_inventories.end(); i++){
1187 void Server::start(unsigned short port)
1189 DSTACK(__FUNCTION_NAME);
1190 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1192 // Stop thread if already running
1195 // Initialize connection
1196 m_con.SetTimeoutMs(30);
1200 m_thread.setRun(true);
1203 // ASCII art for the win!
1205 <<" .__ __ __ "<<std::endl
1206 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1207 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1208 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1209 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1210 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1211 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1212 actionstream<<"Server for gameid=\""<<m_gamespec.id
1213 <<"\" listening on port "<<port<<"."<<std::endl;
1218 DSTACK(__FUNCTION_NAME);
1220 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1222 // Stop threads (set run=false first so both start stopping)
1223 m_thread.setRun(false);
1224 m_emergethread.setRun(false);
1226 m_emergethread.stop();
1228 infostream<<"Server: Threads stopped"<<std::endl;
1231 void Server::step(float dtime)
1233 DSTACK(__FUNCTION_NAME);
1238 JMutexAutoLock lock(m_step_dtime_mutex);
1239 m_step_dtime += dtime;
1241 // Throw if fatal error occurred in thread
1242 std::string async_err = m_async_fatal_error.get();
1243 if(async_err != ""){
1244 throw ServerError(async_err);
1248 void Server::AsyncRunStep()
1250 DSTACK(__FUNCTION_NAME);
1252 g_profiler->add("Server::AsyncRunStep (num)", 1);
1256 JMutexAutoLock lock1(m_step_dtime_mutex);
1257 dtime = m_step_dtime;
1261 // Send blocks to clients
1268 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1270 //infostream<<"Server steps "<<dtime<<std::endl;
1271 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1274 JMutexAutoLock lock1(m_step_dtime_mutex);
1275 m_step_dtime -= dtime;
1282 m_uptime.set(m_uptime.get() + dtime);
1286 // Process connection's timeouts
1287 JMutexAutoLock lock2(m_con_mutex);
1288 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1289 m_con.RunTimeouts(dtime);
1293 // This has to be called so that the client list gets synced
1294 // with the peer list of the connection
1295 handlePeerChanges();
1299 Update time of day and overall game time
1302 JMutexAutoLock envlock(m_env_mutex);
1304 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1307 Send to clients at constant intervals
1310 m_time_of_day_send_timer -= dtime;
1311 if(m_time_of_day_send_timer < 0.0)
1313 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1315 //JMutexAutoLock envlock(m_env_mutex);
1316 JMutexAutoLock conlock(m_con_mutex);
1318 for(core::map<u16, RemoteClient*>::Iterator
1319 i = m_clients.getIterator();
1320 i.atEnd() == false; i++)
1322 RemoteClient *client = i.getNode()->getValue();
1323 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1324 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1326 m_con.Send(client->peer_id, 0, data, true);
1332 JMutexAutoLock lock(m_env_mutex);
1334 ScopeProfiler sp(g_profiler, "SEnv step");
1335 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1339 const float map_timer_and_unload_dtime = 2.92;
1340 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1342 JMutexAutoLock lock(m_env_mutex);
1343 // Run Map's timers and unload unused data
1344 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1345 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1346 g_settings->getFloat("server_unload_unused_data_timeout"));
1357 JMutexAutoLock lock(m_env_mutex);
1358 JMutexAutoLock lock2(m_con_mutex);
1360 ScopeProfiler sp(g_profiler, "Server: handle players");
1362 for(core::map<u16, RemoteClient*>::Iterator
1363 i = m_clients.getIterator();
1364 i.atEnd() == false; i++)
1366 RemoteClient *client = i.getNode()->getValue();
1367 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1368 if(playersao == NULL)
1372 Handle player HPs (die if hp=0)
1374 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
1375 DiePlayer(client->peer_id);
1378 Send player inventories and HPs if necessary
1380 if(playersao->m_moved){
1381 SendMovePlayer(client->peer_id);
1382 playersao->m_moved = false;
1384 if(playersao->m_inventory_not_sent){
1385 UpdateCrafting(client->peer_id);
1386 SendInventory(client->peer_id);
1388 if(playersao->m_hp_not_sent){
1389 SendPlayerHP(client->peer_id);
1394 /* Transform liquids */
1395 m_liquid_transform_timer += dtime;
1396 if(m_liquid_transform_timer >= 1.00)
1398 m_liquid_transform_timer -= 1.00;
1400 JMutexAutoLock lock(m_env_mutex);
1402 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1404 core::map<v3s16, MapBlock*> modified_blocks;
1405 m_env->getMap().transformLiquids(modified_blocks);
1410 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1411 ServerMap &map = ((ServerMap&)m_env->getMap());
1412 map.updateLighting(modified_blocks, lighting_modified_blocks);
1414 // Add blocks modified by lighting to modified_blocks
1415 for(core::map<v3s16, MapBlock*>::Iterator
1416 i = lighting_modified_blocks.getIterator();
1417 i.atEnd() == false; i++)
1419 MapBlock *block = i.getNode()->getValue();
1420 modified_blocks.insert(block->getPos(), block);
1424 Set the modified blocks unsent for all the clients
1427 JMutexAutoLock lock2(m_con_mutex);
1429 for(core::map<u16, RemoteClient*>::Iterator
1430 i = m_clients.getIterator();
1431 i.atEnd() == false; i++)
1433 RemoteClient *client = i.getNode()->getValue();
1435 if(modified_blocks.size() > 0)
1437 // Remove block from sent history
1438 client->SetBlocksNotSent(modified_blocks);
1443 // Periodically print some info
1445 float &counter = m_print_info_timer;
1451 JMutexAutoLock lock2(m_con_mutex);
1453 if(m_clients.size() != 0)
1454 infostream<<"Players:"<<std::endl;
1455 for(core::map<u16, RemoteClient*>::Iterator
1456 i = m_clients.getIterator();
1457 i.atEnd() == false; i++)
1459 //u16 peer_id = i.getNode()->getKey();
1460 RemoteClient *client = i.getNode()->getValue();
1461 Player *player = m_env->getPlayer(client->peer_id);
1464 infostream<<"* "<<player->getName()<<"\t";
1465 client->PrintInfo(infostream);
1470 //if(g_settings->getBool("enable_experimental"))
1474 Check added and deleted active objects
1477 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1478 JMutexAutoLock envlock(m_env_mutex);
1479 JMutexAutoLock conlock(m_con_mutex);
1481 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1483 // Radius inside which objects are active
1484 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1485 radius *= MAP_BLOCKSIZE;
1487 for(core::map<u16, RemoteClient*>::Iterator
1488 i = m_clients.getIterator();
1489 i.atEnd() == false; i++)
1491 RemoteClient *client = i.getNode()->getValue();
1493 // If definitions and textures have not been sent, don't
1494 // send objects either
1495 if(!client->definitions_sent)
1498 Player *player = m_env->getPlayer(client->peer_id);
1501 // This can happen if the client timeouts somehow
1502 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1504 <<" has no associated player"<<std::endl;*/
1507 v3s16 pos = floatToInt(player->getPosition(), BS);
1509 core::map<u16, bool> removed_objects;
1510 core::map<u16, bool> added_objects;
1511 m_env->getRemovedActiveObjects(pos, radius,
1512 client->m_known_objects, removed_objects);
1513 m_env->getAddedActiveObjects(pos, radius,
1514 client->m_known_objects, added_objects);
1516 // Ignore if nothing happened
1517 if(removed_objects.size() == 0 && added_objects.size() == 0)
1519 //infostream<<"active objects: none changed"<<std::endl;
1523 std::string data_buffer;
1527 // Handle removed objects
1528 writeU16((u8*)buf, removed_objects.size());
1529 data_buffer.append(buf, 2);
1530 for(core::map<u16, bool>::Iterator
1531 i = removed_objects.getIterator();
1532 i.atEnd()==false; i++)
1535 u16 id = i.getNode()->getKey();
1536 ServerActiveObject* obj = m_env->getActiveObject(id);
1538 // Add to data buffer for sending
1539 writeU16((u8*)buf, i.getNode()->getKey());
1540 data_buffer.append(buf, 2);
1542 // Remove from known objects
1543 client->m_known_objects.remove(i.getNode()->getKey());
1545 if(obj && obj->m_known_by_count > 0)
1546 obj->m_known_by_count--;
1549 // Handle added objects
1550 writeU16((u8*)buf, added_objects.size());
1551 data_buffer.append(buf, 2);
1552 for(core::map<u16, bool>::Iterator
1553 i = added_objects.getIterator();
1554 i.atEnd()==false; i++)
1557 u16 id = i.getNode()->getKey();
1558 ServerActiveObject* obj = m_env->getActiveObject(id);
1561 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1563 infostream<<"WARNING: "<<__FUNCTION_NAME
1564 <<": NULL object"<<std::endl;
1566 type = obj->getSendType();
1568 // Add to data buffer for sending
1569 writeU16((u8*)buf, id);
1570 data_buffer.append(buf, 2);
1571 writeU8((u8*)buf, type);
1572 data_buffer.append(buf, 1);
1575 data_buffer.append(serializeLongString(
1576 obj->getClientInitializationData(client->net_proto_version)));
1578 data_buffer.append(serializeLongString(""));
1580 // Add to known objects
1581 client->m_known_objects.insert(i.getNode()->getKey(), false);
1584 obj->m_known_by_count++;
1588 SharedBuffer<u8> reply(2 + data_buffer.size());
1589 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1590 memcpy((char*)&reply[2], data_buffer.c_str(),
1591 data_buffer.size());
1593 m_con.Send(client->peer_id, 0, reply, true);
1595 verbosestream<<"Server: Sent object remove/add: "
1596 <<removed_objects.size()<<" removed, "
1597 <<added_objects.size()<<" added, "
1598 <<"packet size is "<<reply.getSize()<<std::endl;
1603 Collect a list of all the objects known by the clients
1604 and report it back to the environment.
1607 core::map<u16, bool> all_known_objects;
1609 for(core::map<u16, RemoteClient*>::Iterator
1610 i = m_clients.getIterator();
1611 i.atEnd() == false; i++)
1613 RemoteClient *client = i.getNode()->getValue();
1614 // Go through all known objects of client
1615 for(core::map<u16, bool>::Iterator
1616 i = client->m_known_objects.getIterator();
1617 i.atEnd()==false; i++)
1619 u16 id = i.getNode()->getKey();
1620 all_known_objects[id] = true;
1624 m_env->setKnownActiveObjects(whatever);
1630 Send object messages
1633 JMutexAutoLock envlock(m_env_mutex);
1634 JMutexAutoLock conlock(m_con_mutex);
1636 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1639 // Value = data sent by object
1640 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1642 // Get active object messages from environment
1645 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1649 core::list<ActiveObjectMessage>* message_list = NULL;
1650 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1651 n = buffered_messages.find(aom.id);
1654 message_list = new core::list<ActiveObjectMessage>;
1655 buffered_messages.insert(aom.id, message_list);
1659 message_list = n->getValue();
1661 message_list->push_back(aom);
1664 // Route data to every client
1665 for(core::map<u16, RemoteClient*>::Iterator
1666 i = m_clients.getIterator();
1667 i.atEnd()==false; i++)
1669 RemoteClient *client = i.getNode()->getValue();
1670 std::string reliable_data;
1671 std::string unreliable_data;
1672 // Go through all objects in message buffer
1673 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1674 j = buffered_messages.getIterator();
1675 j.atEnd()==false; j++)
1677 // If object is not known by client, skip it
1678 u16 id = j.getNode()->getKey();
1679 if(client->m_known_objects.find(id) == NULL)
1681 // Get message list of object
1682 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1683 // Go through every message
1684 for(core::list<ActiveObjectMessage>::Iterator
1685 k = list->begin(); k != list->end(); k++)
1687 // Compose the full new data with header
1688 ActiveObjectMessage aom = *k;
1689 std::string new_data;
1692 writeU16((u8*)&buf[0], aom.id);
1693 new_data.append(buf, 2);
1695 new_data += serializeString(aom.datastring);
1696 // Add data to buffer
1698 reliable_data += new_data;
1700 unreliable_data += new_data;
1704 reliable_data and unreliable_data are now ready.
1707 if(reliable_data.size() > 0)
1709 SharedBuffer<u8> reply(2 + reliable_data.size());
1710 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1711 memcpy((char*)&reply[2], reliable_data.c_str(),
1712 reliable_data.size());
1714 m_con.Send(client->peer_id, 0, reply, true);
1716 if(unreliable_data.size() > 0)
1718 SharedBuffer<u8> reply(2 + unreliable_data.size());
1719 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1720 memcpy((char*)&reply[2], unreliable_data.c_str(),
1721 unreliable_data.size());
1722 // Send as unreliable
1723 m_con.Send(client->peer_id, 0, reply, false);
1726 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1728 infostream<<"Server: Size of object message data: "
1729 <<"reliable: "<<reliable_data.size()
1730 <<", unreliable: "<<unreliable_data.size()
1735 // Clear buffered_messages
1736 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1737 i = buffered_messages.getIterator();
1738 i.atEnd()==false; i++)
1740 delete i.getNode()->getValue();
1744 } // enable_experimental
1747 Send queued-for-sending map edit events.
1750 // We will be accessing the environment and the connection
1751 JMutexAutoLock lock(m_env_mutex);
1752 JMutexAutoLock conlock(m_con_mutex);
1754 // Don't send too many at a time
1757 // Single change sending is disabled if queue size is not small
1758 bool disable_single_change_sending = false;
1759 if(m_unsent_map_edit_queue.size() >= 4)
1760 disable_single_change_sending = true;
1762 int event_count = m_unsent_map_edit_queue.size();
1764 // We'll log the amount of each
1767 while(m_unsent_map_edit_queue.size() != 0)
1769 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1771 // Players far away from the change are stored here.
1772 // Instead of sending the changes, MapBlocks are set not sent
1774 core::list<u16> far_players;
1776 if(event->type == MEET_ADDNODE)
1778 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1779 prof.add("MEET_ADDNODE", 1);
1780 if(disable_single_change_sending)
1781 sendAddNode(event->p, event->n, event->already_known_by_peer,
1784 sendAddNode(event->p, event->n, event->already_known_by_peer,
1787 else if(event->type == MEET_REMOVENODE)
1789 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1790 prof.add("MEET_REMOVENODE", 1);
1791 if(disable_single_change_sending)
1792 sendRemoveNode(event->p, event->already_known_by_peer,
1795 sendRemoveNode(event->p, event->already_known_by_peer,
1798 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1800 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1801 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1802 setBlockNotSent(event->p);
1804 else if(event->type == MEET_OTHER)
1806 infostream<<"Server: MEET_OTHER"<<std::endl;
1807 prof.add("MEET_OTHER", 1);
1808 for(core::map<v3s16, bool>::Iterator
1809 i = event->modified_blocks.getIterator();
1810 i.atEnd()==false; i++)
1812 v3s16 p = i.getNode()->getKey();
1818 prof.add("unknown", 1);
1819 infostream<<"WARNING: Server: Unknown MapEditEvent "
1820 <<((u32)event->type)<<std::endl;
1824 Set blocks not sent to far players
1826 if(far_players.size() > 0)
1828 // Convert list format to that wanted by SetBlocksNotSent
1829 core::map<v3s16, MapBlock*> modified_blocks2;
1830 for(core::map<v3s16, bool>::Iterator
1831 i = event->modified_blocks.getIterator();
1832 i.atEnd()==false; i++)
1834 v3s16 p = i.getNode()->getKey();
1835 modified_blocks2.insert(p,
1836 m_env->getMap().getBlockNoCreateNoEx(p));
1838 // Set blocks not sent
1839 for(core::list<u16>::Iterator
1840 i = far_players.begin();
1841 i != far_players.end(); i++)
1844 RemoteClient *client = getClient(peer_id);
1847 client->SetBlocksNotSent(modified_blocks2);
1853 /*// Don't send too many at a time
1855 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1859 if(event_count >= 5){
1860 infostream<<"Server: MapEditEvents:"<<std::endl;
1861 prof.print(infostream);
1862 } else if(event_count != 0){
1863 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1864 prof.print(verbosestream);
1870 Trigger emergethread (it somehow gets to a non-triggered but
1871 bysy state sometimes)
1874 float &counter = m_emergethread_trigger_timer;
1880 m_emergethread.trigger();
1882 // Update m_enable_rollback_recording here too
1883 m_enable_rollback_recording =
1884 g_settings->getBool("enable_rollback_recording");
1888 // Save map, players and auth stuff
1890 float &counter = m_savemap_timer;
1892 if(counter >= g_settings->getFloat("server_map_save_interval"))
1895 JMutexAutoLock lock(m_env_mutex);
1897 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1900 if(m_banmanager.isModified())
1901 m_banmanager.save();
1903 // Save changed parts of map
1904 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1907 m_env->serializePlayers(m_path_world);
1909 // Save environment metadata
1910 m_env->saveMeta(m_path_world);
1915 void Server::Receive()
1917 DSTACK(__FUNCTION_NAME);
1918 SharedBuffer<u8> data;
1923 JMutexAutoLock conlock(m_con_mutex);
1924 datasize = m_con.Receive(peer_id, data);
1927 // This has to be called so that the client list gets synced
1928 // with the peer list of the connection
1929 handlePeerChanges();
1931 ProcessData(*data, datasize, peer_id);
1933 catch(con::InvalidIncomingDataException &e)
1935 infostream<<"Server::Receive(): "
1936 "InvalidIncomingDataException: what()="
1937 <<e.what()<<std::endl;
1939 catch(con::PeerNotFoundException &e)
1941 //NOTE: This is not needed anymore
1943 // The peer has been disconnected.
1944 // Find the associated player and remove it.
1946 /*JMutexAutoLock envlock(m_env_mutex);
1948 infostream<<"ServerThread: peer_id="<<peer_id
1949 <<" has apparently closed connection. "
1950 <<"Removing player."<<std::endl;
1952 m_env->removePlayer(peer_id);*/
1956 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1958 DSTACK(__FUNCTION_NAME);
1959 // Environment is locked first.
1960 JMutexAutoLock envlock(m_env_mutex);
1961 JMutexAutoLock conlock(m_con_mutex);
1963 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1966 Address address = m_con.GetPeerAddress(peer_id);
1967 std::string addr_s = address.serializeString();
1969 // drop player if is ip is banned
1970 if(m_banmanager.isIpBanned(addr_s)){
1971 infostream<<"Server: A banned client tried to connect from "
1972 <<addr_s<<"; banned name was "
1973 <<m_banmanager.getBanName(addr_s)<<std::endl;
1974 // This actually doesn't seem to transfer to the client
1975 SendAccessDenied(m_con, peer_id,
1976 L"Your ip is banned. Banned name was "
1977 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1978 m_con.DeletePeer(peer_id);
1982 catch(con::PeerNotFoundException &e)
1984 infostream<<"Server::ProcessData(): Cancelling: peer "
1985 <<peer_id<<" not found"<<std::endl;
1989 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1991 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1999 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
2001 if(command == TOSERVER_INIT)
2003 // [0] u16 TOSERVER_INIT
2004 // [2] u8 SER_FMT_VER_HIGHEST
2005 // [3] u8[20] player_name
2006 // [23] u8[28] password <--- can be sent without this, from old versions
2008 if(datasize < 2+1+PLAYERNAME_SIZE)
2011 verbosestream<<"Server: Got TOSERVER_INIT from "
2012 <<peer_id<<std::endl;
2014 // First byte after command is maximum supported
2015 // serialization version
2016 u8 client_max = data[2];
2017 u8 our_max = SER_FMT_VER_HIGHEST;
2018 // Use the highest version supported by both
2019 u8 deployed = core::min_(client_max, our_max);
2020 // If it's lower than the lowest supported, give up.
2021 if(deployed < SER_FMT_VER_LOWEST)
2022 deployed = SER_FMT_VER_INVALID;
2024 //peer->serialization_version = deployed;
2025 getClient(peer_id)->pending_serialization_version = deployed;
2027 if(deployed == SER_FMT_VER_INVALID)
2029 actionstream<<"Server: A mismatched client tried to connect from "
2030 <<addr_s<<std::endl;
2031 infostream<<"Server: Cannot negotiate "
2032 "serialization version with peer "
2033 <<peer_id<<std::endl;
2034 SendAccessDenied(m_con, peer_id, std::wstring(
2035 L"Your client's version is not supported.\n"
2036 L"Server version is ")
2037 + narrow_to_wide(VERSION_STRING) + L"."
2043 Read and check network protocol version
2046 u16 min_net_proto_version = 0;
2047 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2048 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2050 // Use same version as minimum and maximum if maximum version field
2051 // doesn't exist (backwards compatibility)
2052 u16 max_net_proto_version = min_net_proto_version;
2053 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
2054 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
2056 // Start with client's maximum version
2057 u16 net_proto_version = max_net_proto_version;
2059 // Figure out a working version if it is possible at all
2060 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
2061 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
2063 // If maximum is larger than our maximum, go with our maximum
2064 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2065 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
2066 // Else go with client's maximum
2068 net_proto_version = max_net_proto_version;
2071 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
2072 <<min_net_proto_version<<", max: "<<max_net_proto_version
2073 <<", chosen: "<<net_proto_version<<std::endl;
2075 getClient(peer_id)->net_proto_version = net_proto_version;
2077 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
2078 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2080 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
2082 SendAccessDenied(m_con, peer_id, std::wstring(
2083 L"Your client's version is not supported.\n"
2084 L"Server version is ")
2085 + narrow_to_wide(VERSION_STRING) + L",\n"
2086 + L"server's PROTOCOL_VERSION is "
2087 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
2089 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
2090 + L", client's PROTOCOL_VERSION is "
2091 + narrow_to_wide(itos(min_net_proto_version))
2093 + narrow_to_wide(itos(max_net_proto_version))
2098 if(g_settings->getBool("strict_protocol_version_checking"))
2100 if(net_proto_version != LATEST_PROTOCOL_VERSION)
2102 actionstream<<"Server: A mismatched (strict) client tried to "
2103 <<"connect from "<<addr_s<<std::endl;
2104 SendAccessDenied(m_con, peer_id, std::wstring(
2105 L"Your client's version is not supported.\n"
2106 L"Server version is ")
2107 + narrow_to_wide(VERSION_STRING) + L",\n"
2108 + L"server's PROTOCOL_VERSION (strict) is "
2109 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
2110 + L", client's PROTOCOL_VERSION is "
2111 + narrow_to_wide(itos(min_net_proto_version))
2113 + narrow_to_wide(itos(max_net_proto_version))
2124 char playername[PLAYERNAME_SIZE];
2125 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2127 playername[i] = data[3+i];
2129 playername[PLAYERNAME_SIZE-1] = 0;
2131 if(playername[0]=='\0')
2133 actionstream<<"Server: Player with an empty name "
2134 <<"tried to connect from "<<addr_s<<std::endl;
2135 SendAccessDenied(m_con, peer_id,
2140 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2142 actionstream<<"Server: Player with an invalid name "
2143 <<"tried to connect from "<<addr_s<<std::endl;
2144 SendAccessDenied(m_con, peer_id,
2145 L"Name contains unallowed characters");
2149 infostream<<"Server: New connection: \""<<playername<<"\" from "
2150 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2153 char given_password[PASSWORD_SIZE];
2154 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2156 // old version - assume blank password
2157 given_password[0] = 0;
2161 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2163 given_password[i] = data[23+i];
2165 given_password[PASSWORD_SIZE-1] = 0;
2168 if(!base64_is_valid(given_password)){
2169 infostream<<"Server: "<<playername
2170 <<" supplied invalid password hash"<<std::endl;
2171 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2175 std::string checkpwd; // Password hash to check against
2176 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2178 // If no authentication info exists for user, create it
2180 if(!isSingleplayer() &&
2181 g_settings->getBool("disallow_empty_password") &&
2182 std::string(given_password) == ""){
2183 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2184 L"disallowed. Set a password and try again.");
2187 std::wstring raw_default_password =
2188 narrow_to_wide(g_settings->get("default_password"));
2189 std::string initial_password =
2190 translatePassword(playername, raw_default_password);
2192 // If default_password is empty, allow any initial password
2193 if (raw_default_password.length() == 0)
2194 initial_password = given_password;
2196 scriptapi_create_auth(m_lua, playername, initial_password);
2199 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2202 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2206 if(given_password != checkpwd){
2207 infostream<<"Server: peer_id="<<peer_id
2208 <<": supplied invalid password for "
2209 <<playername<<std::endl;
2210 SendAccessDenied(m_con, peer_id, L"Invalid password");
2214 // Do not allow multiple players in simple singleplayer mode.
2215 // This isn't a perfect way to do it, but will suffice for now.
2216 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2217 infostream<<"Server: Not allowing another client to connect in"
2218 <<" simple singleplayer mode"<<std::endl;
2219 SendAccessDenied(m_con, peer_id,
2220 L"Running in simple singleplayer mode.");
2224 // Enforce user limit.
2225 // Don't enforce for users that have some admin right
2226 if(m_clients.size() >= g_settings->getU16("max_users") &&
2227 !checkPriv(playername, "server") &&
2228 !checkPriv(playername, "ban") &&
2229 !checkPriv(playername, "privs") &&
2230 !checkPriv(playername, "password") &&
2231 playername != g_settings->get("name"))
2233 actionstream<<"Server: "<<playername<<" tried to join, but there"
2234 <<" are already max_users="
2235 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2236 SendAccessDenied(m_con, peer_id, L"Too many users.");
2241 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2243 // If failed, cancel
2244 if(playersao == NULL)
2246 errorstream<<"Server: peer_id="<<peer_id
2247 <<": failed to emerge player"<<std::endl;
2252 Answer with a TOCLIENT_INIT
2255 SharedBuffer<u8> reply(2+1+6+8+4);
2256 writeU16(&reply[0], TOCLIENT_INIT);
2257 writeU8(&reply[2], deployed);
2258 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2259 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2260 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2263 m_con.Send(peer_id, 0, reply, true);
2267 Send complete position information
2269 SendMovePlayer(peer_id);
2274 if(command == TOSERVER_INIT2)
2276 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2277 <<peer_id<<std::endl;
2279 Player *player = m_env->getPlayer(peer_id);
2281 verbosestream<<"Server: TOSERVER_INIT2: "
2282 <<"Player not found; ignoring."<<std::endl;
2286 RemoteClient *client = getClient(peer_id);
2287 client->serialization_version =
2288 getClient(peer_id)->pending_serialization_version;
2291 Send some initialization data
2294 infostream<<"Server: Sending content to "
2295 <<getPlayerName(peer_id)<<std::endl;
2297 // Send item definitions
2298 SendItemDef(m_con, peer_id, m_itemdef);
2300 // Send node definitions
2301 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2303 // Send media announcement
2304 sendMediaAnnouncement(peer_id);
2307 SendPlayerPrivileges(peer_id);
2309 // Send inventory formspec
2310 SendPlayerInventoryFormspec(peer_id);
2313 UpdateCrafting(peer_id);
2314 SendInventory(peer_id);
2317 SendPlayerHP(peer_id);
2319 // Send detached inventories
2320 sendDetachedInventories(peer_id);
2322 // Show death screen if necessary
2324 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2328 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2329 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2330 m_con.Send(peer_id, 0, data, true);
2333 // Note things in chat if not in simple singleplayer mode
2334 if(!m_simple_singleplayer_mode)
2336 // Send information about server to player in chat
2337 SendChatMessage(peer_id, getStatusString());
2339 // Send information about joining in chat
2341 std::wstring name = L"unknown";
2342 Player *player = m_env->getPlayer(peer_id);
2344 name = narrow_to_wide(player->getName());
2346 std::wstring message;
2349 message += L" joined the game.";
2350 BroadcastChatMessage(message);
2354 // Warnings about protocol version can be issued here
2355 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2357 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2358 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2365 std::ostringstream os(std::ios_base::binary);
2366 for(core::map<u16, RemoteClient*>::Iterator
2367 i = m_clients.getIterator();
2368 i.atEnd() == false; i++)
2370 RemoteClient *client = i.getNode()->getValue();
2371 assert(client->peer_id == i.getNode()->getKey());
2372 if(client->serialization_version == SER_FMT_VER_INVALID)
2375 Player *player = m_env->getPlayer(client->peer_id);
2378 // Get name of player
2379 os<<player->getName()<<" ";
2382 actionstream<<player->getName()<<" joins game. List of players: "
2383 <<os.str()<<std::endl;
2389 if(peer_ser_ver == SER_FMT_VER_INVALID)
2391 infostream<<"Server::ProcessData(): Cancelling: Peer"
2392 " serialization format invalid or not initialized."
2393 " Skipping incoming command="<<command<<std::endl;
2397 Player *player = m_env->getPlayer(peer_id);
2399 infostream<<"Server::ProcessData(): Cancelling: "
2400 "No player for peer_id="<<peer_id
2405 PlayerSAO *playersao = player->getPlayerSAO();
2406 if(playersao == NULL){
2407 infostream<<"Server::ProcessData(): Cancelling: "
2408 "No player object for peer_id="<<peer_id
2413 if(command == TOSERVER_PLAYERPOS)
2415 if(datasize < 2+12+12+4+4)
2419 v3s32 ps = readV3S32(&data[start+2]);
2420 v3s32 ss = readV3S32(&data[start+2+12]);
2421 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2422 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2424 if(datasize >= 2+12+12+4+4+4)
2425 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2426 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2427 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2428 pitch = wrapDegrees(pitch);
2429 yaw = wrapDegrees(yaw);
2431 player->setPosition(position);
2432 player->setSpeed(speed);
2433 player->setPitch(pitch);
2434 player->setYaw(yaw);
2435 player->keyPressed=keyPressed;
2436 player->control.up = (bool)(keyPressed&1);
2437 player->control.down = (bool)(keyPressed&2);
2438 player->control.left = (bool)(keyPressed&4);
2439 player->control.right = (bool)(keyPressed&8);
2440 player->control.jump = (bool)(keyPressed&16);
2441 player->control.aux1 = (bool)(keyPressed&32);
2442 player->control.sneak = (bool)(keyPressed&64);
2443 player->control.LMB = (bool)(keyPressed&128);
2444 player->control.RMB = (bool)(keyPressed&256);
2446 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2447 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2448 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2450 else if(command == TOSERVER_GOTBLOCKS)
2463 u16 count = data[2];
2464 for(u16 i=0; i<count; i++)
2466 if((s16)datasize < 2+1+(i+1)*6)
2467 throw con::InvalidIncomingDataException
2468 ("GOTBLOCKS length is too short");
2469 v3s16 p = readV3S16(&data[2+1+i*6]);
2470 /*infostream<<"Server: GOTBLOCKS ("
2471 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2472 RemoteClient *client = getClient(peer_id);
2473 client->GotBlock(p);
2476 else if(command == TOSERVER_DELETEDBLOCKS)
2489 u16 count = data[2];
2490 for(u16 i=0; i<count; i++)
2492 if((s16)datasize < 2+1+(i+1)*6)
2493 throw con::InvalidIncomingDataException
2494 ("DELETEDBLOCKS length is too short");
2495 v3s16 p = readV3S16(&data[2+1+i*6]);
2496 /*infostream<<"Server: DELETEDBLOCKS ("
2497 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2498 RemoteClient *client = getClient(peer_id);
2499 client->SetBlockNotSent(p);
2502 else if(command == TOSERVER_CLICK_OBJECT)
2504 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2507 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2509 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2512 else if(command == TOSERVER_GROUND_ACTION)
2514 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2518 else if(command == TOSERVER_RELEASE)
2520 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2523 else if(command == TOSERVER_SIGNTEXT)
2525 infostream<<"Server: SIGNTEXT not supported anymore"
2529 else if(command == TOSERVER_SIGNNODETEXT)
2531 infostream<<"Server: SIGNNODETEXT not supported anymore"
2535 else if(command == TOSERVER_INVENTORY_ACTION)
2537 // Strip command and create a stream
2538 std::string datastring((char*)&data[2], datasize-2);
2539 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2540 std::istringstream is(datastring, std::ios_base::binary);
2542 InventoryAction *a = InventoryAction::deSerialize(is);
2545 infostream<<"TOSERVER_INVENTORY_ACTION: "
2546 <<"InventoryAction::deSerialize() returned NULL"
2551 // If something goes wrong, this player is to blame
2552 RollbackScopeActor rollback_scope(m_rollback,
2553 std::string("player:")+player->getName());
2556 Note: Always set inventory not sent, to repair cases
2557 where the client made a bad prediction.
2561 Handle restrictions and special cases of the move action
2563 if(a->getType() == IACTION_MOVE)
2565 IMoveAction *ma = (IMoveAction*)a;
2567 ma->from_inv.applyCurrentPlayer(player->getName());
2568 ma->to_inv.applyCurrentPlayer(player->getName());
2570 setInventoryModified(ma->from_inv);
2571 setInventoryModified(ma->to_inv);
2573 bool from_inv_is_current_player =
2574 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2575 (ma->from_inv.name == player->getName());
2577 bool to_inv_is_current_player =
2578 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2579 (ma->to_inv.name == player->getName());
2582 Disable moving items out of craftpreview
2584 if(ma->from_list == "craftpreview")
2586 infostream<<"Ignoring IMoveAction from "
2587 <<(ma->from_inv.dump())<<":"<<ma->from_list
2588 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2589 <<" because src is "<<ma->from_list<<std::endl;
2595 Disable moving items into craftresult and craftpreview
2597 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2599 infostream<<"Ignoring IMoveAction from "
2600 <<(ma->from_inv.dump())<<":"<<ma->from_list
2601 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2602 <<" because dst is "<<ma->to_list<<std::endl;
2607 // Disallow moving items in elsewhere than player's inventory
2608 // if not allowed to interact
2609 if(!checkPriv(player->getName(), "interact") &&
2610 (!from_inv_is_current_player ||
2611 !to_inv_is_current_player))
2613 infostream<<"Cannot move outside of player's inventory: "
2614 <<"No interact privilege"<<std::endl;
2620 Handle restrictions and special cases of the drop action
2622 else if(a->getType() == IACTION_DROP)
2624 IDropAction *da = (IDropAction*)a;
2626 da->from_inv.applyCurrentPlayer(player->getName());
2628 setInventoryModified(da->from_inv);
2630 // Disallow dropping items if not allowed to interact
2631 if(!checkPriv(player->getName(), "interact"))
2638 Handle restrictions and special cases of the craft action
2640 else if(a->getType() == IACTION_CRAFT)
2642 ICraftAction *ca = (ICraftAction*)a;
2644 ca->craft_inv.applyCurrentPlayer(player->getName());
2646 setInventoryModified(ca->craft_inv);
2648 //bool craft_inv_is_current_player =
2649 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2650 // (ca->craft_inv.name == player->getName());
2652 // Disallow crafting if not allowed to interact
2653 if(!checkPriv(player->getName(), "interact"))
2655 infostream<<"Cannot craft: "
2656 <<"No interact privilege"<<std::endl;
2663 a->apply(this, playersao, this);
2667 else if(command == TOSERVER_CHAT_MESSAGE)
2675 std::string datastring((char*)&data[2], datasize-2);
2676 std::istringstream is(datastring, std::ios_base::binary);
2679 is.read((char*)buf, 2);
2680 u16 len = readU16(buf);
2682 std::wstring message;
2683 for(u16 i=0; i<len; i++)
2685 is.read((char*)buf, 2);
2686 message += (wchar_t)readU16(buf);
2689 // If something goes wrong, this player is to blame
2690 RollbackScopeActor rollback_scope(m_rollback,
2691 std::string("player:")+player->getName());
2693 // Get player name of this client
2694 std::wstring name = narrow_to_wide(player->getName());
2697 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2698 wide_to_narrow(message));
2699 // If script ate the message, don't proceed
2703 // Line to send to players
2705 // Whether to send to the player that sent the line
2706 bool send_to_sender = false;
2707 // Whether to send to other players
2708 bool send_to_others = false;
2710 // Commands are implemented in Lua, so only catch invalid
2711 // commands that were not "eaten" and send an error back
2712 if(message[0] == L'/')
2714 message = message.substr(1);
2715 send_to_sender = true;
2716 if(message.length() == 0)
2717 line += L"-!- Empty command";
2719 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2723 if(checkPriv(player->getName(), "shout")){
2728 send_to_others = true;
2730 line += L"-!- You don't have permission to shout.";
2731 send_to_sender = true;
2738 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2741 Send the message to clients
2743 for(core::map<u16, RemoteClient*>::Iterator
2744 i = m_clients.getIterator();
2745 i.atEnd() == false; i++)
2747 // Get client and check that it is valid
2748 RemoteClient *client = i.getNode()->getValue();
2749 assert(client->peer_id == i.getNode()->getKey());
2750 if(client->serialization_version == SER_FMT_VER_INVALID)
2754 bool sender_selected = (peer_id == client->peer_id);
2755 if(sender_selected == true && send_to_sender == false)
2757 if(sender_selected == false && send_to_others == false)
2760 SendChatMessage(client->peer_id, line);
2764 else if(command == TOSERVER_DAMAGE)
2766 std::string datastring((char*)&data[2], datasize-2);
2767 std::istringstream is(datastring, std::ios_base::binary);
2768 u8 damage = readU8(is);
2770 actionstream<<player->getName()<<" damaged by "
2771 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2774 playersao->setHP(playersao->getHP() - damage);
2776 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2779 if(playersao->m_hp_not_sent)
2780 SendPlayerHP(peer_id);
2782 else if(command == TOSERVER_PASSWORD)
2785 [0] u16 TOSERVER_PASSWORD
2786 [2] u8[28] old password
2787 [30] u8[28] new password
2790 if(datasize != 2+PASSWORD_SIZE*2)
2792 /*char password[PASSWORD_SIZE];
2793 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2794 password[i] = data[2+i];
2795 password[PASSWORD_SIZE-1] = 0;*/
2797 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2805 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2807 char c = data[2+PASSWORD_SIZE+i];
2813 if(!base64_is_valid(newpwd)){
2814 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2815 // Wrong old password supplied!!
2816 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2820 infostream<<"Server: Client requests a password change from "
2821 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2823 std::string playername = player->getName();
2825 std::string checkpwd;
2826 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2828 if(oldpwd != checkpwd)
2830 infostream<<"Server: invalid old password"<<std::endl;
2831 // Wrong old password supplied!!
2832 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2836 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2838 actionstream<<player->getName()<<" changes password"<<std::endl;
2839 SendChatMessage(peer_id, L"Password change successful.");
2841 actionstream<<player->getName()<<" tries to change password but "
2842 <<"it fails"<<std::endl;
2843 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2846 else if(command == TOSERVER_PLAYERITEM)
2851 u16 item = readU16(&data[2]);
2852 playersao->setWieldIndex(item);
2854 else if(command == TOSERVER_RESPAWN)
2859 RespawnPlayer(peer_id);
2861 actionstream<<player->getName()<<" respawns at "
2862 <<PP(player->getPosition()/BS)<<std::endl;
2864 // ActiveObject is added to environment in AsyncRunStep after
2865 // the previous addition has been succesfully removed
2867 else if(command == TOSERVER_REQUEST_MEDIA) {
2868 std::string datastring((char*)&data[2], datasize-2);
2869 std::istringstream is(datastring, std::ios_base::binary);
2871 core::list<MediaRequest> tosend;
2872 u16 numfiles = readU16(is);
2874 infostream<<"Sending "<<numfiles<<" files to "
2875 <<getPlayerName(peer_id)<<std::endl;
2876 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2878 for(int i = 0; i < numfiles; i++) {
2879 std::string name = deSerializeString(is);
2880 tosend.push_back(MediaRequest(name));
2881 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2885 sendRequestedMedia(peer_id, tosend);
2887 // Now the client should know about everything
2888 // (definitions and files)
2889 getClient(peer_id)->definitions_sent = true;
2891 else if(command == TOSERVER_INTERACT)
2893 std::string datastring((char*)&data[2], datasize-2);
2894 std::istringstream is(datastring, std::ios_base::binary);
2900 [5] u32 length of the next item
2901 [9] serialized PointedThing
2903 0: start digging (from undersurface) or use
2904 1: stop digging (all parameters ignored)
2905 2: digging completed
2906 3: place block or item (to abovesurface)
2909 u8 action = readU8(is);
2910 u16 item_i = readU16(is);
2911 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2912 PointedThing pointed;
2913 pointed.deSerialize(tmp_is);
2915 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2916 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2920 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2921 <<" tried to interact, but is dead!"<<std::endl;
2925 v3f player_pos = playersao->getLastGoodPosition();
2927 // Update wielded item
2928 playersao->setWieldIndex(item_i);
2930 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2931 v3s16 p_under = pointed.node_undersurface;
2932 v3s16 p_above = pointed.node_abovesurface;
2934 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2935 ServerActiveObject *pointed_object = NULL;
2936 if(pointed.type == POINTEDTHING_OBJECT)
2938 pointed_object = m_env->getActiveObject(pointed.object_id);
2939 if(pointed_object == NULL)
2941 verbosestream<<"TOSERVER_INTERACT: "
2942 "pointed object is NULL"<<std::endl;
2948 v3f pointed_pos_under = player_pos;
2949 v3f pointed_pos_above = player_pos;
2950 if(pointed.type == POINTEDTHING_NODE)
2952 pointed_pos_under = intToFloat(p_under, BS);
2953 pointed_pos_above = intToFloat(p_above, BS);
2955 else if(pointed.type == POINTEDTHING_OBJECT)
2957 pointed_pos_under = pointed_object->getBasePosition();
2958 pointed_pos_above = pointed_pos_under;
2962 Check that target is reasonably close
2963 (only when digging or placing things)
2965 if(action == 0 || action == 2 || action == 3)
2967 float d = player_pos.getDistanceFrom(pointed_pos_under);
2968 float max_d = BS * 14; // Just some large enough value
2970 actionstream<<"Player "<<player->getName()
2971 <<" tried to access "<<pointed.dump()
2973 <<"d="<<d<<", max_d="<<max_d
2974 <<". ignoring."<<std::endl;
2975 // Re-send block to revert change on client-side
2976 RemoteClient *client = getClient(peer_id);
2977 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2978 client->SetBlockNotSent(blockpos);
2985 Make sure the player is allowed to do it
2987 if(!checkPriv(player->getName(), "interact"))
2989 actionstream<<player->getName()<<" attempted to interact with "
2990 <<pointed.dump()<<" without 'interact' privilege"
2992 // Re-send block to revert change on client-side
2993 RemoteClient *client = getClient(peer_id);
2994 // Digging completed -> under
2996 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2997 client->SetBlockNotSent(blockpos);
2999 // Placement -> above
3001 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3002 client->SetBlockNotSent(blockpos);
3008 If something goes wrong, this player is to blame
3010 RollbackScopeActor rollback_scope(m_rollback,
3011 std::string("player:")+player->getName());
3014 0: start digging or punch object
3018 if(pointed.type == POINTEDTHING_NODE)
3021 NOTE: This can be used in the future to check if
3022 somebody is cheating, by checking the timing.
3024 MapNode n(CONTENT_IGNORE);
3027 n = m_env->getMap().getNode(p_under);
3029 catch(InvalidPositionException &e)
3031 infostream<<"Server: Not punching: Node not found."
3032 <<" Adding block to emerge queue."
3034 m_emerge_queue.addBlock(peer_id,
3035 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3037 if(n.getContent() != CONTENT_IGNORE)
3038 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3040 playersao->noCheatDigStart(p_under);
3042 else if(pointed.type == POINTEDTHING_OBJECT)
3044 // Skip if object has been removed
3045 if(pointed_object->m_removed)
3048 actionstream<<player->getName()<<" punches object "
3049 <<pointed.object_id<<": "
3050 <<pointed_object->getDescription()<<std::endl;
3052 ItemStack punchitem = playersao->getWieldedItem();
3053 ToolCapabilities toolcap =
3054 punchitem.getToolCapabilities(m_itemdef);
3055 v3f dir = (pointed_object->getBasePosition() -
3056 (player->getPosition() + player->getEyeOffset())
3058 float time_from_last_punch =
3059 playersao->resetTimeFromLastPunch();
3060 pointed_object->punch(dir, &toolcap, playersao,
3061 time_from_last_punch);
3069 else if(action == 1)
3074 2: Digging completed
3076 else if(action == 2)
3078 // Only digging of nodes
3079 if(pointed.type == POINTEDTHING_NODE)
3081 MapNode n(CONTENT_IGNORE);
3084 n = m_env->getMap().getNode(p_under);
3086 catch(InvalidPositionException &e)
3088 infostream<<"Server: Not finishing digging: Node not found."
3089 <<" Adding block to emerge queue."
3091 m_emerge_queue.addBlock(peer_id,
3092 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3095 /* Cheat prevention */
3096 bool is_valid_dig = true;
3097 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3099 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3100 float nocheat_t = playersao->getNoCheatDigTime();
3101 playersao->noCheatDigEnd();
3102 // If player didn't start digging this, ignore dig
3103 if(nocheat_p != p_under){
3104 infostream<<"Server: NoCheat: "<<player->getName()
3105 <<" started digging "
3106 <<PP(nocheat_p)<<" and completed digging "
3107 <<PP(p_under)<<"; not digging."<<std::endl;
3108 is_valid_dig = false;
3110 // Get player's wielded item
3111 ItemStack playeritem;
3112 InventoryList *mlist = playersao->getInventory()->getList("main");
3114 playeritem = mlist->getItem(playersao->getWieldIndex());
3115 ToolCapabilities playeritem_toolcap =
3116 playeritem.getToolCapabilities(m_itemdef);
3117 // Get diggability and expected digging time
3118 DigParams params = getDigParams(m_nodedef->get(n).groups,
3119 &playeritem_toolcap);
3120 // If can't dig, try hand
3121 if(!params.diggable){
3122 const ItemDefinition &hand = m_itemdef->get("");
3123 const ToolCapabilities *tp = hand.tool_capabilities;
3125 params = getDigParams(m_nodedef->get(n).groups, tp);
3127 // If can't dig, ignore dig
3128 if(!params.diggable){
3129 infostream<<"Server: NoCheat: "<<player->getName()
3130 <<" completed digging "<<PP(p_under)
3131 <<", which is not diggable with tool. not digging."
3133 is_valid_dig = false;
3135 // If time is considerably too short, ignore dig
3136 // Check time only for medium and slow timed digs
3137 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3138 infostream<<"Server: NoCheat: "<<player->getName()
3139 <<" completed digging "
3140 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3141 <<params.time<<"s; not digging."<<std::endl;
3142 is_valid_dig = false;
3146 /* Actually dig node */
3148 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3149 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3151 // Send unusual result (that is, node not being removed)
3152 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3154 // Re-send block to revert change on client-side
3155 RemoteClient *client = getClient(peer_id);
3156 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3157 client->SetBlockNotSent(blockpos);
3163 3: place block or right-click object
3165 else if(action == 3)
3167 ItemStack item = playersao->getWieldedItem();
3169 // Reset build time counter
3170 if(pointed.type == POINTEDTHING_NODE &&
3171 item.getDefinition(m_itemdef).type == ITEM_NODE)
3172 getClient(peer_id)->m_time_from_building = 0.0;
3174 if(pointed.type == POINTEDTHING_OBJECT)
3176 // Right click object
3178 // Skip if object has been removed
3179 if(pointed_object->m_removed)
3182 actionstream<<player->getName()<<" right-clicks object "
3183 <<pointed.object_id<<": "
3184 <<pointed_object->getDescription()<<std::endl;
3187 pointed_object->rightClick(playersao);
3189 else if(scriptapi_item_on_place(m_lua,
3190 item, playersao, pointed))
3192 // Placement was handled in lua
3194 // Apply returned ItemStack
3195 playersao->setWieldedItem(item);
3198 // If item has node placement prediction, always send the above
3199 // node to make sure the client knows what exactly happened
3200 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3201 RemoteClient *client = getClient(peer_id);
3202 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3203 client->SetBlockNotSent(blockpos);
3210 else if(action == 4)
3212 ItemStack item = playersao->getWieldedItem();
3214 actionstream<<player->getName()<<" uses "<<item.name
3215 <<", pointing at "<<pointed.dump()<<std::endl;
3217 if(scriptapi_item_on_use(m_lua,
3218 item, playersao, pointed))
3220 // Apply returned ItemStack
3221 playersao->setWieldedItem(item);
3228 Catch invalid actions
3232 infostream<<"WARNING: Server: Invalid action "
3233 <<action<<std::endl;
3236 else if(command == TOSERVER_REMOVED_SOUNDS)
3238 std::string datastring((char*)&data[2], datasize-2);
3239 std::istringstream is(datastring, std::ios_base::binary);
3241 int num = readU16(is);
3242 for(int k=0; k<num; k++){
3243 s32 id = readS32(is);
3244 std::map<s32, ServerPlayingSound>::iterator i =
3245 m_playing_sounds.find(id);
3246 if(i == m_playing_sounds.end())
3248 ServerPlayingSound &psound = i->second;
3249 psound.clients.erase(peer_id);
3250 if(psound.clients.size() == 0)
3251 m_playing_sounds.erase(i++);
3254 else if(command == TOSERVER_NODEMETA_FIELDS)
3256 std::string datastring((char*)&data[2], datasize-2);
3257 std::istringstream is(datastring, std::ios_base::binary);
3259 v3s16 p = readV3S16(is);
3260 std::string formname = deSerializeString(is);
3261 int num = readU16(is);
3262 std::map<std::string, std::string> fields;
3263 for(int k=0; k<num; k++){
3264 std::string fieldname = deSerializeString(is);
3265 std::string fieldvalue = deSerializeLongString(is);
3266 fields[fieldname] = fieldvalue;
3269 // If something goes wrong, this player is to blame
3270 RollbackScopeActor rollback_scope(m_rollback,
3271 std::string("player:")+player->getName());
3273 // Check the target node for rollback data; leave others unnoticed
3274 RollbackNode rn_old(&m_env->getMap(), p, this);
3276 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3279 // Report rollback data
3280 RollbackNode rn_new(&m_env->getMap(), p, this);
3281 if(rollback() && rn_new != rn_old){
3282 RollbackAction action;
3283 action.setSetNode(p, rn_old, rn_new);
3284 rollback()->reportAction(action);
3287 else if(command == TOSERVER_INVENTORY_FIELDS)
3289 std::string datastring((char*)&data[2], datasize-2);
3290 std::istringstream is(datastring, std::ios_base::binary);
3292 std::string formname = deSerializeString(is);
3293 int num = readU16(is);
3294 std::map<std::string, std::string> fields;
3295 for(int k=0; k<num; k++){
3296 std::string fieldname = deSerializeString(is);
3297 std::string fieldvalue = deSerializeLongString(is);
3298 fields[fieldname] = fieldvalue;
3301 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3305 infostream<<"Server::ProcessData(): Ignoring "
3306 "unknown command "<<command<<std::endl;
3310 catch(SendFailedException &e)
3312 errorstream<<"Server::ProcessData(): SendFailedException: "
3318 void Server::onMapEditEvent(MapEditEvent *event)
3320 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3321 if(m_ignore_map_edit_events)
3323 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3325 MapEditEvent *e = event->clone();
3326 m_unsent_map_edit_queue.push_back(e);
3329 Inventory* Server::getInventory(const InventoryLocation &loc)
3332 case InventoryLocation::UNDEFINED:
3335 case InventoryLocation::CURRENT_PLAYER:
3338 case InventoryLocation::PLAYER:
3340 Player *player = m_env->getPlayer(loc.name.c_str());
3343 PlayerSAO *playersao = player->getPlayerSAO();
3346 return playersao->getInventory();
3349 case InventoryLocation::NODEMETA:
3351 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3354 return meta->getInventory();
3357 case InventoryLocation::DETACHED:
3359 if(m_detached_inventories.count(loc.name) == 0)
3361 return m_detached_inventories[loc.name];
3369 void Server::setInventoryModified(const InventoryLocation &loc)
3372 case InventoryLocation::UNDEFINED:
3375 case InventoryLocation::PLAYER:
3377 Player *player = m_env->getPlayer(loc.name.c_str());
3380 PlayerSAO *playersao = player->getPlayerSAO();
3383 playersao->m_inventory_not_sent = true;
3384 playersao->m_wielded_item_not_sent = true;
3387 case InventoryLocation::NODEMETA:
3389 v3s16 blockpos = getNodeBlockPos(loc.p);
3391 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3393 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3395 setBlockNotSent(blockpos);
3398 case InventoryLocation::DETACHED:
3400 sendDetachedInventoryToAll(loc.name);
3408 core::list<PlayerInfo> Server::getPlayerInfo()
3410 DSTACK(__FUNCTION_NAME);
3411 JMutexAutoLock envlock(m_env_mutex);
3412 JMutexAutoLock conlock(m_con_mutex);
3414 core::list<PlayerInfo> list;
3416 core::list<Player*> players = m_env->getPlayers();
3418 core::list<Player*>::Iterator i;
3419 for(i = players.begin();
3420 i != players.end(); i++)
3424 Player *player = *i;
3427 // Copy info from connection to info struct
3428 info.id = player->peer_id;
3429 info.address = m_con.GetPeerAddress(player->peer_id);
3430 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3432 catch(con::PeerNotFoundException &e)
3434 // Set dummy peer info
3436 info.address = Address(0,0,0,0,0);
3440 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3441 info.position = player->getPosition();
3443 list.push_back(info);
3450 void Server::peerAdded(con::Peer *peer)
3452 DSTACK(__FUNCTION_NAME);
3453 verbosestream<<"Server::peerAdded(): peer->id="
3454 <<peer->id<<std::endl;
3457 c.type = PEER_ADDED;
3458 c.peer_id = peer->id;
3460 m_peer_change_queue.push_back(c);
3463 void Server::deletingPeer(con::Peer *peer, bool timeout)
3465 DSTACK(__FUNCTION_NAME);
3466 verbosestream<<"Server::deletingPeer(): peer->id="
3467 <<peer->id<<", timeout="<<timeout<<std::endl;
3470 c.type = PEER_REMOVED;
3471 c.peer_id = peer->id;
3472 c.timeout = timeout;
3473 m_peer_change_queue.push_back(c);
3480 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3482 DSTACK(__FUNCTION_NAME);
3483 std::ostringstream os(std::ios_base::binary);
3485 writeU16(os, TOCLIENT_HP);
3489 std::string s = os.str();
3490 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3492 con.Send(peer_id, 0, data, true);
3495 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3496 const std::wstring &reason)
3498 DSTACK(__FUNCTION_NAME);
3499 std::ostringstream os(std::ios_base::binary);
3501 writeU16(os, TOCLIENT_ACCESS_DENIED);
3502 os<<serializeWideString(reason);
3505 std::string s = os.str();
3506 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3508 con.Send(peer_id, 0, data, true);
3511 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3512 bool set_camera_point_target, v3f camera_point_target)
3514 DSTACK(__FUNCTION_NAME);
3515 std::ostringstream os(std::ios_base::binary);
3517 writeU16(os, TOCLIENT_DEATHSCREEN);
3518 writeU8(os, set_camera_point_target);
3519 writeV3F1000(os, camera_point_target);
3522 std::string s = os.str();
3523 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3525 con.Send(peer_id, 0, data, true);
3528 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3529 IItemDefManager *itemdef)
3531 DSTACK(__FUNCTION_NAME);
3532 std::ostringstream os(std::ios_base::binary);
3536 u32 length of the next item
3537 zlib-compressed serialized ItemDefManager
3539 writeU16(os, TOCLIENT_ITEMDEF);
3540 std::ostringstream tmp_os(std::ios::binary);
3541 itemdef->serialize(tmp_os);
3542 std::ostringstream tmp_os2(std::ios::binary);
3543 compressZlib(tmp_os.str(), tmp_os2);
3544 os<<serializeLongString(tmp_os2.str());
3547 std::string s = os.str();
3548 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3549 <<"): size="<<s.size()<<std::endl;
3550 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3552 con.Send(peer_id, 0, data, true);
3555 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3556 INodeDefManager *nodedef, u16 protocol_version)
3558 DSTACK(__FUNCTION_NAME);
3559 std::ostringstream os(std::ios_base::binary);
3563 u32 length of the next item
3564 zlib-compressed serialized NodeDefManager
3566 writeU16(os, TOCLIENT_NODEDEF);
3567 std::ostringstream tmp_os(std::ios::binary);
3568 nodedef->serialize(tmp_os, protocol_version);
3569 std::ostringstream tmp_os2(std::ios::binary);
3570 compressZlib(tmp_os.str(), tmp_os2);
3571 os<<serializeLongString(tmp_os2.str());
3574 std::string s = os.str();
3575 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3576 <<"): size="<<s.size()<<std::endl;
3577 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3579 con.Send(peer_id, 0, data, true);
3583 Non-static send methods
3586 void Server::SendInventory(u16 peer_id)
3588 DSTACK(__FUNCTION_NAME);
3590 PlayerSAO *playersao = getPlayerSAO(peer_id);
3593 playersao->m_inventory_not_sent = false;
3599 std::ostringstream os;
3600 playersao->getInventory()->serialize(os);
3602 std::string s = os.str();
3604 SharedBuffer<u8> data(s.size()+2);
3605 writeU16(&data[0], TOCLIENT_INVENTORY);
3606 memcpy(&data[2], s.c_str(), s.size());
3609 m_con.Send(peer_id, 0, data, true);
3612 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3614 DSTACK(__FUNCTION_NAME);
3616 std::ostringstream os(std::ios_base::binary);
3620 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3621 os.write((char*)buf, 2);
3624 writeU16(buf, message.size());
3625 os.write((char*)buf, 2);
3628 for(u32 i=0; i<message.size(); i++)
3632 os.write((char*)buf, 2);
3636 std::string s = os.str();
3637 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3639 m_con.Send(peer_id, 0, data, true);
3642 void Server::BroadcastChatMessage(const std::wstring &message)
3644 for(core::map<u16, RemoteClient*>::Iterator
3645 i = m_clients.getIterator();
3646 i.atEnd() == false; i++)
3648 // Get client and check that it is valid
3649 RemoteClient *client = i.getNode()->getValue();
3650 assert(client->peer_id == i.getNode()->getKey());
3651 if(client->serialization_version == SER_FMT_VER_INVALID)
3654 SendChatMessage(client->peer_id, message);
3658 void Server::SendPlayerHP(u16 peer_id)
3660 DSTACK(__FUNCTION_NAME);
3661 PlayerSAO *playersao = getPlayerSAO(peer_id);
3663 playersao->m_hp_not_sent = false;
3664 SendHP(m_con, peer_id, playersao->getHP());
3667 void Server::SendMovePlayer(u16 peer_id)
3669 DSTACK(__FUNCTION_NAME);
3670 Player *player = m_env->getPlayer(peer_id);
3673 std::ostringstream os(std::ios_base::binary);
3674 writeU16(os, TOCLIENT_MOVE_PLAYER);
3675 writeV3F1000(os, player->getPosition());
3676 writeF1000(os, player->getPitch());
3677 writeF1000(os, player->getYaw());
3680 v3f pos = player->getPosition();
3681 f32 pitch = player->getPitch();
3682 f32 yaw = player->getYaw();
3683 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3684 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3691 std::string s = os.str();
3692 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3694 m_con.Send(peer_id, 0, data, true);
3697 void Server::SendPlayerPrivileges(u16 peer_id)
3699 Player *player = m_env->getPlayer(peer_id);
3701 if(player->peer_id == PEER_ID_INEXISTENT)
3704 std::set<std::string> privs;
3705 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3707 std::ostringstream os(std::ios_base::binary);
3708 writeU16(os, TOCLIENT_PRIVILEGES);
3709 writeU16(os, privs.size());
3710 for(std::set<std::string>::const_iterator i = privs.begin();
3711 i != privs.end(); i++){
3712 os<<serializeString(*i);
3716 std::string s = os.str();
3717 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3719 m_con.Send(peer_id, 0, data, true);
3722 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3724 Player *player = m_env->getPlayer(peer_id);
3726 if(player->peer_id == PEER_ID_INEXISTENT)
3729 std::ostringstream os(std::ios_base::binary);
3730 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3731 os<<serializeLongString(player->inventory_formspec);
3734 std::string s = os.str();
3735 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3737 m_con.Send(peer_id, 0, data, true);
3740 s32 Server::playSound(const SimpleSoundSpec &spec,
3741 const ServerSoundParams ¶ms)
3743 // Find out initial position of sound
3744 bool pos_exists = false;
3745 v3f pos = params.getPos(m_env, &pos_exists);
3746 // If position is not found while it should be, cancel sound
3747 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3749 // Filter destination clients
3750 std::set<RemoteClient*> dst_clients;
3751 if(params.to_player != "")
3753 Player *player = m_env->getPlayer(params.to_player.c_str());
3755 infostream<<"Server::playSound: Player \""<<params.to_player
3756 <<"\" not found"<<std::endl;
3759 if(player->peer_id == PEER_ID_INEXISTENT){
3760 infostream<<"Server::playSound: Player \""<<params.to_player
3761 <<"\" not connected"<<std::endl;
3764 RemoteClient *client = getClient(player->peer_id);
3765 dst_clients.insert(client);
3769 for(core::map<u16, RemoteClient*>::Iterator
3770 i = m_clients.getIterator(); i.atEnd() == false; i++)
3772 RemoteClient *client = i.getNode()->getValue();
3773 Player *player = m_env->getPlayer(client->peer_id);
3777 if(player->getPosition().getDistanceFrom(pos) >
3778 params.max_hear_distance)
3781 dst_clients.insert(client);
3784 if(dst_clients.size() == 0)
3787 s32 id = m_next_sound_id++;
3788 // The sound will exist as a reference in m_playing_sounds
3789 m_playing_sounds[id] = ServerPlayingSound();
3790 ServerPlayingSound &psound = m_playing_sounds[id];
3791 psound.params = params;
3792 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3793 i != dst_clients.end(); i++)
3794 psound.clients.insert((*i)->peer_id);
3796 std::ostringstream os(std::ios_base::binary);
3797 writeU16(os, TOCLIENT_PLAY_SOUND);
3799 os<<serializeString(spec.name);
3800 writeF1000(os, spec.gain * params.gain);
3801 writeU8(os, params.type);
3802 writeV3F1000(os, pos);
3803 writeU16(os, params.object);
3804 writeU8(os, params.loop);
3806 std::string s = os.str();
3807 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3809 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3810 i != dst_clients.end(); i++){
3812 m_con.Send((*i)->peer_id, 0, data, true);
3816 void Server::stopSound(s32 handle)
3818 // Get sound reference
3819 std::map<s32, ServerPlayingSound>::iterator i =
3820 m_playing_sounds.find(handle);
3821 if(i == m_playing_sounds.end())
3823 ServerPlayingSound &psound = i->second;
3825 std::ostringstream os(std::ios_base::binary);
3826 writeU16(os, TOCLIENT_STOP_SOUND);
3827 writeS32(os, handle);
3829 std::string s = os.str();
3830 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3832 for(std::set<u16>::iterator i = psound.clients.begin();
3833 i != psound.clients.end(); i++){
3835 m_con.Send(*i, 0, data, true);
3837 // Remove sound reference
3838 m_playing_sounds.erase(i);
3841 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3842 core::list<u16> *far_players, float far_d_nodes)
3844 float maxd = far_d_nodes*BS;
3845 v3f p_f = intToFloat(p, BS);
3849 SharedBuffer<u8> reply(replysize);
3850 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3851 writeS16(&reply[2], p.X);
3852 writeS16(&reply[4], p.Y);
3853 writeS16(&reply[6], p.Z);
3855 for(core::map<u16, RemoteClient*>::Iterator
3856 i = m_clients.getIterator();
3857 i.atEnd() == false; i++)
3859 // Get client and check that it is valid
3860 RemoteClient *client = i.getNode()->getValue();
3861 assert(client->peer_id == i.getNode()->getKey());
3862 if(client->serialization_version == SER_FMT_VER_INVALID)
3865 // Don't send if it's the same one
3866 if(client->peer_id == ignore_id)
3872 Player *player = m_env->getPlayer(client->peer_id);
3875 // If player is far away, only set modified blocks not sent
3876 v3f player_pos = player->getPosition();
3877 if(player_pos.getDistanceFrom(p_f) > maxd)
3879 far_players->push_back(client->peer_id);
3886 m_con.Send(client->peer_id, 0, reply, true);
3890 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3891 core::list<u16> *far_players, float far_d_nodes)
3893 float maxd = far_d_nodes*BS;
3894 v3f p_f = intToFloat(p, BS);
3896 for(core::map<u16, RemoteClient*>::Iterator
3897 i = m_clients.getIterator();
3898 i.atEnd() == false; i++)
3900 // Get client and check that it is valid
3901 RemoteClient *client = i.getNode()->getValue();
3902 assert(client->peer_id == i.getNode()->getKey());
3903 if(client->serialization_version == SER_FMT_VER_INVALID)
3906 // Don't send if it's the same one
3907 if(client->peer_id == ignore_id)
3913 Player *player = m_env->getPlayer(client->peer_id);
3916 // If player is far away, only set modified blocks not sent
3917 v3f player_pos = player->getPosition();
3918 if(player_pos.getDistanceFrom(p_f) > maxd)
3920 far_players->push_back(client->peer_id);
3927 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3928 SharedBuffer<u8> reply(replysize);
3929 writeU16(&reply[0], TOCLIENT_ADDNODE);
3930 writeS16(&reply[2], p.X);
3931 writeS16(&reply[4], p.Y);
3932 writeS16(&reply[6], p.Z);
3933 n.serialize(&reply[8], client->serialization_version);
3936 m_con.Send(client->peer_id, 0, reply, true);
3940 void Server::setBlockNotSent(v3s16 p)
3942 for(core::map<u16, RemoteClient*>::Iterator
3943 i = m_clients.getIterator();
3944 i.atEnd()==false; i++)
3946 RemoteClient *client = i.getNode()->getValue();
3947 client->SetBlockNotSent(p);
3951 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3953 DSTACK(__FUNCTION_NAME);
3955 v3s16 p = block->getPos();
3959 bool completely_air = true;
3960 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3961 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3962 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3964 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3966 completely_air = false;
3967 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3972 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3974 infostream<<"[completely air] ";
3975 infostream<<std::endl;
3979 Create a packet with the block in the right format
3982 std::ostringstream os(std::ios_base::binary);
3983 block->serialize(os, ver, false);
3984 std::string s = os.str();
3985 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3987 u32 replysize = 8 + blockdata.getSize();
3988 SharedBuffer<u8> reply(replysize);
3989 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3990 writeS16(&reply[2], p.X);
3991 writeS16(&reply[4], p.Y);
3992 writeS16(&reply[6], p.Z);
3993 memcpy(&reply[8], *blockdata, blockdata.getSize());
3995 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3996 <<": \tpacket size: "<<replysize<<std::endl;*/
4001 m_con.Send(peer_id, 1, reply, true);
4004 void Server::SendBlocks(float dtime)
4006 DSTACK(__FUNCTION_NAME);
4008 JMutexAutoLock envlock(m_env_mutex);
4009 JMutexAutoLock conlock(m_con_mutex);
4011 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4013 core::array<PrioritySortedBlockTransfer> queue;
4015 s32 total_sending = 0;
4018 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4020 for(core::map<u16, RemoteClient*>::Iterator
4021 i = m_clients.getIterator();
4022 i.atEnd() == false; i++)
4024 RemoteClient *client = i.getNode()->getValue();
4025 assert(client->peer_id == i.getNode()->getKey());
4027 // If definitions and textures have not been sent, don't
4028 // send MapBlocks either
4029 if(!client->definitions_sent)
4032 total_sending += client->SendingCount();
4034 if(client->serialization_version == SER_FMT_VER_INVALID)
4037 client->GetNextBlocks(this, dtime, queue);
4042 // Lowest priority number comes first.
4043 // Lowest is most important.
4046 for(u32 i=0; i<queue.size(); i++)
4048 //TODO: Calculate limit dynamically
4049 if(total_sending >= g_settings->getS32
4050 ("max_simultaneous_block_sends_server_total"))
4053 PrioritySortedBlockTransfer q = queue[i];
4055 MapBlock *block = NULL;
4058 block = m_env->getMap().getBlockNoCreate(q.pos);
4060 catch(InvalidPositionException &e)
4065 RemoteClient *client = getClient(q.peer_id);
4067 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4069 client->SentBlock(q.pos);
4075 void Server::fillMediaCache()
4077 DSTACK(__FUNCTION_NAME);
4079 infostream<<"Server: Calculating media file checksums"<<std::endl;
4081 // Collect all media file paths
4082 std::list<std::string> paths;
4083 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4084 i != m_mods.end(); i++){
4085 const ModSpec &mod = *i;
4086 paths.push_back(mod.path + DIR_DELIM + "textures");
4087 paths.push_back(mod.path + DIR_DELIM + "sounds");
4088 paths.push_back(mod.path + DIR_DELIM + "media");
4089 paths.push_back(mod.path + DIR_DELIM + "models");
4091 std::string path_all = "textures";
4092 paths.push_back(path_all + DIR_DELIM + "all");
4094 // Collect media file information from paths into cache
4095 for(std::list<std::string>::iterator i = paths.begin();
4096 i != paths.end(); i++)
4098 std::string mediapath = *i;
4099 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4100 for(u32 j=0; j<dirlist.size(); j++){
4101 if(dirlist[j].dir) // Ignode dirs
4103 std::string filename = dirlist[j].name;
4104 // If name contains illegal characters, ignore the file
4105 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4106 infostream<<"Server: ignoring illegal file name: \""
4107 <<filename<<"\""<<std::endl;
4110 // If name is not in a supported format, ignore it
4111 const char *supported_ext[] = {
4112 ".png", ".jpg", ".bmp", ".tga",
4113 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4115 ".x", ".b3d", ".md2", ".obj",
4118 if(removeStringEnd(filename, supported_ext) == ""){
4119 infostream<<"Server: ignoring unsupported file extension: \""
4120 <<filename<<"\""<<std::endl;
4123 // Ok, attempt to load the file and add to cache
4124 std::string filepath = mediapath + DIR_DELIM + filename;
4126 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4127 if(fis.good() == false){
4128 errorstream<<"Server::fillMediaCache(): Could not open \""
4129 <<filename<<"\" for reading"<<std::endl;
4132 std::ostringstream tmp_os(std::ios_base::binary);
4136 fis.read(buf, 1024);
4137 std::streamsize len = fis.gcount();
4138 tmp_os.write(buf, len);
4147 errorstream<<"Server::fillMediaCache(): Failed to read \""
4148 <<filename<<"\""<<std::endl;
4151 if(tmp_os.str().length() == 0){
4152 errorstream<<"Server::fillMediaCache(): Empty file \""
4153 <<filepath<<"\""<<std::endl;
4158 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4160 unsigned char *digest = sha1.getDigest();
4161 std::string sha1_base64 = base64_encode(digest, 20);
4162 std::string sha1_hex = hex_encode((char*)digest, 20);
4166 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4167 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4172 struct SendableMediaAnnouncement
4175 std::string sha1_digest;
4177 SendableMediaAnnouncement(const std::string name_="",
4178 const std::string sha1_digest_=""):
4180 sha1_digest(sha1_digest_)
4184 void Server::sendMediaAnnouncement(u16 peer_id)
4186 DSTACK(__FUNCTION_NAME);
4188 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4191 core::list<SendableMediaAnnouncement> file_announcements;
4193 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4194 i != m_media.end(); i++){
4196 file_announcements.push_back(
4197 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4201 std::ostringstream os(std::ios_base::binary);
4209 u16 length of sha1_digest
4214 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4215 writeU16(os, file_announcements.size());
4217 for(core::list<SendableMediaAnnouncement>::Iterator
4218 j = file_announcements.begin();
4219 j != file_announcements.end(); j++){
4220 os<<serializeString(j->name);
4221 os<<serializeString(j->sha1_digest);
4225 std::string s = os.str();
4226 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4229 m_con.Send(peer_id, 0, data, true);
4233 struct SendableMedia
4239 SendableMedia(const std::string &name_="", const std::string path_="",
4240 const std::string &data_=""):
4247 void Server::sendRequestedMedia(u16 peer_id,
4248 const core::list<MediaRequest> &tosend)
4250 DSTACK(__FUNCTION_NAME);
4252 verbosestream<<"Server::sendRequestedMedia(): "
4253 <<"Sending files to client"<<std::endl;
4257 // Put 5kB in one bunch (this is not accurate)
4258 u32 bytes_per_bunch = 5000;
4260 core::array< core::list<SendableMedia> > file_bunches;
4261 file_bunches.push_back(core::list<SendableMedia>());
4263 u32 file_size_bunch_total = 0;
4265 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4266 i != tosend.end(); i++)
4268 if(m_media.find(i->name) == m_media.end()){
4269 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4270 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4274 //TODO get path + name
4275 std::string tpath = m_media[(*i).name].path;
4278 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4279 if(fis.good() == false){
4280 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4281 <<tpath<<"\" for reading"<<std::endl;
4284 std::ostringstream tmp_os(std::ios_base::binary);
4288 fis.read(buf, 1024);
4289 std::streamsize len = fis.gcount();
4290 tmp_os.write(buf, len);
4291 file_size_bunch_total += len;
4300 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4301 <<(*i).name<<"\""<<std::endl;
4304 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4305 <<tname<<"\""<<std::endl;*/
4307 file_bunches[file_bunches.size()-1].push_back(
4308 SendableMedia((*i).name, tpath, tmp_os.str()));
4310 // Start next bunch if got enough data
4311 if(file_size_bunch_total >= bytes_per_bunch){
4312 file_bunches.push_back(core::list<SendableMedia>());
4313 file_size_bunch_total = 0;
4318 /* Create and send packets */
4320 u32 num_bunches = file_bunches.size();
4321 for(u32 i=0; i<num_bunches; i++)
4323 std::ostringstream os(std::ios_base::binary);
4327 u16 total number of texture bunches
4328 u16 index of this bunch
4329 u32 number of files in this bunch
4338 writeU16(os, TOCLIENT_MEDIA);
4339 writeU16(os, num_bunches);
4341 writeU32(os, file_bunches[i].size());
4343 for(core::list<SendableMedia>::Iterator
4344 j = file_bunches[i].begin();
4345 j != file_bunches[i].end(); j++){
4346 os<<serializeString(j->name);
4347 os<<serializeLongString(j->data);
4351 std::string s = os.str();
4352 verbosestream<<"Server::sendRequestedMedia(): bunch "
4353 <<i<<"/"<<num_bunches
4354 <<" files="<<file_bunches[i].size()
4355 <<" size=" <<s.size()<<std::endl;
4356 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4358 m_con.Send(peer_id, 0, data, true);
4362 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4364 if(m_detached_inventories.count(name) == 0){
4365 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4368 Inventory *inv = m_detached_inventories[name];
4370 std::ostringstream os(std::ios_base::binary);
4371 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4372 os<<serializeString(name);
4376 std::string s = os.str();
4377 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4379 m_con.Send(peer_id, 0, data, true);
4382 void Server::sendDetachedInventoryToAll(const std::string &name)
4384 DSTACK(__FUNCTION_NAME);
4386 for(core::map<u16, RemoteClient*>::Iterator
4387 i = m_clients.getIterator();
4388 i.atEnd() == false; i++){
4389 RemoteClient *client = i.getNode()->getValue();
4390 sendDetachedInventory(name, client->peer_id);
4394 void Server::sendDetachedInventories(u16 peer_id)
4396 DSTACK(__FUNCTION_NAME);
4398 for(std::map<std::string, Inventory*>::iterator
4399 i = m_detached_inventories.begin();
4400 i != m_detached_inventories.end(); i++){
4401 const std::string &name = i->first;
4402 //Inventory *inv = i->second;
4403 sendDetachedInventory(name, peer_id);
4411 void Server::DiePlayer(u16 peer_id)
4413 DSTACK(__FUNCTION_NAME);
4415 PlayerSAO *playersao = getPlayerSAO(peer_id);
4418 infostream<<"Server::DiePlayer(): Player "
4419 <<playersao->getPlayer()->getName()
4420 <<" dies"<<std::endl;
4422 playersao->setHP(0);
4424 // Trigger scripted stuff
4425 scriptapi_on_dieplayer(m_lua, playersao);
4427 SendPlayerHP(peer_id);
4428 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4431 void Server::RespawnPlayer(u16 peer_id)
4433 DSTACK(__FUNCTION_NAME);
4435 PlayerSAO *playersao = getPlayerSAO(peer_id);
4438 infostream<<"Server::RespawnPlayer(): Player "
4439 <<playersao->getPlayer()->getName()
4440 <<" respawns"<<std::endl;
4442 playersao->setHP(PLAYER_MAX_HP);
4444 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4446 v3f pos = findSpawnPos(m_env->getServerMap());
4447 playersao->setPos(pos);
4451 void Server::UpdateCrafting(u16 peer_id)
4453 DSTACK(__FUNCTION_NAME);
4455 Player* player = m_env->getPlayer(peer_id);
4458 // Get a preview for crafting
4460 getCraftingResult(&player->inventory, preview, false, this);
4462 // Put the new preview in
4463 InventoryList *plist = player->inventory.getList("craftpreview");
4465 assert(plist->getSize() >= 1);
4466 plist->changeItem(0, preview);
4469 RemoteClient* Server::getClient(u16 peer_id)
4471 DSTACK(__FUNCTION_NAME);
4472 //JMutexAutoLock lock(m_con_mutex);
4473 core::map<u16, RemoteClient*>::Node *n;
4474 n = m_clients.find(peer_id);
4475 // A client should exist for all peers
4477 return n->getValue();
4480 std::wstring Server::getStatusString()
4482 std::wostringstream os(std::ios_base::binary);
4485 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4487 os<<L", uptime="<<m_uptime.get();
4488 // Information about clients
4489 core::map<u16, RemoteClient*>::Iterator i;
4492 for(i = m_clients.getIterator(), first = true;
4493 i.atEnd() == false; i++)
4495 // Get client and check that it is valid
4496 RemoteClient *client = i.getNode()->getValue();
4497 assert(client->peer_id == i.getNode()->getKey());
4498 if(client->serialization_version == SER_FMT_VER_INVALID)
4501 Player *player = m_env->getPlayer(client->peer_id);
4502 // Get name of player
4503 std::wstring name = L"unknown";
4505 name = narrow_to_wide(player->getName());
4506 // Add name to information string
4514 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4515 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4516 if(g_settings->get("motd") != "")
4517 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4521 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4523 std::set<std::string> privs;
4524 scriptapi_get_auth(m_lua, name, NULL, &privs);
4528 bool Server::checkPriv(const std::string &name, const std::string &priv)
4530 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4531 return (privs.count(priv) != 0);
4534 void Server::reportPrivsModified(const std::string &name)
4537 for(core::map<u16, RemoteClient*>::Iterator
4538 i = m_clients.getIterator();
4539 i.atEnd() == false; i++){
4540 RemoteClient *client = i.getNode()->getValue();
4541 Player *player = m_env->getPlayer(client->peer_id);
4542 reportPrivsModified(player->getName());
4545 Player *player = m_env->getPlayer(name.c_str());
4548 SendPlayerPrivileges(player->peer_id);
4549 PlayerSAO *sao = player->getPlayerSAO();
4552 sao->updatePrivileges(
4553 getPlayerEffectivePrivs(name),
4558 void Server::reportInventoryFormspecModified(const std::string &name)
4560 Player *player = m_env->getPlayer(name.c_str());
4563 SendPlayerInventoryFormspec(player->peer_id);
4566 // Saves g_settings to configpath given at initialization
4567 void Server::saveConfig()
4569 if(m_path_config != "")
4570 g_settings->updateConfigFile(m_path_config.c_str());
4573 void Server::notifyPlayer(const char *name, const std::wstring msg)
4575 Player *player = m_env->getPlayer(name);
4578 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4581 void Server::notifyPlayers(const std::wstring msg)
4583 BroadcastChatMessage(msg);
4586 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4590 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4591 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4594 Inventory* Server::createDetachedInventory(const std::string &name)
4596 if(m_detached_inventories.count(name) > 0){
4597 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4598 delete m_detached_inventories[name];
4600 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4602 Inventory *inv = new Inventory(m_itemdef);
4604 m_detached_inventories[name] = inv;
4605 sendDetachedInventoryToAll(name);
4612 BoolScopeSet(bool *dst, bool val):
4615 m_orig_state = *m_dst;
4620 *m_dst = m_orig_state;
4627 // actions: time-reversed list
4628 // Return value: success/failure
4629 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4630 std::list<std::string> *log)
4632 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4633 ServerMap *map = (ServerMap*)(&m_env->getMap());
4634 // Disable rollback report sink while reverting
4635 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4637 // Fail if no actions to handle
4638 if(actions.empty()){
4639 log->push_back("Nothing to do.");
4646 for(std::list<RollbackAction>::const_iterator
4647 i = actions.begin();
4648 i != actions.end(); i++)
4650 const RollbackAction &action = *i;
4652 bool success = action.applyRevert(map, this, this);
4655 std::ostringstream os;
4656 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4657 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4659 log->push_back(os.str());
4661 std::ostringstream os;
4662 os<<"Succesfully reverted step ("<<num_tried<<") "<<action.toString();
4663 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4665 log->push_back(os.str());
4669 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4670 <<" failed"<<std::endl;
4672 // Call it done if less than half failed
4673 return num_failed <= num_tried/2;
4676 // IGameDef interface
4678 IItemDefManager* Server::getItemDefManager()
4682 INodeDefManager* Server::getNodeDefManager()
4686 ICraftDefManager* Server::getCraftDefManager()
4690 ITextureSource* Server::getTextureSource()
4694 u16 Server::allocateUnknownNodeId(const std::string &name)
4696 return m_nodedef->allocateDummy(name);
4698 ISoundManager* Server::getSoundManager()
4700 return &dummySoundManager;
4702 MtEventManager* Server::getEventManager()
4706 IRollbackReportSink* Server::getRollbackReportSink()
4708 if(!m_enable_rollback_recording)
4710 if(!m_rollback_sink_enabled)
4715 IWritableItemDefManager* Server::getWritableItemDefManager()
4719 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4723 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4728 const ModSpec* Server::getModSpec(const std::string &modname)
4730 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4731 i != m_mods.end(); i++){
4732 const ModSpec &mod = *i;
4733 if(mod.name == modname)
4738 void Server::getModNames(core::list<std::string> &modlist)
4740 for(core::list<ModSpec>::Iterator i = m_mods.begin(); i != m_mods.end(); i++)
4742 modlist.push_back((*i).name);
4745 std::string Server::getBuiltinLuaPath()
4747 return porting::path_share + DIR_DELIM + "builtin";
4750 v3f findSpawnPos(ServerMap &map)
4752 //return v3f(50,50,50)*BS;
4757 nodepos = v2s16(0,0);
4762 // Try to find a good place a few times
4763 for(s32 i=0; i<1000; i++)
4766 // We're going to try to throw the player to this position
4767 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4768 -range + (myrand()%(range*2)));
4769 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4770 // Get ground height at point (fallbacks to heightmap function)
4771 s16 groundheight = map.findGroundLevel(nodepos2d);
4772 // Don't go underwater
4773 if(groundheight < WATER_LEVEL)
4775 //infostream<<"-> Underwater"<<std::endl;
4778 // Don't go to high places
4779 if(groundheight > WATER_LEVEL + 4)
4781 //infostream<<"-> Underwater"<<std::endl;
4785 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4786 bool is_good = false;
4788 for(s32 i=0; i<10; i++){
4789 v3s16 blockpos = getNodeBlockPos(nodepos);
4790 map.emergeBlock(blockpos, true);
4791 MapNode n = map.getNodeNoEx(nodepos);
4792 if(n.getContent() == CONTENT_AIR){
4803 // Found a good place
4804 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4810 return intToFloat(nodepos, BS);
4813 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4815 RemotePlayer *player = NULL;
4816 bool newplayer = false;
4819 Try to get an existing player
4821 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4823 // If player is already connected, cancel
4824 if(player != NULL && player->peer_id != 0)
4826 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4831 If player with the wanted peer_id already exists, cancel.
4833 if(m_env->getPlayer(peer_id) != NULL)
4835 infostream<<"emergePlayer(): Player with wrong name but same"
4836 " peer_id already exists"<<std::endl;
4841 Create a new player if it doesn't exist yet
4846 player = new RemotePlayer(this);
4847 player->updateName(name);
4849 /* Set player position */
4850 infostream<<"Server: Finding spawn place for player \""
4851 <<name<<"\""<<std::endl;
4852 v3f pos = findSpawnPos(m_env->getServerMap());
4853 player->setPosition(pos);
4855 /* Add player to environment */
4856 m_env->addPlayer(player);
4860 Create a new player active object
4862 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4863 getPlayerEffectivePrivs(player->getName()),
4866 /* Add object to environment */
4867 m_env->addActiveObject(playersao);
4871 scriptapi_on_newplayer(m_lua, playersao);
4873 scriptapi_on_joinplayer(m_lua, playersao);
4878 void Server::handlePeerChange(PeerChange &c)
4880 JMutexAutoLock envlock(m_env_mutex);
4881 JMutexAutoLock conlock(m_con_mutex);
4883 if(c.type == PEER_ADDED)
4890 core::map<u16, RemoteClient*>::Node *n;
4891 n = m_clients.find(c.peer_id);
4892 // The client shouldn't already exist
4896 RemoteClient *client = new RemoteClient();
4897 client->peer_id = c.peer_id;
4898 m_clients.insert(client->peer_id, client);
4901 else if(c.type == PEER_REMOVED)
4908 core::map<u16, RemoteClient*>::Node *n;
4909 n = m_clients.find(c.peer_id);
4910 // The client should exist
4914 Mark objects to be not known by the client
4916 RemoteClient *client = n->getValue();
4918 for(core::map<u16, bool>::Iterator
4919 i = client->m_known_objects.getIterator();
4920 i.atEnd()==false; i++)
4923 u16 id = i.getNode()->getKey();
4924 ServerActiveObject* obj = m_env->getActiveObject(id);
4926 if(obj && obj->m_known_by_count > 0)
4927 obj->m_known_by_count--;
4931 Clear references to playing sounds
4933 for(std::map<s32, ServerPlayingSound>::iterator
4934 i = m_playing_sounds.begin();
4935 i != m_playing_sounds.end();)
4937 ServerPlayingSound &psound = i->second;
4938 psound.clients.erase(c.peer_id);
4939 if(psound.clients.size() == 0)
4940 m_playing_sounds.erase(i++);
4945 Player *player = m_env->getPlayer(c.peer_id);
4947 // Collect information about leaving in chat
4948 std::wstring message;
4952 std::wstring name = narrow_to_wide(player->getName());
4955 message += L" left the game.";
4957 message += L" (timed out)";
4961 /* Run scripts and remove from environment */
4965 PlayerSAO *playersao = player->getPlayerSAO();
4968 scriptapi_on_leaveplayer(m_lua, playersao);
4970 playersao->disconnected();
4980 std::ostringstream os(std::ios_base::binary);
4981 for(core::map<u16, RemoteClient*>::Iterator
4982 i = m_clients.getIterator();
4983 i.atEnd() == false; i++)
4985 RemoteClient *client = i.getNode()->getValue();
4986 assert(client->peer_id == i.getNode()->getKey());
4987 if(client->serialization_version == SER_FMT_VER_INVALID)
4990 Player *player = m_env->getPlayer(client->peer_id);
4993 // Get name of player
4994 os<<player->getName()<<" ";
4997 actionstream<<player->getName()<<" "
4998 <<(c.timeout?"times out.":"leaves game.")
4999 <<" List of players: "
5000 <<os.str()<<std::endl;
5005 delete m_clients[c.peer_id];
5006 m_clients.remove(c.peer_id);
5008 // Send player info to all remaining clients
5009 //SendPlayerInfos();
5011 // Send leave chat message to all remaining clients
5012 if(message.length() != 0)
5013 BroadcastChatMessage(message);
5022 void Server::handlePeerChanges()
5024 while(m_peer_change_queue.size() > 0)
5026 PeerChange c = m_peer_change_queue.pop_front();
5028 verbosestream<<"Server: Handling peer change: "
5029 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5032 handlePeerChange(c);
5036 void dedicated_server_loop(Server &server, bool &kill)
5038 DSTACK(__FUNCTION_NAME);
5040 verbosestream<<"dedicated_server_loop()"<<std::endl;
5042 IntervalLimiter m_profiler_interval;
5046 float steplen = g_settings->getFloat("dedicated_server_step");
5047 // This is kind of a hack but can be done like this
5048 // because server.step() is very light
5050 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5051 sleep_ms((int)(steplen*1000.0));
5053 server.step(steplen);
5055 if(server.getShutdownRequested() || kill)
5057 infostream<<"Dedicated server quitting"<<std::endl;
5064 float profiler_print_interval =
5065 g_settings->getFloat("profiler_print_interval");
5066 if(profiler_print_interval != 0)
5068 if(m_profiler_interval.step(steplen, profiler_print_interval))
5070 infostream<<"Profiler:"<<std::endl;
5071 g_profiler->print(infostream);
5072 g_profiler->clear();