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);
1118 JMutexAutoLock conlock(m_con_mutex);
1121 Execute script shutdown hooks
1123 scriptapi_on_shutdown(m_lua);
1127 JMutexAutoLock envlock(m_env_mutex);
1132 infostream<<"Server: Saving players"<<std::endl;
1133 m_env->serializePlayers(m_path_world);
1136 Save environment metadata
1138 infostream<<"Server: Saving environment metadata"<<std::endl;
1139 m_env->saveMeta(m_path_world);
1151 JMutexAutoLock clientslock(m_con_mutex);
1153 for(core::map<u16, RemoteClient*>::Iterator
1154 i = m_clients.getIterator();
1155 i.atEnd() == false; i++)
1158 delete i.getNode()->getValue();
1162 // Delete things in the reverse order of creation
1170 // Deinitialize scripting
1171 infostream<<"Server: Deinitializing scripting"<<std::endl;
1172 script_deinit(m_lua);
1174 // Delete detached inventories
1176 for(std::map<std::string, Inventory*>::iterator
1177 i = m_detached_inventories.begin();
1178 i != m_detached_inventories.end(); i++){
1184 void Server::start(unsigned short port)
1186 DSTACK(__FUNCTION_NAME);
1187 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1189 // Stop thread if already running
1192 // Initialize connection
1193 m_con.SetTimeoutMs(30);
1197 m_thread.setRun(true);
1200 // ASCII art for the win!
1202 <<" .__ __ __ "<<std::endl
1203 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1204 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1205 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1206 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1207 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1208 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1209 actionstream<<"Server for gameid=\""<<m_gamespec.id
1210 <<"\" listening on port "<<port<<"."<<std::endl;
1215 DSTACK(__FUNCTION_NAME);
1217 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1219 // Stop threads (set run=false first so both start stopping)
1220 m_thread.setRun(false);
1221 m_emergethread.setRun(false);
1223 m_emergethread.stop();
1225 infostream<<"Server: Threads stopped"<<std::endl;
1228 void Server::step(float dtime)
1230 DSTACK(__FUNCTION_NAME);
1235 JMutexAutoLock lock(m_step_dtime_mutex);
1236 m_step_dtime += dtime;
1238 // Throw if fatal error occurred in thread
1239 std::string async_err = m_async_fatal_error.get();
1240 if(async_err != ""){
1241 throw ServerError(async_err);
1245 void Server::AsyncRunStep()
1247 DSTACK(__FUNCTION_NAME);
1249 g_profiler->add("Server::AsyncRunStep (num)", 1);
1253 JMutexAutoLock lock1(m_step_dtime_mutex);
1254 dtime = m_step_dtime;
1258 // Send blocks to clients
1265 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1267 //infostream<<"Server steps "<<dtime<<std::endl;
1268 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1271 JMutexAutoLock lock1(m_step_dtime_mutex);
1272 m_step_dtime -= dtime;
1279 m_uptime.set(m_uptime.get() + dtime);
1283 // Process connection's timeouts
1284 JMutexAutoLock lock2(m_con_mutex);
1285 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1286 m_con.RunTimeouts(dtime);
1290 // This has to be called so that the client list gets synced
1291 // with the peer list of the connection
1292 handlePeerChanges();
1296 Update time of day and overall game time
1299 JMutexAutoLock envlock(m_env_mutex);
1301 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1304 Send to clients at constant intervals
1307 m_time_of_day_send_timer -= dtime;
1308 if(m_time_of_day_send_timer < 0.0)
1310 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1312 //JMutexAutoLock envlock(m_env_mutex);
1313 JMutexAutoLock conlock(m_con_mutex);
1315 for(core::map<u16, RemoteClient*>::Iterator
1316 i = m_clients.getIterator();
1317 i.atEnd() == false; i++)
1319 RemoteClient *client = i.getNode()->getValue();
1320 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1321 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1323 m_con.Send(client->peer_id, 0, data, true);
1329 JMutexAutoLock lock(m_env_mutex);
1331 ScopeProfiler sp(g_profiler, "SEnv step");
1332 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1336 const float map_timer_and_unload_dtime = 2.92;
1337 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1339 JMutexAutoLock lock(m_env_mutex);
1340 // Run Map's timers and unload unused data
1341 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1342 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1343 g_settings->getFloat("server_unload_unused_data_timeout"));
1354 JMutexAutoLock lock(m_env_mutex);
1355 JMutexAutoLock lock2(m_con_mutex);
1357 ScopeProfiler sp(g_profiler, "Server: handle players");
1359 for(core::map<u16, RemoteClient*>::Iterator
1360 i = m_clients.getIterator();
1361 i.atEnd() == false; i++)
1363 RemoteClient *client = i.getNode()->getValue();
1364 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1365 if(playersao == NULL)
1369 Handle player HPs (die if hp=0)
1371 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
1372 DiePlayer(client->peer_id);
1375 Send player inventories and HPs if necessary
1377 if(playersao->m_moved){
1378 SendMovePlayer(client->peer_id);
1379 playersao->m_moved = false;
1381 if(playersao->m_inventory_not_sent){
1382 UpdateCrafting(client->peer_id);
1383 SendInventory(client->peer_id);
1385 if(playersao->m_hp_not_sent){
1386 SendPlayerHP(client->peer_id);
1391 /* Transform liquids */
1392 m_liquid_transform_timer += dtime;
1393 if(m_liquid_transform_timer >= 1.00)
1395 m_liquid_transform_timer -= 1.00;
1397 JMutexAutoLock lock(m_env_mutex);
1399 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1401 core::map<v3s16, MapBlock*> modified_blocks;
1402 m_env->getMap().transformLiquids(modified_blocks);
1407 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1408 ServerMap &map = ((ServerMap&)m_env->getMap());
1409 map.updateLighting(modified_blocks, lighting_modified_blocks);
1411 // Add blocks modified by lighting to modified_blocks
1412 for(core::map<v3s16, MapBlock*>::Iterator
1413 i = lighting_modified_blocks.getIterator();
1414 i.atEnd() == false; i++)
1416 MapBlock *block = i.getNode()->getValue();
1417 modified_blocks.insert(block->getPos(), block);
1421 Set the modified blocks unsent for all the clients
1424 JMutexAutoLock lock2(m_con_mutex);
1426 for(core::map<u16, RemoteClient*>::Iterator
1427 i = m_clients.getIterator();
1428 i.atEnd() == false; i++)
1430 RemoteClient *client = i.getNode()->getValue();
1432 if(modified_blocks.size() > 0)
1434 // Remove block from sent history
1435 client->SetBlocksNotSent(modified_blocks);
1440 // Periodically print some info
1442 float &counter = m_print_info_timer;
1448 JMutexAutoLock lock2(m_con_mutex);
1450 if(m_clients.size() != 0)
1451 infostream<<"Players:"<<std::endl;
1452 for(core::map<u16, RemoteClient*>::Iterator
1453 i = m_clients.getIterator();
1454 i.atEnd() == false; i++)
1456 //u16 peer_id = i.getNode()->getKey();
1457 RemoteClient *client = i.getNode()->getValue();
1458 Player *player = m_env->getPlayer(client->peer_id);
1461 infostream<<"* "<<player->getName()<<"\t";
1462 client->PrintInfo(infostream);
1467 //if(g_settings->getBool("enable_experimental"))
1471 Check added and deleted active objects
1474 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1475 JMutexAutoLock envlock(m_env_mutex);
1476 JMutexAutoLock conlock(m_con_mutex);
1478 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1480 // Radius inside which objects are active
1481 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1482 radius *= MAP_BLOCKSIZE;
1484 for(core::map<u16, RemoteClient*>::Iterator
1485 i = m_clients.getIterator();
1486 i.atEnd() == false; i++)
1488 RemoteClient *client = i.getNode()->getValue();
1490 // If definitions and textures have not been sent, don't
1491 // send objects either
1492 if(!client->definitions_sent)
1495 Player *player = m_env->getPlayer(client->peer_id);
1498 // This can happen if the client timeouts somehow
1499 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1501 <<" has no associated player"<<std::endl;*/
1504 v3s16 pos = floatToInt(player->getPosition(), BS);
1506 core::map<u16, bool> removed_objects;
1507 core::map<u16, bool> added_objects;
1508 m_env->getRemovedActiveObjects(pos, radius,
1509 client->m_known_objects, removed_objects);
1510 m_env->getAddedActiveObjects(pos, radius,
1511 client->m_known_objects, added_objects);
1513 // Ignore if nothing happened
1514 if(removed_objects.size() == 0 && added_objects.size() == 0)
1516 //infostream<<"active objects: none changed"<<std::endl;
1520 std::string data_buffer;
1524 // Handle removed objects
1525 writeU16((u8*)buf, removed_objects.size());
1526 data_buffer.append(buf, 2);
1527 for(core::map<u16, bool>::Iterator
1528 i = removed_objects.getIterator();
1529 i.atEnd()==false; i++)
1532 u16 id = i.getNode()->getKey();
1533 ServerActiveObject* obj = m_env->getActiveObject(id);
1535 // Add to data buffer for sending
1536 writeU16((u8*)buf, i.getNode()->getKey());
1537 data_buffer.append(buf, 2);
1539 // Remove from known objects
1540 client->m_known_objects.remove(i.getNode()->getKey());
1542 if(obj && obj->m_known_by_count > 0)
1543 obj->m_known_by_count--;
1546 // Handle added objects
1547 writeU16((u8*)buf, added_objects.size());
1548 data_buffer.append(buf, 2);
1549 for(core::map<u16, bool>::Iterator
1550 i = added_objects.getIterator();
1551 i.atEnd()==false; i++)
1554 u16 id = i.getNode()->getKey();
1555 ServerActiveObject* obj = m_env->getActiveObject(id);
1558 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1560 infostream<<"WARNING: "<<__FUNCTION_NAME
1561 <<": NULL object"<<std::endl;
1563 type = obj->getSendType();
1565 // Add to data buffer for sending
1566 writeU16((u8*)buf, id);
1567 data_buffer.append(buf, 2);
1568 writeU8((u8*)buf, type);
1569 data_buffer.append(buf, 1);
1572 data_buffer.append(serializeLongString(
1573 obj->getClientInitializationData(client->net_proto_version)));
1575 data_buffer.append(serializeLongString(""));
1577 // Add to known objects
1578 client->m_known_objects.insert(i.getNode()->getKey(), false);
1581 obj->m_known_by_count++;
1585 SharedBuffer<u8> reply(2 + data_buffer.size());
1586 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1587 memcpy((char*)&reply[2], data_buffer.c_str(),
1588 data_buffer.size());
1590 m_con.Send(client->peer_id, 0, reply, true);
1592 verbosestream<<"Server: Sent object remove/add: "
1593 <<removed_objects.size()<<" removed, "
1594 <<added_objects.size()<<" added, "
1595 <<"packet size is "<<reply.getSize()<<std::endl;
1600 Collect a list of all the objects known by the clients
1601 and report it back to the environment.
1604 core::map<u16, bool> all_known_objects;
1606 for(core::map<u16, RemoteClient*>::Iterator
1607 i = m_clients.getIterator();
1608 i.atEnd() == false; i++)
1610 RemoteClient *client = i.getNode()->getValue();
1611 // Go through all known objects of client
1612 for(core::map<u16, bool>::Iterator
1613 i = client->m_known_objects.getIterator();
1614 i.atEnd()==false; i++)
1616 u16 id = i.getNode()->getKey();
1617 all_known_objects[id] = true;
1621 m_env->setKnownActiveObjects(whatever);
1627 Send object messages
1630 JMutexAutoLock envlock(m_env_mutex);
1631 JMutexAutoLock conlock(m_con_mutex);
1633 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1636 // Value = data sent by object
1637 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1639 // Get active object messages from environment
1642 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1646 core::list<ActiveObjectMessage>* message_list = NULL;
1647 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1648 n = buffered_messages.find(aom.id);
1651 message_list = new core::list<ActiveObjectMessage>;
1652 buffered_messages.insert(aom.id, message_list);
1656 message_list = n->getValue();
1658 message_list->push_back(aom);
1661 // Route data to every client
1662 for(core::map<u16, RemoteClient*>::Iterator
1663 i = m_clients.getIterator();
1664 i.atEnd()==false; i++)
1666 RemoteClient *client = i.getNode()->getValue();
1667 std::string reliable_data;
1668 std::string unreliable_data;
1669 // Go through all objects in message buffer
1670 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1671 j = buffered_messages.getIterator();
1672 j.atEnd()==false; j++)
1674 // If object is not known by client, skip it
1675 u16 id = j.getNode()->getKey();
1676 if(client->m_known_objects.find(id) == NULL)
1678 // Get message list of object
1679 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1680 // Go through every message
1681 for(core::list<ActiveObjectMessage>::Iterator
1682 k = list->begin(); k != list->end(); k++)
1684 // Compose the full new data with header
1685 ActiveObjectMessage aom = *k;
1686 std::string new_data;
1689 writeU16((u8*)&buf[0], aom.id);
1690 new_data.append(buf, 2);
1692 new_data += serializeString(aom.datastring);
1693 // Add data to buffer
1695 reliable_data += new_data;
1697 unreliable_data += new_data;
1701 reliable_data and unreliable_data are now ready.
1704 if(reliable_data.size() > 0)
1706 SharedBuffer<u8> reply(2 + reliable_data.size());
1707 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1708 memcpy((char*)&reply[2], reliable_data.c_str(),
1709 reliable_data.size());
1711 m_con.Send(client->peer_id, 0, reply, true);
1713 if(unreliable_data.size() > 0)
1715 SharedBuffer<u8> reply(2 + unreliable_data.size());
1716 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1717 memcpy((char*)&reply[2], unreliable_data.c_str(),
1718 unreliable_data.size());
1719 // Send as unreliable
1720 m_con.Send(client->peer_id, 0, reply, false);
1723 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1725 infostream<<"Server: Size of object message data: "
1726 <<"reliable: "<<reliable_data.size()
1727 <<", unreliable: "<<unreliable_data.size()
1732 // Clear buffered_messages
1733 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1734 i = buffered_messages.getIterator();
1735 i.atEnd()==false; i++)
1737 delete i.getNode()->getValue();
1741 } // enable_experimental
1744 Send queued-for-sending map edit events.
1747 // We will be accessing the environment and the connection
1748 JMutexAutoLock lock(m_env_mutex);
1749 JMutexAutoLock conlock(m_con_mutex);
1751 // Don't send too many at a time
1754 // Single change sending is disabled if queue size is not small
1755 bool disable_single_change_sending = false;
1756 if(m_unsent_map_edit_queue.size() >= 4)
1757 disable_single_change_sending = true;
1759 int event_count = m_unsent_map_edit_queue.size();
1761 // We'll log the amount of each
1764 while(m_unsent_map_edit_queue.size() != 0)
1766 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1768 // Players far away from the change are stored here.
1769 // Instead of sending the changes, MapBlocks are set not sent
1771 core::list<u16> far_players;
1773 if(event->type == MEET_ADDNODE)
1775 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1776 prof.add("MEET_ADDNODE", 1);
1777 if(disable_single_change_sending)
1778 sendAddNode(event->p, event->n, event->already_known_by_peer,
1781 sendAddNode(event->p, event->n, event->already_known_by_peer,
1784 else if(event->type == MEET_REMOVENODE)
1786 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1787 prof.add("MEET_REMOVENODE", 1);
1788 if(disable_single_change_sending)
1789 sendRemoveNode(event->p, event->already_known_by_peer,
1792 sendRemoveNode(event->p, event->already_known_by_peer,
1795 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1797 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1798 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1799 setBlockNotSent(event->p);
1801 else if(event->type == MEET_OTHER)
1803 infostream<<"Server: MEET_OTHER"<<std::endl;
1804 prof.add("MEET_OTHER", 1);
1805 for(core::map<v3s16, bool>::Iterator
1806 i = event->modified_blocks.getIterator();
1807 i.atEnd()==false; i++)
1809 v3s16 p = i.getNode()->getKey();
1815 prof.add("unknown", 1);
1816 infostream<<"WARNING: Server: Unknown MapEditEvent "
1817 <<((u32)event->type)<<std::endl;
1821 Set blocks not sent to far players
1823 if(far_players.size() > 0)
1825 // Convert list format to that wanted by SetBlocksNotSent
1826 core::map<v3s16, MapBlock*> modified_blocks2;
1827 for(core::map<v3s16, bool>::Iterator
1828 i = event->modified_blocks.getIterator();
1829 i.atEnd()==false; i++)
1831 v3s16 p = i.getNode()->getKey();
1832 modified_blocks2.insert(p,
1833 m_env->getMap().getBlockNoCreateNoEx(p));
1835 // Set blocks not sent
1836 for(core::list<u16>::Iterator
1837 i = far_players.begin();
1838 i != far_players.end(); i++)
1841 RemoteClient *client = getClient(peer_id);
1844 client->SetBlocksNotSent(modified_blocks2);
1850 /*// Don't send too many at a time
1852 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1856 if(event_count >= 5){
1857 infostream<<"Server: MapEditEvents:"<<std::endl;
1858 prof.print(infostream);
1859 } else if(event_count != 0){
1860 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1861 prof.print(verbosestream);
1867 Trigger emergethread (it somehow gets to a non-triggered but
1868 bysy state sometimes)
1871 float &counter = m_emergethread_trigger_timer;
1877 m_emergethread.trigger();
1879 // Update m_enable_rollback_recording here too
1880 m_enable_rollback_recording =
1881 g_settings->getBool("enable_rollback_recording");
1885 // Save map, players and auth stuff
1887 float &counter = m_savemap_timer;
1889 if(counter >= g_settings->getFloat("server_map_save_interval"))
1892 JMutexAutoLock lock(m_env_mutex);
1894 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1897 if(m_banmanager.isModified())
1898 m_banmanager.save();
1900 // Save changed parts of map
1901 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1904 m_env->serializePlayers(m_path_world);
1906 // Save environment metadata
1907 m_env->saveMeta(m_path_world);
1912 void Server::Receive()
1914 DSTACK(__FUNCTION_NAME);
1915 SharedBuffer<u8> data;
1920 JMutexAutoLock conlock(m_con_mutex);
1921 datasize = m_con.Receive(peer_id, data);
1924 // This has to be called so that the client list gets synced
1925 // with the peer list of the connection
1926 handlePeerChanges();
1928 ProcessData(*data, datasize, peer_id);
1930 catch(con::InvalidIncomingDataException &e)
1932 infostream<<"Server::Receive(): "
1933 "InvalidIncomingDataException: what()="
1934 <<e.what()<<std::endl;
1936 catch(con::PeerNotFoundException &e)
1938 //NOTE: This is not needed anymore
1940 // The peer has been disconnected.
1941 // Find the associated player and remove it.
1943 /*JMutexAutoLock envlock(m_env_mutex);
1945 infostream<<"ServerThread: peer_id="<<peer_id
1946 <<" has apparently closed connection. "
1947 <<"Removing player."<<std::endl;
1949 m_env->removePlayer(peer_id);*/
1953 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1955 DSTACK(__FUNCTION_NAME);
1956 // Environment is locked first.
1957 JMutexAutoLock envlock(m_env_mutex);
1958 JMutexAutoLock conlock(m_con_mutex);
1960 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1963 Address address = m_con.GetPeerAddress(peer_id);
1964 std::string addr_s = address.serializeString();
1966 // drop player if is ip is banned
1967 if(m_banmanager.isIpBanned(addr_s)){
1968 infostream<<"Server: A banned client tried to connect from "
1969 <<addr_s<<"; banned name was "
1970 <<m_banmanager.getBanName(addr_s)<<std::endl;
1971 // This actually doesn't seem to transfer to the client
1972 SendAccessDenied(m_con, peer_id,
1973 L"Your ip is banned. Banned name was "
1974 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1975 m_con.DeletePeer(peer_id);
1979 catch(con::PeerNotFoundException &e)
1981 infostream<<"Server::ProcessData(): Cancelling: peer "
1982 <<peer_id<<" not found"<<std::endl;
1986 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1988 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1996 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1998 if(command == TOSERVER_INIT)
2000 // [0] u16 TOSERVER_INIT
2001 // [2] u8 SER_FMT_VER_HIGHEST
2002 // [3] u8[20] player_name
2003 // [23] u8[28] password <--- can be sent without this, from old versions
2005 if(datasize < 2+1+PLAYERNAME_SIZE)
2008 verbosestream<<"Server: Got TOSERVER_INIT from "
2009 <<peer_id<<std::endl;
2011 // First byte after command is maximum supported
2012 // serialization version
2013 u8 client_max = data[2];
2014 u8 our_max = SER_FMT_VER_HIGHEST;
2015 // Use the highest version supported by both
2016 u8 deployed = core::min_(client_max, our_max);
2017 // If it's lower than the lowest supported, give up.
2018 if(deployed < SER_FMT_VER_LOWEST)
2019 deployed = SER_FMT_VER_INVALID;
2021 //peer->serialization_version = deployed;
2022 getClient(peer_id)->pending_serialization_version = deployed;
2024 if(deployed == SER_FMT_VER_INVALID)
2026 actionstream<<"Server: A mismatched client tried to connect from "
2027 <<addr_s<<std::endl;
2028 infostream<<"Server: Cannot negotiate "
2029 "serialization version with peer "
2030 <<peer_id<<std::endl;
2031 SendAccessDenied(m_con, peer_id, std::wstring(
2032 L"Your client's version is not supported.\n"
2033 L"Server version is ")
2034 + narrow_to_wide(VERSION_STRING) + L"."
2040 Read and check network protocol version
2043 u16 min_net_proto_version = 0;
2044 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2045 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2047 // Use same version as minimum and maximum if maximum version field
2048 // doesn't exist (backwards compatibility)
2049 u16 max_net_proto_version = min_net_proto_version;
2050 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
2051 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
2053 // Start with client's maximum version
2054 u16 net_proto_version = max_net_proto_version;
2056 // Figure out a working version if it is possible at all
2057 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
2058 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
2060 // If maximum is larger than our maximum, go with our maximum
2061 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2062 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
2063 // Else go with client's maximum
2065 net_proto_version = max_net_proto_version;
2068 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
2069 <<min_net_proto_version<<", max: "<<max_net_proto_version
2070 <<", chosen: "<<net_proto_version<<std::endl;
2072 getClient(peer_id)->net_proto_version = net_proto_version;
2074 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
2075 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2077 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
2079 SendAccessDenied(m_con, peer_id, std::wstring(
2080 L"Your client's version is not supported.\n"
2081 L"Server version is ")
2082 + narrow_to_wide(VERSION_STRING) + L",\n"
2083 + L"server's PROTOCOL_VERSION is "
2084 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
2086 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
2087 + L", client's PROTOCOL_VERSION is "
2088 + narrow_to_wide(itos(min_net_proto_version))
2090 + narrow_to_wide(itos(max_net_proto_version))
2095 if(g_settings->getBool("strict_protocol_version_checking"))
2097 if(net_proto_version != LATEST_PROTOCOL_VERSION)
2099 actionstream<<"Server: A mismatched (strict) client tried to "
2100 <<"connect from "<<addr_s<<std::endl;
2101 SendAccessDenied(m_con, peer_id, std::wstring(
2102 L"Your client's version is not supported.\n"
2103 L"Server version is ")
2104 + narrow_to_wide(VERSION_STRING) + L",\n"
2105 + L"server's PROTOCOL_VERSION (strict) is "
2106 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
2107 + L", client's PROTOCOL_VERSION is "
2108 + narrow_to_wide(itos(min_net_proto_version))
2110 + narrow_to_wide(itos(max_net_proto_version))
2121 char playername[PLAYERNAME_SIZE];
2122 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2124 playername[i] = data[3+i];
2126 playername[PLAYERNAME_SIZE-1] = 0;
2128 if(playername[0]=='\0')
2130 actionstream<<"Server: Player with an empty name "
2131 <<"tried to connect from "<<addr_s<<std::endl;
2132 SendAccessDenied(m_con, peer_id,
2137 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2139 actionstream<<"Server: Player with an invalid name "
2140 <<"tried to connect from "<<addr_s<<std::endl;
2141 SendAccessDenied(m_con, peer_id,
2142 L"Name contains unallowed characters");
2146 infostream<<"Server: New connection: \""<<playername<<"\" from "
2147 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2150 char given_password[PASSWORD_SIZE];
2151 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2153 // old version - assume blank password
2154 given_password[0] = 0;
2158 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2160 given_password[i] = data[23+i];
2162 given_password[PASSWORD_SIZE-1] = 0;
2165 if(!base64_is_valid(given_password)){
2166 infostream<<"Server: "<<playername
2167 <<" supplied invalid password hash"<<std::endl;
2168 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2172 std::string checkpwd; // Password hash to check against
2173 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2175 // If no authentication info exists for user, create it
2177 if(!isSingleplayer() &&
2178 g_settings->getBool("disallow_empty_password") &&
2179 std::string(given_password) == ""){
2180 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2181 L"disallowed. Set a password and try again.");
2184 std::wstring raw_default_password =
2185 narrow_to_wide(g_settings->get("default_password"));
2186 std::string initial_password =
2187 translatePassword(playername, raw_default_password);
2189 // If default_password is empty, allow any initial password
2190 if (raw_default_password.length() == 0)
2191 initial_password = given_password;
2193 scriptapi_create_auth(m_lua, playername, initial_password);
2196 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2199 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2203 if(given_password != checkpwd){
2204 infostream<<"Server: peer_id="<<peer_id
2205 <<": supplied invalid password for "
2206 <<playername<<std::endl;
2207 SendAccessDenied(m_con, peer_id, L"Invalid password");
2211 // Do not allow multiple players in simple singleplayer mode.
2212 // This isn't a perfect way to do it, but will suffice for now.
2213 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2214 infostream<<"Server: Not allowing another client to connect in"
2215 <<" simple singleplayer mode"<<std::endl;
2216 SendAccessDenied(m_con, peer_id,
2217 L"Running in simple singleplayer mode.");
2221 // Enforce user limit.
2222 // Don't enforce for users that have some admin right
2223 if(m_clients.size() >= g_settings->getU16("max_users") &&
2224 !checkPriv(playername, "server") &&
2225 !checkPriv(playername, "ban") &&
2226 !checkPriv(playername, "privs") &&
2227 !checkPriv(playername, "password") &&
2228 playername != g_settings->get("name"))
2230 actionstream<<"Server: "<<playername<<" tried to join, but there"
2231 <<" are already max_users="
2232 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2233 SendAccessDenied(m_con, peer_id, L"Too many users.");
2238 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2240 // If failed, cancel
2241 if(playersao == NULL)
2243 errorstream<<"Server: peer_id="<<peer_id
2244 <<": failed to emerge player"<<std::endl;
2249 Answer with a TOCLIENT_INIT
2252 SharedBuffer<u8> reply(2+1+6+8+4);
2253 writeU16(&reply[0], TOCLIENT_INIT);
2254 writeU8(&reply[2], deployed);
2255 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2256 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2257 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2260 m_con.Send(peer_id, 0, reply, true);
2264 Send complete position information
2266 SendMovePlayer(peer_id);
2271 if(command == TOSERVER_INIT2)
2273 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2274 <<peer_id<<std::endl;
2276 Player *player = m_env->getPlayer(peer_id);
2278 verbosestream<<"Server: TOSERVER_INIT2: "
2279 <<"Player not found; ignoring."<<std::endl;
2283 RemoteClient *client = getClient(peer_id);
2284 client->serialization_version =
2285 getClient(peer_id)->pending_serialization_version;
2288 Send some initialization data
2291 infostream<<"Server: Sending content to "
2292 <<getPlayerName(peer_id)<<std::endl;
2294 // Send item definitions
2295 SendItemDef(m_con, peer_id, m_itemdef);
2297 // Send node definitions
2298 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2300 // Send media announcement
2301 sendMediaAnnouncement(peer_id);
2304 SendPlayerPrivileges(peer_id);
2306 // Send inventory formspec
2307 SendPlayerInventoryFormspec(peer_id);
2310 UpdateCrafting(peer_id);
2311 SendInventory(peer_id);
2314 SendPlayerHP(peer_id);
2316 // Send detached inventories
2317 sendDetachedInventories(peer_id);
2319 // Show death screen if necessary
2321 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2325 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2326 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2327 m_con.Send(peer_id, 0, data, true);
2330 // Note things in chat if not in simple singleplayer mode
2331 if(!m_simple_singleplayer_mode)
2333 // Send information about server to player in chat
2334 SendChatMessage(peer_id, getStatusString());
2336 // Send information about joining in chat
2338 std::wstring name = L"unknown";
2339 Player *player = m_env->getPlayer(peer_id);
2341 name = narrow_to_wide(player->getName());
2343 std::wstring message;
2346 message += L" joined the game.";
2347 BroadcastChatMessage(message);
2351 // Warnings about protocol version can be issued here
2352 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2354 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2355 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2362 std::ostringstream os(std::ios_base::binary);
2363 for(core::map<u16, RemoteClient*>::Iterator
2364 i = m_clients.getIterator();
2365 i.atEnd() == false; i++)
2367 RemoteClient *client = i.getNode()->getValue();
2368 assert(client->peer_id == i.getNode()->getKey());
2369 if(client->serialization_version == SER_FMT_VER_INVALID)
2372 Player *player = m_env->getPlayer(client->peer_id);
2375 // Get name of player
2376 os<<player->getName()<<" ";
2379 actionstream<<player->getName()<<" joins game. List of players: "
2380 <<os.str()<<std::endl;
2386 if(peer_ser_ver == SER_FMT_VER_INVALID)
2388 infostream<<"Server::ProcessData(): Cancelling: Peer"
2389 " serialization format invalid or not initialized."
2390 " Skipping incoming command="<<command<<std::endl;
2394 Player *player = m_env->getPlayer(peer_id);
2396 infostream<<"Server::ProcessData(): Cancelling: "
2397 "No player for peer_id="<<peer_id
2402 PlayerSAO *playersao = player->getPlayerSAO();
2403 if(playersao == NULL){
2404 infostream<<"Server::ProcessData(): Cancelling: "
2405 "No player object for peer_id="<<peer_id
2410 if(command == TOSERVER_PLAYERPOS)
2412 if(datasize < 2+12+12+4+4)
2416 v3s32 ps = readV3S32(&data[start+2]);
2417 v3s32 ss = readV3S32(&data[start+2+12]);
2418 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2419 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2421 if(datasize >= 2+12+12+4+4+4)
2422 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2423 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2424 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2425 pitch = wrapDegrees(pitch);
2426 yaw = wrapDegrees(yaw);
2428 player->setPosition(position);
2429 player->setSpeed(speed);
2430 player->setPitch(pitch);
2431 player->setYaw(yaw);
2432 player->keyPressed=keyPressed;
2433 player->control.up = (bool)(keyPressed&1);
2434 player->control.down = (bool)(keyPressed&2);
2435 player->control.left = (bool)(keyPressed&4);
2436 player->control.right = (bool)(keyPressed&8);
2437 player->control.jump = (bool)(keyPressed&16);
2438 player->control.aux1 = (bool)(keyPressed&32);
2439 player->control.sneak = (bool)(keyPressed&64);
2440 player->control.LMB = (bool)(keyPressed&128);
2441 player->control.RMB = (bool)(keyPressed&256);
2443 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2444 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2445 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2447 else if(command == TOSERVER_GOTBLOCKS)
2460 u16 count = data[2];
2461 for(u16 i=0; i<count; i++)
2463 if((s16)datasize < 2+1+(i+1)*6)
2464 throw con::InvalidIncomingDataException
2465 ("GOTBLOCKS length is too short");
2466 v3s16 p = readV3S16(&data[2+1+i*6]);
2467 /*infostream<<"Server: GOTBLOCKS ("
2468 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2469 RemoteClient *client = getClient(peer_id);
2470 client->GotBlock(p);
2473 else if(command == TOSERVER_DELETEDBLOCKS)
2486 u16 count = data[2];
2487 for(u16 i=0; i<count; i++)
2489 if((s16)datasize < 2+1+(i+1)*6)
2490 throw con::InvalidIncomingDataException
2491 ("DELETEDBLOCKS length is too short");
2492 v3s16 p = readV3S16(&data[2+1+i*6]);
2493 /*infostream<<"Server: DELETEDBLOCKS ("
2494 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2495 RemoteClient *client = getClient(peer_id);
2496 client->SetBlockNotSent(p);
2499 else if(command == TOSERVER_CLICK_OBJECT)
2501 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2504 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2506 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2509 else if(command == TOSERVER_GROUND_ACTION)
2511 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2515 else if(command == TOSERVER_RELEASE)
2517 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2520 else if(command == TOSERVER_SIGNTEXT)
2522 infostream<<"Server: SIGNTEXT not supported anymore"
2526 else if(command == TOSERVER_SIGNNODETEXT)
2528 infostream<<"Server: SIGNNODETEXT not supported anymore"
2532 else if(command == TOSERVER_INVENTORY_ACTION)
2534 // Strip command and create a stream
2535 std::string datastring((char*)&data[2], datasize-2);
2536 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2537 std::istringstream is(datastring, std::ios_base::binary);
2539 InventoryAction *a = InventoryAction::deSerialize(is);
2542 infostream<<"TOSERVER_INVENTORY_ACTION: "
2543 <<"InventoryAction::deSerialize() returned NULL"
2548 // If something goes wrong, this player is to blame
2549 RollbackScopeActor rollback_scope(m_rollback,
2550 std::string("player:")+player->getName());
2553 Note: Always set inventory not sent, to repair cases
2554 where the client made a bad prediction.
2558 Handle restrictions and special cases of the move action
2560 if(a->getType() == IACTION_MOVE)
2562 IMoveAction *ma = (IMoveAction*)a;
2564 ma->from_inv.applyCurrentPlayer(player->getName());
2565 ma->to_inv.applyCurrentPlayer(player->getName());
2567 setInventoryModified(ma->from_inv);
2568 setInventoryModified(ma->to_inv);
2570 bool from_inv_is_current_player =
2571 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2572 (ma->from_inv.name == player->getName());
2574 bool to_inv_is_current_player =
2575 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2576 (ma->to_inv.name == player->getName());
2579 Disable moving items out of craftpreview
2581 if(ma->from_list == "craftpreview")
2583 infostream<<"Ignoring IMoveAction from "
2584 <<(ma->from_inv.dump())<<":"<<ma->from_list
2585 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2586 <<" because src is "<<ma->from_list<<std::endl;
2592 Disable moving items into craftresult and craftpreview
2594 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2596 infostream<<"Ignoring IMoveAction from "
2597 <<(ma->from_inv.dump())<<":"<<ma->from_list
2598 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2599 <<" because dst is "<<ma->to_list<<std::endl;
2604 // Disallow moving items in elsewhere than player's inventory
2605 // if not allowed to interact
2606 if(!checkPriv(player->getName(), "interact") &&
2607 (!from_inv_is_current_player ||
2608 !to_inv_is_current_player))
2610 infostream<<"Cannot move outside of player's inventory: "
2611 <<"No interact privilege"<<std::endl;
2617 Handle restrictions and special cases of the drop action
2619 else if(a->getType() == IACTION_DROP)
2621 IDropAction *da = (IDropAction*)a;
2623 da->from_inv.applyCurrentPlayer(player->getName());
2625 setInventoryModified(da->from_inv);
2627 // Disallow dropping items if not allowed to interact
2628 if(!checkPriv(player->getName(), "interact"))
2635 Handle restrictions and special cases of the craft action
2637 else if(a->getType() == IACTION_CRAFT)
2639 ICraftAction *ca = (ICraftAction*)a;
2641 ca->craft_inv.applyCurrentPlayer(player->getName());
2643 setInventoryModified(ca->craft_inv);
2645 //bool craft_inv_is_current_player =
2646 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2647 // (ca->craft_inv.name == player->getName());
2649 // Disallow crafting if not allowed to interact
2650 if(!checkPriv(player->getName(), "interact"))
2652 infostream<<"Cannot craft: "
2653 <<"No interact privilege"<<std::endl;
2660 a->apply(this, playersao, this);
2664 else if(command == TOSERVER_CHAT_MESSAGE)
2672 std::string datastring((char*)&data[2], datasize-2);
2673 std::istringstream is(datastring, std::ios_base::binary);
2676 is.read((char*)buf, 2);
2677 u16 len = readU16(buf);
2679 std::wstring message;
2680 for(u16 i=0; i<len; i++)
2682 is.read((char*)buf, 2);
2683 message += (wchar_t)readU16(buf);
2686 // If something goes wrong, this player is to blame
2687 RollbackScopeActor rollback_scope(m_rollback,
2688 std::string("player:")+player->getName());
2690 // Get player name of this client
2691 std::wstring name = narrow_to_wide(player->getName());
2694 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2695 wide_to_narrow(message));
2696 // If script ate the message, don't proceed
2700 // Line to send to players
2702 // Whether to send to the player that sent the line
2703 bool send_to_sender = false;
2704 // Whether to send to other players
2705 bool send_to_others = false;
2707 // Commands are implemented in Lua, so only catch invalid
2708 // commands that were not "eaten" and send an error back
2709 if(message[0] == L'/')
2711 message = message.substr(1);
2712 send_to_sender = true;
2713 if(message.length() == 0)
2714 line += L"-!- Empty command";
2716 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2720 if(checkPriv(player->getName(), "shout")){
2725 send_to_others = true;
2727 line += L"-!- You don't have permission to shout.";
2728 send_to_sender = true;
2735 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2738 Send the message to clients
2740 for(core::map<u16, RemoteClient*>::Iterator
2741 i = m_clients.getIterator();
2742 i.atEnd() == false; i++)
2744 // Get client and check that it is valid
2745 RemoteClient *client = i.getNode()->getValue();
2746 assert(client->peer_id == i.getNode()->getKey());
2747 if(client->serialization_version == SER_FMT_VER_INVALID)
2751 bool sender_selected = (peer_id == client->peer_id);
2752 if(sender_selected == true && send_to_sender == false)
2754 if(sender_selected == false && send_to_others == false)
2757 SendChatMessage(client->peer_id, line);
2761 else if(command == TOSERVER_DAMAGE)
2763 std::string datastring((char*)&data[2], datasize-2);
2764 std::istringstream is(datastring, std::ios_base::binary);
2765 u8 damage = readU8(is);
2767 actionstream<<player->getName()<<" damaged by "
2768 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2771 playersao->setHP(playersao->getHP() - damage);
2773 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2776 if(playersao->m_hp_not_sent)
2777 SendPlayerHP(peer_id);
2779 else if(command == TOSERVER_PASSWORD)
2782 [0] u16 TOSERVER_PASSWORD
2783 [2] u8[28] old password
2784 [30] u8[28] new password
2787 if(datasize != 2+PASSWORD_SIZE*2)
2789 /*char password[PASSWORD_SIZE];
2790 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2791 password[i] = data[2+i];
2792 password[PASSWORD_SIZE-1] = 0;*/
2794 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2802 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2804 char c = data[2+PASSWORD_SIZE+i];
2810 if(!base64_is_valid(newpwd)){
2811 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2812 // Wrong old password supplied!!
2813 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2817 infostream<<"Server: Client requests a password change from "
2818 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2820 std::string playername = player->getName();
2822 std::string checkpwd;
2823 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2825 if(oldpwd != checkpwd)
2827 infostream<<"Server: invalid old password"<<std::endl;
2828 // Wrong old password supplied!!
2829 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2833 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2835 actionstream<<player->getName()<<" changes password"<<std::endl;
2836 SendChatMessage(peer_id, L"Password change successful.");
2838 actionstream<<player->getName()<<" tries to change password but "
2839 <<"it fails"<<std::endl;
2840 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2843 else if(command == TOSERVER_PLAYERITEM)
2848 u16 item = readU16(&data[2]);
2849 playersao->setWieldIndex(item);
2851 else if(command == TOSERVER_RESPAWN)
2856 RespawnPlayer(peer_id);
2858 actionstream<<player->getName()<<" respawns at "
2859 <<PP(player->getPosition()/BS)<<std::endl;
2861 // ActiveObject is added to environment in AsyncRunStep after
2862 // the previous addition has been succesfully removed
2864 else if(command == TOSERVER_REQUEST_MEDIA) {
2865 std::string datastring((char*)&data[2], datasize-2);
2866 std::istringstream is(datastring, std::ios_base::binary);
2868 core::list<MediaRequest> tosend;
2869 u16 numfiles = readU16(is);
2871 infostream<<"Sending "<<numfiles<<" files to "
2872 <<getPlayerName(peer_id)<<std::endl;
2873 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2875 for(int i = 0; i < numfiles; i++) {
2876 std::string name = deSerializeString(is);
2877 tosend.push_back(MediaRequest(name));
2878 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2882 sendRequestedMedia(peer_id, tosend);
2884 // Now the client should know about everything
2885 // (definitions and files)
2886 getClient(peer_id)->definitions_sent = true;
2888 else if(command == TOSERVER_INTERACT)
2890 std::string datastring((char*)&data[2], datasize-2);
2891 std::istringstream is(datastring, std::ios_base::binary);
2897 [5] u32 length of the next item
2898 [9] serialized PointedThing
2900 0: start digging (from undersurface) or use
2901 1: stop digging (all parameters ignored)
2902 2: digging completed
2903 3: place block or item (to abovesurface)
2906 u8 action = readU8(is);
2907 u16 item_i = readU16(is);
2908 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2909 PointedThing pointed;
2910 pointed.deSerialize(tmp_is);
2912 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2913 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2917 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2918 <<" tried to interact, but is dead!"<<std::endl;
2922 v3f player_pos = playersao->getLastGoodPosition();
2924 // Update wielded item
2925 playersao->setWieldIndex(item_i);
2927 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2928 v3s16 p_under = pointed.node_undersurface;
2929 v3s16 p_above = pointed.node_abovesurface;
2931 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2932 ServerActiveObject *pointed_object = NULL;
2933 if(pointed.type == POINTEDTHING_OBJECT)
2935 pointed_object = m_env->getActiveObject(pointed.object_id);
2936 if(pointed_object == NULL)
2938 verbosestream<<"TOSERVER_INTERACT: "
2939 "pointed object is NULL"<<std::endl;
2945 v3f pointed_pos_under = player_pos;
2946 v3f pointed_pos_above = player_pos;
2947 if(pointed.type == POINTEDTHING_NODE)
2949 pointed_pos_under = intToFloat(p_under, BS);
2950 pointed_pos_above = intToFloat(p_above, BS);
2952 else if(pointed.type == POINTEDTHING_OBJECT)
2954 pointed_pos_under = pointed_object->getBasePosition();
2955 pointed_pos_above = pointed_pos_under;
2959 Check that target is reasonably close
2960 (only when digging or placing things)
2962 if(action == 0 || action == 2 || action == 3)
2964 float d = player_pos.getDistanceFrom(pointed_pos_under);
2965 float max_d = BS * 14; // Just some large enough value
2967 actionstream<<"Player "<<player->getName()
2968 <<" tried to access "<<pointed.dump()
2970 <<"d="<<d<<", max_d="<<max_d
2971 <<". ignoring."<<std::endl;
2972 // Re-send block to revert change on client-side
2973 RemoteClient *client = getClient(peer_id);
2974 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2975 client->SetBlockNotSent(blockpos);
2982 Make sure the player is allowed to do it
2984 if(!checkPriv(player->getName(), "interact"))
2986 actionstream<<player->getName()<<" attempted to interact with "
2987 <<pointed.dump()<<" without 'interact' privilege"
2989 // Re-send block to revert change on client-side
2990 RemoteClient *client = getClient(peer_id);
2991 // Digging completed -> under
2993 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2994 client->SetBlockNotSent(blockpos);
2996 // Placement -> above
2998 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2999 client->SetBlockNotSent(blockpos);
3005 If something goes wrong, this player is to blame
3007 RollbackScopeActor rollback_scope(m_rollback,
3008 std::string("player:")+player->getName());
3011 0: start digging or punch object
3015 if(pointed.type == POINTEDTHING_NODE)
3018 NOTE: This can be used in the future to check if
3019 somebody is cheating, by checking the timing.
3021 MapNode n(CONTENT_IGNORE);
3024 n = m_env->getMap().getNode(p_under);
3026 catch(InvalidPositionException &e)
3028 infostream<<"Server: Not punching: Node not found."
3029 <<" Adding block to emerge queue."
3031 m_emerge_queue.addBlock(peer_id,
3032 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3034 if(n.getContent() != CONTENT_IGNORE)
3035 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3037 playersao->noCheatDigStart(p_under);
3039 else if(pointed.type == POINTEDTHING_OBJECT)
3041 // Skip if object has been removed
3042 if(pointed_object->m_removed)
3045 actionstream<<player->getName()<<" punches object "
3046 <<pointed.object_id<<": "
3047 <<pointed_object->getDescription()<<std::endl;
3049 ItemStack punchitem = playersao->getWieldedItem();
3050 ToolCapabilities toolcap =
3051 punchitem.getToolCapabilities(m_itemdef);
3052 v3f dir = (pointed_object->getBasePosition() -
3053 (player->getPosition() + player->getEyeOffset())
3055 float time_from_last_punch =
3056 playersao->resetTimeFromLastPunch();
3057 pointed_object->punch(dir, &toolcap, playersao,
3058 time_from_last_punch);
3066 else if(action == 1)
3071 2: Digging completed
3073 else if(action == 2)
3075 // Only digging of nodes
3076 if(pointed.type == POINTEDTHING_NODE)
3078 MapNode n(CONTENT_IGNORE);
3081 n = m_env->getMap().getNode(p_under);
3083 catch(InvalidPositionException &e)
3085 infostream<<"Server: Not finishing digging: Node not found."
3086 <<" Adding block to emerge queue."
3088 m_emerge_queue.addBlock(peer_id,
3089 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3092 /* Cheat prevention */
3093 bool is_valid_dig = true;
3094 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3096 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3097 float nocheat_t = playersao->getNoCheatDigTime();
3098 playersao->noCheatDigEnd();
3099 // If player didn't start digging this, ignore dig
3100 if(nocheat_p != p_under){
3101 infostream<<"Server: NoCheat: "<<player->getName()
3102 <<" started digging "
3103 <<PP(nocheat_p)<<" and completed digging "
3104 <<PP(p_under)<<"; not digging."<<std::endl;
3105 is_valid_dig = false;
3107 // Get player's wielded item
3108 ItemStack playeritem;
3109 InventoryList *mlist = playersao->getInventory()->getList("main");
3111 playeritem = mlist->getItem(playersao->getWieldIndex());
3112 ToolCapabilities playeritem_toolcap =
3113 playeritem.getToolCapabilities(m_itemdef);
3114 // Get diggability and expected digging time
3115 DigParams params = getDigParams(m_nodedef->get(n).groups,
3116 &playeritem_toolcap);
3117 // If can't dig, try hand
3118 if(!params.diggable){
3119 const ItemDefinition &hand = m_itemdef->get("");
3120 const ToolCapabilities *tp = hand.tool_capabilities;
3122 params = getDigParams(m_nodedef->get(n).groups, tp);
3124 // If can't dig, ignore dig
3125 if(!params.diggable){
3126 infostream<<"Server: NoCheat: "<<player->getName()
3127 <<" completed digging "<<PP(p_under)
3128 <<", which is not diggable with tool. not digging."
3130 is_valid_dig = false;
3132 // If time is considerably too short, ignore dig
3133 // Check time only for medium and slow timed digs
3134 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3135 infostream<<"Server: NoCheat: "<<player->getName()
3136 <<" completed digging "
3137 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3138 <<params.time<<"s; not digging."<<std::endl;
3139 is_valid_dig = false;
3143 /* Actually dig node */
3145 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3146 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3148 // Send unusual result (that is, node not being removed)
3149 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3151 // Re-send block to revert change on client-side
3152 RemoteClient *client = getClient(peer_id);
3153 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3154 client->SetBlockNotSent(blockpos);
3160 3: place block or right-click object
3162 else if(action == 3)
3164 ItemStack item = playersao->getWieldedItem();
3166 // Reset build time counter
3167 if(pointed.type == POINTEDTHING_NODE &&
3168 item.getDefinition(m_itemdef).type == ITEM_NODE)
3169 getClient(peer_id)->m_time_from_building = 0.0;
3171 if(pointed.type == POINTEDTHING_OBJECT)
3173 // Right click object
3175 // Skip if object has been removed
3176 if(pointed_object->m_removed)
3179 actionstream<<player->getName()<<" right-clicks object "
3180 <<pointed.object_id<<": "
3181 <<pointed_object->getDescription()<<std::endl;
3184 pointed_object->rightClick(playersao);
3186 else if(scriptapi_item_on_place(m_lua,
3187 item, playersao, pointed))
3189 // Placement was handled in lua
3191 // Apply returned ItemStack
3192 playersao->setWieldedItem(item);
3195 // If item has node placement prediction, always send the above
3196 // node to make sure the client knows what exactly happened
3197 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3198 RemoteClient *client = getClient(peer_id);
3199 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3200 client->SetBlockNotSent(blockpos);
3207 else if(action == 4)
3209 ItemStack item = playersao->getWieldedItem();
3211 actionstream<<player->getName()<<" uses "<<item.name
3212 <<", pointing at "<<pointed.dump()<<std::endl;
3214 if(scriptapi_item_on_use(m_lua,
3215 item, playersao, pointed))
3217 // Apply returned ItemStack
3218 playersao->setWieldedItem(item);
3225 Catch invalid actions
3229 infostream<<"WARNING: Server: Invalid action "
3230 <<action<<std::endl;
3233 else if(command == TOSERVER_REMOVED_SOUNDS)
3235 std::string datastring((char*)&data[2], datasize-2);
3236 std::istringstream is(datastring, std::ios_base::binary);
3238 int num = readU16(is);
3239 for(int k=0; k<num; k++){
3240 s32 id = readS32(is);
3241 std::map<s32, ServerPlayingSound>::iterator i =
3242 m_playing_sounds.find(id);
3243 if(i == m_playing_sounds.end())
3245 ServerPlayingSound &psound = i->second;
3246 psound.clients.erase(peer_id);
3247 if(psound.clients.size() == 0)
3248 m_playing_sounds.erase(i++);
3251 else if(command == TOSERVER_NODEMETA_FIELDS)
3253 std::string datastring((char*)&data[2], datasize-2);
3254 std::istringstream is(datastring, std::ios_base::binary);
3256 v3s16 p = readV3S16(is);
3257 std::string formname = deSerializeString(is);
3258 int num = readU16(is);
3259 std::map<std::string, std::string> fields;
3260 for(int k=0; k<num; k++){
3261 std::string fieldname = deSerializeString(is);
3262 std::string fieldvalue = deSerializeLongString(is);
3263 fields[fieldname] = fieldvalue;
3266 // If something goes wrong, this player is to blame
3267 RollbackScopeActor rollback_scope(m_rollback,
3268 std::string("player:")+player->getName());
3270 // Check the target node for rollback data; leave others unnoticed
3271 RollbackNode rn_old(&m_env->getMap(), p, this);
3273 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3276 // Report rollback data
3277 RollbackNode rn_new(&m_env->getMap(), p, this);
3278 if(rollback() && rn_new != rn_old){
3279 RollbackAction action;
3280 action.setSetNode(p, rn_old, rn_new);
3281 rollback()->reportAction(action);
3284 else if(command == TOSERVER_INVENTORY_FIELDS)
3286 std::string datastring((char*)&data[2], datasize-2);
3287 std::istringstream is(datastring, std::ios_base::binary);
3289 std::string formname = deSerializeString(is);
3290 int num = readU16(is);
3291 std::map<std::string, std::string> fields;
3292 for(int k=0; k<num; k++){
3293 std::string fieldname = deSerializeString(is);
3294 std::string fieldvalue = deSerializeLongString(is);
3295 fields[fieldname] = fieldvalue;
3298 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3302 infostream<<"Server::ProcessData(): Ignoring "
3303 "unknown command "<<command<<std::endl;
3307 catch(SendFailedException &e)
3309 errorstream<<"Server::ProcessData(): SendFailedException: "
3315 void Server::onMapEditEvent(MapEditEvent *event)
3317 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3318 if(m_ignore_map_edit_events)
3320 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3322 MapEditEvent *e = event->clone();
3323 m_unsent_map_edit_queue.push_back(e);
3326 Inventory* Server::getInventory(const InventoryLocation &loc)
3329 case InventoryLocation::UNDEFINED:
3332 case InventoryLocation::CURRENT_PLAYER:
3335 case InventoryLocation::PLAYER:
3337 Player *player = m_env->getPlayer(loc.name.c_str());
3340 PlayerSAO *playersao = player->getPlayerSAO();
3343 return playersao->getInventory();
3346 case InventoryLocation::NODEMETA:
3348 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3351 return meta->getInventory();
3354 case InventoryLocation::DETACHED:
3356 if(m_detached_inventories.count(loc.name) == 0)
3358 return m_detached_inventories[loc.name];
3366 void Server::setInventoryModified(const InventoryLocation &loc)
3369 case InventoryLocation::UNDEFINED:
3372 case InventoryLocation::PLAYER:
3374 Player *player = m_env->getPlayer(loc.name.c_str());
3377 PlayerSAO *playersao = player->getPlayerSAO();
3380 playersao->m_inventory_not_sent = true;
3381 playersao->m_wielded_item_not_sent = true;
3384 case InventoryLocation::NODEMETA:
3386 v3s16 blockpos = getNodeBlockPos(loc.p);
3388 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3390 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3392 setBlockNotSent(blockpos);
3395 case InventoryLocation::DETACHED:
3397 sendDetachedInventoryToAll(loc.name);
3405 core::list<PlayerInfo> Server::getPlayerInfo()
3407 DSTACK(__FUNCTION_NAME);
3408 JMutexAutoLock envlock(m_env_mutex);
3409 JMutexAutoLock conlock(m_con_mutex);
3411 core::list<PlayerInfo> list;
3413 core::list<Player*> players = m_env->getPlayers();
3415 core::list<Player*>::Iterator i;
3416 for(i = players.begin();
3417 i != players.end(); i++)
3421 Player *player = *i;
3424 // Copy info from connection to info struct
3425 info.id = player->peer_id;
3426 info.address = m_con.GetPeerAddress(player->peer_id);
3427 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3429 catch(con::PeerNotFoundException &e)
3431 // Set dummy peer info
3433 info.address = Address(0,0,0,0,0);
3437 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3438 info.position = player->getPosition();
3440 list.push_back(info);
3447 void Server::peerAdded(con::Peer *peer)
3449 DSTACK(__FUNCTION_NAME);
3450 verbosestream<<"Server::peerAdded(): peer->id="
3451 <<peer->id<<std::endl;
3454 c.type = PEER_ADDED;
3455 c.peer_id = peer->id;
3457 m_peer_change_queue.push_back(c);
3460 void Server::deletingPeer(con::Peer *peer, bool timeout)
3462 DSTACK(__FUNCTION_NAME);
3463 verbosestream<<"Server::deletingPeer(): peer->id="
3464 <<peer->id<<", timeout="<<timeout<<std::endl;
3467 c.type = PEER_REMOVED;
3468 c.peer_id = peer->id;
3469 c.timeout = timeout;
3470 m_peer_change_queue.push_back(c);
3477 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3479 DSTACK(__FUNCTION_NAME);
3480 std::ostringstream os(std::ios_base::binary);
3482 writeU16(os, TOCLIENT_HP);
3486 std::string s = os.str();
3487 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3489 con.Send(peer_id, 0, data, true);
3492 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3493 const std::wstring &reason)
3495 DSTACK(__FUNCTION_NAME);
3496 std::ostringstream os(std::ios_base::binary);
3498 writeU16(os, TOCLIENT_ACCESS_DENIED);
3499 os<<serializeWideString(reason);
3502 std::string s = os.str();
3503 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3505 con.Send(peer_id, 0, data, true);
3508 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3509 bool set_camera_point_target, v3f camera_point_target)
3511 DSTACK(__FUNCTION_NAME);
3512 std::ostringstream os(std::ios_base::binary);
3514 writeU16(os, TOCLIENT_DEATHSCREEN);
3515 writeU8(os, set_camera_point_target);
3516 writeV3F1000(os, camera_point_target);
3519 std::string s = os.str();
3520 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3522 con.Send(peer_id, 0, data, true);
3525 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3526 IItemDefManager *itemdef)
3528 DSTACK(__FUNCTION_NAME);
3529 std::ostringstream os(std::ios_base::binary);
3533 u32 length of the next item
3534 zlib-compressed serialized ItemDefManager
3536 writeU16(os, TOCLIENT_ITEMDEF);
3537 std::ostringstream tmp_os(std::ios::binary);
3538 itemdef->serialize(tmp_os);
3539 std::ostringstream tmp_os2(std::ios::binary);
3540 compressZlib(tmp_os.str(), tmp_os2);
3541 os<<serializeLongString(tmp_os2.str());
3544 std::string s = os.str();
3545 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3546 <<"): size="<<s.size()<<std::endl;
3547 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3549 con.Send(peer_id, 0, data, true);
3552 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3553 INodeDefManager *nodedef, u16 protocol_version)
3555 DSTACK(__FUNCTION_NAME);
3556 std::ostringstream os(std::ios_base::binary);
3560 u32 length of the next item
3561 zlib-compressed serialized NodeDefManager
3563 writeU16(os, TOCLIENT_NODEDEF);
3564 std::ostringstream tmp_os(std::ios::binary);
3565 nodedef->serialize(tmp_os, protocol_version);
3566 std::ostringstream tmp_os2(std::ios::binary);
3567 compressZlib(tmp_os.str(), tmp_os2);
3568 os<<serializeLongString(tmp_os2.str());
3571 std::string s = os.str();
3572 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3573 <<"): size="<<s.size()<<std::endl;
3574 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3576 con.Send(peer_id, 0, data, true);
3580 Non-static send methods
3583 void Server::SendInventory(u16 peer_id)
3585 DSTACK(__FUNCTION_NAME);
3587 PlayerSAO *playersao = getPlayerSAO(peer_id);
3590 playersao->m_inventory_not_sent = false;
3596 std::ostringstream os;
3597 playersao->getInventory()->serialize(os);
3599 std::string s = os.str();
3601 SharedBuffer<u8> data(s.size()+2);
3602 writeU16(&data[0], TOCLIENT_INVENTORY);
3603 memcpy(&data[2], s.c_str(), s.size());
3606 m_con.Send(peer_id, 0, data, true);
3609 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3611 DSTACK(__FUNCTION_NAME);
3613 std::ostringstream os(std::ios_base::binary);
3617 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3618 os.write((char*)buf, 2);
3621 writeU16(buf, message.size());
3622 os.write((char*)buf, 2);
3625 for(u32 i=0; i<message.size(); i++)
3629 os.write((char*)buf, 2);
3633 std::string s = os.str();
3634 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3636 m_con.Send(peer_id, 0, data, true);
3639 void Server::BroadcastChatMessage(const std::wstring &message)
3641 for(core::map<u16, RemoteClient*>::Iterator
3642 i = m_clients.getIterator();
3643 i.atEnd() == false; i++)
3645 // Get client and check that it is valid
3646 RemoteClient *client = i.getNode()->getValue();
3647 assert(client->peer_id == i.getNode()->getKey());
3648 if(client->serialization_version == SER_FMT_VER_INVALID)
3651 SendChatMessage(client->peer_id, message);
3655 void Server::SendPlayerHP(u16 peer_id)
3657 DSTACK(__FUNCTION_NAME);
3658 PlayerSAO *playersao = getPlayerSAO(peer_id);
3660 playersao->m_hp_not_sent = false;
3661 SendHP(m_con, peer_id, playersao->getHP());
3664 void Server::SendMovePlayer(u16 peer_id)
3666 DSTACK(__FUNCTION_NAME);
3667 Player *player = m_env->getPlayer(peer_id);
3670 std::ostringstream os(std::ios_base::binary);
3671 writeU16(os, TOCLIENT_MOVE_PLAYER);
3672 writeV3F1000(os, player->getPosition());
3673 writeF1000(os, player->getPitch());
3674 writeF1000(os, player->getYaw());
3677 v3f pos = player->getPosition();
3678 f32 pitch = player->getPitch();
3679 f32 yaw = player->getYaw();
3680 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3681 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3688 std::string s = os.str();
3689 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3691 m_con.Send(peer_id, 0, data, true);
3694 void Server::SendPlayerPrivileges(u16 peer_id)
3696 Player *player = m_env->getPlayer(peer_id);
3698 if(player->peer_id == PEER_ID_INEXISTENT)
3701 std::set<std::string> privs;
3702 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3704 std::ostringstream os(std::ios_base::binary);
3705 writeU16(os, TOCLIENT_PRIVILEGES);
3706 writeU16(os, privs.size());
3707 for(std::set<std::string>::const_iterator i = privs.begin();
3708 i != privs.end(); i++){
3709 os<<serializeString(*i);
3713 std::string s = os.str();
3714 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3716 m_con.Send(peer_id, 0, data, true);
3719 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3721 Player *player = m_env->getPlayer(peer_id);
3723 if(player->peer_id == PEER_ID_INEXISTENT)
3726 std::ostringstream os(std::ios_base::binary);
3727 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3728 os<<serializeLongString(player->inventory_formspec);
3731 std::string s = os.str();
3732 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3734 m_con.Send(peer_id, 0, data, true);
3737 s32 Server::playSound(const SimpleSoundSpec &spec,
3738 const ServerSoundParams ¶ms)
3740 // Find out initial position of sound
3741 bool pos_exists = false;
3742 v3f pos = params.getPos(m_env, &pos_exists);
3743 // If position is not found while it should be, cancel sound
3744 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3746 // Filter destination clients
3747 std::set<RemoteClient*> dst_clients;
3748 if(params.to_player != "")
3750 Player *player = m_env->getPlayer(params.to_player.c_str());
3752 infostream<<"Server::playSound: Player \""<<params.to_player
3753 <<"\" not found"<<std::endl;
3756 if(player->peer_id == PEER_ID_INEXISTENT){
3757 infostream<<"Server::playSound: Player \""<<params.to_player
3758 <<"\" not connected"<<std::endl;
3761 RemoteClient *client = getClient(player->peer_id);
3762 dst_clients.insert(client);
3766 for(core::map<u16, RemoteClient*>::Iterator
3767 i = m_clients.getIterator(); i.atEnd() == false; i++)
3769 RemoteClient *client = i.getNode()->getValue();
3770 Player *player = m_env->getPlayer(client->peer_id);
3774 if(player->getPosition().getDistanceFrom(pos) >
3775 params.max_hear_distance)
3778 dst_clients.insert(client);
3781 if(dst_clients.size() == 0)
3784 s32 id = m_next_sound_id++;
3785 // The sound will exist as a reference in m_playing_sounds
3786 m_playing_sounds[id] = ServerPlayingSound();
3787 ServerPlayingSound &psound = m_playing_sounds[id];
3788 psound.params = params;
3789 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3790 i != dst_clients.end(); i++)
3791 psound.clients.insert((*i)->peer_id);
3793 std::ostringstream os(std::ios_base::binary);
3794 writeU16(os, TOCLIENT_PLAY_SOUND);
3796 os<<serializeString(spec.name);
3797 writeF1000(os, spec.gain * params.gain);
3798 writeU8(os, params.type);
3799 writeV3F1000(os, pos);
3800 writeU16(os, params.object);
3801 writeU8(os, params.loop);
3803 std::string s = os.str();
3804 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3806 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3807 i != dst_clients.end(); i++){
3809 m_con.Send((*i)->peer_id, 0, data, true);
3813 void Server::stopSound(s32 handle)
3815 // Get sound reference
3816 std::map<s32, ServerPlayingSound>::iterator i =
3817 m_playing_sounds.find(handle);
3818 if(i == m_playing_sounds.end())
3820 ServerPlayingSound &psound = i->second;
3822 std::ostringstream os(std::ios_base::binary);
3823 writeU16(os, TOCLIENT_STOP_SOUND);
3824 writeS32(os, handle);
3826 std::string s = os.str();
3827 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3829 for(std::set<u16>::iterator i = psound.clients.begin();
3830 i != psound.clients.end(); i++){
3832 m_con.Send(*i, 0, data, true);
3834 // Remove sound reference
3835 m_playing_sounds.erase(i);
3838 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3839 core::list<u16> *far_players, float far_d_nodes)
3841 float maxd = far_d_nodes*BS;
3842 v3f p_f = intToFloat(p, BS);
3846 SharedBuffer<u8> reply(replysize);
3847 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3848 writeS16(&reply[2], p.X);
3849 writeS16(&reply[4], p.Y);
3850 writeS16(&reply[6], p.Z);
3852 for(core::map<u16, RemoteClient*>::Iterator
3853 i = m_clients.getIterator();
3854 i.atEnd() == false; i++)
3856 // Get client and check that it is valid
3857 RemoteClient *client = i.getNode()->getValue();
3858 assert(client->peer_id == i.getNode()->getKey());
3859 if(client->serialization_version == SER_FMT_VER_INVALID)
3862 // Don't send if it's the same one
3863 if(client->peer_id == ignore_id)
3869 Player *player = m_env->getPlayer(client->peer_id);
3872 // If player is far away, only set modified blocks not sent
3873 v3f player_pos = player->getPosition();
3874 if(player_pos.getDistanceFrom(p_f) > maxd)
3876 far_players->push_back(client->peer_id);
3883 m_con.Send(client->peer_id, 0, reply, true);
3887 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3888 core::list<u16> *far_players, float far_d_nodes)
3890 float maxd = far_d_nodes*BS;
3891 v3f p_f = intToFloat(p, BS);
3893 for(core::map<u16, RemoteClient*>::Iterator
3894 i = m_clients.getIterator();
3895 i.atEnd() == false; i++)
3897 // Get client and check that it is valid
3898 RemoteClient *client = i.getNode()->getValue();
3899 assert(client->peer_id == i.getNode()->getKey());
3900 if(client->serialization_version == SER_FMT_VER_INVALID)
3903 // Don't send if it's the same one
3904 if(client->peer_id == ignore_id)
3910 Player *player = m_env->getPlayer(client->peer_id);
3913 // If player is far away, only set modified blocks not sent
3914 v3f player_pos = player->getPosition();
3915 if(player_pos.getDistanceFrom(p_f) > maxd)
3917 far_players->push_back(client->peer_id);
3924 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3925 SharedBuffer<u8> reply(replysize);
3926 writeU16(&reply[0], TOCLIENT_ADDNODE);
3927 writeS16(&reply[2], p.X);
3928 writeS16(&reply[4], p.Y);
3929 writeS16(&reply[6], p.Z);
3930 n.serialize(&reply[8], client->serialization_version);
3933 m_con.Send(client->peer_id, 0, reply, true);
3937 void Server::setBlockNotSent(v3s16 p)
3939 for(core::map<u16, RemoteClient*>::Iterator
3940 i = m_clients.getIterator();
3941 i.atEnd()==false; i++)
3943 RemoteClient *client = i.getNode()->getValue();
3944 client->SetBlockNotSent(p);
3948 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3950 DSTACK(__FUNCTION_NAME);
3952 v3s16 p = block->getPos();
3956 bool completely_air = true;
3957 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3958 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3959 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3961 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3963 completely_air = false;
3964 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3969 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3971 infostream<<"[completely air] ";
3972 infostream<<std::endl;
3976 Create a packet with the block in the right format
3979 std::ostringstream os(std::ios_base::binary);
3980 block->serialize(os, ver, false);
3981 std::string s = os.str();
3982 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3984 u32 replysize = 8 + blockdata.getSize();
3985 SharedBuffer<u8> reply(replysize);
3986 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3987 writeS16(&reply[2], p.X);
3988 writeS16(&reply[4], p.Y);
3989 writeS16(&reply[6], p.Z);
3990 memcpy(&reply[8], *blockdata, blockdata.getSize());
3992 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3993 <<": \tpacket size: "<<replysize<<std::endl;*/
3998 m_con.Send(peer_id, 1, reply, true);
4001 void Server::SendBlocks(float dtime)
4003 DSTACK(__FUNCTION_NAME);
4005 JMutexAutoLock envlock(m_env_mutex);
4006 JMutexAutoLock conlock(m_con_mutex);
4008 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4010 core::array<PrioritySortedBlockTransfer> queue;
4012 s32 total_sending = 0;
4015 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4017 for(core::map<u16, RemoteClient*>::Iterator
4018 i = m_clients.getIterator();
4019 i.atEnd() == false; i++)
4021 RemoteClient *client = i.getNode()->getValue();
4022 assert(client->peer_id == i.getNode()->getKey());
4024 // If definitions and textures have not been sent, don't
4025 // send MapBlocks either
4026 if(!client->definitions_sent)
4029 total_sending += client->SendingCount();
4031 if(client->serialization_version == SER_FMT_VER_INVALID)
4034 client->GetNextBlocks(this, dtime, queue);
4039 // Lowest priority number comes first.
4040 // Lowest is most important.
4043 for(u32 i=0; i<queue.size(); i++)
4045 //TODO: Calculate limit dynamically
4046 if(total_sending >= g_settings->getS32
4047 ("max_simultaneous_block_sends_server_total"))
4050 PrioritySortedBlockTransfer q = queue[i];
4052 MapBlock *block = NULL;
4055 block = m_env->getMap().getBlockNoCreate(q.pos);
4057 catch(InvalidPositionException &e)
4062 RemoteClient *client = getClient(q.peer_id);
4064 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4066 client->SentBlock(q.pos);
4072 void Server::fillMediaCache()
4074 DSTACK(__FUNCTION_NAME);
4076 infostream<<"Server: Calculating media file checksums"<<std::endl;
4078 // Collect all media file paths
4079 std::list<std::string> paths;
4080 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4081 i != m_mods.end(); i++){
4082 const ModSpec &mod = *i;
4083 paths.push_back(mod.path + DIR_DELIM + "textures");
4084 paths.push_back(mod.path + DIR_DELIM + "sounds");
4085 paths.push_back(mod.path + DIR_DELIM + "media");
4086 paths.push_back(mod.path + DIR_DELIM + "models");
4088 std::string path_all = "textures";
4089 paths.push_back(path_all + DIR_DELIM + "all");
4091 // Collect media file information from paths into cache
4092 for(std::list<std::string>::iterator i = paths.begin();
4093 i != paths.end(); i++)
4095 std::string mediapath = *i;
4096 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4097 for(u32 j=0; j<dirlist.size(); j++){
4098 if(dirlist[j].dir) // Ignode dirs
4100 std::string filename = dirlist[j].name;
4101 // If name contains illegal characters, ignore the file
4102 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4103 infostream<<"Server: ignoring illegal file name: \""
4104 <<filename<<"\""<<std::endl;
4107 // If name is not in a supported format, ignore it
4108 const char *supported_ext[] = {
4109 ".png", ".jpg", ".bmp", ".tga",
4110 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4112 ".x", ".b3d", ".md2", ".obj",
4115 if(removeStringEnd(filename, supported_ext) == ""){
4116 infostream<<"Server: ignoring unsupported file extension: \""
4117 <<filename<<"\""<<std::endl;
4120 // Ok, attempt to load the file and add to cache
4121 std::string filepath = mediapath + DIR_DELIM + filename;
4123 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4124 if(fis.good() == false){
4125 errorstream<<"Server::fillMediaCache(): Could not open \""
4126 <<filename<<"\" for reading"<<std::endl;
4129 std::ostringstream tmp_os(std::ios_base::binary);
4133 fis.read(buf, 1024);
4134 std::streamsize len = fis.gcount();
4135 tmp_os.write(buf, len);
4144 errorstream<<"Server::fillMediaCache(): Failed to read \""
4145 <<filename<<"\""<<std::endl;
4148 if(tmp_os.str().length() == 0){
4149 errorstream<<"Server::fillMediaCache(): Empty file \""
4150 <<filepath<<"\""<<std::endl;
4155 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4157 unsigned char *digest = sha1.getDigest();
4158 std::string sha1_base64 = base64_encode(digest, 20);
4159 std::string sha1_hex = hex_encode((char*)digest, 20);
4163 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4164 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4169 struct SendableMediaAnnouncement
4172 std::string sha1_digest;
4174 SendableMediaAnnouncement(const std::string name_="",
4175 const std::string sha1_digest_=""):
4177 sha1_digest(sha1_digest_)
4181 void Server::sendMediaAnnouncement(u16 peer_id)
4183 DSTACK(__FUNCTION_NAME);
4185 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4188 core::list<SendableMediaAnnouncement> file_announcements;
4190 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4191 i != m_media.end(); i++){
4193 file_announcements.push_back(
4194 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4198 std::ostringstream os(std::ios_base::binary);
4206 u16 length of sha1_digest
4211 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4212 writeU16(os, file_announcements.size());
4214 for(core::list<SendableMediaAnnouncement>::Iterator
4215 j = file_announcements.begin();
4216 j != file_announcements.end(); j++){
4217 os<<serializeString(j->name);
4218 os<<serializeString(j->sha1_digest);
4222 std::string s = os.str();
4223 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4226 m_con.Send(peer_id, 0, data, true);
4230 struct SendableMedia
4236 SendableMedia(const std::string &name_="", const std::string path_="",
4237 const std::string &data_=""):
4244 void Server::sendRequestedMedia(u16 peer_id,
4245 const core::list<MediaRequest> &tosend)
4247 DSTACK(__FUNCTION_NAME);
4249 verbosestream<<"Server::sendRequestedMedia(): "
4250 <<"Sending files to client"<<std::endl;
4254 // Put 5kB in one bunch (this is not accurate)
4255 u32 bytes_per_bunch = 5000;
4257 core::array< core::list<SendableMedia> > file_bunches;
4258 file_bunches.push_back(core::list<SendableMedia>());
4260 u32 file_size_bunch_total = 0;
4262 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4263 i != tosend.end(); i++)
4265 if(m_media.find(i->name) == m_media.end()){
4266 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4267 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4271 //TODO get path + name
4272 std::string tpath = m_media[(*i).name].path;
4275 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4276 if(fis.good() == false){
4277 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4278 <<tpath<<"\" for reading"<<std::endl;
4281 std::ostringstream tmp_os(std::ios_base::binary);
4285 fis.read(buf, 1024);
4286 std::streamsize len = fis.gcount();
4287 tmp_os.write(buf, len);
4288 file_size_bunch_total += len;
4297 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4298 <<(*i).name<<"\""<<std::endl;
4301 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4302 <<tname<<"\""<<std::endl;*/
4304 file_bunches[file_bunches.size()-1].push_back(
4305 SendableMedia((*i).name, tpath, tmp_os.str()));
4307 // Start next bunch if got enough data
4308 if(file_size_bunch_total >= bytes_per_bunch){
4309 file_bunches.push_back(core::list<SendableMedia>());
4310 file_size_bunch_total = 0;
4315 /* Create and send packets */
4317 u32 num_bunches = file_bunches.size();
4318 for(u32 i=0; i<num_bunches; i++)
4320 std::ostringstream os(std::ios_base::binary);
4324 u16 total number of texture bunches
4325 u16 index of this bunch
4326 u32 number of files in this bunch
4335 writeU16(os, TOCLIENT_MEDIA);
4336 writeU16(os, num_bunches);
4338 writeU32(os, file_bunches[i].size());
4340 for(core::list<SendableMedia>::Iterator
4341 j = file_bunches[i].begin();
4342 j != file_bunches[i].end(); j++){
4343 os<<serializeString(j->name);
4344 os<<serializeLongString(j->data);
4348 std::string s = os.str();
4349 verbosestream<<"Server::sendRequestedMedia(): bunch "
4350 <<i<<"/"<<num_bunches
4351 <<" files="<<file_bunches[i].size()
4352 <<" size=" <<s.size()<<std::endl;
4353 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4355 m_con.Send(peer_id, 0, data, true);
4359 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4361 if(m_detached_inventories.count(name) == 0){
4362 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4365 Inventory *inv = m_detached_inventories[name];
4367 std::ostringstream os(std::ios_base::binary);
4368 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4369 os<<serializeString(name);
4373 std::string s = os.str();
4374 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4376 m_con.Send(peer_id, 0, data, true);
4379 void Server::sendDetachedInventoryToAll(const std::string &name)
4381 DSTACK(__FUNCTION_NAME);
4383 for(core::map<u16, RemoteClient*>::Iterator
4384 i = m_clients.getIterator();
4385 i.atEnd() == false; i++){
4386 RemoteClient *client = i.getNode()->getValue();
4387 sendDetachedInventory(name, client->peer_id);
4391 void Server::sendDetachedInventories(u16 peer_id)
4393 DSTACK(__FUNCTION_NAME);
4395 for(std::map<std::string, Inventory*>::iterator
4396 i = m_detached_inventories.begin();
4397 i != m_detached_inventories.end(); i++){
4398 const std::string &name = i->first;
4399 //Inventory *inv = i->second;
4400 sendDetachedInventory(name, peer_id);
4408 void Server::DiePlayer(u16 peer_id)
4410 DSTACK(__FUNCTION_NAME);
4412 PlayerSAO *playersao = getPlayerSAO(peer_id);
4415 infostream<<"Server::DiePlayer(): Player "
4416 <<playersao->getPlayer()->getName()
4417 <<" dies"<<std::endl;
4419 playersao->setHP(0);
4421 // Trigger scripted stuff
4422 scriptapi_on_dieplayer(m_lua, playersao);
4424 SendPlayerHP(peer_id);
4425 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4428 void Server::RespawnPlayer(u16 peer_id)
4430 DSTACK(__FUNCTION_NAME);
4432 PlayerSAO *playersao = getPlayerSAO(peer_id);
4435 infostream<<"Server::RespawnPlayer(): Player "
4436 <<playersao->getPlayer()->getName()
4437 <<" respawns"<<std::endl;
4439 playersao->setHP(PLAYER_MAX_HP);
4441 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4443 v3f pos = findSpawnPos(m_env->getServerMap());
4444 playersao->setPos(pos);
4448 void Server::UpdateCrafting(u16 peer_id)
4450 DSTACK(__FUNCTION_NAME);
4452 Player* player = m_env->getPlayer(peer_id);
4455 // Get a preview for crafting
4457 getCraftingResult(&player->inventory, preview, false, this);
4459 // Put the new preview in
4460 InventoryList *plist = player->inventory.getList("craftpreview");
4462 assert(plist->getSize() >= 1);
4463 plist->changeItem(0, preview);
4466 RemoteClient* Server::getClient(u16 peer_id)
4468 DSTACK(__FUNCTION_NAME);
4469 //JMutexAutoLock lock(m_con_mutex);
4470 core::map<u16, RemoteClient*>::Node *n;
4471 n = m_clients.find(peer_id);
4472 // A client should exist for all peers
4474 return n->getValue();
4477 std::wstring Server::getStatusString()
4479 std::wostringstream os(std::ios_base::binary);
4482 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4484 os<<L", uptime="<<m_uptime.get();
4485 // Information about clients
4486 core::map<u16, RemoteClient*>::Iterator i;
4489 for(i = m_clients.getIterator(), first = true;
4490 i.atEnd() == false; i++)
4492 // Get client and check that it is valid
4493 RemoteClient *client = i.getNode()->getValue();
4494 assert(client->peer_id == i.getNode()->getKey());
4495 if(client->serialization_version == SER_FMT_VER_INVALID)
4498 Player *player = m_env->getPlayer(client->peer_id);
4499 // Get name of player
4500 std::wstring name = L"unknown";
4502 name = narrow_to_wide(player->getName());
4503 // Add name to information string
4511 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4512 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4513 if(g_settings->get("motd") != "")
4514 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4518 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4520 std::set<std::string> privs;
4521 scriptapi_get_auth(m_lua, name, NULL, &privs);
4525 bool Server::checkPriv(const std::string &name, const std::string &priv)
4527 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4528 return (privs.count(priv) != 0);
4531 void Server::reportPrivsModified(const std::string &name)
4534 for(core::map<u16, RemoteClient*>::Iterator
4535 i = m_clients.getIterator();
4536 i.atEnd() == false; i++){
4537 RemoteClient *client = i.getNode()->getValue();
4538 Player *player = m_env->getPlayer(client->peer_id);
4539 reportPrivsModified(player->getName());
4542 Player *player = m_env->getPlayer(name.c_str());
4545 SendPlayerPrivileges(player->peer_id);
4546 PlayerSAO *sao = player->getPlayerSAO();
4549 sao->updatePrivileges(
4550 getPlayerEffectivePrivs(name),
4555 void Server::reportInventoryFormspecModified(const std::string &name)
4557 Player *player = m_env->getPlayer(name.c_str());
4560 SendPlayerInventoryFormspec(player->peer_id);
4563 // Saves g_settings to configpath given at initialization
4564 void Server::saveConfig()
4566 if(m_path_config != "")
4567 g_settings->updateConfigFile(m_path_config.c_str());
4570 void Server::notifyPlayer(const char *name, const std::wstring msg)
4572 Player *player = m_env->getPlayer(name);
4575 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4578 void Server::notifyPlayers(const std::wstring msg)
4580 BroadcastChatMessage(msg);
4583 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4587 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4588 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4591 Inventory* Server::createDetachedInventory(const std::string &name)
4593 if(m_detached_inventories.count(name) > 0){
4594 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4595 delete m_detached_inventories[name];
4597 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4599 Inventory *inv = new Inventory(m_itemdef);
4601 m_detached_inventories[name] = inv;
4602 sendDetachedInventoryToAll(name);
4609 BoolScopeSet(bool *dst, bool val):
4612 m_orig_state = *m_dst;
4617 *m_dst = m_orig_state;
4624 // actions: time-reversed list
4625 // Return value: success/failure
4626 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4627 std::list<std::string> *log)
4629 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4630 ServerMap *map = (ServerMap*)(&m_env->getMap());
4631 // Disable rollback report sink while reverting
4632 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4634 // Fail if no actions to handle
4635 if(actions.empty()){
4636 log->push_back("Nothing to do.");
4643 for(std::list<RollbackAction>::const_iterator
4644 i = actions.begin();
4645 i != actions.end(); i++)
4647 const RollbackAction &action = *i;
4649 bool success = action.applyRevert(map, this, this);
4652 std::ostringstream os;
4653 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4654 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4656 log->push_back(os.str());
4658 std::ostringstream os;
4659 os<<"Succesfully reverted step ("<<num_tried<<") "<<action.toString();
4660 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4662 log->push_back(os.str());
4666 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4667 <<" failed"<<std::endl;
4669 // Call it done if less than half failed
4670 return num_failed <= num_tried/2;
4673 // IGameDef interface
4675 IItemDefManager* Server::getItemDefManager()
4679 INodeDefManager* Server::getNodeDefManager()
4683 ICraftDefManager* Server::getCraftDefManager()
4687 ITextureSource* Server::getTextureSource()
4691 IShaderSource* Server::getShaderSource()
4695 u16 Server::allocateUnknownNodeId(const std::string &name)
4697 return m_nodedef->allocateDummy(name);
4699 ISoundManager* Server::getSoundManager()
4701 return &dummySoundManager;
4703 MtEventManager* Server::getEventManager()
4707 IRollbackReportSink* Server::getRollbackReportSink()
4709 if(!m_enable_rollback_recording)
4711 if(!m_rollback_sink_enabled)
4716 IWritableItemDefManager* Server::getWritableItemDefManager()
4720 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4724 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4729 const ModSpec* Server::getModSpec(const std::string &modname)
4731 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4732 i != m_mods.end(); i++){
4733 const ModSpec &mod = *i;
4734 if(mod.name == modname)
4739 void Server::getModNames(core::list<std::string> &modlist)
4741 for(core::list<ModSpec>::Iterator i = m_mods.begin(); i != m_mods.end(); i++)
4743 modlist.push_back((*i).name);
4746 std::string Server::getBuiltinLuaPath()
4748 return porting::path_share + DIR_DELIM + "builtin";
4751 v3f findSpawnPos(ServerMap &map)
4753 //return v3f(50,50,50)*BS;
4758 nodepos = v2s16(0,0);
4763 // Try to find a good place a few times
4764 for(s32 i=0; i<1000; i++)
4767 // We're going to try to throw the player to this position
4768 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4769 -range + (myrand()%(range*2)));
4770 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4771 // Get ground height at point (fallbacks to heightmap function)
4772 s16 groundheight = map.findGroundLevel(nodepos2d);
4773 // Don't go underwater
4774 if(groundheight < WATER_LEVEL)
4776 //infostream<<"-> Underwater"<<std::endl;
4779 // Don't go to high places
4780 if(groundheight > WATER_LEVEL + 4)
4782 //infostream<<"-> Underwater"<<std::endl;
4786 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4787 bool is_good = false;
4789 for(s32 i=0; i<10; i++){
4790 v3s16 blockpos = getNodeBlockPos(nodepos);
4791 map.emergeBlock(blockpos, true);
4792 MapNode n = map.getNodeNoEx(nodepos);
4793 if(n.getContent() == CONTENT_AIR){
4804 // Found a good place
4805 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4811 return intToFloat(nodepos, BS);
4814 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4816 RemotePlayer *player = NULL;
4817 bool newplayer = false;
4820 Try to get an existing player
4822 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4824 // If player is already connected, cancel
4825 if(player != NULL && player->peer_id != 0)
4827 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4832 If player with the wanted peer_id already exists, cancel.
4834 if(m_env->getPlayer(peer_id) != NULL)
4836 infostream<<"emergePlayer(): Player with wrong name but same"
4837 " peer_id already exists"<<std::endl;
4842 Create a new player if it doesn't exist yet
4847 player = new RemotePlayer(this);
4848 player->updateName(name);
4850 /* Set player position */
4851 infostream<<"Server: Finding spawn place for player \""
4852 <<name<<"\""<<std::endl;
4853 v3f pos = findSpawnPos(m_env->getServerMap());
4854 player->setPosition(pos);
4856 /* Add player to environment */
4857 m_env->addPlayer(player);
4861 Create a new player active object
4863 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4864 getPlayerEffectivePrivs(player->getName()),
4867 /* Add object to environment */
4868 m_env->addActiveObject(playersao);
4872 scriptapi_on_newplayer(m_lua, playersao);
4874 scriptapi_on_joinplayer(m_lua, playersao);
4879 void Server::handlePeerChange(PeerChange &c)
4881 JMutexAutoLock envlock(m_env_mutex);
4882 JMutexAutoLock conlock(m_con_mutex);
4884 if(c.type == PEER_ADDED)
4891 core::map<u16, RemoteClient*>::Node *n;
4892 n = m_clients.find(c.peer_id);
4893 // The client shouldn't already exist
4897 RemoteClient *client = new RemoteClient();
4898 client->peer_id = c.peer_id;
4899 m_clients.insert(client->peer_id, client);
4902 else if(c.type == PEER_REMOVED)
4909 core::map<u16, RemoteClient*>::Node *n;
4910 n = m_clients.find(c.peer_id);
4911 // The client should exist
4915 Mark objects to be not known by the client
4917 RemoteClient *client = n->getValue();
4919 for(core::map<u16, bool>::Iterator
4920 i = client->m_known_objects.getIterator();
4921 i.atEnd()==false; i++)
4924 u16 id = i.getNode()->getKey();
4925 ServerActiveObject* obj = m_env->getActiveObject(id);
4927 if(obj && obj->m_known_by_count > 0)
4928 obj->m_known_by_count--;
4932 Clear references to playing sounds
4934 for(std::map<s32, ServerPlayingSound>::iterator
4935 i = m_playing_sounds.begin();
4936 i != m_playing_sounds.end();)
4938 ServerPlayingSound &psound = i->second;
4939 psound.clients.erase(c.peer_id);
4940 if(psound.clients.size() == 0)
4941 m_playing_sounds.erase(i++);
4946 Player *player = m_env->getPlayer(c.peer_id);
4948 // Collect information about leaving in chat
4949 std::wstring message;
4953 std::wstring name = narrow_to_wide(player->getName());
4956 message += L" left the game.";
4958 message += L" (timed out)";
4962 /* Run scripts and remove from environment */
4966 PlayerSAO *playersao = player->getPlayerSAO();
4969 scriptapi_on_leaveplayer(m_lua, playersao);
4971 playersao->disconnected();
4981 std::ostringstream os(std::ios_base::binary);
4982 for(core::map<u16, RemoteClient*>::Iterator
4983 i = m_clients.getIterator();
4984 i.atEnd() == false; i++)
4986 RemoteClient *client = i.getNode()->getValue();
4987 assert(client->peer_id == i.getNode()->getKey());
4988 if(client->serialization_version == SER_FMT_VER_INVALID)
4991 Player *player = m_env->getPlayer(client->peer_id);
4994 // Get name of player
4995 os<<player->getName()<<" ";
4998 actionstream<<player->getName()<<" "
4999 <<(c.timeout?"times out.":"leaves game.")
5000 <<" List of players: "
5001 <<os.str()<<std::endl;
5006 delete m_clients[c.peer_id];
5007 m_clients.remove(c.peer_id);
5009 // Send player info to all remaining clients
5010 //SendPlayerInfos();
5012 // Send leave chat message to all remaining clients
5013 if(message.length() != 0)
5014 BroadcastChatMessage(message);
5023 void Server::handlePeerChanges()
5025 while(m_peer_change_queue.size() > 0)
5027 PeerChange c = m_peer_change_queue.pop_front();
5029 verbosestream<<"Server: Handling peer change: "
5030 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5033 handlePeerChange(c);
5037 void dedicated_server_loop(Server &server, bool &kill)
5039 DSTACK(__FUNCTION_NAME);
5041 verbosestream<<"dedicated_server_loop()"<<std::endl;
5043 IntervalLimiter m_profiler_interval;
5047 float steplen = g_settings->getFloat("dedicated_server_step");
5048 // This is kind of a hack but can be done like this
5049 // because server.step() is very light
5051 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5052 sleep_ms((int)(steplen*1000.0));
5054 server.step(steplen);
5056 if(server.getShutdownRequested() || kill)
5058 infostream<<"Dedicated server quitting"<<std::endl;
5065 float profiler_print_interval =
5066 g_settings->getFloat("profiler_print_interval");
5067 if(profiler_print_interval != 0)
5069 if(m_profiler_interval.step(steplen, profiler_print_interval))
5071 infostream<<"Profiler:"<<std::endl;
5072 g_profiler->print(infostream);
5073 g_profiler->clear();