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 JMutexAutoLock envlock(m_env_mutex);
1122 infostream<<"Server: Saving players"<<std::endl;
1123 m_env->serializePlayers(m_path_world);
1126 Save environment metadata
1128 infostream<<"Server: Saving environment metadata"<<std::endl;
1129 m_env->saveMeta(m_path_world);
1141 JMutexAutoLock clientslock(m_con_mutex);
1143 for(core::map<u16, RemoteClient*>::Iterator
1144 i = m_clients.getIterator();
1145 i.atEnd() == false; i++)
1148 // NOTE: These are removed by env destructor
1150 u16 peer_id = i.getNode()->getKey();
1151 JMutexAutoLock envlock(m_env_mutex);
1152 m_env->removePlayer(peer_id);
1156 delete i.getNode()->getValue();
1160 // Delete things in the reverse order of creation
1168 // Deinitialize scripting
1169 infostream<<"Server: Deinitializing scripting"<<std::endl;
1170 script_deinit(m_lua);
1172 // Delete detached inventories
1174 for(std::map<std::string, Inventory*>::iterator
1175 i = m_detached_inventories.begin();
1176 i != m_detached_inventories.end(); i++){
1182 void Server::start(unsigned short port)
1184 DSTACK(__FUNCTION_NAME);
1185 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1187 // Stop thread if already running
1190 // Initialize connection
1191 m_con.SetTimeoutMs(30);
1195 m_thread.setRun(true);
1198 // ASCII art for the win!
1200 <<" .__ __ __ "<<std::endl
1201 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1202 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1203 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1204 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1205 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1206 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1207 actionstream<<"Server for gameid=\""<<m_gamespec.id
1208 <<"\" listening on port "<<port<<"."<<std::endl;
1213 DSTACK(__FUNCTION_NAME);
1215 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1217 // Stop threads (set run=false first so both start stopping)
1218 m_thread.setRun(false);
1219 m_emergethread.setRun(false);
1221 m_emergethread.stop();
1223 infostream<<"Server: Threads stopped"<<std::endl;
1226 void Server::step(float dtime)
1228 DSTACK(__FUNCTION_NAME);
1233 JMutexAutoLock lock(m_step_dtime_mutex);
1234 m_step_dtime += dtime;
1236 // Throw if fatal error occurred in thread
1237 std::string async_err = m_async_fatal_error.get();
1238 if(async_err != ""){
1239 throw ServerError(async_err);
1243 void Server::AsyncRunStep()
1245 DSTACK(__FUNCTION_NAME);
1247 g_profiler->add("Server::AsyncRunStep (num)", 1);
1251 JMutexAutoLock lock1(m_step_dtime_mutex);
1252 dtime = m_step_dtime;
1256 // Send blocks to clients
1263 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1265 //infostream<<"Server steps "<<dtime<<std::endl;
1266 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1269 JMutexAutoLock lock1(m_step_dtime_mutex);
1270 m_step_dtime -= dtime;
1277 m_uptime.set(m_uptime.get() + dtime);
1281 // Process connection's timeouts
1282 JMutexAutoLock lock2(m_con_mutex);
1283 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1284 m_con.RunTimeouts(dtime);
1288 // This has to be called so that the client list gets synced
1289 // with the peer list of the connection
1290 handlePeerChanges();
1294 Update time of day and overall game time
1297 JMutexAutoLock envlock(m_env_mutex);
1299 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1302 Send to clients at constant intervals
1305 m_time_of_day_send_timer -= dtime;
1306 if(m_time_of_day_send_timer < 0.0)
1308 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1310 //JMutexAutoLock envlock(m_env_mutex);
1311 JMutexAutoLock conlock(m_con_mutex);
1313 for(core::map<u16, RemoteClient*>::Iterator
1314 i = m_clients.getIterator();
1315 i.atEnd() == false; i++)
1317 RemoteClient *client = i.getNode()->getValue();
1318 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1319 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1321 m_con.Send(client->peer_id, 0, data, true);
1327 JMutexAutoLock lock(m_env_mutex);
1329 ScopeProfiler sp(g_profiler, "SEnv step");
1330 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1334 const float map_timer_and_unload_dtime = 2.92;
1335 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1337 JMutexAutoLock lock(m_env_mutex);
1338 // Run Map's timers and unload unused data
1339 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1340 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1341 g_settings->getFloat("server_unload_unused_data_timeout"));
1352 JMutexAutoLock lock(m_env_mutex);
1353 JMutexAutoLock lock2(m_con_mutex);
1355 ScopeProfiler sp(g_profiler, "Server: handle players");
1357 for(core::map<u16, RemoteClient*>::Iterator
1358 i = m_clients.getIterator();
1359 i.atEnd() == false; i++)
1361 RemoteClient *client = i.getNode()->getValue();
1362 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1363 if(playersao == NULL)
1367 Handle player HPs (die if hp=0)
1369 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
1370 DiePlayer(client->peer_id);
1373 Send player inventories and HPs if necessary
1375 if(playersao->m_moved){
1376 SendMovePlayer(client->peer_id);
1377 playersao->m_moved = false;
1379 if(playersao->m_inventory_not_sent){
1380 UpdateCrafting(client->peer_id);
1381 SendInventory(client->peer_id);
1383 if(playersao->m_hp_not_sent){
1384 SendPlayerHP(client->peer_id);
1389 /* Transform liquids */
1390 m_liquid_transform_timer += dtime;
1391 if(m_liquid_transform_timer >= 1.00)
1393 m_liquid_transform_timer -= 1.00;
1395 JMutexAutoLock lock(m_env_mutex);
1397 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1399 core::map<v3s16, MapBlock*> modified_blocks;
1400 m_env->getMap().transformLiquids(modified_blocks);
1405 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1406 ServerMap &map = ((ServerMap&)m_env->getMap());
1407 map.updateLighting(modified_blocks, lighting_modified_blocks);
1409 // Add blocks modified by lighting to modified_blocks
1410 for(core::map<v3s16, MapBlock*>::Iterator
1411 i = lighting_modified_blocks.getIterator();
1412 i.atEnd() == false; i++)
1414 MapBlock *block = i.getNode()->getValue();
1415 modified_blocks.insert(block->getPos(), block);
1419 Set the modified blocks unsent for all the clients
1422 JMutexAutoLock lock2(m_con_mutex);
1424 for(core::map<u16, RemoteClient*>::Iterator
1425 i = m_clients.getIterator();
1426 i.atEnd() == false; i++)
1428 RemoteClient *client = i.getNode()->getValue();
1430 if(modified_blocks.size() > 0)
1432 // Remove block from sent history
1433 client->SetBlocksNotSent(modified_blocks);
1438 // Periodically print some info
1440 float &counter = m_print_info_timer;
1446 JMutexAutoLock lock2(m_con_mutex);
1448 if(m_clients.size() != 0)
1449 infostream<<"Players:"<<std::endl;
1450 for(core::map<u16, RemoteClient*>::Iterator
1451 i = m_clients.getIterator();
1452 i.atEnd() == false; i++)
1454 //u16 peer_id = i.getNode()->getKey();
1455 RemoteClient *client = i.getNode()->getValue();
1456 Player *player = m_env->getPlayer(client->peer_id);
1459 infostream<<"* "<<player->getName()<<"\t";
1460 client->PrintInfo(infostream);
1465 //if(g_settings->getBool("enable_experimental"))
1469 Check added and deleted active objects
1472 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1473 JMutexAutoLock envlock(m_env_mutex);
1474 JMutexAutoLock conlock(m_con_mutex);
1476 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1478 // Radius inside which objects are active
1479 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1480 radius *= MAP_BLOCKSIZE;
1482 for(core::map<u16, RemoteClient*>::Iterator
1483 i = m_clients.getIterator();
1484 i.atEnd() == false; i++)
1486 RemoteClient *client = i.getNode()->getValue();
1488 // If definitions and textures have not been sent, don't
1489 // send objects either
1490 if(!client->definitions_sent)
1493 Player *player = m_env->getPlayer(client->peer_id);
1496 // This can happen if the client timeouts somehow
1497 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1499 <<" has no associated player"<<std::endl;*/
1502 v3s16 pos = floatToInt(player->getPosition(), BS);
1504 core::map<u16, bool> removed_objects;
1505 core::map<u16, bool> added_objects;
1506 m_env->getRemovedActiveObjects(pos, radius,
1507 client->m_known_objects, removed_objects);
1508 m_env->getAddedActiveObjects(pos, radius,
1509 client->m_known_objects, added_objects);
1511 // Ignore if nothing happened
1512 if(removed_objects.size() == 0 && added_objects.size() == 0)
1514 //infostream<<"active objects: none changed"<<std::endl;
1518 std::string data_buffer;
1522 // Handle removed objects
1523 writeU16((u8*)buf, removed_objects.size());
1524 data_buffer.append(buf, 2);
1525 for(core::map<u16, bool>::Iterator
1526 i = removed_objects.getIterator();
1527 i.atEnd()==false; i++)
1530 u16 id = i.getNode()->getKey();
1531 ServerActiveObject* obj = m_env->getActiveObject(id);
1533 // Add to data buffer for sending
1534 writeU16((u8*)buf, i.getNode()->getKey());
1535 data_buffer.append(buf, 2);
1537 // Remove from known objects
1538 client->m_known_objects.remove(i.getNode()->getKey());
1540 if(obj && obj->m_known_by_count > 0)
1541 obj->m_known_by_count--;
1544 // Handle added objects
1545 writeU16((u8*)buf, added_objects.size());
1546 data_buffer.append(buf, 2);
1547 for(core::map<u16, bool>::Iterator
1548 i = added_objects.getIterator();
1549 i.atEnd()==false; i++)
1552 u16 id = i.getNode()->getKey();
1553 ServerActiveObject* obj = m_env->getActiveObject(id);
1556 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1558 infostream<<"WARNING: "<<__FUNCTION_NAME
1559 <<": NULL object"<<std::endl;
1561 type = obj->getSendType();
1563 // Add to data buffer for sending
1564 writeU16((u8*)buf, id);
1565 data_buffer.append(buf, 2);
1566 writeU8((u8*)buf, type);
1567 data_buffer.append(buf, 1);
1570 data_buffer.append(serializeLongString(
1571 obj->getClientInitializationData(client->net_proto_version)));
1573 data_buffer.append(serializeLongString(""));
1575 // Add to known objects
1576 client->m_known_objects.insert(i.getNode()->getKey(), false);
1579 obj->m_known_by_count++;
1583 SharedBuffer<u8> reply(2 + data_buffer.size());
1584 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1585 memcpy((char*)&reply[2], data_buffer.c_str(),
1586 data_buffer.size());
1588 m_con.Send(client->peer_id, 0, reply, true);
1590 verbosestream<<"Server: Sent object remove/add: "
1591 <<removed_objects.size()<<" removed, "
1592 <<added_objects.size()<<" added, "
1593 <<"packet size is "<<reply.getSize()<<std::endl;
1598 Collect a list of all the objects known by the clients
1599 and report it back to the environment.
1602 core::map<u16, bool> all_known_objects;
1604 for(core::map<u16, RemoteClient*>::Iterator
1605 i = m_clients.getIterator();
1606 i.atEnd() == false; i++)
1608 RemoteClient *client = i.getNode()->getValue();
1609 // Go through all known objects of client
1610 for(core::map<u16, bool>::Iterator
1611 i = client->m_known_objects.getIterator();
1612 i.atEnd()==false; i++)
1614 u16 id = i.getNode()->getKey();
1615 all_known_objects[id] = true;
1619 m_env->setKnownActiveObjects(whatever);
1625 Send object messages
1628 JMutexAutoLock envlock(m_env_mutex);
1629 JMutexAutoLock conlock(m_con_mutex);
1631 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1634 // Value = data sent by object
1635 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1637 // Get active object messages from environment
1640 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1644 core::list<ActiveObjectMessage>* message_list = NULL;
1645 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1646 n = buffered_messages.find(aom.id);
1649 message_list = new core::list<ActiveObjectMessage>;
1650 buffered_messages.insert(aom.id, message_list);
1654 message_list = n->getValue();
1656 message_list->push_back(aom);
1659 // Route data to every client
1660 for(core::map<u16, RemoteClient*>::Iterator
1661 i = m_clients.getIterator();
1662 i.atEnd()==false; i++)
1664 RemoteClient *client = i.getNode()->getValue();
1665 std::string reliable_data;
1666 std::string unreliable_data;
1667 // Go through all objects in message buffer
1668 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1669 j = buffered_messages.getIterator();
1670 j.atEnd()==false; j++)
1672 // If object is not known by client, skip it
1673 u16 id = j.getNode()->getKey();
1674 if(client->m_known_objects.find(id) == NULL)
1676 // Get message list of object
1677 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1678 // Go through every message
1679 for(core::list<ActiveObjectMessage>::Iterator
1680 k = list->begin(); k != list->end(); k++)
1682 // Compose the full new data with header
1683 ActiveObjectMessage aom = *k;
1684 std::string new_data;
1687 writeU16((u8*)&buf[0], aom.id);
1688 new_data.append(buf, 2);
1690 new_data += serializeString(aom.datastring);
1691 // Add data to buffer
1693 reliable_data += new_data;
1695 unreliable_data += new_data;
1699 reliable_data and unreliable_data are now ready.
1702 if(reliable_data.size() > 0)
1704 SharedBuffer<u8> reply(2 + reliable_data.size());
1705 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1706 memcpy((char*)&reply[2], reliable_data.c_str(),
1707 reliable_data.size());
1709 m_con.Send(client->peer_id, 0, reply, true);
1711 if(unreliable_data.size() > 0)
1713 SharedBuffer<u8> reply(2 + unreliable_data.size());
1714 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1715 memcpy((char*)&reply[2], unreliable_data.c_str(),
1716 unreliable_data.size());
1717 // Send as unreliable
1718 m_con.Send(client->peer_id, 0, reply, false);
1721 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1723 infostream<<"Server: Size of object message data: "
1724 <<"reliable: "<<reliable_data.size()
1725 <<", unreliable: "<<unreliable_data.size()
1730 // Clear buffered_messages
1731 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1732 i = buffered_messages.getIterator();
1733 i.atEnd()==false; i++)
1735 delete i.getNode()->getValue();
1739 } // enable_experimental
1742 Send queued-for-sending map edit events.
1745 // We will be accessing the environment and the connection
1746 JMutexAutoLock lock(m_env_mutex);
1747 JMutexAutoLock conlock(m_con_mutex);
1749 // Don't send too many at a time
1752 // Single change sending is disabled if queue size is not small
1753 bool disable_single_change_sending = false;
1754 if(m_unsent_map_edit_queue.size() >= 4)
1755 disable_single_change_sending = true;
1757 int event_count = m_unsent_map_edit_queue.size();
1759 // We'll log the amount of each
1762 while(m_unsent_map_edit_queue.size() != 0)
1764 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1766 // Players far away from the change are stored here.
1767 // Instead of sending the changes, MapBlocks are set not sent
1769 core::list<u16> far_players;
1771 if(event->type == MEET_ADDNODE)
1773 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1774 prof.add("MEET_ADDNODE", 1);
1775 if(disable_single_change_sending)
1776 sendAddNode(event->p, event->n, event->already_known_by_peer,
1779 sendAddNode(event->p, event->n, event->already_known_by_peer,
1782 else if(event->type == MEET_REMOVENODE)
1784 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1785 prof.add("MEET_REMOVENODE", 1);
1786 if(disable_single_change_sending)
1787 sendRemoveNode(event->p, event->already_known_by_peer,
1790 sendRemoveNode(event->p, event->already_known_by_peer,
1793 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1795 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1796 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1797 setBlockNotSent(event->p);
1799 else if(event->type == MEET_OTHER)
1801 infostream<<"Server: MEET_OTHER"<<std::endl;
1802 prof.add("MEET_OTHER", 1);
1803 for(core::map<v3s16, bool>::Iterator
1804 i = event->modified_blocks.getIterator();
1805 i.atEnd()==false; i++)
1807 v3s16 p = i.getNode()->getKey();
1813 prof.add("unknown", 1);
1814 infostream<<"WARNING: Server: Unknown MapEditEvent "
1815 <<((u32)event->type)<<std::endl;
1819 Set blocks not sent to far players
1821 if(far_players.size() > 0)
1823 // Convert list format to that wanted by SetBlocksNotSent
1824 core::map<v3s16, MapBlock*> modified_blocks2;
1825 for(core::map<v3s16, bool>::Iterator
1826 i = event->modified_blocks.getIterator();
1827 i.atEnd()==false; i++)
1829 v3s16 p = i.getNode()->getKey();
1830 modified_blocks2.insert(p,
1831 m_env->getMap().getBlockNoCreateNoEx(p));
1833 // Set blocks not sent
1834 for(core::list<u16>::Iterator
1835 i = far_players.begin();
1836 i != far_players.end(); i++)
1839 RemoteClient *client = getClient(peer_id);
1842 client->SetBlocksNotSent(modified_blocks2);
1848 /*// Don't send too many at a time
1850 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1854 if(event_count >= 5){
1855 infostream<<"Server: MapEditEvents:"<<std::endl;
1856 prof.print(infostream);
1857 } else if(event_count != 0){
1858 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1859 prof.print(verbosestream);
1865 Trigger emergethread (it somehow gets to a non-triggered but
1866 bysy state sometimes)
1869 float &counter = m_emergethread_trigger_timer;
1875 m_emergethread.trigger();
1877 // Update m_enable_rollback_recording here too
1878 m_enable_rollback_recording =
1879 g_settings->getBool("enable_rollback_recording");
1883 // Save map, players and auth stuff
1885 float &counter = m_savemap_timer;
1887 if(counter >= g_settings->getFloat("server_map_save_interval"))
1890 JMutexAutoLock lock(m_env_mutex);
1892 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1895 if(m_banmanager.isModified())
1896 m_banmanager.save();
1898 // Save changed parts of map
1899 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1902 m_env->serializePlayers(m_path_world);
1904 // Save environment metadata
1905 m_env->saveMeta(m_path_world);
1910 void Server::Receive()
1912 DSTACK(__FUNCTION_NAME);
1913 SharedBuffer<u8> data;
1918 JMutexAutoLock conlock(m_con_mutex);
1919 datasize = m_con.Receive(peer_id, data);
1922 // This has to be called so that the client list gets synced
1923 // with the peer list of the connection
1924 handlePeerChanges();
1926 ProcessData(*data, datasize, peer_id);
1928 catch(con::InvalidIncomingDataException &e)
1930 infostream<<"Server::Receive(): "
1931 "InvalidIncomingDataException: what()="
1932 <<e.what()<<std::endl;
1934 catch(con::PeerNotFoundException &e)
1936 //NOTE: This is not needed anymore
1938 // The peer has been disconnected.
1939 // Find the associated player and remove it.
1941 /*JMutexAutoLock envlock(m_env_mutex);
1943 infostream<<"ServerThread: peer_id="<<peer_id
1944 <<" has apparently closed connection. "
1945 <<"Removing player."<<std::endl;
1947 m_env->removePlayer(peer_id);*/
1951 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1953 DSTACK(__FUNCTION_NAME);
1954 // Environment is locked first.
1955 JMutexAutoLock envlock(m_env_mutex);
1956 JMutexAutoLock conlock(m_con_mutex);
1958 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1961 Address address = m_con.GetPeerAddress(peer_id);
1962 std::string addr_s = address.serializeString();
1964 // drop player if is ip is banned
1965 if(m_banmanager.isIpBanned(addr_s)){
1966 infostream<<"Server: A banned client tried to connect from "
1967 <<addr_s<<"; banned name was "
1968 <<m_banmanager.getBanName(addr_s)<<std::endl;
1969 // This actually doesn't seem to transfer to the client
1970 SendAccessDenied(m_con, peer_id,
1971 L"Your ip is banned. Banned name was "
1972 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1973 m_con.DeletePeer(peer_id);
1977 catch(con::PeerNotFoundException &e)
1979 infostream<<"Server::ProcessData(): Cancelling: peer "
1980 <<peer_id<<" not found"<<std::endl;
1984 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1986 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1994 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1996 if(command == TOSERVER_INIT)
1998 // [0] u16 TOSERVER_INIT
1999 // [2] u8 SER_FMT_VER_HIGHEST
2000 // [3] u8[20] player_name
2001 // [23] u8[28] password <--- can be sent without this, from old versions
2003 if(datasize < 2+1+PLAYERNAME_SIZE)
2006 verbosestream<<"Server: Got TOSERVER_INIT from "
2007 <<peer_id<<std::endl;
2009 // First byte after command is maximum supported
2010 // serialization version
2011 u8 client_max = data[2];
2012 u8 our_max = SER_FMT_VER_HIGHEST;
2013 // Use the highest version supported by both
2014 u8 deployed = core::min_(client_max, our_max);
2015 // If it's lower than the lowest supported, give up.
2016 if(deployed < SER_FMT_VER_LOWEST)
2017 deployed = SER_FMT_VER_INVALID;
2019 //peer->serialization_version = deployed;
2020 getClient(peer_id)->pending_serialization_version = deployed;
2022 if(deployed == SER_FMT_VER_INVALID)
2024 actionstream<<"Server: A mismatched client tried to connect from "
2025 <<addr_s<<std::endl;
2026 infostream<<"Server: Cannot negotiate "
2027 "serialization version with peer "
2028 <<peer_id<<std::endl;
2029 SendAccessDenied(m_con, peer_id, std::wstring(
2030 L"Your client's version is not supported.\n"
2031 L"Server version is ")
2032 + narrow_to_wide(VERSION_STRING) + L"."
2038 Read and check network protocol version
2041 u16 min_net_proto_version = 0;
2042 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2043 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2045 // Use same version as minimum and maximum if maximum version field
2046 // doesn't exist (backwards compatibility)
2047 u16 max_net_proto_version = min_net_proto_version;
2048 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
2049 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
2051 // Start with client's maximum version
2052 u16 net_proto_version = max_net_proto_version;
2054 // Figure out a working version if it is possible at all
2055 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
2056 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
2058 // If maximum is larger than our maximum, go with our maximum
2059 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2060 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
2061 // Else go with client's maximum
2063 net_proto_version = max_net_proto_version;
2066 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
2067 <<min_net_proto_version<<", max: "<<max_net_proto_version
2068 <<", chosen: "<<net_proto_version<<std::endl;
2070 getClient(peer_id)->net_proto_version = net_proto_version;
2072 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
2073 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2075 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
2077 SendAccessDenied(m_con, peer_id, std::wstring(
2078 L"Your client's version is not supported.\n"
2079 L"Server version is ")
2080 + narrow_to_wide(VERSION_STRING) + L",\n"
2081 + L"server's PROTOCOL_VERSION is "
2082 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
2084 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
2085 + L", client's PROTOCOL_VERSION is "
2086 + narrow_to_wide(itos(min_net_proto_version))
2088 + narrow_to_wide(itos(max_net_proto_version))
2093 if(g_settings->getBool("strict_protocol_version_checking"))
2095 if(net_proto_version != LATEST_PROTOCOL_VERSION)
2097 actionstream<<"Server: A mismatched (strict) client tried to "
2098 <<"connect from "<<addr_s<<std::endl;
2099 SendAccessDenied(m_con, peer_id, std::wstring(
2100 L"Your client's version is not supported.\n"
2101 L"Server version is ")
2102 + narrow_to_wide(VERSION_STRING) + L",\n"
2103 + L"server's PROTOCOL_VERSION (strict) is "
2104 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
2105 + L", client's PROTOCOL_VERSION is "
2106 + narrow_to_wide(itos(min_net_proto_version))
2108 + narrow_to_wide(itos(max_net_proto_version))
2119 char playername[PLAYERNAME_SIZE];
2120 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2122 playername[i] = data[3+i];
2124 playername[PLAYERNAME_SIZE-1] = 0;
2126 if(playername[0]=='\0')
2128 actionstream<<"Server: Player with an empty name "
2129 <<"tried to connect from "<<addr_s<<std::endl;
2130 SendAccessDenied(m_con, peer_id,
2135 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2137 actionstream<<"Server: Player with an invalid name "
2138 <<"tried to connect from "<<addr_s<<std::endl;
2139 SendAccessDenied(m_con, peer_id,
2140 L"Name contains unallowed characters");
2144 infostream<<"Server: New connection: \""<<playername<<"\" from "
2145 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2148 char given_password[PASSWORD_SIZE];
2149 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2151 // old version - assume blank password
2152 given_password[0] = 0;
2156 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2158 given_password[i] = data[23+i];
2160 given_password[PASSWORD_SIZE-1] = 0;
2163 if(!base64_is_valid(given_password)){
2164 infostream<<"Server: "<<playername
2165 <<" supplied invalid password hash"<<std::endl;
2166 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2170 std::string checkpwd; // Password hash to check against
2171 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2173 // If no authentication info exists for user, create it
2175 if(!isSingleplayer() &&
2176 g_settings->getBool("disallow_empty_password") &&
2177 std::string(given_password) == ""){
2178 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2179 L"disallowed. Set a password and try again.");
2182 std::wstring raw_default_password =
2183 narrow_to_wide(g_settings->get("default_password"));
2184 std::string initial_password =
2185 translatePassword(playername, raw_default_password);
2187 // If default_password is empty, allow any initial password
2188 if (raw_default_password.length() == 0)
2189 initial_password = given_password;
2191 scriptapi_create_auth(m_lua, playername, initial_password);
2194 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2197 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2201 if(given_password != checkpwd){
2202 infostream<<"Server: peer_id="<<peer_id
2203 <<": supplied invalid password for "
2204 <<playername<<std::endl;
2205 SendAccessDenied(m_con, peer_id, L"Invalid password");
2209 // Do not allow multiple players in simple singleplayer mode.
2210 // This isn't a perfect way to do it, but will suffice for now.
2211 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2212 infostream<<"Server: Not allowing another client to connect in"
2213 <<" simple singleplayer mode"<<std::endl;
2214 SendAccessDenied(m_con, peer_id,
2215 L"Running in simple singleplayer mode.");
2219 // Enforce user limit.
2220 // Don't enforce for users that have some admin right
2221 if(m_clients.size() >= g_settings->getU16("max_users") &&
2222 !checkPriv(playername, "server") &&
2223 !checkPriv(playername, "ban") &&
2224 !checkPriv(playername, "privs") &&
2225 !checkPriv(playername, "password") &&
2226 playername != g_settings->get("name"))
2228 actionstream<<"Server: "<<playername<<" tried to join, but there"
2229 <<" are already max_users="
2230 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2231 SendAccessDenied(m_con, peer_id, L"Too many users.");
2236 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2238 // If failed, cancel
2239 if(playersao == NULL)
2241 errorstream<<"Server: peer_id="<<peer_id
2242 <<": failed to emerge player"<<std::endl;
2247 Answer with a TOCLIENT_INIT
2250 SharedBuffer<u8> reply(2+1+6+8+4);
2251 writeU16(&reply[0], TOCLIENT_INIT);
2252 writeU8(&reply[2], deployed);
2253 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2254 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2255 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2258 m_con.Send(peer_id, 0, reply, true);
2262 Send complete position information
2264 SendMovePlayer(peer_id);
2269 if(command == TOSERVER_INIT2)
2271 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2272 <<peer_id<<std::endl;
2274 Player *player = m_env->getPlayer(peer_id);
2276 verbosestream<<"Server: TOSERVER_INIT2: "
2277 <<"Player not found; ignoring."<<std::endl;
2281 RemoteClient *client = getClient(peer_id);
2282 client->serialization_version =
2283 getClient(peer_id)->pending_serialization_version;
2286 Send some initialization data
2289 infostream<<"Server: Sending content to "
2290 <<getPlayerName(peer_id)<<std::endl;
2292 // Send item definitions
2293 SendItemDef(m_con, peer_id, m_itemdef);
2295 // Send node definitions
2296 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2298 // Send media announcement
2299 sendMediaAnnouncement(peer_id);
2302 SendPlayerPrivileges(peer_id);
2304 // Send inventory formspec
2305 SendPlayerInventoryFormspec(peer_id);
2308 UpdateCrafting(peer_id);
2309 SendInventory(peer_id);
2312 SendPlayerHP(peer_id);
2314 // Send detached inventories
2315 sendDetachedInventories(peer_id);
2317 // Show death screen if necessary
2319 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2323 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2324 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2325 m_con.Send(peer_id, 0, data, true);
2328 // Note things in chat if not in simple singleplayer mode
2329 if(!m_simple_singleplayer_mode)
2331 // Send information about server to player in chat
2332 SendChatMessage(peer_id, getStatusString());
2334 // Send information about joining in chat
2336 std::wstring name = L"unknown";
2337 Player *player = m_env->getPlayer(peer_id);
2339 name = narrow_to_wide(player->getName());
2341 std::wstring message;
2344 message += L" joined the game.";
2345 BroadcastChatMessage(message);
2349 // Warnings about protocol version can be issued here
2350 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2352 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2353 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2360 std::ostringstream os(std::ios_base::binary);
2361 for(core::map<u16, RemoteClient*>::Iterator
2362 i = m_clients.getIterator();
2363 i.atEnd() == false; i++)
2365 RemoteClient *client = i.getNode()->getValue();
2366 assert(client->peer_id == i.getNode()->getKey());
2367 if(client->serialization_version == SER_FMT_VER_INVALID)
2370 Player *player = m_env->getPlayer(client->peer_id);
2373 // Get name of player
2374 os<<player->getName()<<" ";
2377 actionstream<<player->getName()<<" joins game. List of players: "
2378 <<os.str()<<std::endl;
2384 if(peer_ser_ver == SER_FMT_VER_INVALID)
2386 infostream<<"Server::ProcessData(): Cancelling: Peer"
2387 " serialization format invalid or not initialized."
2388 " Skipping incoming command="<<command<<std::endl;
2392 Player *player = m_env->getPlayer(peer_id);
2394 infostream<<"Server::ProcessData(): Cancelling: "
2395 "No player for peer_id="<<peer_id
2400 PlayerSAO *playersao = player->getPlayerSAO();
2401 if(playersao == NULL){
2402 infostream<<"Server::ProcessData(): Cancelling: "
2403 "No player object for peer_id="<<peer_id
2408 if(command == TOSERVER_PLAYERPOS)
2410 if(datasize < 2+12+12+4+4)
2414 v3s32 ps = readV3S32(&data[start+2]);
2415 v3s32 ss = readV3S32(&data[start+2+12]);
2416 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2417 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2419 if(datasize >= 2+12+12+4+4+4)
2420 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2421 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2422 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2423 pitch = wrapDegrees(pitch);
2424 yaw = wrapDegrees(yaw);
2426 player->setPosition(position);
2427 player->setSpeed(speed);
2428 player->setPitch(pitch);
2429 player->setYaw(yaw);
2430 player->keyPressed=keyPressed;
2431 player->control.up = (bool)(keyPressed&1);
2432 player->control.down = (bool)(keyPressed&2);
2433 player->control.left = (bool)(keyPressed&4);
2434 player->control.right = (bool)(keyPressed&8);
2435 player->control.jump = (bool)(keyPressed&16);
2436 player->control.aux1 = (bool)(keyPressed&32);
2437 player->control.sneak = (bool)(keyPressed&64);
2438 player->control.LMB = (bool)(keyPressed&128);
2439 player->control.RMB = (bool)(keyPressed&256);
2441 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2442 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2443 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2445 else if(command == TOSERVER_GOTBLOCKS)
2458 u16 count = data[2];
2459 for(u16 i=0; i<count; i++)
2461 if((s16)datasize < 2+1+(i+1)*6)
2462 throw con::InvalidIncomingDataException
2463 ("GOTBLOCKS length is too short");
2464 v3s16 p = readV3S16(&data[2+1+i*6]);
2465 /*infostream<<"Server: GOTBLOCKS ("
2466 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2467 RemoteClient *client = getClient(peer_id);
2468 client->GotBlock(p);
2471 else if(command == TOSERVER_DELETEDBLOCKS)
2484 u16 count = data[2];
2485 for(u16 i=0; i<count; i++)
2487 if((s16)datasize < 2+1+(i+1)*6)
2488 throw con::InvalidIncomingDataException
2489 ("DELETEDBLOCKS length is too short");
2490 v3s16 p = readV3S16(&data[2+1+i*6]);
2491 /*infostream<<"Server: DELETEDBLOCKS ("
2492 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2493 RemoteClient *client = getClient(peer_id);
2494 client->SetBlockNotSent(p);
2497 else if(command == TOSERVER_CLICK_OBJECT)
2499 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2502 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2504 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2507 else if(command == TOSERVER_GROUND_ACTION)
2509 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2513 else if(command == TOSERVER_RELEASE)
2515 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2518 else if(command == TOSERVER_SIGNTEXT)
2520 infostream<<"Server: SIGNTEXT not supported anymore"
2524 else if(command == TOSERVER_SIGNNODETEXT)
2526 infostream<<"Server: SIGNNODETEXT not supported anymore"
2530 else if(command == TOSERVER_INVENTORY_ACTION)
2532 // Strip command and create a stream
2533 std::string datastring((char*)&data[2], datasize-2);
2534 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2535 std::istringstream is(datastring, std::ios_base::binary);
2537 InventoryAction *a = InventoryAction::deSerialize(is);
2540 infostream<<"TOSERVER_INVENTORY_ACTION: "
2541 <<"InventoryAction::deSerialize() returned NULL"
2546 // If something goes wrong, this player is to blame
2547 RollbackScopeActor rollback_scope(m_rollback,
2548 std::string("player:")+player->getName());
2551 Note: Always set inventory not sent, to repair cases
2552 where the client made a bad prediction.
2556 Handle restrictions and special cases of the move action
2558 if(a->getType() == IACTION_MOVE)
2560 IMoveAction *ma = (IMoveAction*)a;
2562 ma->from_inv.applyCurrentPlayer(player->getName());
2563 ma->to_inv.applyCurrentPlayer(player->getName());
2565 setInventoryModified(ma->from_inv);
2566 setInventoryModified(ma->to_inv);
2568 bool from_inv_is_current_player =
2569 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2570 (ma->from_inv.name == player->getName());
2572 bool to_inv_is_current_player =
2573 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2574 (ma->to_inv.name == player->getName());
2577 Disable moving items out of craftpreview
2579 if(ma->from_list == "craftpreview")
2581 infostream<<"Ignoring IMoveAction from "
2582 <<(ma->from_inv.dump())<<":"<<ma->from_list
2583 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2584 <<" because src is "<<ma->from_list<<std::endl;
2590 Disable moving items into craftresult and craftpreview
2592 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2594 infostream<<"Ignoring IMoveAction from "
2595 <<(ma->from_inv.dump())<<":"<<ma->from_list
2596 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2597 <<" because dst is "<<ma->to_list<<std::endl;
2602 // Disallow moving items in elsewhere than player's inventory
2603 // if not allowed to interact
2604 if(!checkPriv(player->getName(), "interact") &&
2605 (!from_inv_is_current_player ||
2606 !to_inv_is_current_player))
2608 infostream<<"Cannot move outside of player's inventory: "
2609 <<"No interact privilege"<<std::endl;
2615 Handle restrictions and special cases of the drop action
2617 else if(a->getType() == IACTION_DROP)
2619 IDropAction *da = (IDropAction*)a;
2621 da->from_inv.applyCurrentPlayer(player->getName());
2623 setInventoryModified(da->from_inv);
2625 // Disallow dropping items if not allowed to interact
2626 if(!checkPriv(player->getName(), "interact"))
2633 Handle restrictions and special cases of the craft action
2635 else if(a->getType() == IACTION_CRAFT)
2637 ICraftAction *ca = (ICraftAction*)a;
2639 ca->craft_inv.applyCurrentPlayer(player->getName());
2641 setInventoryModified(ca->craft_inv);
2643 //bool craft_inv_is_current_player =
2644 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2645 // (ca->craft_inv.name == player->getName());
2647 // Disallow crafting if not allowed to interact
2648 if(!checkPriv(player->getName(), "interact"))
2650 infostream<<"Cannot craft: "
2651 <<"No interact privilege"<<std::endl;
2658 a->apply(this, playersao, this);
2662 else if(command == TOSERVER_CHAT_MESSAGE)
2670 std::string datastring((char*)&data[2], datasize-2);
2671 std::istringstream is(datastring, std::ios_base::binary);
2674 is.read((char*)buf, 2);
2675 u16 len = readU16(buf);
2677 std::wstring message;
2678 for(u16 i=0; i<len; i++)
2680 is.read((char*)buf, 2);
2681 message += (wchar_t)readU16(buf);
2684 // If something goes wrong, this player is to blame
2685 RollbackScopeActor rollback_scope(m_rollback,
2686 std::string("player:")+player->getName());
2688 // Get player name of this client
2689 std::wstring name = narrow_to_wide(player->getName());
2692 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2693 wide_to_narrow(message));
2694 // If script ate the message, don't proceed
2698 // Line to send to players
2700 // Whether to send to the player that sent the line
2701 bool send_to_sender = false;
2702 // Whether to send to other players
2703 bool send_to_others = false;
2705 // Commands are implemented in Lua, so only catch invalid
2706 // commands that were not "eaten" and send an error back
2707 if(message[0] == L'/')
2709 message = message.substr(1);
2710 send_to_sender = true;
2711 if(message.length() == 0)
2712 line += L"-!- Empty command";
2714 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2718 if(checkPriv(player->getName(), "shout")){
2723 send_to_others = true;
2725 line += L"-!- You don't have permission to shout.";
2726 send_to_sender = true;
2733 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2736 Send the message to clients
2738 for(core::map<u16, RemoteClient*>::Iterator
2739 i = m_clients.getIterator();
2740 i.atEnd() == false; i++)
2742 // Get client and check that it is valid
2743 RemoteClient *client = i.getNode()->getValue();
2744 assert(client->peer_id == i.getNode()->getKey());
2745 if(client->serialization_version == SER_FMT_VER_INVALID)
2749 bool sender_selected = (peer_id == client->peer_id);
2750 if(sender_selected == true && send_to_sender == false)
2752 if(sender_selected == false && send_to_others == false)
2755 SendChatMessage(client->peer_id, line);
2759 else if(command == TOSERVER_DAMAGE)
2761 std::string datastring((char*)&data[2], datasize-2);
2762 std::istringstream is(datastring, std::ios_base::binary);
2763 u8 damage = readU8(is);
2765 actionstream<<player->getName()<<" damaged by "
2766 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2769 playersao->setHP(playersao->getHP() - damage);
2771 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2774 if(playersao->m_hp_not_sent)
2775 SendPlayerHP(peer_id);
2777 else if(command == TOSERVER_PASSWORD)
2780 [0] u16 TOSERVER_PASSWORD
2781 [2] u8[28] old password
2782 [30] u8[28] new password
2785 if(datasize != 2+PASSWORD_SIZE*2)
2787 /*char password[PASSWORD_SIZE];
2788 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2789 password[i] = data[2+i];
2790 password[PASSWORD_SIZE-1] = 0;*/
2792 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2800 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2802 char c = data[2+PASSWORD_SIZE+i];
2808 if(!base64_is_valid(newpwd)){
2809 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2810 // Wrong old password supplied!!
2811 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2815 infostream<<"Server: Client requests a password change from "
2816 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2818 std::string playername = player->getName();
2820 std::string checkpwd;
2821 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2823 if(oldpwd != checkpwd)
2825 infostream<<"Server: invalid old password"<<std::endl;
2826 // Wrong old password supplied!!
2827 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2831 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2833 actionstream<<player->getName()<<" changes password"<<std::endl;
2834 SendChatMessage(peer_id, L"Password change successful.");
2836 actionstream<<player->getName()<<" tries to change password but "
2837 <<"it fails"<<std::endl;
2838 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2841 else if(command == TOSERVER_PLAYERITEM)
2846 u16 item = readU16(&data[2]);
2847 playersao->setWieldIndex(item);
2849 else if(command == TOSERVER_RESPAWN)
2854 RespawnPlayer(peer_id);
2856 actionstream<<player->getName()<<" respawns at "
2857 <<PP(player->getPosition()/BS)<<std::endl;
2859 // ActiveObject is added to environment in AsyncRunStep after
2860 // the previous addition has been succesfully removed
2862 else if(command == TOSERVER_REQUEST_MEDIA) {
2863 std::string datastring((char*)&data[2], datasize-2);
2864 std::istringstream is(datastring, std::ios_base::binary);
2866 core::list<MediaRequest> tosend;
2867 u16 numfiles = readU16(is);
2869 infostream<<"Sending "<<numfiles<<" files to "
2870 <<getPlayerName(peer_id)<<std::endl;
2871 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2873 for(int i = 0; i < numfiles; i++) {
2874 std::string name = deSerializeString(is);
2875 tosend.push_back(MediaRequest(name));
2876 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2880 sendRequestedMedia(peer_id, tosend);
2882 // Now the client should know about everything
2883 // (definitions and files)
2884 getClient(peer_id)->definitions_sent = true;
2886 else if(command == TOSERVER_INTERACT)
2888 std::string datastring((char*)&data[2], datasize-2);
2889 std::istringstream is(datastring, std::ios_base::binary);
2895 [5] u32 length of the next item
2896 [9] serialized PointedThing
2898 0: start digging (from undersurface) or use
2899 1: stop digging (all parameters ignored)
2900 2: digging completed
2901 3: place block or item (to abovesurface)
2904 u8 action = readU8(is);
2905 u16 item_i = readU16(is);
2906 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2907 PointedThing pointed;
2908 pointed.deSerialize(tmp_is);
2910 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2911 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2915 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2916 <<" tried to interact, but is dead!"<<std::endl;
2920 v3f player_pos = playersao->getLastGoodPosition();
2922 // Update wielded item
2923 playersao->setWieldIndex(item_i);
2925 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2926 v3s16 p_under = pointed.node_undersurface;
2927 v3s16 p_above = pointed.node_abovesurface;
2929 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2930 ServerActiveObject *pointed_object = NULL;
2931 if(pointed.type == POINTEDTHING_OBJECT)
2933 pointed_object = m_env->getActiveObject(pointed.object_id);
2934 if(pointed_object == NULL)
2936 verbosestream<<"TOSERVER_INTERACT: "
2937 "pointed object is NULL"<<std::endl;
2943 v3f pointed_pos_under = player_pos;
2944 v3f pointed_pos_above = player_pos;
2945 if(pointed.type == POINTEDTHING_NODE)
2947 pointed_pos_under = intToFloat(p_under, BS);
2948 pointed_pos_above = intToFloat(p_above, BS);
2950 else if(pointed.type == POINTEDTHING_OBJECT)
2952 pointed_pos_under = pointed_object->getBasePosition();
2953 pointed_pos_above = pointed_pos_under;
2957 Check that target is reasonably close
2958 (only when digging or placing things)
2960 if(action == 0 || action == 2 || action == 3)
2962 float d = player_pos.getDistanceFrom(pointed_pos_under);
2963 float max_d = BS * 14; // Just some large enough value
2965 actionstream<<"Player "<<player->getName()
2966 <<" tried to access "<<pointed.dump()
2968 <<"d="<<d<<", max_d="<<max_d
2969 <<". ignoring."<<std::endl;
2970 // Re-send block to revert change on client-side
2971 RemoteClient *client = getClient(peer_id);
2972 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2973 client->SetBlockNotSent(blockpos);
2980 Make sure the player is allowed to do it
2982 if(!checkPriv(player->getName(), "interact"))
2984 actionstream<<player->getName()<<" attempted to interact with "
2985 <<pointed.dump()<<" without 'interact' privilege"
2987 // Re-send block to revert change on client-side
2988 RemoteClient *client = getClient(peer_id);
2989 // Digging completed -> under
2991 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2992 client->SetBlockNotSent(blockpos);
2994 // Placement -> above
2996 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2997 client->SetBlockNotSent(blockpos);
3003 If something goes wrong, this player is to blame
3005 RollbackScopeActor rollback_scope(m_rollback,
3006 std::string("player:")+player->getName());
3009 0: start digging or punch object
3013 if(pointed.type == POINTEDTHING_NODE)
3016 NOTE: This can be used in the future to check if
3017 somebody is cheating, by checking the timing.
3019 MapNode n(CONTENT_IGNORE);
3022 n = m_env->getMap().getNode(p_under);
3024 catch(InvalidPositionException &e)
3026 infostream<<"Server: Not punching: Node not found."
3027 <<" Adding block to emerge queue."
3029 m_emerge_queue.addBlock(peer_id,
3030 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3032 if(n.getContent() != CONTENT_IGNORE)
3033 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3035 playersao->noCheatDigStart(p_under);
3037 else if(pointed.type == POINTEDTHING_OBJECT)
3039 // Skip if object has been removed
3040 if(pointed_object->m_removed)
3043 actionstream<<player->getName()<<" punches object "
3044 <<pointed.object_id<<": "
3045 <<pointed_object->getDescription()<<std::endl;
3047 ItemStack punchitem = playersao->getWieldedItem();
3048 ToolCapabilities toolcap =
3049 punchitem.getToolCapabilities(m_itemdef);
3050 v3f dir = (pointed_object->getBasePosition() -
3051 (player->getPosition() + player->getEyeOffset())
3053 float time_from_last_punch =
3054 playersao->resetTimeFromLastPunch();
3055 pointed_object->punch(dir, &toolcap, playersao,
3056 time_from_last_punch);
3064 else if(action == 1)
3069 2: Digging completed
3071 else if(action == 2)
3073 // Only digging of nodes
3074 if(pointed.type == POINTEDTHING_NODE)
3076 MapNode n(CONTENT_IGNORE);
3079 n = m_env->getMap().getNode(p_under);
3081 catch(InvalidPositionException &e)
3083 infostream<<"Server: Not finishing digging: Node not found."
3084 <<" Adding block to emerge queue."
3086 m_emerge_queue.addBlock(peer_id,
3087 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3090 /* Cheat prevention */
3091 bool is_valid_dig = true;
3092 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3094 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3095 float nocheat_t = playersao->getNoCheatDigTime();
3096 playersao->noCheatDigEnd();
3097 // If player didn't start digging this, ignore dig
3098 if(nocheat_p != p_under){
3099 infostream<<"Server: NoCheat: "<<player->getName()
3100 <<" started digging "
3101 <<PP(nocheat_p)<<" and completed digging "
3102 <<PP(p_under)<<"; not digging."<<std::endl;
3103 is_valid_dig = false;
3105 // Get player's wielded item
3106 ItemStack playeritem;
3107 InventoryList *mlist = playersao->getInventory()->getList("main");
3109 playeritem = mlist->getItem(playersao->getWieldIndex());
3110 ToolCapabilities playeritem_toolcap =
3111 playeritem.getToolCapabilities(m_itemdef);
3112 // Get diggability and expected digging time
3113 DigParams params = getDigParams(m_nodedef->get(n).groups,
3114 &playeritem_toolcap);
3115 // If can't dig, try hand
3116 if(!params.diggable){
3117 const ItemDefinition &hand = m_itemdef->get("");
3118 const ToolCapabilities *tp = hand.tool_capabilities;
3120 params = getDigParams(m_nodedef->get(n).groups, tp);
3122 // If can't dig, ignore dig
3123 if(!params.diggable){
3124 infostream<<"Server: NoCheat: "<<player->getName()
3125 <<" completed digging "<<PP(p_under)
3126 <<", which is not diggable with tool. not digging."
3128 is_valid_dig = false;
3130 // If time is considerably too short, ignore dig
3131 // Check time only for medium and slow timed digs
3132 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3133 infostream<<"Server: NoCheat: "<<player->getName()
3134 <<" completed digging "
3135 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3136 <<params.time<<"s; not digging."<<std::endl;
3137 is_valid_dig = false;
3141 /* Actually dig node */
3143 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3144 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3146 // Send unusual result (that is, node not being removed)
3147 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3149 // Re-send block to revert change on client-side
3150 RemoteClient *client = getClient(peer_id);
3151 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3152 client->SetBlockNotSent(blockpos);
3158 3: place block or right-click object
3160 else if(action == 3)
3162 ItemStack item = playersao->getWieldedItem();
3164 // Reset build time counter
3165 if(pointed.type == POINTEDTHING_NODE &&
3166 item.getDefinition(m_itemdef).type == ITEM_NODE)
3167 getClient(peer_id)->m_time_from_building = 0.0;
3169 if(pointed.type == POINTEDTHING_OBJECT)
3171 // Right click object
3173 // Skip if object has been removed
3174 if(pointed_object->m_removed)
3177 actionstream<<player->getName()<<" right-clicks object "
3178 <<pointed.object_id<<": "
3179 <<pointed_object->getDescription()<<std::endl;
3182 pointed_object->rightClick(playersao);
3184 else if(scriptapi_item_on_place(m_lua,
3185 item, playersao, pointed))
3187 // Placement was handled in lua
3189 // Apply returned ItemStack
3190 playersao->setWieldedItem(item);
3193 // If item has node placement prediction, always send the above
3194 // node to make sure the client knows what exactly happened
3195 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3196 RemoteClient *client = getClient(peer_id);
3197 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3198 client->SetBlockNotSent(blockpos);
3205 else if(action == 4)
3207 ItemStack item = playersao->getWieldedItem();
3209 actionstream<<player->getName()<<" uses "<<item.name
3210 <<", pointing at "<<pointed.dump()<<std::endl;
3212 if(scriptapi_item_on_use(m_lua,
3213 item, playersao, pointed))
3215 // Apply returned ItemStack
3216 playersao->setWieldedItem(item);
3223 Catch invalid actions
3227 infostream<<"WARNING: Server: Invalid action "
3228 <<action<<std::endl;
3231 else if(command == TOSERVER_REMOVED_SOUNDS)
3233 std::string datastring((char*)&data[2], datasize-2);
3234 std::istringstream is(datastring, std::ios_base::binary);
3236 int num = readU16(is);
3237 for(int k=0; k<num; k++){
3238 s32 id = readS32(is);
3239 std::map<s32, ServerPlayingSound>::iterator i =
3240 m_playing_sounds.find(id);
3241 if(i == m_playing_sounds.end())
3243 ServerPlayingSound &psound = i->second;
3244 psound.clients.erase(peer_id);
3245 if(psound.clients.size() == 0)
3246 m_playing_sounds.erase(i++);
3249 else if(command == TOSERVER_NODEMETA_FIELDS)
3251 std::string datastring((char*)&data[2], datasize-2);
3252 std::istringstream is(datastring, std::ios_base::binary);
3254 v3s16 p = readV3S16(is);
3255 std::string formname = deSerializeString(is);
3256 int num = readU16(is);
3257 std::map<std::string, std::string> fields;
3258 for(int k=0; k<num; k++){
3259 std::string fieldname = deSerializeString(is);
3260 std::string fieldvalue = deSerializeLongString(is);
3261 fields[fieldname] = fieldvalue;
3264 // If something goes wrong, this player is to blame
3265 RollbackScopeActor rollback_scope(m_rollback,
3266 std::string("player:")+player->getName());
3268 // Check the target node for rollback data; leave others unnoticed
3269 RollbackNode rn_old(&m_env->getMap(), p, this);
3271 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3274 // Report rollback data
3275 RollbackNode rn_new(&m_env->getMap(), p, this);
3276 if(rollback() && rn_new != rn_old){
3277 RollbackAction action;
3278 action.setSetNode(p, rn_old, rn_new);
3279 rollback()->reportAction(action);
3282 else if(command == TOSERVER_INVENTORY_FIELDS)
3284 std::string datastring((char*)&data[2], datasize-2);
3285 std::istringstream is(datastring, std::ios_base::binary);
3287 std::string formname = deSerializeString(is);
3288 int num = readU16(is);
3289 std::map<std::string, std::string> fields;
3290 for(int k=0; k<num; k++){
3291 std::string fieldname = deSerializeString(is);
3292 std::string fieldvalue = deSerializeLongString(is);
3293 fields[fieldname] = fieldvalue;
3296 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3300 infostream<<"Server::ProcessData(): Ignoring "
3301 "unknown command "<<command<<std::endl;
3305 catch(SendFailedException &e)
3307 errorstream<<"Server::ProcessData(): SendFailedException: "
3313 void Server::onMapEditEvent(MapEditEvent *event)
3315 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3316 if(m_ignore_map_edit_events)
3318 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3320 MapEditEvent *e = event->clone();
3321 m_unsent_map_edit_queue.push_back(e);
3324 Inventory* Server::getInventory(const InventoryLocation &loc)
3327 case InventoryLocation::UNDEFINED:
3330 case InventoryLocation::CURRENT_PLAYER:
3333 case InventoryLocation::PLAYER:
3335 Player *player = m_env->getPlayer(loc.name.c_str());
3338 PlayerSAO *playersao = player->getPlayerSAO();
3341 return playersao->getInventory();
3344 case InventoryLocation::NODEMETA:
3346 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3349 return meta->getInventory();
3352 case InventoryLocation::DETACHED:
3354 if(m_detached_inventories.count(loc.name) == 0)
3356 return m_detached_inventories[loc.name];
3364 void Server::setInventoryModified(const InventoryLocation &loc)
3367 case InventoryLocation::UNDEFINED:
3370 case InventoryLocation::PLAYER:
3372 Player *player = m_env->getPlayer(loc.name.c_str());
3375 PlayerSAO *playersao = player->getPlayerSAO();
3378 playersao->m_inventory_not_sent = true;
3379 playersao->m_wielded_item_not_sent = true;
3382 case InventoryLocation::NODEMETA:
3384 v3s16 blockpos = getNodeBlockPos(loc.p);
3386 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3388 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3390 setBlockNotSent(blockpos);
3393 case InventoryLocation::DETACHED:
3395 sendDetachedInventoryToAll(loc.name);
3403 core::list<PlayerInfo> Server::getPlayerInfo()
3405 DSTACK(__FUNCTION_NAME);
3406 JMutexAutoLock envlock(m_env_mutex);
3407 JMutexAutoLock conlock(m_con_mutex);
3409 core::list<PlayerInfo> list;
3411 core::list<Player*> players = m_env->getPlayers();
3413 core::list<Player*>::Iterator i;
3414 for(i = players.begin();
3415 i != players.end(); i++)
3419 Player *player = *i;
3422 // Copy info from connection to info struct
3423 info.id = player->peer_id;
3424 info.address = m_con.GetPeerAddress(player->peer_id);
3425 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3427 catch(con::PeerNotFoundException &e)
3429 // Set dummy peer info
3431 info.address = Address(0,0,0,0,0);
3435 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3436 info.position = player->getPosition();
3438 list.push_back(info);
3445 void Server::peerAdded(con::Peer *peer)
3447 DSTACK(__FUNCTION_NAME);
3448 verbosestream<<"Server::peerAdded(): peer->id="
3449 <<peer->id<<std::endl;
3452 c.type = PEER_ADDED;
3453 c.peer_id = peer->id;
3455 m_peer_change_queue.push_back(c);
3458 void Server::deletingPeer(con::Peer *peer, bool timeout)
3460 DSTACK(__FUNCTION_NAME);
3461 verbosestream<<"Server::deletingPeer(): peer->id="
3462 <<peer->id<<", timeout="<<timeout<<std::endl;
3465 c.type = PEER_REMOVED;
3466 c.peer_id = peer->id;
3467 c.timeout = timeout;
3468 m_peer_change_queue.push_back(c);
3475 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3477 DSTACK(__FUNCTION_NAME);
3478 std::ostringstream os(std::ios_base::binary);
3480 writeU16(os, TOCLIENT_HP);
3484 std::string s = os.str();
3485 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3487 con.Send(peer_id, 0, data, true);
3490 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3491 const std::wstring &reason)
3493 DSTACK(__FUNCTION_NAME);
3494 std::ostringstream os(std::ios_base::binary);
3496 writeU16(os, TOCLIENT_ACCESS_DENIED);
3497 os<<serializeWideString(reason);
3500 std::string s = os.str();
3501 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3503 con.Send(peer_id, 0, data, true);
3506 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3507 bool set_camera_point_target, v3f camera_point_target)
3509 DSTACK(__FUNCTION_NAME);
3510 std::ostringstream os(std::ios_base::binary);
3512 writeU16(os, TOCLIENT_DEATHSCREEN);
3513 writeU8(os, set_camera_point_target);
3514 writeV3F1000(os, camera_point_target);
3517 std::string s = os.str();
3518 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3520 con.Send(peer_id, 0, data, true);
3523 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3524 IItemDefManager *itemdef)
3526 DSTACK(__FUNCTION_NAME);
3527 std::ostringstream os(std::ios_base::binary);
3531 u32 length of the next item
3532 zlib-compressed serialized ItemDefManager
3534 writeU16(os, TOCLIENT_ITEMDEF);
3535 std::ostringstream tmp_os(std::ios::binary);
3536 itemdef->serialize(tmp_os);
3537 std::ostringstream tmp_os2(std::ios::binary);
3538 compressZlib(tmp_os.str(), tmp_os2);
3539 os<<serializeLongString(tmp_os2.str());
3542 std::string s = os.str();
3543 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3544 <<"): size="<<s.size()<<std::endl;
3545 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3547 con.Send(peer_id, 0, data, true);
3550 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3551 INodeDefManager *nodedef, u16 protocol_version)
3553 DSTACK(__FUNCTION_NAME);
3554 std::ostringstream os(std::ios_base::binary);
3558 u32 length of the next item
3559 zlib-compressed serialized NodeDefManager
3561 writeU16(os, TOCLIENT_NODEDEF);
3562 std::ostringstream tmp_os(std::ios::binary);
3563 nodedef->serialize(tmp_os, protocol_version);
3564 std::ostringstream tmp_os2(std::ios::binary);
3565 compressZlib(tmp_os.str(), tmp_os2);
3566 os<<serializeLongString(tmp_os2.str());
3569 std::string s = os.str();
3570 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3571 <<"): size="<<s.size()<<std::endl;
3572 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3574 con.Send(peer_id, 0, data, true);
3578 Non-static send methods
3581 void Server::SendInventory(u16 peer_id)
3583 DSTACK(__FUNCTION_NAME);
3585 PlayerSAO *playersao = getPlayerSAO(peer_id);
3588 playersao->m_inventory_not_sent = false;
3594 std::ostringstream os;
3595 playersao->getInventory()->serialize(os);
3597 std::string s = os.str();
3599 SharedBuffer<u8> data(s.size()+2);
3600 writeU16(&data[0], TOCLIENT_INVENTORY);
3601 memcpy(&data[2], s.c_str(), s.size());
3604 m_con.Send(peer_id, 0, data, true);
3607 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3609 DSTACK(__FUNCTION_NAME);
3611 std::ostringstream os(std::ios_base::binary);
3615 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3616 os.write((char*)buf, 2);
3619 writeU16(buf, message.size());
3620 os.write((char*)buf, 2);
3623 for(u32 i=0; i<message.size(); i++)
3627 os.write((char*)buf, 2);
3631 std::string s = os.str();
3632 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3634 m_con.Send(peer_id, 0, data, true);
3637 void Server::BroadcastChatMessage(const std::wstring &message)
3639 for(core::map<u16, RemoteClient*>::Iterator
3640 i = m_clients.getIterator();
3641 i.atEnd() == false; i++)
3643 // Get client and check that it is valid
3644 RemoteClient *client = i.getNode()->getValue();
3645 assert(client->peer_id == i.getNode()->getKey());
3646 if(client->serialization_version == SER_FMT_VER_INVALID)
3649 SendChatMessage(client->peer_id, message);
3653 void Server::SendPlayerHP(u16 peer_id)
3655 DSTACK(__FUNCTION_NAME);
3656 PlayerSAO *playersao = getPlayerSAO(peer_id);
3658 playersao->m_hp_not_sent = false;
3659 SendHP(m_con, peer_id, playersao->getHP());
3662 void Server::SendMovePlayer(u16 peer_id)
3664 DSTACK(__FUNCTION_NAME);
3665 Player *player = m_env->getPlayer(peer_id);
3668 std::ostringstream os(std::ios_base::binary);
3669 writeU16(os, TOCLIENT_MOVE_PLAYER);
3670 writeV3F1000(os, player->getPosition());
3671 writeF1000(os, player->getPitch());
3672 writeF1000(os, player->getYaw());
3675 v3f pos = player->getPosition();
3676 f32 pitch = player->getPitch();
3677 f32 yaw = player->getYaw();
3678 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3679 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3686 std::string s = os.str();
3687 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3689 m_con.Send(peer_id, 0, data, true);
3692 void Server::SendPlayerPrivileges(u16 peer_id)
3694 Player *player = m_env->getPlayer(peer_id);
3696 if(player->peer_id == PEER_ID_INEXISTENT)
3699 std::set<std::string> privs;
3700 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3702 std::ostringstream os(std::ios_base::binary);
3703 writeU16(os, TOCLIENT_PRIVILEGES);
3704 writeU16(os, privs.size());
3705 for(std::set<std::string>::const_iterator i = privs.begin();
3706 i != privs.end(); i++){
3707 os<<serializeString(*i);
3711 std::string s = os.str();
3712 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3714 m_con.Send(peer_id, 0, data, true);
3717 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3719 Player *player = m_env->getPlayer(peer_id);
3721 if(player->peer_id == PEER_ID_INEXISTENT)
3724 std::ostringstream os(std::ios_base::binary);
3725 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3726 os<<serializeLongString(player->inventory_formspec);
3729 std::string s = os.str();
3730 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3732 m_con.Send(peer_id, 0, data, true);
3735 s32 Server::playSound(const SimpleSoundSpec &spec,
3736 const ServerSoundParams ¶ms)
3738 // Find out initial position of sound
3739 bool pos_exists = false;
3740 v3f pos = params.getPos(m_env, &pos_exists);
3741 // If position is not found while it should be, cancel sound
3742 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3744 // Filter destination clients
3745 std::set<RemoteClient*> dst_clients;
3746 if(params.to_player != "")
3748 Player *player = m_env->getPlayer(params.to_player.c_str());
3750 infostream<<"Server::playSound: Player \""<<params.to_player
3751 <<"\" not found"<<std::endl;
3754 if(player->peer_id == PEER_ID_INEXISTENT){
3755 infostream<<"Server::playSound: Player \""<<params.to_player
3756 <<"\" not connected"<<std::endl;
3759 RemoteClient *client = getClient(player->peer_id);
3760 dst_clients.insert(client);
3764 for(core::map<u16, RemoteClient*>::Iterator
3765 i = m_clients.getIterator(); i.atEnd() == false; i++)
3767 RemoteClient *client = i.getNode()->getValue();
3768 Player *player = m_env->getPlayer(client->peer_id);
3772 if(player->getPosition().getDistanceFrom(pos) >
3773 params.max_hear_distance)
3776 dst_clients.insert(client);
3779 if(dst_clients.size() == 0)
3782 s32 id = m_next_sound_id++;
3783 // The sound will exist as a reference in m_playing_sounds
3784 m_playing_sounds[id] = ServerPlayingSound();
3785 ServerPlayingSound &psound = m_playing_sounds[id];
3786 psound.params = params;
3787 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3788 i != dst_clients.end(); i++)
3789 psound.clients.insert((*i)->peer_id);
3791 std::ostringstream os(std::ios_base::binary);
3792 writeU16(os, TOCLIENT_PLAY_SOUND);
3794 os<<serializeString(spec.name);
3795 writeF1000(os, spec.gain * params.gain);
3796 writeU8(os, params.type);
3797 writeV3F1000(os, pos);
3798 writeU16(os, params.object);
3799 writeU8(os, params.loop);
3801 std::string s = os.str();
3802 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3804 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3805 i != dst_clients.end(); i++){
3807 m_con.Send((*i)->peer_id, 0, data, true);
3811 void Server::stopSound(s32 handle)
3813 // Get sound reference
3814 std::map<s32, ServerPlayingSound>::iterator i =
3815 m_playing_sounds.find(handle);
3816 if(i == m_playing_sounds.end())
3818 ServerPlayingSound &psound = i->second;
3820 std::ostringstream os(std::ios_base::binary);
3821 writeU16(os, TOCLIENT_STOP_SOUND);
3822 writeS32(os, handle);
3824 std::string s = os.str();
3825 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3827 for(std::set<u16>::iterator i = psound.clients.begin();
3828 i != psound.clients.end(); i++){
3830 m_con.Send(*i, 0, data, true);
3832 // Remove sound reference
3833 m_playing_sounds.erase(i);
3836 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3837 core::list<u16> *far_players, float far_d_nodes)
3839 float maxd = far_d_nodes*BS;
3840 v3f p_f = intToFloat(p, BS);
3844 SharedBuffer<u8> reply(replysize);
3845 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3846 writeS16(&reply[2], p.X);
3847 writeS16(&reply[4], p.Y);
3848 writeS16(&reply[6], p.Z);
3850 for(core::map<u16, RemoteClient*>::Iterator
3851 i = m_clients.getIterator();
3852 i.atEnd() == false; i++)
3854 // Get client and check that it is valid
3855 RemoteClient *client = i.getNode()->getValue();
3856 assert(client->peer_id == i.getNode()->getKey());
3857 if(client->serialization_version == SER_FMT_VER_INVALID)
3860 // Don't send if it's the same one
3861 if(client->peer_id == ignore_id)
3867 Player *player = m_env->getPlayer(client->peer_id);
3870 // If player is far away, only set modified blocks not sent
3871 v3f player_pos = player->getPosition();
3872 if(player_pos.getDistanceFrom(p_f) > maxd)
3874 far_players->push_back(client->peer_id);
3881 m_con.Send(client->peer_id, 0, reply, true);
3885 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3886 core::list<u16> *far_players, float far_d_nodes)
3888 float maxd = far_d_nodes*BS;
3889 v3f p_f = intToFloat(p, BS);
3891 for(core::map<u16, RemoteClient*>::Iterator
3892 i = m_clients.getIterator();
3893 i.atEnd() == false; i++)
3895 // Get client and check that it is valid
3896 RemoteClient *client = i.getNode()->getValue();
3897 assert(client->peer_id == i.getNode()->getKey());
3898 if(client->serialization_version == SER_FMT_VER_INVALID)
3901 // Don't send if it's the same one
3902 if(client->peer_id == ignore_id)
3908 Player *player = m_env->getPlayer(client->peer_id);
3911 // If player is far away, only set modified blocks not sent
3912 v3f player_pos = player->getPosition();
3913 if(player_pos.getDistanceFrom(p_f) > maxd)
3915 far_players->push_back(client->peer_id);
3922 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3923 SharedBuffer<u8> reply(replysize);
3924 writeU16(&reply[0], TOCLIENT_ADDNODE);
3925 writeS16(&reply[2], p.X);
3926 writeS16(&reply[4], p.Y);
3927 writeS16(&reply[6], p.Z);
3928 n.serialize(&reply[8], client->serialization_version);
3931 m_con.Send(client->peer_id, 0, reply, true);
3935 void Server::setBlockNotSent(v3s16 p)
3937 for(core::map<u16, RemoteClient*>::Iterator
3938 i = m_clients.getIterator();
3939 i.atEnd()==false; i++)
3941 RemoteClient *client = i.getNode()->getValue();
3942 client->SetBlockNotSent(p);
3946 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3948 DSTACK(__FUNCTION_NAME);
3950 v3s16 p = block->getPos();
3954 bool completely_air = true;
3955 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3956 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3957 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3959 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3961 completely_air = false;
3962 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3967 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3969 infostream<<"[completely air] ";
3970 infostream<<std::endl;
3974 Create a packet with the block in the right format
3977 std::ostringstream os(std::ios_base::binary);
3978 block->serialize(os, ver, false);
3979 std::string s = os.str();
3980 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3982 u32 replysize = 8 + blockdata.getSize();
3983 SharedBuffer<u8> reply(replysize);
3984 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3985 writeS16(&reply[2], p.X);
3986 writeS16(&reply[4], p.Y);
3987 writeS16(&reply[6], p.Z);
3988 memcpy(&reply[8], *blockdata, blockdata.getSize());
3990 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3991 <<": \tpacket size: "<<replysize<<std::endl;*/
3996 m_con.Send(peer_id, 1, reply, true);
3999 void Server::SendBlocks(float dtime)
4001 DSTACK(__FUNCTION_NAME);
4003 JMutexAutoLock envlock(m_env_mutex);
4004 JMutexAutoLock conlock(m_con_mutex);
4006 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4008 core::array<PrioritySortedBlockTransfer> queue;
4010 s32 total_sending = 0;
4013 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4015 for(core::map<u16, RemoteClient*>::Iterator
4016 i = m_clients.getIterator();
4017 i.atEnd() == false; i++)
4019 RemoteClient *client = i.getNode()->getValue();
4020 assert(client->peer_id == i.getNode()->getKey());
4022 // If definitions and textures have not been sent, don't
4023 // send MapBlocks either
4024 if(!client->definitions_sent)
4027 total_sending += client->SendingCount();
4029 if(client->serialization_version == SER_FMT_VER_INVALID)
4032 client->GetNextBlocks(this, dtime, queue);
4037 // Lowest priority number comes first.
4038 // Lowest is most important.
4041 for(u32 i=0; i<queue.size(); i++)
4043 //TODO: Calculate limit dynamically
4044 if(total_sending >= g_settings->getS32
4045 ("max_simultaneous_block_sends_server_total"))
4048 PrioritySortedBlockTransfer q = queue[i];
4050 MapBlock *block = NULL;
4053 block = m_env->getMap().getBlockNoCreate(q.pos);
4055 catch(InvalidPositionException &e)
4060 RemoteClient *client = getClient(q.peer_id);
4062 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4064 client->SentBlock(q.pos);
4070 void Server::fillMediaCache()
4072 DSTACK(__FUNCTION_NAME);
4074 infostream<<"Server: Calculating media file checksums"<<std::endl;
4076 // Collect all media file paths
4077 std::list<std::string> paths;
4078 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4079 i != m_mods.end(); i++){
4080 const ModSpec &mod = *i;
4081 paths.push_back(mod.path + DIR_DELIM + "textures");
4082 paths.push_back(mod.path + DIR_DELIM + "sounds");
4083 paths.push_back(mod.path + DIR_DELIM + "media");
4084 paths.push_back(mod.path + DIR_DELIM + "models");
4086 std::string path_all = "textures";
4087 paths.push_back(path_all + DIR_DELIM + "all");
4089 // Collect media file information from paths into cache
4090 for(std::list<std::string>::iterator i = paths.begin();
4091 i != paths.end(); i++)
4093 std::string mediapath = *i;
4094 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4095 for(u32 j=0; j<dirlist.size(); j++){
4096 if(dirlist[j].dir) // Ignode dirs
4098 std::string filename = dirlist[j].name;
4099 // If name contains illegal characters, ignore the file
4100 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4101 infostream<<"Server: ignoring illegal file name: \""
4102 <<filename<<"\""<<std::endl;
4105 // If name is not in a supported format, ignore it
4106 const char *supported_ext[] = {
4107 ".png", ".jpg", ".bmp", ".tga",
4108 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4110 ".x", ".b3d", ".md2", ".obj",
4113 if(removeStringEnd(filename, supported_ext) == ""){
4114 infostream<<"Server: ignoring unsupported file extension: \""
4115 <<filename<<"\""<<std::endl;
4118 // Ok, attempt to load the file and add to cache
4119 std::string filepath = mediapath + DIR_DELIM + filename;
4121 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4122 if(fis.good() == false){
4123 errorstream<<"Server::fillMediaCache(): Could not open \""
4124 <<filename<<"\" for reading"<<std::endl;
4127 std::ostringstream tmp_os(std::ios_base::binary);
4131 fis.read(buf, 1024);
4132 std::streamsize len = fis.gcount();
4133 tmp_os.write(buf, len);
4142 errorstream<<"Server::fillMediaCache(): Failed to read \""
4143 <<filename<<"\""<<std::endl;
4146 if(tmp_os.str().length() == 0){
4147 errorstream<<"Server::fillMediaCache(): Empty file \""
4148 <<filepath<<"\""<<std::endl;
4153 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4155 unsigned char *digest = sha1.getDigest();
4156 std::string sha1_base64 = base64_encode(digest, 20);
4157 std::string sha1_hex = hex_encode((char*)digest, 20);
4161 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4162 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4167 struct SendableMediaAnnouncement
4170 std::string sha1_digest;
4172 SendableMediaAnnouncement(const std::string name_="",
4173 const std::string sha1_digest_=""):
4175 sha1_digest(sha1_digest_)
4179 void Server::sendMediaAnnouncement(u16 peer_id)
4181 DSTACK(__FUNCTION_NAME);
4183 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4186 core::list<SendableMediaAnnouncement> file_announcements;
4188 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4189 i != m_media.end(); i++){
4191 file_announcements.push_back(
4192 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4196 std::ostringstream os(std::ios_base::binary);
4204 u16 length of sha1_digest
4209 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4210 writeU16(os, file_announcements.size());
4212 for(core::list<SendableMediaAnnouncement>::Iterator
4213 j = file_announcements.begin();
4214 j != file_announcements.end(); j++){
4215 os<<serializeString(j->name);
4216 os<<serializeString(j->sha1_digest);
4220 std::string s = os.str();
4221 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4224 m_con.Send(peer_id, 0, data, true);
4228 struct SendableMedia
4234 SendableMedia(const std::string &name_="", const std::string path_="",
4235 const std::string &data_=""):
4242 void Server::sendRequestedMedia(u16 peer_id,
4243 const core::list<MediaRequest> &tosend)
4245 DSTACK(__FUNCTION_NAME);
4247 verbosestream<<"Server::sendRequestedMedia(): "
4248 <<"Sending files to client"<<std::endl;
4252 // Put 5kB in one bunch (this is not accurate)
4253 u32 bytes_per_bunch = 5000;
4255 core::array< core::list<SendableMedia> > file_bunches;
4256 file_bunches.push_back(core::list<SendableMedia>());
4258 u32 file_size_bunch_total = 0;
4260 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4261 i != tosend.end(); i++)
4263 if(m_media.find(i->name) == m_media.end()){
4264 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4265 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4269 //TODO get path + name
4270 std::string tpath = m_media[(*i).name].path;
4273 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4274 if(fis.good() == false){
4275 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4276 <<tpath<<"\" for reading"<<std::endl;
4279 std::ostringstream tmp_os(std::ios_base::binary);
4283 fis.read(buf, 1024);
4284 std::streamsize len = fis.gcount();
4285 tmp_os.write(buf, len);
4286 file_size_bunch_total += len;
4295 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4296 <<(*i).name<<"\""<<std::endl;
4299 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4300 <<tname<<"\""<<std::endl;*/
4302 file_bunches[file_bunches.size()-1].push_back(
4303 SendableMedia((*i).name, tpath, tmp_os.str()));
4305 // Start next bunch if got enough data
4306 if(file_size_bunch_total >= bytes_per_bunch){
4307 file_bunches.push_back(core::list<SendableMedia>());
4308 file_size_bunch_total = 0;
4313 /* Create and send packets */
4315 u32 num_bunches = file_bunches.size();
4316 for(u32 i=0; i<num_bunches; i++)
4318 std::ostringstream os(std::ios_base::binary);
4322 u16 total number of texture bunches
4323 u16 index of this bunch
4324 u32 number of files in this bunch
4333 writeU16(os, TOCLIENT_MEDIA);
4334 writeU16(os, num_bunches);
4336 writeU32(os, file_bunches[i].size());
4338 for(core::list<SendableMedia>::Iterator
4339 j = file_bunches[i].begin();
4340 j != file_bunches[i].end(); j++){
4341 os<<serializeString(j->name);
4342 os<<serializeLongString(j->data);
4346 std::string s = os.str();
4347 verbosestream<<"Server::sendRequestedMedia(): bunch "
4348 <<i<<"/"<<num_bunches
4349 <<" files="<<file_bunches[i].size()
4350 <<" size=" <<s.size()<<std::endl;
4351 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4353 m_con.Send(peer_id, 0, data, true);
4357 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4359 if(m_detached_inventories.count(name) == 0){
4360 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4363 Inventory *inv = m_detached_inventories[name];
4365 std::ostringstream os(std::ios_base::binary);
4366 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4367 os<<serializeString(name);
4371 std::string s = os.str();
4372 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4374 m_con.Send(peer_id, 0, data, true);
4377 void Server::sendDetachedInventoryToAll(const std::string &name)
4379 DSTACK(__FUNCTION_NAME);
4381 for(core::map<u16, RemoteClient*>::Iterator
4382 i = m_clients.getIterator();
4383 i.atEnd() == false; i++){
4384 RemoteClient *client = i.getNode()->getValue();
4385 sendDetachedInventory(name, client->peer_id);
4389 void Server::sendDetachedInventories(u16 peer_id)
4391 DSTACK(__FUNCTION_NAME);
4393 for(std::map<std::string, Inventory*>::iterator
4394 i = m_detached_inventories.begin();
4395 i != m_detached_inventories.end(); i++){
4396 const std::string &name = i->first;
4397 //Inventory *inv = i->second;
4398 sendDetachedInventory(name, peer_id);
4406 void Server::DiePlayer(u16 peer_id)
4408 DSTACK(__FUNCTION_NAME);
4410 PlayerSAO *playersao = getPlayerSAO(peer_id);
4413 infostream<<"Server::DiePlayer(): Player "
4414 <<playersao->getPlayer()->getName()
4415 <<" dies"<<std::endl;
4417 playersao->setHP(0);
4419 // Trigger scripted stuff
4420 scriptapi_on_dieplayer(m_lua, playersao);
4422 SendPlayerHP(peer_id);
4423 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4426 void Server::RespawnPlayer(u16 peer_id)
4428 DSTACK(__FUNCTION_NAME);
4430 PlayerSAO *playersao = getPlayerSAO(peer_id);
4433 infostream<<"Server::RespawnPlayer(): Player "
4434 <<playersao->getPlayer()->getName()
4435 <<" respawns"<<std::endl;
4437 playersao->setHP(PLAYER_MAX_HP);
4439 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4441 v3f pos = findSpawnPos(m_env->getServerMap());
4442 playersao->setPos(pos);
4446 void Server::UpdateCrafting(u16 peer_id)
4448 DSTACK(__FUNCTION_NAME);
4450 Player* player = m_env->getPlayer(peer_id);
4453 // Get a preview for crafting
4455 getCraftingResult(&player->inventory, preview, false, this);
4457 // Put the new preview in
4458 InventoryList *plist = player->inventory.getList("craftpreview");
4460 assert(plist->getSize() >= 1);
4461 plist->changeItem(0, preview);
4464 RemoteClient* Server::getClient(u16 peer_id)
4466 DSTACK(__FUNCTION_NAME);
4467 //JMutexAutoLock lock(m_con_mutex);
4468 core::map<u16, RemoteClient*>::Node *n;
4469 n = m_clients.find(peer_id);
4470 // A client should exist for all peers
4472 return n->getValue();
4475 std::wstring Server::getStatusString()
4477 std::wostringstream os(std::ios_base::binary);
4480 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4482 os<<L", uptime="<<m_uptime.get();
4483 // Information about clients
4484 core::map<u16, RemoteClient*>::Iterator i;
4487 for(i = m_clients.getIterator(), first = true;
4488 i.atEnd() == false; i++)
4490 // Get client and check that it is valid
4491 RemoteClient *client = i.getNode()->getValue();
4492 assert(client->peer_id == i.getNode()->getKey());
4493 if(client->serialization_version == SER_FMT_VER_INVALID)
4496 Player *player = m_env->getPlayer(client->peer_id);
4497 // Get name of player
4498 std::wstring name = L"unknown";
4500 name = narrow_to_wide(player->getName());
4501 // Add name to information string
4509 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4510 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4511 if(g_settings->get("motd") != "")
4512 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4516 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4518 std::set<std::string> privs;
4519 scriptapi_get_auth(m_lua, name, NULL, &privs);
4523 bool Server::checkPriv(const std::string &name, const std::string &priv)
4525 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4526 return (privs.count(priv) != 0);
4529 void Server::reportPrivsModified(const std::string &name)
4532 for(core::map<u16, RemoteClient*>::Iterator
4533 i = m_clients.getIterator();
4534 i.atEnd() == false; i++){
4535 RemoteClient *client = i.getNode()->getValue();
4536 Player *player = m_env->getPlayer(client->peer_id);
4537 reportPrivsModified(player->getName());
4540 Player *player = m_env->getPlayer(name.c_str());
4543 SendPlayerPrivileges(player->peer_id);
4544 PlayerSAO *sao = player->getPlayerSAO();
4547 sao->updatePrivileges(
4548 getPlayerEffectivePrivs(name),
4553 void Server::reportInventoryFormspecModified(const std::string &name)
4555 Player *player = m_env->getPlayer(name.c_str());
4558 SendPlayerInventoryFormspec(player->peer_id);
4561 // Saves g_settings to configpath given at initialization
4562 void Server::saveConfig()
4564 if(m_path_config != "")
4565 g_settings->updateConfigFile(m_path_config.c_str());
4568 void Server::notifyPlayer(const char *name, const std::wstring msg)
4570 Player *player = m_env->getPlayer(name);
4573 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4576 void Server::notifyPlayers(const std::wstring msg)
4578 BroadcastChatMessage(msg);
4581 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4585 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4586 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4589 Inventory* Server::createDetachedInventory(const std::string &name)
4591 if(m_detached_inventories.count(name) > 0){
4592 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4593 delete m_detached_inventories[name];
4595 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4597 Inventory *inv = new Inventory(m_itemdef);
4599 m_detached_inventories[name] = inv;
4600 sendDetachedInventoryToAll(name);
4607 BoolScopeSet(bool *dst, bool val):
4610 m_orig_state = *m_dst;
4615 *m_dst = m_orig_state;
4622 // actions: time-reversed list
4623 // Return value: success/failure
4624 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4625 std::list<std::string> *log)
4627 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4628 ServerMap *map = (ServerMap*)(&m_env->getMap());
4629 // Disable rollback report sink while reverting
4630 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4632 // Fail if no actions to handle
4633 if(actions.empty()){
4634 log->push_back("Nothing to do.");
4641 for(std::list<RollbackAction>::const_iterator
4642 i = actions.begin();
4643 i != actions.end(); i++)
4645 const RollbackAction &action = *i;
4647 bool success = action.applyRevert(map, this, this);
4650 std::ostringstream os;
4651 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4652 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4654 log->push_back(os.str());
4656 std::ostringstream os;
4657 os<<"Succesfully reverted step ("<<num_tried<<") "<<action.toString();
4658 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4660 log->push_back(os.str());
4664 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4665 <<" failed"<<std::endl;
4667 // Call it done if less than half failed
4668 return num_failed <= num_tried/2;
4671 // IGameDef interface
4673 IItemDefManager* Server::getItemDefManager()
4677 INodeDefManager* Server::getNodeDefManager()
4681 ICraftDefManager* Server::getCraftDefManager()
4685 ITextureSource* Server::getTextureSource()
4689 u16 Server::allocateUnknownNodeId(const std::string &name)
4691 return m_nodedef->allocateDummy(name);
4693 ISoundManager* Server::getSoundManager()
4695 return &dummySoundManager;
4697 MtEventManager* Server::getEventManager()
4701 IRollbackReportSink* Server::getRollbackReportSink()
4703 if(!m_enable_rollback_recording)
4705 if(!m_rollback_sink_enabled)
4710 IWritableItemDefManager* Server::getWritableItemDefManager()
4714 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4718 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4723 const ModSpec* Server::getModSpec(const std::string &modname)
4725 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4726 i != m_mods.end(); i++){
4727 const ModSpec &mod = *i;
4728 if(mod.name == modname)
4733 void Server::getModNames(core::list<std::string> &modlist)
4735 for(core::list<ModSpec>::Iterator i = m_mods.begin(); i != m_mods.end(); i++)
4737 modlist.push_back((*i).name);
4740 std::string Server::getBuiltinLuaPath()
4742 return porting::path_share + DIR_DELIM + "builtin";
4745 v3f findSpawnPos(ServerMap &map)
4747 //return v3f(50,50,50)*BS;
4752 nodepos = v2s16(0,0);
4757 // Try to find a good place a few times
4758 for(s32 i=0; i<1000; i++)
4761 // We're going to try to throw the player to this position
4762 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4763 -range + (myrand()%(range*2)));
4764 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4765 // Get ground height at point (fallbacks to heightmap function)
4766 s16 groundheight = map.findGroundLevel(nodepos2d);
4767 // Don't go underwater
4768 if(groundheight < WATER_LEVEL)
4770 //infostream<<"-> Underwater"<<std::endl;
4773 // Don't go to high places
4774 if(groundheight > WATER_LEVEL + 4)
4776 //infostream<<"-> Underwater"<<std::endl;
4780 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4781 bool is_good = false;
4783 for(s32 i=0; i<10; i++){
4784 v3s16 blockpos = getNodeBlockPos(nodepos);
4785 map.emergeBlock(blockpos, true);
4786 MapNode n = map.getNodeNoEx(nodepos);
4787 if(n.getContent() == CONTENT_AIR){
4798 // Found a good place
4799 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4805 return intToFloat(nodepos, BS);
4808 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4810 RemotePlayer *player = NULL;
4811 bool newplayer = false;
4814 Try to get an existing player
4816 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4818 // If player is already connected, cancel
4819 if(player != NULL && player->peer_id != 0)
4821 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4826 If player with the wanted peer_id already exists, cancel.
4828 if(m_env->getPlayer(peer_id) != NULL)
4830 infostream<<"emergePlayer(): Player with wrong name but same"
4831 " peer_id already exists"<<std::endl;
4836 Create a new player if it doesn't exist yet
4841 player = new RemotePlayer(this);
4842 player->updateName(name);
4844 /* Set player position */
4845 infostream<<"Server: Finding spawn place for player \""
4846 <<name<<"\""<<std::endl;
4847 v3f pos = findSpawnPos(m_env->getServerMap());
4848 player->setPosition(pos);
4850 /* Add player to environment */
4851 m_env->addPlayer(player);
4855 Create a new player active object
4857 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4858 getPlayerEffectivePrivs(player->getName()),
4861 /* Add object to environment */
4862 m_env->addActiveObject(playersao);
4866 scriptapi_on_newplayer(m_lua, playersao);
4868 scriptapi_on_joinplayer(m_lua, playersao);
4873 void Server::handlePeerChange(PeerChange &c)
4875 JMutexAutoLock envlock(m_env_mutex);
4876 JMutexAutoLock conlock(m_con_mutex);
4878 if(c.type == PEER_ADDED)
4885 core::map<u16, RemoteClient*>::Node *n;
4886 n = m_clients.find(c.peer_id);
4887 // The client shouldn't already exist
4891 RemoteClient *client = new RemoteClient();
4892 client->peer_id = c.peer_id;
4893 m_clients.insert(client->peer_id, client);
4896 else if(c.type == PEER_REMOVED)
4903 core::map<u16, RemoteClient*>::Node *n;
4904 n = m_clients.find(c.peer_id);
4905 // The client should exist
4909 Mark objects to be not known by the client
4911 RemoteClient *client = n->getValue();
4913 for(core::map<u16, bool>::Iterator
4914 i = client->m_known_objects.getIterator();
4915 i.atEnd()==false; i++)
4918 u16 id = i.getNode()->getKey();
4919 ServerActiveObject* obj = m_env->getActiveObject(id);
4921 if(obj && obj->m_known_by_count > 0)
4922 obj->m_known_by_count--;
4926 Clear references to playing sounds
4928 for(std::map<s32, ServerPlayingSound>::iterator
4929 i = m_playing_sounds.begin();
4930 i != m_playing_sounds.end();)
4932 ServerPlayingSound &psound = i->second;
4933 psound.clients.erase(c.peer_id);
4934 if(psound.clients.size() == 0)
4935 m_playing_sounds.erase(i++);
4940 Player *player = m_env->getPlayer(c.peer_id);
4942 // Collect information about leaving in chat
4943 std::wstring message;
4947 std::wstring name = narrow_to_wide(player->getName());
4950 message += L" left the game.";
4952 message += L" (timed out)";
4956 /* Run scripts and remove from environment */
4960 PlayerSAO *playersao = player->getPlayerSAO();
4963 scriptapi_on_leaveplayer(m_lua, playersao);
4965 playersao->disconnected();
4975 std::ostringstream os(std::ios_base::binary);
4976 for(core::map<u16, RemoteClient*>::Iterator
4977 i = m_clients.getIterator();
4978 i.atEnd() == false; i++)
4980 RemoteClient *client = i.getNode()->getValue();
4981 assert(client->peer_id == i.getNode()->getKey());
4982 if(client->serialization_version == SER_FMT_VER_INVALID)
4985 Player *player = m_env->getPlayer(client->peer_id);
4988 // Get name of player
4989 os<<player->getName()<<" ";
4992 actionstream<<player->getName()<<" "
4993 <<(c.timeout?"times out.":"leaves game.")
4994 <<" List of players: "
4995 <<os.str()<<std::endl;
5000 delete m_clients[c.peer_id];
5001 m_clients.remove(c.peer_id);
5003 // Send player info to all remaining clients
5004 //SendPlayerInfos();
5006 // Send leave chat message to all remaining clients
5007 if(message.length() != 0)
5008 BroadcastChatMessage(message);
5017 void Server::handlePeerChanges()
5019 while(m_peer_change_queue.size() > 0)
5021 PeerChange c = m_peer_change_queue.pop_front();
5023 verbosestream<<"Server: Handling peer change: "
5024 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5027 handlePeerChange(c);
5031 void dedicated_server_loop(Server &server, bool &kill)
5033 DSTACK(__FUNCTION_NAME);
5035 verbosestream<<"dedicated_server_loop()"<<std::endl;
5037 IntervalLimiter m_profiler_interval;
5041 float steplen = g_settings->getFloat("dedicated_server_step");
5042 // This is kind of a hack but can be done like this
5043 // because server.step() is very light
5045 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5046 sleep_ms((int)(steplen*1000.0));
5048 server.step(steplen);
5050 if(server.getShutdownRequested() || kill)
5052 infostream<<"Dedicated server quitting"<<std::endl;
5059 float profiler_print_interval =
5060 g_settings->getFloat("profiler_print_interval");
5061 if(profiler_print_interval != 0)
5063 if(m_profiler_interval.step(steplen, profiler_print_interval))
5065 infostream<<"Profiler:"<<std::endl;
5066 g_profiler->print(infostream);
5067 g_profiler->clear();