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_RECEIVED_MEDIA) {
2889 getClient(peer_id)->definitions_sent = true;
2891 else if(command == TOSERVER_INTERACT)
2893 std::string datastring((char*)&data[2], datasize-2);
2894 std::istringstream is(datastring, std::ios_base::binary);
2900 [5] u32 length of the next item
2901 [9] serialized PointedThing
2903 0: start digging (from undersurface) or use
2904 1: stop digging (all parameters ignored)
2905 2: digging completed
2906 3: place block or item (to abovesurface)
2909 u8 action = readU8(is);
2910 u16 item_i = readU16(is);
2911 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2912 PointedThing pointed;
2913 pointed.deSerialize(tmp_is);
2915 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2916 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2920 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2921 <<" tried to interact, but is dead!"<<std::endl;
2925 v3f player_pos = playersao->getLastGoodPosition();
2927 // Update wielded item
2928 playersao->setWieldIndex(item_i);
2930 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2931 v3s16 p_under = pointed.node_undersurface;
2932 v3s16 p_above = pointed.node_abovesurface;
2934 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2935 ServerActiveObject *pointed_object = NULL;
2936 if(pointed.type == POINTEDTHING_OBJECT)
2938 pointed_object = m_env->getActiveObject(pointed.object_id);
2939 if(pointed_object == NULL)
2941 verbosestream<<"TOSERVER_INTERACT: "
2942 "pointed object is NULL"<<std::endl;
2948 v3f pointed_pos_under = player_pos;
2949 v3f pointed_pos_above = player_pos;
2950 if(pointed.type == POINTEDTHING_NODE)
2952 pointed_pos_under = intToFloat(p_under, BS);
2953 pointed_pos_above = intToFloat(p_above, BS);
2955 else if(pointed.type == POINTEDTHING_OBJECT)
2957 pointed_pos_under = pointed_object->getBasePosition();
2958 pointed_pos_above = pointed_pos_under;
2962 Check that target is reasonably close
2963 (only when digging or placing things)
2965 if(action == 0 || action == 2 || action == 3)
2967 float d = player_pos.getDistanceFrom(pointed_pos_under);
2968 float max_d = BS * 14; // Just some large enough value
2970 actionstream<<"Player "<<player->getName()
2971 <<" tried to access "<<pointed.dump()
2973 <<"d="<<d<<", max_d="<<max_d
2974 <<". ignoring."<<std::endl;
2975 // Re-send block to revert change on client-side
2976 RemoteClient *client = getClient(peer_id);
2977 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2978 client->SetBlockNotSent(blockpos);
2985 Make sure the player is allowed to do it
2987 if(!checkPriv(player->getName(), "interact"))
2989 actionstream<<player->getName()<<" attempted to interact with "
2990 <<pointed.dump()<<" without 'interact' privilege"
2992 // Re-send block to revert change on client-side
2993 RemoteClient *client = getClient(peer_id);
2994 // Digging completed -> under
2996 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2997 client->SetBlockNotSent(blockpos);
2999 // Placement -> above
3001 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3002 client->SetBlockNotSent(blockpos);
3008 If something goes wrong, this player is to blame
3010 RollbackScopeActor rollback_scope(m_rollback,
3011 std::string("player:")+player->getName());
3014 0: start digging or punch object
3018 if(pointed.type == POINTEDTHING_NODE)
3021 NOTE: This can be used in the future to check if
3022 somebody is cheating, by checking the timing.
3024 MapNode n(CONTENT_IGNORE);
3027 n = m_env->getMap().getNode(p_under);
3029 catch(InvalidPositionException &e)
3031 infostream<<"Server: Not punching: Node not found."
3032 <<" Adding block to emerge queue."
3034 m_emerge_queue.addBlock(peer_id,
3035 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3037 if(n.getContent() != CONTENT_IGNORE)
3038 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3040 playersao->noCheatDigStart(p_under);
3042 else if(pointed.type == POINTEDTHING_OBJECT)
3044 // Skip if object has been removed
3045 if(pointed_object->m_removed)
3048 actionstream<<player->getName()<<" punches object "
3049 <<pointed.object_id<<": "
3050 <<pointed_object->getDescription()<<std::endl;
3052 ItemStack punchitem = playersao->getWieldedItem();
3053 ToolCapabilities toolcap =
3054 punchitem.getToolCapabilities(m_itemdef);
3055 v3f dir = (pointed_object->getBasePosition() -
3056 (player->getPosition() + player->getEyeOffset())
3058 float time_from_last_punch =
3059 playersao->resetTimeFromLastPunch();
3060 pointed_object->punch(dir, &toolcap, playersao,
3061 time_from_last_punch);
3069 else if(action == 1)
3074 2: Digging completed
3076 else if(action == 2)
3078 // Only digging of nodes
3079 if(pointed.type == POINTEDTHING_NODE)
3081 MapNode n(CONTENT_IGNORE);
3084 n = m_env->getMap().getNode(p_under);
3086 catch(InvalidPositionException &e)
3088 infostream<<"Server: Not finishing digging: Node not found."
3089 <<" Adding block to emerge queue."
3091 m_emerge_queue.addBlock(peer_id,
3092 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3095 /* Cheat prevention */
3096 bool is_valid_dig = true;
3097 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3099 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3100 float nocheat_t = playersao->getNoCheatDigTime();
3101 playersao->noCheatDigEnd();
3102 // If player didn't start digging this, ignore dig
3103 if(nocheat_p != p_under){
3104 infostream<<"Server: NoCheat: "<<player->getName()
3105 <<" started digging "
3106 <<PP(nocheat_p)<<" and completed digging "
3107 <<PP(p_under)<<"; not digging."<<std::endl;
3108 is_valid_dig = false;
3110 // Get player's wielded item
3111 ItemStack playeritem;
3112 InventoryList *mlist = playersao->getInventory()->getList("main");
3114 playeritem = mlist->getItem(playersao->getWieldIndex());
3115 ToolCapabilities playeritem_toolcap =
3116 playeritem.getToolCapabilities(m_itemdef);
3117 // Get diggability and expected digging time
3118 DigParams params = getDigParams(m_nodedef->get(n).groups,
3119 &playeritem_toolcap);
3120 // If can't dig, try hand
3121 if(!params.diggable){
3122 const ItemDefinition &hand = m_itemdef->get("");
3123 const ToolCapabilities *tp = hand.tool_capabilities;
3125 params = getDigParams(m_nodedef->get(n).groups, tp);
3127 // If can't dig, ignore dig
3128 if(!params.diggable){
3129 infostream<<"Server: NoCheat: "<<player->getName()
3130 <<" completed digging "<<PP(p_under)
3131 <<", which is not diggable with tool. not digging."
3133 is_valid_dig = false;
3135 // If time is considerably too short, ignore dig
3136 // Check time only for medium and slow timed digs
3137 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3138 infostream<<"Server: NoCheat: "<<player->getName()
3139 <<" completed digging "
3140 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3141 <<params.time<<"s; not digging."<<std::endl;
3142 is_valid_dig = false;
3146 /* Actually dig node */
3148 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3149 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3151 // Send unusual result (that is, node not being removed)
3152 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3154 // Re-send block to revert change on client-side
3155 RemoteClient *client = getClient(peer_id);
3156 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3157 client->SetBlockNotSent(blockpos);
3163 3: place block or right-click object
3165 else if(action == 3)
3167 ItemStack item = playersao->getWieldedItem();
3169 // Reset build time counter
3170 if(pointed.type == POINTEDTHING_NODE &&
3171 item.getDefinition(m_itemdef).type == ITEM_NODE)
3172 getClient(peer_id)->m_time_from_building = 0.0;
3174 if(pointed.type == POINTEDTHING_OBJECT)
3176 // Right click object
3178 // Skip if object has been removed
3179 if(pointed_object->m_removed)
3182 actionstream<<player->getName()<<" right-clicks object "
3183 <<pointed.object_id<<": "
3184 <<pointed_object->getDescription()<<std::endl;
3187 pointed_object->rightClick(playersao);
3189 else if(scriptapi_item_on_place(m_lua,
3190 item, playersao, pointed))
3192 // Placement was handled in lua
3194 // Apply returned ItemStack
3195 playersao->setWieldedItem(item);
3198 // If item has node placement prediction, always send the above
3199 // node to make sure the client knows what exactly happened
3200 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3201 RemoteClient *client = getClient(peer_id);
3202 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3203 client->SetBlockNotSent(blockpos);
3210 else if(action == 4)
3212 ItemStack item = playersao->getWieldedItem();
3214 actionstream<<player->getName()<<" uses "<<item.name
3215 <<", pointing at "<<pointed.dump()<<std::endl;
3217 if(scriptapi_item_on_use(m_lua,
3218 item, playersao, pointed))
3220 // Apply returned ItemStack
3221 playersao->setWieldedItem(item);
3228 Catch invalid actions
3232 infostream<<"WARNING: Server: Invalid action "
3233 <<action<<std::endl;
3236 else if(command == TOSERVER_REMOVED_SOUNDS)
3238 std::string datastring((char*)&data[2], datasize-2);
3239 std::istringstream is(datastring, std::ios_base::binary);
3241 int num = readU16(is);
3242 for(int k=0; k<num; k++){
3243 s32 id = readS32(is);
3244 std::map<s32, ServerPlayingSound>::iterator i =
3245 m_playing_sounds.find(id);
3246 if(i == m_playing_sounds.end())
3248 ServerPlayingSound &psound = i->second;
3249 psound.clients.erase(peer_id);
3250 if(psound.clients.size() == 0)
3251 m_playing_sounds.erase(i++);
3254 else if(command == TOSERVER_NODEMETA_FIELDS)
3256 std::string datastring((char*)&data[2], datasize-2);
3257 std::istringstream is(datastring, std::ios_base::binary);
3259 v3s16 p = readV3S16(is);
3260 std::string formname = deSerializeString(is);
3261 int num = readU16(is);
3262 std::map<std::string, std::string> fields;
3263 for(int k=0; k<num; k++){
3264 std::string fieldname = deSerializeString(is);
3265 std::string fieldvalue = deSerializeLongString(is);
3266 fields[fieldname] = fieldvalue;
3269 // If something goes wrong, this player is to blame
3270 RollbackScopeActor rollback_scope(m_rollback,
3271 std::string("player:")+player->getName());
3273 // Check the target node for rollback data; leave others unnoticed
3274 RollbackNode rn_old(&m_env->getMap(), p, this);
3276 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3279 // Report rollback data
3280 RollbackNode rn_new(&m_env->getMap(), p, this);
3281 if(rollback() && rn_new != rn_old){
3282 RollbackAction action;
3283 action.setSetNode(p, rn_old, rn_new);
3284 rollback()->reportAction(action);
3287 else if(command == TOSERVER_INVENTORY_FIELDS)
3289 std::string datastring((char*)&data[2], datasize-2);
3290 std::istringstream is(datastring, std::ios_base::binary);
3292 std::string formname = deSerializeString(is);
3293 int num = readU16(is);
3294 std::map<std::string, std::string> fields;
3295 for(int k=0; k<num; k++){
3296 std::string fieldname = deSerializeString(is);
3297 std::string fieldvalue = deSerializeLongString(is);
3298 fields[fieldname] = fieldvalue;
3301 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3305 infostream<<"Server::ProcessData(): Ignoring "
3306 "unknown command "<<command<<std::endl;
3310 catch(SendFailedException &e)
3312 errorstream<<"Server::ProcessData(): SendFailedException: "
3318 void Server::onMapEditEvent(MapEditEvent *event)
3320 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3321 if(m_ignore_map_edit_events)
3323 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3325 MapEditEvent *e = event->clone();
3326 m_unsent_map_edit_queue.push_back(e);
3329 Inventory* Server::getInventory(const InventoryLocation &loc)
3332 case InventoryLocation::UNDEFINED:
3335 case InventoryLocation::CURRENT_PLAYER:
3338 case InventoryLocation::PLAYER:
3340 Player *player = m_env->getPlayer(loc.name.c_str());
3343 PlayerSAO *playersao = player->getPlayerSAO();
3346 return playersao->getInventory();
3349 case InventoryLocation::NODEMETA:
3351 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3354 return meta->getInventory();
3357 case InventoryLocation::DETACHED:
3359 if(m_detached_inventories.count(loc.name) == 0)
3361 return m_detached_inventories[loc.name];
3369 void Server::setInventoryModified(const InventoryLocation &loc)
3372 case InventoryLocation::UNDEFINED:
3375 case InventoryLocation::PLAYER:
3377 Player *player = m_env->getPlayer(loc.name.c_str());
3380 PlayerSAO *playersao = player->getPlayerSAO();
3383 playersao->m_inventory_not_sent = true;
3384 playersao->m_wielded_item_not_sent = true;
3387 case InventoryLocation::NODEMETA:
3389 v3s16 blockpos = getNodeBlockPos(loc.p);
3391 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3393 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3395 setBlockNotSent(blockpos);
3398 case InventoryLocation::DETACHED:
3400 sendDetachedInventoryToAll(loc.name);
3408 core::list<PlayerInfo> Server::getPlayerInfo()
3410 DSTACK(__FUNCTION_NAME);
3411 JMutexAutoLock envlock(m_env_mutex);
3412 JMutexAutoLock conlock(m_con_mutex);
3414 core::list<PlayerInfo> list;
3416 core::list<Player*> players = m_env->getPlayers();
3418 core::list<Player*>::Iterator i;
3419 for(i = players.begin();
3420 i != players.end(); i++)
3424 Player *player = *i;
3427 // Copy info from connection to info struct
3428 info.id = player->peer_id;
3429 info.address = m_con.GetPeerAddress(player->peer_id);
3430 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3432 catch(con::PeerNotFoundException &e)
3434 // Set dummy peer info
3436 info.address = Address(0,0,0,0,0);
3440 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3441 info.position = player->getPosition();
3443 list.push_back(info);
3450 void Server::peerAdded(con::Peer *peer)
3452 DSTACK(__FUNCTION_NAME);
3453 verbosestream<<"Server::peerAdded(): peer->id="
3454 <<peer->id<<std::endl;
3457 c.type = PEER_ADDED;
3458 c.peer_id = peer->id;
3460 m_peer_change_queue.push_back(c);
3463 void Server::deletingPeer(con::Peer *peer, bool timeout)
3465 DSTACK(__FUNCTION_NAME);
3466 verbosestream<<"Server::deletingPeer(): peer->id="
3467 <<peer->id<<", timeout="<<timeout<<std::endl;
3470 c.type = PEER_REMOVED;
3471 c.peer_id = peer->id;
3472 c.timeout = timeout;
3473 m_peer_change_queue.push_back(c);
3480 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3482 DSTACK(__FUNCTION_NAME);
3483 std::ostringstream os(std::ios_base::binary);
3485 writeU16(os, TOCLIENT_HP);
3489 std::string s = os.str();
3490 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3492 con.Send(peer_id, 0, data, true);
3495 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3496 const std::wstring &reason)
3498 DSTACK(__FUNCTION_NAME);
3499 std::ostringstream os(std::ios_base::binary);
3501 writeU16(os, TOCLIENT_ACCESS_DENIED);
3502 os<<serializeWideString(reason);
3505 std::string s = os.str();
3506 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3508 con.Send(peer_id, 0, data, true);
3511 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3512 bool set_camera_point_target, v3f camera_point_target)
3514 DSTACK(__FUNCTION_NAME);
3515 std::ostringstream os(std::ios_base::binary);
3517 writeU16(os, TOCLIENT_DEATHSCREEN);
3518 writeU8(os, set_camera_point_target);
3519 writeV3F1000(os, camera_point_target);
3522 std::string s = os.str();
3523 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3525 con.Send(peer_id, 0, data, true);
3528 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3529 IItemDefManager *itemdef)
3531 DSTACK(__FUNCTION_NAME);
3532 std::ostringstream os(std::ios_base::binary);
3536 u32 length of the next item
3537 zlib-compressed serialized ItemDefManager
3539 writeU16(os, TOCLIENT_ITEMDEF);
3540 std::ostringstream tmp_os(std::ios::binary);
3541 itemdef->serialize(tmp_os);
3542 std::ostringstream tmp_os2(std::ios::binary);
3543 compressZlib(tmp_os.str(), tmp_os2);
3544 os<<serializeLongString(tmp_os2.str());
3547 std::string s = os.str();
3548 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3549 <<"): size="<<s.size()<<std::endl;
3550 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3552 con.Send(peer_id, 0, data, true);
3555 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3556 INodeDefManager *nodedef, u16 protocol_version)
3558 DSTACK(__FUNCTION_NAME);
3559 std::ostringstream os(std::ios_base::binary);
3563 u32 length of the next item
3564 zlib-compressed serialized NodeDefManager
3566 writeU16(os, TOCLIENT_NODEDEF);
3567 std::ostringstream tmp_os(std::ios::binary);
3568 nodedef->serialize(tmp_os, protocol_version);
3569 std::ostringstream tmp_os2(std::ios::binary);
3570 compressZlib(tmp_os.str(), tmp_os2);
3571 os<<serializeLongString(tmp_os2.str());
3574 std::string s = os.str();
3575 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3576 <<"): size="<<s.size()<<std::endl;
3577 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3579 con.Send(peer_id, 0, data, true);
3583 Non-static send methods
3586 void Server::SendInventory(u16 peer_id)
3588 DSTACK(__FUNCTION_NAME);
3590 PlayerSAO *playersao = getPlayerSAO(peer_id);
3593 playersao->m_inventory_not_sent = false;
3599 std::ostringstream os;
3600 playersao->getInventory()->serialize(os);
3602 std::string s = os.str();
3604 SharedBuffer<u8> data(s.size()+2);
3605 writeU16(&data[0], TOCLIENT_INVENTORY);
3606 memcpy(&data[2], s.c_str(), s.size());
3609 m_con.Send(peer_id, 0, data, true);
3612 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3614 DSTACK(__FUNCTION_NAME);
3616 std::ostringstream os(std::ios_base::binary);
3620 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3621 os.write((char*)buf, 2);
3624 writeU16(buf, message.size());
3625 os.write((char*)buf, 2);
3628 for(u32 i=0; i<message.size(); i++)
3632 os.write((char*)buf, 2);
3636 std::string s = os.str();
3637 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3639 m_con.Send(peer_id, 0, data, true);
3641 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3643 DSTACK(__FUNCTION_NAME);
3645 std::ostringstream os(std::ios_base::binary);
3649 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3650 os.write((char*)buf, 2);
3651 os<<serializeLongString(formspec);
3652 os<<serializeString(formname);
3655 std::string s = os.str();
3656 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3658 m_con.Send(peer_id, 0, data, true);
3661 void Server::BroadcastChatMessage(const std::wstring &message)
3663 for(core::map<u16, RemoteClient*>::Iterator
3664 i = m_clients.getIterator();
3665 i.atEnd() == false; i++)
3667 // Get client and check that it is valid
3668 RemoteClient *client = i.getNode()->getValue();
3669 assert(client->peer_id == i.getNode()->getKey());
3670 if(client->serialization_version == SER_FMT_VER_INVALID)
3673 SendChatMessage(client->peer_id, message);
3677 void Server::SendPlayerHP(u16 peer_id)
3679 DSTACK(__FUNCTION_NAME);
3680 PlayerSAO *playersao = getPlayerSAO(peer_id);
3682 playersao->m_hp_not_sent = false;
3683 SendHP(m_con, peer_id, playersao->getHP());
3686 void Server::SendMovePlayer(u16 peer_id)
3688 DSTACK(__FUNCTION_NAME);
3689 Player *player = m_env->getPlayer(peer_id);
3692 std::ostringstream os(std::ios_base::binary);
3693 writeU16(os, TOCLIENT_MOVE_PLAYER);
3694 writeV3F1000(os, player->getPosition());
3695 writeF1000(os, player->getPitch());
3696 writeF1000(os, player->getYaw());
3699 v3f pos = player->getPosition();
3700 f32 pitch = player->getPitch();
3701 f32 yaw = player->getYaw();
3702 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3703 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3710 std::string s = os.str();
3711 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3713 m_con.Send(peer_id, 0, data, true);
3716 void Server::SendPlayerPrivileges(u16 peer_id)
3718 Player *player = m_env->getPlayer(peer_id);
3720 if(player->peer_id == PEER_ID_INEXISTENT)
3723 std::set<std::string> privs;
3724 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3726 std::ostringstream os(std::ios_base::binary);
3727 writeU16(os, TOCLIENT_PRIVILEGES);
3728 writeU16(os, privs.size());
3729 for(std::set<std::string>::const_iterator i = privs.begin();
3730 i != privs.end(); i++){
3731 os<<serializeString(*i);
3735 std::string s = os.str();
3736 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3738 m_con.Send(peer_id, 0, data, true);
3741 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3743 Player *player = m_env->getPlayer(peer_id);
3745 if(player->peer_id == PEER_ID_INEXISTENT)
3748 std::ostringstream os(std::ios_base::binary);
3749 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3750 os<<serializeLongString(player->inventory_formspec);
3753 std::string s = os.str();
3754 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3756 m_con.Send(peer_id, 0, data, true);
3759 s32 Server::playSound(const SimpleSoundSpec &spec,
3760 const ServerSoundParams ¶ms)
3762 // Find out initial position of sound
3763 bool pos_exists = false;
3764 v3f pos = params.getPos(m_env, &pos_exists);
3765 // If position is not found while it should be, cancel sound
3766 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3768 // Filter destination clients
3769 std::set<RemoteClient*> dst_clients;
3770 if(params.to_player != "")
3772 Player *player = m_env->getPlayer(params.to_player.c_str());
3774 infostream<<"Server::playSound: Player \""<<params.to_player
3775 <<"\" not found"<<std::endl;
3778 if(player->peer_id == PEER_ID_INEXISTENT){
3779 infostream<<"Server::playSound: Player \""<<params.to_player
3780 <<"\" not connected"<<std::endl;
3783 RemoteClient *client = getClient(player->peer_id);
3784 dst_clients.insert(client);
3788 for(core::map<u16, RemoteClient*>::Iterator
3789 i = m_clients.getIterator(); i.atEnd() == false; i++)
3791 RemoteClient *client = i.getNode()->getValue();
3792 Player *player = m_env->getPlayer(client->peer_id);
3796 if(player->getPosition().getDistanceFrom(pos) >
3797 params.max_hear_distance)
3800 dst_clients.insert(client);
3803 if(dst_clients.size() == 0)
3806 s32 id = m_next_sound_id++;
3807 // The sound will exist as a reference in m_playing_sounds
3808 m_playing_sounds[id] = ServerPlayingSound();
3809 ServerPlayingSound &psound = m_playing_sounds[id];
3810 psound.params = params;
3811 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3812 i != dst_clients.end(); i++)
3813 psound.clients.insert((*i)->peer_id);
3815 std::ostringstream os(std::ios_base::binary);
3816 writeU16(os, TOCLIENT_PLAY_SOUND);
3818 os<<serializeString(spec.name);
3819 writeF1000(os, spec.gain * params.gain);
3820 writeU8(os, params.type);
3821 writeV3F1000(os, pos);
3822 writeU16(os, params.object);
3823 writeU8(os, params.loop);
3825 std::string s = os.str();
3826 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3828 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3829 i != dst_clients.end(); i++){
3831 m_con.Send((*i)->peer_id, 0, data, true);
3835 void Server::stopSound(s32 handle)
3837 // Get sound reference
3838 std::map<s32, ServerPlayingSound>::iterator i =
3839 m_playing_sounds.find(handle);
3840 if(i == m_playing_sounds.end())
3842 ServerPlayingSound &psound = i->second;
3844 std::ostringstream os(std::ios_base::binary);
3845 writeU16(os, TOCLIENT_STOP_SOUND);
3846 writeS32(os, handle);
3848 std::string s = os.str();
3849 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3851 for(std::set<u16>::iterator i = psound.clients.begin();
3852 i != psound.clients.end(); i++){
3854 m_con.Send(*i, 0, data, true);
3856 // Remove sound reference
3857 m_playing_sounds.erase(i);
3860 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3861 core::list<u16> *far_players, float far_d_nodes)
3863 float maxd = far_d_nodes*BS;
3864 v3f p_f = intToFloat(p, BS);
3868 SharedBuffer<u8> reply(replysize);
3869 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3870 writeS16(&reply[2], p.X);
3871 writeS16(&reply[4], p.Y);
3872 writeS16(&reply[6], p.Z);
3874 for(core::map<u16, RemoteClient*>::Iterator
3875 i = m_clients.getIterator();
3876 i.atEnd() == false; i++)
3878 // Get client and check that it is valid
3879 RemoteClient *client = i.getNode()->getValue();
3880 assert(client->peer_id == i.getNode()->getKey());
3881 if(client->serialization_version == SER_FMT_VER_INVALID)
3884 // Don't send if it's the same one
3885 if(client->peer_id == ignore_id)
3891 Player *player = m_env->getPlayer(client->peer_id);
3894 // If player is far away, only set modified blocks not sent
3895 v3f player_pos = player->getPosition();
3896 if(player_pos.getDistanceFrom(p_f) > maxd)
3898 far_players->push_back(client->peer_id);
3905 m_con.Send(client->peer_id, 0, reply, true);
3909 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3910 core::list<u16> *far_players, float far_d_nodes)
3912 float maxd = far_d_nodes*BS;
3913 v3f p_f = intToFloat(p, BS);
3915 for(core::map<u16, RemoteClient*>::Iterator
3916 i = m_clients.getIterator();
3917 i.atEnd() == false; i++)
3919 // Get client and check that it is valid
3920 RemoteClient *client = i.getNode()->getValue();
3921 assert(client->peer_id == i.getNode()->getKey());
3922 if(client->serialization_version == SER_FMT_VER_INVALID)
3925 // Don't send if it's the same one
3926 if(client->peer_id == ignore_id)
3932 Player *player = m_env->getPlayer(client->peer_id);
3935 // If player is far away, only set modified blocks not sent
3936 v3f player_pos = player->getPosition();
3937 if(player_pos.getDistanceFrom(p_f) > maxd)
3939 far_players->push_back(client->peer_id);
3946 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3947 SharedBuffer<u8> reply(replysize);
3948 writeU16(&reply[0], TOCLIENT_ADDNODE);
3949 writeS16(&reply[2], p.X);
3950 writeS16(&reply[4], p.Y);
3951 writeS16(&reply[6], p.Z);
3952 n.serialize(&reply[8], client->serialization_version);
3955 m_con.Send(client->peer_id, 0, reply, true);
3959 void Server::setBlockNotSent(v3s16 p)
3961 for(core::map<u16, RemoteClient*>::Iterator
3962 i = m_clients.getIterator();
3963 i.atEnd()==false; i++)
3965 RemoteClient *client = i.getNode()->getValue();
3966 client->SetBlockNotSent(p);
3970 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3972 DSTACK(__FUNCTION_NAME);
3974 v3s16 p = block->getPos();
3978 bool completely_air = true;
3979 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3980 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3981 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3983 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3985 completely_air = false;
3986 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3991 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3993 infostream<<"[completely air] ";
3994 infostream<<std::endl;
3998 Create a packet with the block in the right format
4001 std::ostringstream os(std::ios_base::binary);
4002 block->serialize(os, ver, false);
4003 std::string s = os.str();
4004 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4006 u32 replysize = 8 + blockdata.getSize();
4007 SharedBuffer<u8> reply(replysize);
4008 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4009 writeS16(&reply[2], p.X);
4010 writeS16(&reply[4], p.Y);
4011 writeS16(&reply[6], p.Z);
4012 memcpy(&reply[8], *blockdata, blockdata.getSize());
4014 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4015 <<": \tpacket size: "<<replysize<<std::endl;*/
4020 m_con.Send(peer_id, 1, reply, true);
4023 void Server::SendBlocks(float dtime)
4025 DSTACK(__FUNCTION_NAME);
4027 JMutexAutoLock envlock(m_env_mutex);
4028 JMutexAutoLock conlock(m_con_mutex);
4030 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4032 core::array<PrioritySortedBlockTransfer> queue;
4034 s32 total_sending = 0;
4037 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4039 for(core::map<u16, RemoteClient*>::Iterator
4040 i = m_clients.getIterator();
4041 i.atEnd() == false; i++)
4043 RemoteClient *client = i.getNode()->getValue();
4044 assert(client->peer_id == i.getNode()->getKey());
4046 // If definitions and textures have not been sent, don't
4047 // send MapBlocks either
4048 if(!client->definitions_sent)
4051 total_sending += client->SendingCount();
4053 if(client->serialization_version == SER_FMT_VER_INVALID)
4056 client->GetNextBlocks(this, dtime, queue);
4061 // Lowest priority number comes first.
4062 // Lowest is most important.
4065 for(u32 i=0; i<queue.size(); i++)
4067 //TODO: Calculate limit dynamically
4068 if(total_sending >= g_settings->getS32
4069 ("max_simultaneous_block_sends_server_total"))
4072 PrioritySortedBlockTransfer q = queue[i];
4074 MapBlock *block = NULL;
4077 block = m_env->getMap().getBlockNoCreate(q.pos);
4079 catch(InvalidPositionException &e)
4084 RemoteClient *client = getClient(q.peer_id);
4086 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4088 client->SentBlock(q.pos);
4094 void Server::fillMediaCache()
4096 DSTACK(__FUNCTION_NAME);
4098 infostream<<"Server: Calculating media file checksums"<<std::endl;
4100 // Collect all media file paths
4101 std::list<std::string> paths;
4102 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4103 i != m_mods.end(); i++){
4104 const ModSpec &mod = *i;
4105 paths.push_back(mod.path + DIR_DELIM + "textures");
4106 paths.push_back(mod.path + DIR_DELIM + "sounds");
4107 paths.push_back(mod.path + DIR_DELIM + "media");
4108 paths.push_back(mod.path + DIR_DELIM + "models");
4110 std::string path_all = "textures";
4111 paths.push_back(path_all + DIR_DELIM + "all");
4113 // Collect media file information from paths into cache
4114 for(std::list<std::string>::iterator i = paths.begin();
4115 i != paths.end(); i++)
4117 std::string mediapath = *i;
4118 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4119 for(u32 j=0; j<dirlist.size(); j++){
4120 if(dirlist[j].dir) // Ignode dirs
4122 std::string filename = dirlist[j].name;
4123 // If name contains illegal characters, ignore the file
4124 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4125 infostream<<"Server: ignoring illegal file name: \""
4126 <<filename<<"\""<<std::endl;
4129 // If name is not in a supported format, ignore it
4130 const char *supported_ext[] = {
4131 ".png", ".jpg", ".bmp", ".tga",
4132 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4134 ".x", ".b3d", ".md2", ".obj",
4137 if(removeStringEnd(filename, supported_ext) == ""){
4138 infostream<<"Server: ignoring unsupported file extension: \""
4139 <<filename<<"\""<<std::endl;
4142 // Ok, attempt to load the file and add to cache
4143 std::string filepath = mediapath + DIR_DELIM + filename;
4145 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4146 if(fis.good() == false){
4147 errorstream<<"Server::fillMediaCache(): Could not open \""
4148 <<filename<<"\" for reading"<<std::endl;
4151 std::ostringstream tmp_os(std::ios_base::binary);
4155 fis.read(buf, 1024);
4156 std::streamsize len = fis.gcount();
4157 tmp_os.write(buf, len);
4166 errorstream<<"Server::fillMediaCache(): Failed to read \""
4167 <<filename<<"\""<<std::endl;
4170 if(tmp_os.str().length() == 0){
4171 errorstream<<"Server::fillMediaCache(): Empty file \""
4172 <<filepath<<"\""<<std::endl;
4177 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4179 unsigned char *digest = sha1.getDigest();
4180 std::string sha1_base64 = base64_encode(digest, 20);
4181 std::string sha1_hex = hex_encode((char*)digest, 20);
4185 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4186 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4191 struct SendableMediaAnnouncement
4194 std::string sha1_digest;
4196 SendableMediaAnnouncement(const std::string name_="",
4197 const std::string sha1_digest_=""):
4199 sha1_digest(sha1_digest_)
4203 void Server::sendMediaAnnouncement(u16 peer_id)
4205 DSTACK(__FUNCTION_NAME);
4207 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4210 core::list<SendableMediaAnnouncement> file_announcements;
4212 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4213 i != m_media.end(); i++){
4215 file_announcements.push_back(
4216 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4220 std::ostringstream os(std::ios_base::binary);
4228 u16 length of sha1_digest
4233 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4234 writeU16(os, file_announcements.size());
4236 for(core::list<SendableMediaAnnouncement>::Iterator
4237 j = file_announcements.begin();
4238 j != file_announcements.end(); j++){
4239 os<<serializeString(j->name);
4240 os<<serializeString(j->sha1_digest);
4242 os<<serializeString(g_settings->get("remote_media"));
4245 std::string s = os.str();
4246 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4249 m_con.Send(peer_id, 0, data, true);
4252 struct SendableMedia
4258 SendableMedia(const std::string &name_="", const std::string path_="",
4259 const std::string &data_=""):
4266 void Server::sendRequestedMedia(u16 peer_id,
4267 const core::list<MediaRequest> &tosend)
4269 DSTACK(__FUNCTION_NAME);
4271 verbosestream<<"Server::sendRequestedMedia(): "
4272 <<"Sending files to client"<<std::endl;
4276 // Put 5kB in one bunch (this is not accurate)
4277 u32 bytes_per_bunch = 5000;
4279 core::array< core::list<SendableMedia> > file_bunches;
4280 file_bunches.push_back(core::list<SendableMedia>());
4282 u32 file_size_bunch_total = 0;
4284 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4285 i != tosend.end(); i++)
4287 if(m_media.find(i->name) == m_media.end()){
4288 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4289 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4293 //TODO get path + name
4294 std::string tpath = m_media[(*i).name].path;
4297 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4298 if(fis.good() == false){
4299 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4300 <<tpath<<"\" for reading"<<std::endl;
4303 std::ostringstream tmp_os(std::ios_base::binary);
4307 fis.read(buf, 1024);
4308 std::streamsize len = fis.gcount();
4309 tmp_os.write(buf, len);
4310 file_size_bunch_total += len;
4319 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4320 <<(*i).name<<"\""<<std::endl;
4323 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4324 <<tname<<"\""<<std::endl;*/
4326 file_bunches[file_bunches.size()-1].push_back(
4327 SendableMedia((*i).name, tpath, tmp_os.str()));
4329 // Start next bunch if got enough data
4330 if(file_size_bunch_total >= bytes_per_bunch){
4331 file_bunches.push_back(core::list<SendableMedia>());
4332 file_size_bunch_total = 0;
4337 /* Create and send packets */
4339 u32 num_bunches = file_bunches.size();
4340 for(u32 i=0; i<num_bunches; i++)
4342 std::ostringstream os(std::ios_base::binary);
4346 u16 total number of texture bunches
4347 u16 index of this bunch
4348 u32 number of files in this bunch
4357 writeU16(os, TOCLIENT_MEDIA);
4358 writeU16(os, num_bunches);
4360 writeU32(os, file_bunches[i].size());
4362 for(core::list<SendableMedia>::Iterator
4363 j = file_bunches[i].begin();
4364 j != file_bunches[i].end(); j++){
4365 os<<serializeString(j->name);
4366 os<<serializeLongString(j->data);
4370 std::string s = os.str();
4371 verbosestream<<"Server::sendRequestedMedia(): bunch "
4372 <<i<<"/"<<num_bunches
4373 <<" files="<<file_bunches[i].size()
4374 <<" size=" <<s.size()<<std::endl;
4375 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4377 m_con.Send(peer_id, 0, data, true);
4381 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4383 if(m_detached_inventories.count(name) == 0){
4384 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4387 Inventory *inv = m_detached_inventories[name];
4389 std::ostringstream os(std::ios_base::binary);
4390 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4391 os<<serializeString(name);
4395 std::string s = os.str();
4396 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4398 m_con.Send(peer_id, 0, data, true);
4401 void Server::sendDetachedInventoryToAll(const std::string &name)
4403 DSTACK(__FUNCTION_NAME);
4405 for(core::map<u16, RemoteClient*>::Iterator
4406 i = m_clients.getIterator();
4407 i.atEnd() == false; i++){
4408 RemoteClient *client = i.getNode()->getValue();
4409 sendDetachedInventory(name, client->peer_id);
4413 void Server::sendDetachedInventories(u16 peer_id)
4415 DSTACK(__FUNCTION_NAME);
4417 for(std::map<std::string, Inventory*>::iterator
4418 i = m_detached_inventories.begin();
4419 i != m_detached_inventories.end(); i++){
4420 const std::string &name = i->first;
4421 //Inventory *inv = i->second;
4422 sendDetachedInventory(name, peer_id);
4430 void Server::DiePlayer(u16 peer_id)
4432 DSTACK(__FUNCTION_NAME);
4434 PlayerSAO *playersao = getPlayerSAO(peer_id);
4437 infostream<<"Server::DiePlayer(): Player "
4438 <<playersao->getPlayer()->getName()
4439 <<" dies"<<std::endl;
4441 playersao->setHP(0);
4443 // Trigger scripted stuff
4444 scriptapi_on_dieplayer(m_lua, playersao);
4446 SendPlayerHP(peer_id);
4447 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4450 void Server::RespawnPlayer(u16 peer_id)
4452 DSTACK(__FUNCTION_NAME);
4454 PlayerSAO *playersao = getPlayerSAO(peer_id);
4457 infostream<<"Server::RespawnPlayer(): Player "
4458 <<playersao->getPlayer()->getName()
4459 <<" respawns"<<std::endl;
4461 playersao->setHP(PLAYER_MAX_HP);
4463 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4465 v3f pos = findSpawnPos(m_env->getServerMap());
4466 playersao->setPos(pos);
4470 void Server::UpdateCrafting(u16 peer_id)
4472 DSTACK(__FUNCTION_NAME);
4474 Player* player = m_env->getPlayer(peer_id);
4477 // Get a preview for crafting
4479 getCraftingResult(&player->inventory, preview, false, this);
4481 // Put the new preview in
4482 InventoryList *plist = player->inventory.getList("craftpreview");
4484 assert(plist->getSize() >= 1);
4485 plist->changeItem(0, preview);
4488 RemoteClient* Server::getClient(u16 peer_id)
4490 DSTACK(__FUNCTION_NAME);
4491 //JMutexAutoLock lock(m_con_mutex);
4492 core::map<u16, RemoteClient*>::Node *n;
4493 n = m_clients.find(peer_id);
4494 // A client should exist for all peers
4496 return n->getValue();
4499 std::wstring Server::getStatusString()
4501 std::wostringstream os(std::ios_base::binary);
4504 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4506 os<<L", uptime="<<m_uptime.get();
4507 // Information about clients
4508 core::map<u16, RemoteClient*>::Iterator i;
4511 for(i = m_clients.getIterator(), first = true;
4512 i.atEnd() == false; i++)
4514 // Get client and check that it is valid
4515 RemoteClient *client = i.getNode()->getValue();
4516 assert(client->peer_id == i.getNode()->getKey());
4517 if(client->serialization_version == SER_FMT_VER_INVALID)
4520 Player *player = m_env->getPlayer(client->peer_id);
4521 // Get name of player
4522 std::wstring name = L"unknown";
4524 name = narrow_to_wide(player->getName());
4525 // Add name to information string
4533 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4534 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4535 if(g_settings->get("motd") != "")
4536 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4540 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4542 std::set<std::string> privs;
4543 scriptapi_get_auth(m_lua, name, NULL, &privs);
4547 bool Server::checkPriv(const std::string &name, const std::string &priv)
4549 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4550 return (privs.count(priv) != 0);
4553 void Server::reportPrivsModified(const std::string &name)
4556 for(core::map<u16, RemoteClient*>::Iterator
4557 i = m_clients.getIterator();
4558 i.atEnd() == false; i++){
4559 RemoteClient *client = i.getNode()->getValue();
4560 Player *player = m_env->getPlayer(client->peer_id);
4561 reportPrivsModified(player->getName());
4564 Player *player = m_env->getPlayer(name.c_str());
4567 SendPlayerPrivileges(player->peer_id);
4568 PlayerSAO *sao = player->getPlayerSAO();
4571 sao->updatePrivileges(
4572 getPlayerEffectivePrivs(name),
4577 void Server::reportInventoryFormspecModified(const std::string &name)
4579 Player *player = m_env->getPlayer(name.c_str());
4582 SendPlayerInventoryFormspec(player->peer_id);
4585 // Saves g_settings to configpath given at initialization
4586 void Server::saveConfig()
4588 if(m_path_config != "")
4589 g_settings->updateConfigFile(m_path_config.c_str());
4592 void Server::notifyPlayer(const char *name, const std::wstring msg)
4594 Player *player = m_env->getPlayer(name);
4597 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4600 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4602 Player *player = m_env->getPlayer(playername);
4606 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4610 SendShowFormspecMessage(player->peer_id, formspec, formname);
4614 void Server::notifyPlayers(const std::wstring msg)
4616 BroadcastChatMessage(msg);
4619 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4623 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4624 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4627 Inventory* Server::createDetachedInventory(const std::string &name)
4629 if(m_detached_inventories.count(name) > 0){
4630 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4631 delete m_detached_inventories[name];
4633 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4635 Inventory *inv = new Inventory(m_itemdef);
4637 m_detached_inventories[name] = inv;
4638 sendDetachedInventoryToAll(name);
4645 BoolScopeSet(bool *dst, bool val):
4648 m_orig_state = *m_dst;
4653 *m_dst = m_orig_state;
4660 // actions: time-reversed list
4661 // Return value: success/failure
4662 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4663 std::list<std::string> *log)
4665 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4666 ServerMap *map = (ServerMap*)(&m_env->getMap());
4667 // Disable rollback report sink while reverting
4668 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4670 // Fail if no actions to handle
4671 if(actions.empty()){
4672 log->push_back("Nothing to do.");
4679 for(std::list<RollbackAction>::const_iterator
4680 i = actions.begin();
4681 i != actions.end(); i++)
4683 const RollbackAction &action = *i;
4685 bool success = action.applyRevert(map, this, this);
4688 std::ostringstream os;
4689 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4690 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4692 log->push_back(os.str());
4694 std::ostringstream os;
4695 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4696 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4698 log->push_back(os.str());
4702 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4703 <<" failed"<<std::endl;
4705 // Call it done if less than half failed
4706 return num_failed <= num_tried/2;
4709 // IGameDef interface
4711 IItemDefManager* Server::getItemDefManager()
4715 INodeDefManager* Server::getNodeDefManager()
4719 ICraftDefManager* Server::getCraftDefManager()
4723 ITextureSource* Server::getTextureSource()
4727 IShaderSource* Server::getShaderSource()
4731 u16 Server::allocateUnknownNodeId(const std::string &name)
4733 return m_nodedef->allocateDummy(name);
4735 ISoundManager* Server::getSoundManager()
4737 return &dummySoundManager;
4739 MtEventManager* Server::getEventManager()
4743 IRollbackReportSink* Server::getRollbackReportSink()
4745 if(!m_enable_rollback_recording)
4747 if(!m_rollback_sink_enabled)
4752 IWritableItemDefManager* Server::getWritableItemDefManager()
4756 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4760 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4765 const ModSpec* Server::getModSpec(const std::string &modname)
4767 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4768 i != m_mods.end(); i++){
4769 const ModSpec &mod = *i;
4770 if(mod.name == modname)
4775 void Server::getModNames(core::list<std::string> &modlist)
4777 for(core::list<ModSpec>::Iterator i = m_mods.begin(); i != m_mods.end(); i++)
4779 modlist.push_back((*i).name);
4782 std::string Server::getBuiltinLuaPath()
4784 return porting::path_share + DIR_DELIM + "builtin";
4787 v3f findSpawnPos(ServerMap &map)
4789 //return v3f(50,50,50)*BS;
4794 nodepos = v2s16(0,0);
4799 // Try to find a good place a few times
4800 for(s32 i=0; i<1000; i++)
4803 // We're going to try to throw the player to this position
4804 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4805 -range + (myrand()%(range*2)));
4806 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4807 // Get ground height at point (fallbacks to heightmap function)
4808 s16 groundheight = map.findGroundLevel(nodepos2d);
4809 // Don't go underwater
4810 if(groundheight < WATER_LEVEL)
4812 //infostream<<"-> Underwater"<<std::endl;
4815 // Don't go to high places
4816 if(groundheight > WATER_LEVEL + 4)
4818 //infostream<<"-> Underwater"<<std::endl;
4822 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4823 bool is_good = false;
4825 for(s32 i=0; i<10; i++){
4826 v3s16 blockpos = getNodeBlockPos(nodepos);
4827 map.emergeBlock(blockpos, true);
4828 MapNode n = map.getNodeNoEx(nodepos);
4829 if(n.getContent() == CONTENT_AIR){
4840 // Found a good place
4841 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4847 return intToFloat(nodepos, BS);
4850 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4852 RemotePlayer *player = NULL;
4853 bool newplayer = false;
4856 Try to get an existing player
4858 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4860 // If player is already connected, cancel
4861 if(player != NULL && player->peer_id != 0)
4863 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4868 If player with the wanted peer_id already exists, cancel.
4870 if(m_env->getPlayer(peer_id) != NULL)
4872 infostream<<"emergePlayer(): Player with wrong name but same"
4873 " peer_id already exists"<<std::endl;
4878 Create a new player if it doesn't exist yet
4883 player = new RemotePlayer(this);
4884 player->updateName(name);
4886 /* Set player position */
4887 infostream<<"Server: Finding spawn place for player \""
4888 <<name<<"\""<<std::endl;
4889 v3f pos = findSpawnPos(m_env->getServerMap());
4890 player->setPosition(pos);
4892 /* Add player to environment */
4893 m_env->addPlayer(player);
4897 Create a new player active object
4899 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4900 getPlayerEffectivePrivs(player->getName()),
4903 /* Add object to environment */
4904 m_env->addActiveObject(playersao);
4908 scriptapi_on_newplayer(m_lua, playersao);
4910 scriptapi_on_joinplayer(m_lua, playersao);
4915 void Server::handlePeerChange(PeerChange &c)
4917 JMutexAutoLock envlock(m_env_mutex);
4918 JMutexAutoLock conlock(m_con_mutex);
4920 if(c.type == PEER_ADDED)
4927 core::map<u16, RemoteClient*>::Node *n;
4928 n = m_clients.find(c.peer_id);
4929 // The client shouldn't already exist
4933 RemoteClient *client = new RemoteClient();
4934 client->peer_id = c.peer_id;
4935 m_clients.insert(client->peer_id, client);
4938 else if(c.type == PEER_REMOVED)
4945 core::map<u16, RemoteClient*>::Node *n;
4946 n = m_clients.find(c.peer_id);
4947 // The client should exist
4951 Mark objects to be not known by the client
4953 RemoteClient *client = n->getValue();
4955 for(core::map<u16, bool>::Iterator
4956 i = client->m_known_objects.getIterator();
4957 i.atEnd()==false; i++)
4960 u16 id = i.getNode()->getKey();
4961 ServerActiveObject* obj = m_env->getActiveObject(id);
4963 if(obj && obj->m_known_by_count > 0)
4964 obj->m_known_by_count--;
4968 Clear references to playing sounds
4970 for(std::map<s32, ServerPlayingSound>::iterator
4971 i = m_playing_sounds.begin();
4972 i != m_playing_sounds.end();)
4974 ServerPlayingSound &psound = i->second;
4975 psound.clients.erase(c.peer_id);
4976 if(psound.clients.size() == 0)
4977 m_playing_sounds.erase(i++);
4982 Player *player = m_env->getPlayer(c.peer_id);
4984 // Collect information about leaving in chat
4985 std::wstring message;
4989 std::wstring name = narrow_to_wide(player->getName());
4992 message += L" left the game.";
4994 message += L" (timed out)";
4998 /* Run scripts and remove from environment */
5002 PlayerSAO *playersao = player->getPlayerSAO();
5005 scriptapi_on_leaveplayer(m_lua, playersao);
5007 playersao->disconnected();
5017 std::ostringstream os(std::ios_base::binary);
5018 for(core::map<u16, RemoteClient*>::Iterator
5019 i = m_clients.getIterator();
5020 i.atEnd() == false; i++)
5022 RemoteClient *client = i.getNode()->getValue();
5023 assert(client->peer_id == i.getNode()->getKey());
5024 if(client->serialization_version == SER_FMT_VER_INVALID)
5027 Player *player = m_env->getPlayer(client->peer_id);
5030 // Get name of player
5031 os<<player->getName()<<" ";
5034 actionstream<<player->getName()<<" "
5035 <<(c.timeout?"times out.":"leaves game.")
5036 <<" List of players: "
5037 <<os.str()<<std::endl;
5042 delete m_clients[c.peer_id];
5043 m_clients.remove(c.peer_id);
5045 // Send player info to all remaining clients
5046 //SendPlayerInfos();
5048 // Send leave chat message to all remaining clients
5049 if(message.length() != 0)
5050 BroadcastChatMessage(message);
5059 void Server::handlePeerChanges()
5061 while(m_peer_change_queue.size() > 0)
5063 PeerChange c = m_peer_change_queue.pop_front();
5065 verbosestream<<"Server: Handling peer change: "
5066 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5069 handlePeerChange(c);
5073 void dedicated_server_loop(Server &server, bool &kill)
5075 DSTACK(__FUNCTION_NAME);
5077 verbosestream<<"dedicated_server_loop()"<<std::endl;
5079 IntervalLimiter m_profiler_interval;
5083 float steplen = g_settings->getFloat("dedicated_server_step");
5084 // This is kind of a hack but can be done like this
5085 // because server.step() is very light
5087 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5088 sleep_ms((int)(steplen*1000.0));
5090 server.step(steplen);
5092 if(server.getShutdownRequested() || kill)
5094 infostream<<"Dedicated server quitting"<<std::endl;
5101 float profiler_print_interval =
5102 g_settings->getFloat("profiler_print_interval");
5103 if(profiler_print_interval != 0)
5105 if(m_profiler_interval.step(steplen, profiler_print_interval))
5107 infostream<<"Profiler:"<<std::endl;
5108 g_profiler->print(infostream);
5109 g_profiler->clear();