3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "clientserver.h"
25 #include "jmutexautolock.h"
27 #include "constants.h"
32 #include "serverobject.h"
37 #include "scriptapi.h"
42 #include "content_mapnode.h"
43 #include "content_nodemeta.h"
44 #include "content_abm.h"
45 #include "content_sao.h"
50 #include "sound.h" // dummySoundManager
51 #include "event_manager.h"
53 #include "util/string.h"
54 #include "util/pointedthing.h"
55 #include "util/mathconstants.h"
57 #include "util/serialize.h"
59 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
61 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
63 class MapEditEventIgnorer
66 MapEditEventIgnorer(bool *flag):
75 ~MapEditEventIgnorer()
88 class MapEditEventAreaIgnorer
91 MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
92 m_ignorevariable(ignorevariable)
94 if(m_ignorevariable->getVolume() == 0)
95 *m_ignorevariable = a;
97 m_ignorevariable = NULL;
100 ~MapEditEventAreaIgnorer()
104 assert(m_ignorevariable->getVolume() != 0);
105 *m_ignorevariable = VoxelArea();
110 VoxelArea *m_ignorevariable;
113 void * ServerThread::Thread()
117 log_register_thread("ServerThread");
119 DSTACK(__FUNCTION_NAME);
121 BEGIN_DEBUG_EXCEPTION_HANDLER
126 //TimeTaker timer("AsyncRunStep() + Receive()");
129 //TimeTaker timer("AsyncRunStep()");
130 m_server->AsyncRunStep();
133 //infostream<<"Running m_server->Receive()"<<std::endl;
136 catch(con::NoIncomingDataException &e)
139 catch(con::PeerNotFoundException &e)
141 infostream<<"Server: PeerNotFoundException"<<std::endl;
143 catch(con::ConnectionBindFailed &e)
145 m_server->setAsyncFatalError(e.what());
149 m_server->setAsyncFatalError(e.what());
153 END_DEBUG_EXCEPTION_HANDLER(errorstream)
158 void * EmergeThread::Thread()
162 log_register_thread("EmergeThread");
164 DSTACK(__FUNCTION_NAME);
166 BEGIN_DEBUG_EXCEPTION_HANDLER
168 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
170 v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
173 Get block info from queue, emerge them and send them
176 After queue is empty, exit.
180 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
184 SharedPtr<QueuedBlockEmerge> q(qptr);
192 Do not generate over-limit
194 if(blockpos_over_limit(p))
197 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
199 //TimeTaker timer("block emerge");
202 Try to emerge it from somewhere.
204 If it is only wanted as optional, only loading from disk
209 Check if any peer wants it as non-optional. In that case it
212 Also decrement the emerge queue count in clients.
215 bool only_from_disk = true;
218 core::map<u16, u8>::Iterator i;
219 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
221 //u16 peer_id = i.getNode()->getKey();
224 u8 flags = i.getNode()->getValue();
225 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
226 only_from_disk = false;
231 if(enable_mapgen_debug_info)
232 infostream<<"EmergeThread: p="
233 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
234 <<"only_from_disk="<<only_from_disk<<std::endl;
236 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
238 MapBlock *block = NULL;
239 bool got_block = true;
240 core::map<v3s16, MapBlock*> modified_blocks;
243 Try to fetch block from memory or disk.
244 If not found and asked to generate, initialize generator.
247 bool started_generate = false;
248 mapgen::BlockMakeData data;
251 JMutexAutoLock envlock(m_server->m_env_mutex);
253 // Load sector if it isn't loaded
254 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
255 map.loadSectorMeta(p2d);
257 // Attempt to load block
258 block = map.getBlockNoCreateNoEx(p);
259 if(!block || block->isDummy() || !block->isGenerated())
261 if(enable_mapgen_debug_info)
262 infostream<<"EmergeThread: not in memory, "
263 <<"attempting to load from disk"<<std::endl;
265 block = map.loadBlock(p);
268 // If could not load and allowed to generate, start generation
269 // inside this same envlock
270 if(only_from_disk == false &&
271 (block == NULL || block->isGenerated() == false)){
272 if(enable_mapgen_debug_info)
273 infostream<<"EmergeThread: generating"<<std::endl;
274 started_generate = true;
276 map.initBlockMake(&data, p);
281 If generator was initialized, generate now when envlock is free.
286 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
288 TimeTaker t("mapgen::make_block()");
290 mapgen::make_block(&data);
292 if(enable_mapgen_debug_info == false)
293 t.stop(true); // Hide output
297 // Lock environment again to access the map
298 JMutexAutoLock envlock(m_server->m_env_mutex);
300 ScopeProfiler sp(g_profiler, "EmergeThread: after "
301 "mapgen::make_block (envlock)", SPT_AVG);
303 // Blit data back on map, update lighting, add mobs and
304 // whatever this does
305 map.finishBlockMake(&data, modified_blocks);
308 block = map.getBlockNoCreateNoEx(p);
310 // If block doesn't exist, don't try doing anything with it
311 // This happens if the block is not in generation boundaries
316 Do some post-generate stuff
319 v3s16 minp = data.blockpos_min*MAP_BLOCKSIZE;
320 v3s16 maxp = data.blockpos_max*MAP_BLOCKSIZE +
321 v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
324 Ignore map edit events, they will not need to be
325 sent to anybody because the block hasn't been sent
328 //MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
329 MapEditEventAreaIgnorer ign(
330 &m_server->m_ignore_map_edit_events_area,
331 VoxelArea(minp, maxp));
333 TimeTaker timer("on_generated");
334 scriptapi_environment_on_generated(m_server->m_lua,
335 minp, maxp, mapgen::get_blockseed(data.seed, minp));
336 /*int t = timer.stop(true);
337 dstream<<"on_generated took "<<t<<"ms"<<std::endl;*/
340 if(enable_mapgen_debug_info)
341 infostream<<"EmergeThread: ended up with: "
342 <<analyze_block(block)<<std::endl;
344 // Activate objects and stuff
345 m_server->m_env->activateBlock(block, 0);
353 Set sent status of modified blocks on clients
356 // NOTE: Server's clients are also behind the connection mutex
357 JMutexAutoLock lock(m_server->m_con_mutex);
360 Add the originally fetched block to the modified list
364 modified_blocks.insert(p, block);
368 Set the modified blocks unsent for all the clients
371 for(core::map<u16, RemoteClient*>::Iterator
372 i = m_server->m_clients.getIterator();
373 i.atEnd() == false; i++)
375 RemoteClient *client = i.getNode()->getValue();
377 if(modified_blocks.size() > 0)
379 // Remove block from sent history
380 client->SetBlocksNotSent(modified_blocks);
384 catch(VersionMismatchException &e)
386 std::ostringstream err;
387 err<<"World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl;
388 err<<"----"<<std::endl;
389 err<<"\""<<e.what()<<"\""<<std::endl;
390 err<<"See debug.txt."<<std::endl;
391 err<<"World probably saved by a newer version of Minetest."<<std::endl;
392 m_server->setAsyncFatalError(err.str());
394 catch(SerializationError &e)
396 std::ostringstream err;
397 err<<"Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl;
398 err<<"----"<<std::endl;
399 err<<"\""<<e.what()<<"\""<<std::endl;
400 err<<"See debug.txt."<<std::endl;
401 err<<"You can ignore this using [ignore_world_load_errors = true]."<<std::endl;
402 m_server->setAsyncFatalError(err.str());
405 END_DEBUG_EXCEPTION_HANDLER(errorstream)
407 log_deregister_thread();
412 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
414 if(pos_exists) *pos_exists = false;
419 if(pos_exists) *pos_exists = true;
424 ServerActiveObject *sao = env->getActiveObject(object);
427 if(pos_exists) *pos_exists = true;
428 return sao->getBasePosition(); }
433 void RemoteClient::GetNextBlocks(Server *server, float dtime,
434 core::array<PrioritySortedBlockTransfer> &dest)
436 DSTACK(__FUNCTION_NAME);
439 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
442 m_nothing_to_send_pause_timer -= dtime;
443 m_nearest_unsent_reset_timer += dtime;
445 if(m_nothing_to_send_pause_timer >= 0)
448 Player *player = server->m_env->getPlayer(peer_id);
449 // This can happen sometimes; clients and players are not in perfect sync.
453 // Won't send anything if already sending
454 if(m_blocks_sending.size() >= g_settings->getU16
455 ("max_simultaneous_block_sends_per_client"))
457 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
461 //TimeTaker timer("RemoteClient::GetNextBlocks");
463 v3f playerpos = player->getPosition();
464 v3f playerspeed = player->getSpeed();
465 v3f playerspeeddir(0,0,0);
466 if(playerspeed.getLength() > 1.0*BS)
467 playerspeeddir = playerspeed / playerspeed.getLength();
468 // Predict to next block
469 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
471 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
473 v3s16 center = getNodeBlockPos(center_nodepos);
475 // Camera position and direction
476 v3f camera_pos = player->getEyePosition();
477 v3f camera_dir = v3f(0,0,1);
478 camera_dir.rotateYZBy(player->getPitch());
479 camera_dir.rotateXZBy(player->getYaw());
481 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
482 <<camera_dir.Z<<")"<<std::endl;*/
485 Get the starting value of the block finder radius.
488 if(m_last_center != center)
490 m_nearest_unsent_d = 0;
491 m_last_center = center;
494 /*infostream<<"m_nearest_unsent_reset_timer="
495 <<m_nearest_unsent_reset_timer<<std::endl;*/
497 // Reset periodically to workaround for some bugs or stuff
498 if(m_nearest_unsent_reset_timer > 20.0)
500 m_nearest_unsent_reset_timer = 0;
501 m_nearest_unsent_d = 0;
502 //infostream<<"Resetting m_nearest_unsent_d for "
503 // <<server->getPlayerName(peer_id)<<std::endl;
506 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
507 s16 d_start = m_nearest_unsent_d;
509 //infostream<<"d_start="<<d_start<<std::endl;
511 u16 max_simul_sends_setting = g_settings->getU16
512 ("max_simultaneous_block_sends_per_client");
513 u16 max_simul_sends_usually = max_simul_sends_setting;
516 Check the time from last addNode/removeNode.
518 Decrease send rate if player is building stuff.
520 m_time_from_building += dtime;
521 if(m_time_from_building < g_settings->getFloat(
522 "full_block_send_enable_min_time_from_building"))
524 max_simul_sends_usually
525 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
529 Number of blocks sending + number of blocks selected for sending
531 u32 num_blocks_selected = m_blocks_sending.size();
534 next time d will be continued from the d from which the nearest
535 unsent block was found this time.
537 This is because not necessarily any of the blocks found this
538 time are actually sent.
540 s32 new_nearest_unsent_d = -1;
542 s16 d_max = g_settings->getS16("max_block_send_distance");
543 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
545 // Don't loop very much at a time
546 s16 max_d_increment_at_time = 2;
547 if(d_max > d_start + max_d_increment_at_time)
548 d_max = d_start + max_d_increment_at_time;
549 /*if(d_max_gen > d_start+2)
550 d_max_gen = d_start+2;*/
552 //infostream<<"Starting from "<<d_start<<std::endl;
554 s32 nearest_emerged_d = -1;
555 s32 nearest_emergefull_d = -1;
556 s32 nearest_sent_d = -1;
557 bool queue_is_full = false;
560 for(d = d_start; d <= d_max; d++)
562 /*errorstream<<"checking d="<<d<<" for "
563 <<server->getPlayerName(peer_id)<<std::endl;*/
564 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
567 If m_nearest_unsent_d was changed by the EmergeThread
568 (it can change it to 0 through SetBlockNotSent),
570 Else update m_nearest_unsent_d
572 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
574 d = m_nearest_unsent_d;
575 last_nearest_unsent_d = m_nearest_unsent_d;
579 Get the border/face dot coordinates of a "d-radiused"
582 core::list<v3s16> list;
583 getFacePositions(list, d);
585 core::list<v3s16>::Iterator li;
586 for(li=list.begin(); li!=list.end(); li++)
588 v3s16 p = *li + center;
592 - Don't allow too many simultaneous transfers
593 - EXCEPT when the blocks are very close
595 Also, don't send blocks that are already flying.
598 // Start with the usual maximum
599 u16 max_simul_dynamic = max_simul_sends_usually;
601 // If block is very close, allow full maximum
602 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
603 max_simul_dynamic = max_simul_sends_setting;
605 // Don't select too many blocks for sending
606 if(num_blocks_selected >= max_simul_dynamic)
608 queue_is_full = true;
609 goto queue_full_break;
612 // Don't send blocks that are currently being transferred
613 if(m_blocks_sending.find(p) != NULL)
619 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
620 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
621 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
622 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
623 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
624 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
627 // If this is true, inexistent block will be made from scratch
628 bool generate = d <= d_max_gen;
631 /*// Limit the generating area vertically to 2/3
632 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
635 // Limit the send area vertically to 1/2
636 if(abs(p.Y - center.Y) > d_max / 2)
642 If block is far away, don't generate it unless it is
648 // Block center y in nodes
649 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
650 // Don't generate if it's very high or very low
651 if(y < -64 || y > 64)
655 v2s16 p2d_nodes_center(
659 // Get ground height in nodes
660 s16 gh = server->m_env->getServerMap().findGroundLevel(
663 // If differs a lot, don't generate
664 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
666 // Actually, don't even send it
672 //infostream<<"d="<<d<<std::endl;
675 Don't generate or send if not in sight
676 FIXME This only works if the client uses a small enough
677 FOV setting. The default of 72 degrees is fine.
680 float camera_fov = (72.0*M_PI/180) * 4./3.;
681 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
687 Don't send already sent blocks
690 if(m_blocks_sent.find(p) != NULL)
697 Check if map has this block
699 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
701 bool surely_not_found_on_disk = false;
702 bool block_is_invalid = false;
705 // Reset usage timer, this block will be of use in the future.
706 block->resetUsageTimer();
708 // Block is dummy if data doesn't exist.
709 // It means it has been not found from disk and not generated
712 surely_not_found_on_disk = true;
715 // Block is valid if lighting is up-to-date and data exists
716 if(block->isValid() == false)
718 block_is_invalid = true;
721 /*if(block->isFullyGenerated() == false)
723 block_is_invalid = true;
728 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
729 v2s16 chunkpos = map->sector_to_chunk(p2d);
730 if(map->chunkNonVolatile(chunkpos) == false)
731 block_is_invalid = true;
733 if(block->isGenerated() == false)
734 block_is_invalid = true;
737 If block is not close, don't send it unless it is near
740 Block is near ground level if night-time mesh
741 differs from day-time mesh.
745 if(block->getDayNightDiff() == false)
752 If block has been marked to not exist on disk (dummy)
753 and generating new ones is not wanted, skip block.
755 if(generate == false && surely_not_found_on_disk == true)
762 Add inexistent block to emerge queue.
764 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
766 //TODO: Get value from somewhere
767 // Allow only one block in emerge queue
768 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
769 // Allow two blocks in queue per client
770 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
772 // Make it more responsive when needing to generate stuff
773 if(surely_not_found_on_disk)
775 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
777 //infostream<<"Adding block to emerge queue"<<std::endl;
779 // Add it to the emerge queue and trigger the thread
782 if(generate == false)
783 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
785 server->m_emerge_queue.addBlock(peer_id, p, flags);
786 server->m_emergethread.trigger();
788 if(nearest_emerged_d == -1)
789 nearest_emerged_d = d;
791 if(nearest_emergefull_d == -1)
792 nearest_emergefull_d = d;
799 if(nearest_sent_d == -1)
803 Add block to send queue
806 /*errorstream<<"sending from d="<<d<<" to "
807 <<server->getPlayerName(peer_id)<<std::endl;*/
809 PrioritySortedBlockTransfer q((float)d, p, peer_id);
813 num_blocks_selected += 1;
818 //infostream<<"Stopped at "<<d<<std::endl;
820 // If nothing was found for sending and nothing was queued for
821 // emerging, continue next time browsing from here
822 if(nearest_emerged_d != -1){
823 new_nearest_unsent_d = nearest_emerged_d;
824 } else if(nearest_emergefull_d != -1){
825 new_nearest_unsent_d = nearest_emergefull_d;
827 if(d > g_settings->getS16("max_block_send_distance")){
828 new_nearest_unsent_d = 0;
829 m_nothing_to_send_pause_timer = 2.0;
830 /*infostream<<"GetNextBlocks(): d wrapped around for "
831 <<server->getPlayerName(peer_id)
832 <<"; setting to 0 and pausing"<<std::endl;*/
834 if(nearest_sent_d != -1)
835 new_nearest_unsent_d = nearest_sent_d;
837 new_nearest_unsent_d = d;
841 if(new_nearest_unsent_d != -1)
842 m_nearest_unsent_d = new_nearest_unsent_d;
844 /*timer_result = timer.stop(true);
845 if(timer_result != 0)
846 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
849 void RemoteClient::GotBlock(v3s16 p)
851 if(m_blocks_sending.find(p) != NULL)
852 m_blocks_sending.remove(p);
855 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
856 " m_blocks_sending"<<std::endl;*/
857 m_excess_gotblocks++;
859 m_blocks_sent.insert(p, true);
862 void RemoteClient::SentBlock(v3s16 p)
864 if(m_blocks_sending.find(p) == NULL)
865 m_blocks_sending.insert(p, 0.0);
867 infostream<<"RemoteClient::SentBlock(): Sent block"
868 " already in m_blocks_sending"<<std::endl;
871 void RemoteClient::SetBlockNotSent(v3s16 p)
873 m_nearest_unsent_d = 0;
875 if(m_blocks_sending.find(p) != NULL)
876 m_blocks_sending.remove(p);
877 if(m_blocks_sent.find(p) != NULL)
878 m_blocks_sent.remove(p);
881 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
883 m_nearest_unsent_d = 0;
885 for(core::map<v3s16, MapBlock*>::Iterator
886 i = blocks.getIterator();
887 i.atEnd()==false; i++)
889 v3s16 p = i.getNode()->getKey();
891 if(m_blocks_sending.find(p) != NULL)
892 m_blocks_sending.remove(p);
893 if(m_blocks_sent.find(p) != NULL)
894 m_blocks_sent.remove(p);
902 PlayerInfo::PlayerInfo()
908 void PlayerInfo::PrintLine(std::ostream *s)
911 (*s)<<"\""<<name<<"\" ("
912 <<(position.X/10)<<","<<(position.Y/10)
913 <<","<<(position.Z/10)<<") ";
915 (*s)<<" avg_rtt="<<avg_rtt;
924 const std::string &path_world,
925 const std::string &path_config,
926 const SubgameSpec &gamespec,
927 bool simple_singleplayer_mode
929 m_path_world(path_world),
930 m_path_config(path_config),
931 m_gamespec(gamespec),
932 m_simple_singleplayer_mode(simple_singleplayer_mode),
933 m_async_fatal_error(""),
935 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
936 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
938 m_rollback_sink_enabled(true),
939 m_enable_rollback_recording(false),
941 m_itemdef(createItemDefManager()),
942 m_nodedef(createNodeDefManager()),
943 m_craftdef(createCraftDefManager()),
944 m_event(new EventManager()),
946 m_emergethread(this),
947 m_time_of_day_send_timer(0),
949 m_shutdown_requested(false),
950 m_ignore_map_edit_events(false),
951 m_ignore_map_edit_events_peer_id(0)
953 m_liquid_transform_timer = 0.0;
954 m_print_info_timer = 0.0;
955 m_objectdata_timer = 0.0;
956 m_emergethread_trigger_timer = 0.0;
957 m_savemap_timer = 0.0;
961 m_step_dtime_mutex.Init();
965 throw ServerError("Supplied empty world path");
967 if(!gamespec.isValid())
968 throw ServerError("Supplied invalid gamespec");
970 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
971 if(m_simple_singleplayer_mode)
972 infostream<<" in simple singleplayer mode"<<std::endl;
974 infostream<<std::endl;
975 infostream<<"- world: "<<m_path_world<<std::endl;
976 infostream<<"- config: "<<m_path_config<<std::endl;
977 infostream<<"- game: "<<m_gamespec.path<<std::endl;
979 // Create rollback manager
980 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
981 m_rollback = createRollbackManager(rollback_path, this);
983 // Add world mod search path
984 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
985 // Add addon mod search path
986 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
987 i != m_gamespec.mods_paths.end(); i++)
988 m_modspaths.push_front((*i));
990 // Print out mod search paths
991 for(core::list<std::string>::Iterator i = m_modspaths.begin();
992 i != m_modspaths.end(); i++){
993 std::string modspath = *i;
994 infostream<<"- mods: "<<modspath<<std::endl;
997 // Path to builtin.lua
998 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
1000 // Create world if it doesn't exist
1001 if(!initializeWorld(m_path_world, m_gamespec.id))
1002 throw ServerError("Failed to initialize world");
1005 JMutexAutoLock envlock(m_env_mutex);
1006 JMutexAutoLock conlock(m_con_mutex);
1008 // Initialize scripting
1010 infostream<<"Server: Initializing Lua"<<std::endl;
1011 m_lua = script_init();
1014 scriptapi_export(m_lua, this);
1015 // Load and run builtin.lua
1016 infostream<<"Server: Loading builtin.lua [\""
1017 <<builtinpath<<"\"]"<<std::endl;
1018 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1020 errorstream<<"Server: Failed to load and run "
1021 <<builtinpath<<std::endl;
1022 throw ModError("Failed to load and run "+builtinpath);
1024 // Find mods in mod search paths
1025 m_mods = getMods(m_modspaths);
1027 infostream<<"Server: Loading mods: ";
1028 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1029 i != m_mods.end(); i++){
1030 const ModSpec &mod = *i;
1031 infostream<<mod.name<<" ";
1033 infostream<<std::endl;
1034 // Load and run "mod" scripts
1035 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1036 i != m_mods.end(); i++){
1037 const ModSpec &mod = *i;
1038 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1039 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1040 <<scriptpath<<"\"]"<<std::endl;
1041 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1043 errorstream<<"Server: Failed to load and run "
1044 <<scriptpath<<std::endl;
1045 throw ModError("Failed to load and run "+scriptpath);
1049 // Read Textures and calculate sha1 sums
1052 // Apply item aliases in the node definition manager
1053 m_nodedef->updateAliases(m_itemdef);
1055 // Initialize Environment
1057 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
1060 // Give environment reference to scripting api
1061 scriptapi_add_environment(m_lua, m_env);
1063 // Register us to receive map edit events
1064 m_env->getMap().addEventReceiver(this);
1066 // If file exists, load environment metadata
1067 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1069 infostream<<"Server: Loading environment metadata"<<std::endl;
1070 m_env->loadMeta(m_path_world);
1074 infostream<<"Server: Loading players"<<std::endl;
1075 m_env->deSerializePlayers(m_path_world);
1078 Add some test ActiveBlockModifiers to environment
1080 add_legacy_abms(m_env, m_nodedef);
1085 infostream<<"Server destructing"<<std::endl;
1088 Send shutdown message
1091 JMutexAutoLock conlock(m_con_mutex);
1093 std::wstring line = L"*** Server shutting down";
1096 Send the message to clients
1098 for(core::map<u16, RemoteClient*>::Iterator
1099 i = m_clients.getIterator();
1100 i.atEnd() == false; i++)
1102 // Get client and check that it is valid
1103 RemoteClient *client = i.getNode()->getValue();
1104 assert(client->peer_id == i.getNode()->getKey());
1105 if(client->serialization_version == SER_FMT_VER_INVALID)
1109 SendChatMessage(client->peer_id, line);
1111 catch(con::PeerNotFoundException &e)
1117 JMutexAutoLock envlock(m_env_mutex);
1122 infostream<<"Server: Saving players"<<std::endl;
1123 m_env->serializePlayers(m_path_world);
1126 Save environment metadata
1128 infostream<<"Server: Saving environment metadata"<<std::endl;
1129 m_env->saveMeta(m_path_world);
1141 JMutexAutoLock clientslock(m_con_mutex);
1143 for(core::map<u16, RemoteClient*>::Iterator
1144 i = m_clients.getIterator();
1145 i.atEnd() == false; i++)
1148 // NOTE: These are removed by env destructor
1150 u16 peer_id = i.getNode()->getKey();
1151 JMutexAutoLock envlock(m_env_mutex);
1152 m_env->removePlayer(peer_id);
1156 delete i.getNode()->getValue();
1160 // Delete things in the reverse order of creation
1168 // Deinitialize scripting
1169 infostream<<"Server: Deinitializing scripting"<<std::endl;
1170 script_deinit(m_lua);
1172 // Delete detached inventories
1174 for(std::map<std::string, Inventory*>::iterator
1175 i = m_detached_inventories.begin();
1176 i != m_detached_inventories.end(); i++){
1182 void Server::start(unsigned short port)
1184 DSTACK(__FUNCTION_NAME);
1185 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1187 // Stop thread if already running
1190 // Initialize connection
1191 m_con.SetTimeoutMs(30);
1195 m_thread.setRun(true);
1198 // ASCII art for the win!
1200 <<" .__ __ __ "<<std::endl
1201 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1202 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1203 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1204 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1205 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1206 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1207 actionstream<<"Server for gameid=\""<<m_gamespec.id
1208 <<"\" listening on port "<<port<<"."<<std::endl;
1213 DSTACK(__FUNCTION_NAME);
1215 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1217 // Stop threads (set run=false first so both start stopping)
1218 m_thread.setRun(false);
1219 m_emergethread.setRun(false);
1221 m_emergethread.stop();
1223 infostream<<"Server: Threads stopped"<<std::endl;
1226 void Server::step(float dtime)
1228 DSTACK(__FUNCTION_NAME);
1233 JMutexAutoLock lock(m_step_dtime_mutex);
1234 m_step_dtime += dtime;
1236 // Throw if fatal error occurred in thread
1237 std::string async_err = m_async_fatal_error.get();
1238 if(async_err != ""){
1239 throw ServerError(async_err);
1243 void Server::AsyncRunStep()
1245 DSTACK(__FUNCTION_NAME);
1247 g_profiler->add("Server::AsyncRunStep (num)", 1);
1251 JMutexAutoLock lock1(m_step_dtime_mutex);
1252 dtime = m_step_dtime;
1256 // Send blocks to clients
1263 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1265 //infostream<<"Server steps "<<dtime<<std::endl;
1266 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1269 JMutexAutoLock lock1(m_step_dtime_mutex);
1270 m_step_dtime -= dtime;
1277 m_uptime.set(m_uptime.get() + dtime);
1281 // Process connection's timeouts
1282 JMutexAutoLock lock2(m_con_mutex);
1283 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1284 m_con.RunTimeouts(dtime);
1288 // This has to be called so that the client list gets synced
1289 // with the peer list of the connection
1290 handlePeerChanges();
1294 Update time of day and overall game time
1297 JMutexAutoLock envlock(m_env_mutex);
1299 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1302 Send to clients at constant intervals
1305 m_time_of_day_send_timer -= dtime;
1306 if(m_time_of_day_send_timer < 0.0)
1308 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1310 //JMutexAutoLock envlock(m_env_mutex);
1311 JMutexAutoLock conlock(m_con_mutex);
1313 for(core::map<u16, RemoteClient*>::Iterator
1314 i = m_clients.getIterator();
1315 i.atEnd() == false; i++)
1317 RemoteClient *client = i.getNode()->getValue();
1318 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1319 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1321 m_con.Send(client->peer_id, 0, data, true);
1327 JMutexAutoLock lock(m_env_mutex);
1329 ScopeProfiler sp(g_profiler, "SEnv step");
1330 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1334 const float map_timer_and_unload_dtime = 2.92;
1335 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1337 JMutexAutoLock lock(m_env_mutex);
1338 // Run Map's timers and unload unused data
1339 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1340 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1341 g_settings->getFloat("server_unload_unused_data_timeout"));
1352 JMutexAutoLock lock(m_env_mutex);
1353 JMutexAutoLock lock2(m_con_mutex);
1355 ScopeProfiler sp(g_profiler, "Server: handle players");
1357 for(core::map<u16, RemoteClient*>::Iterator
1358 i = m_clients.getIterator();
1359 i.atEnd() == false; i++)
1361 RemoteClient *client = i.getNode()->getValue();
1362 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1363 if(playersao == NULL)
1367 Handle player HPs (die if hp=0)
1369 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
1370 DiePlayer(client->peer_id);
1373 Send player inventories and HPs if necessary
1375 if(playersao->m_moved){
1376 SendMovePlayer(client->peer_id);
1377 playersao->m_moved = false;
1379 if(playersao->m_inventory_not_sent){
1380 UpdateCrafting(client->peer_id);
1381 SendInventory(client->peer_id);
1383 if(playersao->m_hp_not_sent){
1384 SendPlayerHP(client->peer_id);
1389 /* Transform liquids */
1390 m_liquid_transform_timer += dtime;
1391 if(m_liquid_transform_timer >= 1.00)
1393 m_liquid_transform_timer -= 1.00;
1395 JMutexAutoLock lock(m_env_mutex);
1397 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1399 core::map<v3s16, MapBlock*> modified_blocks;
1400 m_env->getMap().transformLiquids(modified_blocks);
1405 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1406 ServerMap &map = ((ServerMap&)m_env->getMap());
1407 map.updateLighting(modified_blocks, lighting_modified_blocks);
1409 // Add blocks modified by lighting to modified_blocks
1410 for(core::map<v3s16, MapBlock*>::Iterator
1411 i = lighting_modified_blocks.getIterator();
1412 i.atEnd() == false; i++)
1414 MapBlock *block = i.getNode()->getValue();
1415 modified_blocks.insert(block->getPos(), block);
1419 Set the modified blocks unsent for all the clients
1422 JMutexAutoLock lock2(m_con_mutex);
1424 for(core::map<u16, RemoteClient*>::Iterator
1425 i = m_clients.getIterator();
1426 i.atEnd() == false; i++)
1428 RemoteClient *client = i.getNode()->getValue();
1430 if(modified_blocks.size() > 0)
1432 // Remove block from sent history
1433 client->SetBlocksNotSent(modified_blocks);
1438 // Periodically print some info
1440 float &counter = m_print_info_timer;
1446 JMutexAutoLock lock2(m_con_mutex);
1448 if(m_clients.size() != 0)
1449 infostream<<"Players:"<<std::endl;
1450 for(core::map<u16, RemoteClient*>::Iterator
1451 i = m_clients.getIterator();
1452 i.atEnd() == false; i++)
1454 //u16 peer_id = i.getNode()->getKey();
1455 RemoteClient *client = i.getNode()->getValue();
1456 Player *player = m_env->getPlayer(client->peer_id);
1459 infostream<<"* "<<player->getName()<<"\t";
1460 client->PrintInfo(infostream);
1465 //if(g_settings->getBool("enable_experimental"))
1469 Check added and deleted active objects
1472 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1473 JMutexAutoLock envlock(m_env_mutex);
1474 JMutexAutoLock conlock(m_con_mutex);
1476 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1478 // Radius inside which objects are active
1479 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1480 radius *= MAP_BLOCKSIZE;
1482 for(core::map<u16, RemoteClient*>::Iterator
1483 i = m_clients.getIterator();
1484 i.atEnd() == false; i++)
1486 RemoteClient *client = i.getNode()->getValue();
1488 // If definitions and textures have not been sent, don't
1489 // send objects either
1490 if(!client->definitions_sent)
1493 Player *player = m_env->getPlayer(client->peer_id);
1496 // This can happen if the client timeouts somehow
1497 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1499 <<" has no associated player"<<std::endl;*/
1502 v3s16 pos = floatToInt(player->getPosition(), BS);
1504 core::map<u16, bool> removed_objects;
1505 core::map<u16, bool> added_objects;
1506 m_env->getRemovedActiveObjects(pos, radius,
1507 client->m_known_objects, removed_objects);
1508 m_env->getAddedActiveObjects(pos, radius,
1509 client->m_known_objects, added_objects);
1511 // Ignore if nothing happened
1512 if(removed_objects.size() == 0 && added_objects.size() == 0)
1514 //infostream<<"active objects: none changed"<<std::endl;
1518 std::string data_buffer;
1522 // Handle removed objects
1523 writeU16((u8*)buf, removed_objects.size());
1524 data_buffer.append(buf, 2);
1525 for(core::map<u16, bool>::Iterator
1526 i = removed_objects.getIterator();
1527 i.atEnd()==false; i++)
1530 u16 id = i.getNode()->getKey();
1531 ServerActiveObject* obj = m_env->getActiveObject(id);
1533 // Add to data buffer for sending
1534 writeU16((u8*)buf, i.getNode()->getKey());
1535 data_buffer.append(buf, 2);
1537 // Remove from known objects
1538 client->m_known_objects.remove(i.getNode()->getKey());
1540 if(obj && obj->m_known_by_count > 0)
1541 obj->m_known_by_count--;
1544 // Handle added objects
1545 writeU16((u8*)buf, added_objects.size());
1546 data_buffer.append(buf, 2);
1547 for(core::map<u16, bool>::Iterator
1548 i = added_objects.getIterator();
1549 i.atEnd()==false; i++)
1552 u16 id = i.getNode()->getKey();
1553 ServerActiveObject* obj = m_env->getActiveObject(id);
1556 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1558 infostream<<"WARNING: "<<__FUNCTION_NAME
1559 <<": NULL object"<<std::endl;
1561 type = obj->getSendType();
1563 // Add to data buffer for sending
1564 writeU16((u8*)buf, id);
1565 data_buffer.append(buf, 2);
1566 writeU8((u8*)buf, type);
1567 data_buffer.append(buf, 1);
1570 data_buffer.append(serializeLongString(
1571 obj->getClientInitializationData()));
1573 data_buffer.append(serializeLongString(""));
1575 // Add to known objects
1576 client->m_known_objects.insert(i.getNode()->getKey(), false);
1579 obj->m_known_by_count++;
1583 SharedBuffer<u8> reply(2 + data_buffer.size());
1584 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1585 memcpy((char*)&reply[2], data_buffer.c_str(),
1586 data_buffer.size());
1588 m_con.Send(client->peer_id, 0, reply, true);
1590 verbosestream<<"Server: Sent object remove/add: "
1591 <<removed_objects.size()<<" removed, "
1592 <<added_objects.size()<<" added, "
1593 <<"packet size is "<<reply.getSize()<<std::endl;
1598 Collect a list of all the objects known by the clients
1599 and report it back to the environment.
1602 core::map<u16, bool> all_known_objects;
1604 for(core::map<u16, RemoteClient*>::Iterator
1605 i = m_clients.getIterator();
1606 i.atEnd() == false; i++)
1608 RemoteClient *client = i.getNode()->getValue();
1609 // Go through all known objects of client
1610 for(core::map<u16, bool>::Iterator
1611 i = client->m_known_objects.getIterator();
1612 i.atEnd()==false; i++)
1614 u16 id = i.getNode()->getKey();
1615 all_known_objects[id] = true;
1619 m_env->setKnownActiveObjects(whatever);
1625 Send object messages
1628 JMutexAutoLock envlock(m_env_mutex);
1629 JMutexAutoLock conlock(m_con_mutex);
1631 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1634 // Value = data sent by object
1635 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1637 // Get active object messages from environment
1640 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1644 core::list<ActiveObjectMessage>* message_list = NULL;
1645 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1646 n = buffered_messages.find(aom.id);
1649 message_list = new core::list<ActiveObjectMessage>;
1650 buffered_messages.insert(aom.id, message_list);
1654 message_list = n->getValue();
1656 message_list->push_back(aom);
1659 // Route data to every client
1660 for(core::map<u16, RemoteClient*>::Iterator
1661 i = m_clients.getIterator();
1662 i.atEnd()==false; i++)
1664 RemoteClient *client = i.getNode()->getValue();
1665 std::string reliable_data;
1666 std::string unreliable_data;
1667 // Go through all objects in message buffer
1668 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1669 j = buffered_messages.getIterator();
1670 j.atEnd()==false; j++)
1672 // If object is not known by client, skip it
1673 u16 id = j.getNode()->getKey();
1674 if(client->m_known_objects.find(id) == NULL)
1676 // Get message list of object
1677 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1678 // Go through every message
1679 for(core::list<ActiveObjectMessage>::Iterator
1680 k = list->begin(); k != list->end(); k++)
1682 // Compose the full new data with header
1683 ActiveObjectMessage aom = *k;
1684 std::string new_data;
1687 writeU16((u8*)&buf[0], aom.id);
1688 new_data.append(buf, 2);
1690 new_data += serializeString(aom.datastring);
1691 // Add data to buffer
1693 reliable_data += new_data;
1695 unreliable_data += new_data;
1699 reliable_data and unreliable_data are now ready.
1702 if(reliable_data.size() > 0)
1704 SharedBuffer<u8> reply(2 + reliable_data.size());
1705 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1706 memcpy((char*)&reply[2], reliable_data.c_str(),
1707 reliable_data.size());
1709 m_con.Send(client->peer_id, 0, reply, true);
1711 if(unreliable_data.size() > 0)
1713 SharedBuffer<u8> reply(2 + unreliable_data.size());
1714 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1715 memcpy((char*)&reply[2], unreliable_data.c_str(),
1716 unreliable_data.size());
1717 // Send as unreliable
1718 m_con.Send(client->peer_id, 0, reply, false);
1721 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1723 infostream<<"Server: Size of object message data: "
1724 <<"reliable: "<<reliable_data.size()
1725 <<", unreliable: "<<unreliable_data.size()
1730 // Clear buffered_messages
1731 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1732 i = buffered_messages.getIterator();
1733 i.atEnd()==false; i++)
1735 delete i.getNode()->getValue();
1739 } // enable_experimental
1742 Send queued-for-sending map edit events.
1745 // We will be accessing the environment and the connection
1746 JMutexAutoLock lock(m_env_mutex);
1747 JMutexAutoLock conlock(m_con_mutex);
1749 // Don't send too many at a time
1752 // Single change sending is disabled if queue size is not small
1753 bool disable_single_change_sending = false;
1754 if(m_unsent_map_edit_queue.size() >= 4)
1755 disable_single_change_sending = true;
1757 int event_count = m_unsent_map_edit_queue.size();
1759 // We'll log the amount of each
1762 while(m_unsent_map_edit_queue.size() != 0)
1764 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1766 // Players far away from the change are stored here.
1767 // Instead of sending the changes, MapBlocks are set not sent
1769 core::list<u16> far_players;
1771 if(event->type == MEET_ADDNODE)
1773 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1774 prof.add("MEET_ADDNODE", 1);
1775 if(disable_single_change_sending)
1776 sendAddNode(event->p, event->n, event->already_known_by_peer,
1779 sendAddNode(event->p, event->n, event->already_known_by_peer,
1782 else if(event->type == MEET_REMOVENODE)
1784 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1785 prof.add("MEET_REMOVENODE", 1);
1786 if(disable_single_change_sending)
1787 sendRemoveNode(event->p, event->already_known_by_peer,
1790 sendRemoveNode(event->p, event->already_known_by_peer,
1793 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1795 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1796 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1797 setBlockNotSent(event->p);
1799 else if(event->type == MEET_OTHER)
1801 infostream<<"Server: MEET_OTHER"<<std::endl;
1802 prof.add("MEET_OTHER", 1);
1803 for(core::map<v3s16, bool>::Iterator
1804 i = event->modified_blocks.getIterator();
1805 i.atEnd()==false; i++)
1807 v3s16 p = i.getNode()->getKey();
1813 prof.add("unknown", 1);
1814 infostream<<"WARNING: Server: Unknown MapEditEvent "
1815 <<((u32)event->type)<<std::endl;
1819 Set blocks not sent to far players
1821 if(far_players.size() > 0)
1823 // Convert list format to that wanted by SetBlocksNotSent
1824 core::map<v3s16, MapBlock*> modified_blocks2;
1825 for(core::map<v3s16, bool>::Iterator
1826 i = event->modified_blocks.getIterator();
1827 i.atEnd()==false; i++)
1829 v3s16 p = i.getNode()->getKey();
1830 modified_blocks2.insert(p,
1831 m_env->getMap().getBlockNoCreateNoEx(p));
1833 // Set blocks not sent
1834 for(core::list<u16>::Iterator
1835 i = far_players.begin();
1836 i != far_players.end(); i++)
1839 RemoteClient *client = getClient(peer_id);
1842 client->SetBlocksNotSent(modified_blocks2);
1848 /*// Don't send too many at a time
1850 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1854 if(event_count >= 5){
1855 infostream<<"Server: MapEditEvents:"<<std::endl;
1856 prof.print(infostream);
1857 } else if(event_count != 0){
1858 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1859 prof.print(verbosestream);
1865 Trigger emergethread (it somehow gets to a non-triggered but
1866 bysy state sometimes)
1869 float &counter = m_emergethread_trigger_timer;
1875 m_emergethread.trigger();
1877 // Update m_enable_rollback_recording here too
1878 m_enable_rollback_recording =
1879 g_settings->getBool("enable_rollback_recording");
1883 // Save map, players and auth stuff
1885 float &counter = m_savemap_timer;
1887 if(counter >= g_settings->getFloat("server_map_save_interval"))
1890 JMutexAutoLock lock(m_env_mutex);
1892 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1895 if(m_banmanager.isModified())
1896 m_banmanager.save();
1898 // Save changed parts of map
1899 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1902 m_env->serializePlayers(m_path_world);
1904 // Save environment metadata
1905 m_env->saveMeta(m_path_world);
1910 void Server::Receive()
1912 DSTACK(__FUNCTION_NAME);
1913 SharedBuffer<u8> data;
1918 JMutexAutoLock conlock(m_con_mutex);
1919 datasize = m_con.Receive(peer_id, data);
1922 // This has to be called so that the client list gets synced
1923 // with the peer list of the connection
1924 handlePeerChanges();
1926 ProcessData(*data, datasize, peer_id);
1928 catch(con::InvalidIncomingDataException &e)
1930 infostream<<"Server::Receive(): "
1931 "InvalidIncomingDataException: what()="
1932 <<e.what()<<std::endl;
1934 catch(con::PeerNotFoundException &e)
1936 //NOTE: This is not needed anymore
1938 // The peer has been disconnected.
1939 // Find the associated player and remove it.
1941 /*JMutexAutoLock envlock(m_env_mutex);
1943 infostream<<"ServerThread: peer_id="<<peer_id
1944 <<" has apparently closed connection. "
1945 <<"Removing player."<<std::endl;
1947 m_env->removePlayer(peer_id);*/
1951 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1953 DSTACK(__FUNCTION_NAME);
1954 // Environment is locked first.
1955 JMutexAutoLock envlock(m_env_mutex);
1956 JMutexAutoLock conlock(m_con_mutex);
1958 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1961 Address address = m_con.GetPeerAddress(peer_id);
1962 std::string addr_s = address.serializeString();
1964 // drop player if is ip is banned
1965 if(m_banmanager.isIpBanned(addr_s)){
1966 infostream<<"Server: A banned client tried to connect from "
1967 <<addr_s<<"; banned name was "
1968 <<m_banmanager.getBanName(addr_s)<<std::endl;
1969 // This actually doesn't seem to transfer to the client
1970 SendAccessDenied(m_con, peer_id,
1971 L"Your ip is banned. Banned name was "
1972 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1973 m_con.DeletePeer(peer_id);
1977 catch(con::PeerNotFoundException &e)
1979 infostream<<"Server::ProcessData(): Cancelling: peer "
1980 <<peer_id<<" not found"<<std::endl;
1984 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1986 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1994 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1996 if(command == TOSERVER_INIT)
1998 // [0] u16 TOSERVER_INIT
1999 // [2] u8 SER_FMT_VER_HIGHEST
2000 // [3] u8[20] player_name
2001 // [23] u8[28] password <--- can be sent without this, from old versions
2003 if(datasize < 2+1+PLAYERNAME_SIZE)
2006 verbosestream<<"Server: Got TOSERVER_INIT from "
2007 <<peer_id<<std::endl;
2009 // First byte after command is maximum supported
2010 // serialization version
2011 u8 client_max = data[2];
2012 u8 our_max = SER_FMT_VER_HIGHEST;
2013 // Use the highest version supported by both
2014 u8 deployed = core::min_(client_max, our_max);
2015 // If it's lower than the lowest supported, give up.
2016 if(deployed < SER_FMT_VER_LOWEST)
2017 deployed = SER_FMT_VER_INVALID;
2019 //peer->serialization_version = deployed;
2020 getClient(peer_id)->pending_serialization_version = deployed;
2022 if(deployed == SER_FMT_VER_INVALID)
2024 actionstream<<"Server: A mismatched client tried to connect from "
2025 <<addr_s<<std::endl;
2026 infostream<<"Server: Cannot negotiate "
2027 "serialization version with peer "
2028 <<peer_id<<std::endl;
2029 SendAccessDenied(m_con, peer_id, std::wstring(
2030 L"Your client's version is not supported.\n"
2031 L"Server version is ")
2032 + narrow_to_wide(VERSION_STRING) + L"."
2038 Read and check network protocol version
2041 u16 min_net_proto_version = 0;
2042 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2043 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2045 // Use min if version field doesn't exist (backwards compatibility)
2046 u16 max_net_proto_version = min_net_proto_version;
2047 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
2048 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
2050 u16 net_proto_version = max_net_proto_version;
2051 if(max_net_proto_version != SERVER_PROTOCOL_VERSION && min_net_proto_version <= SERVER_PROTOCOL_VERSION)
2052 net_proto_version = SERVER_PROTOCOL_VERSION;
2054 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
2055 <<min_net_proto_version<<", max: "<<max_net_proto_version
2056 <<", chosen: "<<net_proto_version<<std::endl;
2058 getClient(peer_id)->net_proto_version = net_proto_version;
2060 if(net_proto_version == 0)
2062 actionstream<<"Server: An old tried to connect from "<<addr_s
2064 SendAccessDenied(m_con, peer_id, std::wstring(
2065 L"Your client's version is not supported.\n"
2066 L"Server version is ")
2067 + narrow_to_wide(VERSION_STRING) + L"."
2072 if(g_settings->getBool("strict_protocol_version_checking"))
2074 if(net_proto_version != SERVER_PROTOCOL_VERSION)
2076 actionstream<<"Server: A mismatched client tried to connect"
2077 <<" from "<<addr_s<<std::endl;
2078 SendAccessDenied(m_con, peer_id, std::wstring(
2079 L"Your client's version is not supported.\n"
2080 L"Server version is ")
2081 + narrow_to_wide(VERSION_STRING) + L",\n"
2082 + L"server's PROTOCOL_VERSION is "
2083 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION))
2084 + L", client's PROTOCOL_VERSION is "
2085 + narrow_to_wide(itos(net_proto_version))
2096 char playername[PLAYERNAME_SIZE];
2097 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2099 playername[i] = data[3+i];
2101 playername[PLAYERNAME_SIZE-1] = 0;
2103 if(playername[0]=='\0')
2105 actionstream<<"Server: Player with an empty name "
2106 <<"tried to connect from "<<addr_s<<std::endl;
2107 SendAccessDenied(m_con, peer_id,
2112 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2114 actionstream<<"Server: Player with an invalid name "
2115 <<"tried to connect from "<<addr_s<<std::endl;
2116 SendAccessDenied(m_con, peer_id,
2117 L"Name contains unallowed characters");
2121 infostream<<"Server: New connection: \""<<playername<<"\" from "
2122 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2125 char given_password[PASSWORD_SIZE];
2126 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2128 // old version - assume blank password
2129 given_password[0] = 0;
2133 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2135 given_password[i] = data[23+i];
2137 given_password[PASSWORD_SIZE-1] = 0;
2140 if(!base64_is_valid(given_password)){
2141 infostream<<"Server: "<<playername
2142 <<" supplied invalid password hash"<<std::endl;
2143 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2147 std::string checkpwd; // Password hash to check against
2148 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2150 // If no authentication info exists for user, create it
2152 if(!isSingleplayer() &&
2153 g_settings->getBool("disallow_empty_password") &&
2154 std::string(given_password) == ""){
2155 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2156 L"disallowed. Set a password and try again.");
2159 std::wstring raw_default_password =
2160 narrow_to_wide(g_settings->get("default_password"));
2161 std::string initial_password =
2162 translatePassword(playername, raw_default_password);
2164 // If default_password is empty, allow any initial password
2165 if (raw_default_password.length() == 0)
2166 initial_password = given_password;
2168 scriptapi_create_auth(m_lua, playername, initial_password);
2171 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2174 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2178 if(given_password != checkpwd){
2179 infostream<<"Server: peer_id="<<peer_id
2180 <<": supplied invalid password for "
2181 <<playername<<std::endl;
2182 SendAccessDenied(m_con, peer_id, L"Invalid password");
2186 // Do not allow multiple players in simple singleplayer mode.
2187 // This isn't a perfect way to do it, but will suffice for now.
2188 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2189 infostream<<"Server: Not allowing another client to connect in"
2190 <<" simple singleplayer mode"<<std::endl;
2191 SendAccessDenied(m_con, peer_id,
2192 L"Running in simple singleplayer mode.");
2196 // Enforce user limit.
2197 // Don't enforce for users that have some admin right
2198 if(m_clients.size() >= g_settings->getU16("max_users") &&
2199 !checkPriv(playername, "server") &&
2200 !checkPriv(playername, "ban") &&
2201 !checkPriv(playername, "privs") &&
2202 !checkPriv(playername, "password") &&
2203 playername != g_settings->get("name"))
2205 actionstream<<"Server: "<<playername<<" tried to join, but there"
2206 <<" are already max_users="
2207 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2208 SendAccessDenied(m_con, peer_id, L"Too many users.");
2213 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2215 // If failed, cancel
2216 if(playersao == NULL)
2218 errorstream<<"Server: peer_id="<<peer_id
2219 <<": failed to emerge player"<<std::endl;
2224 Answer with a TOCLIENT_INIT
2227 SharedBuffer<u8> reply(2+1+6+8+4);
2228 writeU16(&reply[0], TOCLIENT_INIT);
2229 writeU8(&reply[2], deployed);
2230 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2231 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2232 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2235 m_con.Send(peer_id, 0, reply, true);
2239 Send complete position information
2241 SendMovePlayer(peer_id);
2246 if(command == TOSERVER_INIT2)
2248 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2249 <<peer_id<<std::endl;
2251 Player *player = m_env->getPlayer(peer_id);
2253 verbosestream<<"Server: TOSERVER_INIT2: "
2254 <<"Player not found; ignoring."<<std::endl;
2258 RemoteClient *client = getClient(peer_id);
2259 client->serialization_version =
2260 getClient(peer_id)->pending_serialization_version;
2263 Send some initialization data
2266 infostream<<"Server: Sending content to "
2267 <<getPlayerName(peer_id)<<std::endl;
2269 // Send item definitions
2270 SendItemDef(m_con, peer_id, m_itemdef);
2272 // Send node definitions
2273 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2275 // Send media announcement
2276 sendMediaAnnouncement(peer_id);
2279 SendPlayerPrivileges(peer_id);
2281 // Send inventory formspec
2282 SendPlayerInventoryFormspec(peer_id);
2285 UpdateCrafting(peer_id);
2286 SendInventory(peer_id);
2289 SendPlayerHP(peer_id);
2291 // Send detached inventories
2292 sendDetachedInventories(peer_id);
2294 // Show death screen if necessary
2296 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2300 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2301 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2302 m_con.Send(peer_id, 0, data, true);
2305 // Note things in chat if not in simple singleplayer mode
2306 if(!m_simple_singleplayer_mode)
2308 // Send information about server to player in chat
2309 SendChatMessage(peer_id, getStatusString());
2311 // Send information about joining in chat
2313 std::wstring name = L"unknown";
2314 Player *player = m_env->getPlayer(peer_id);
2316 name = narrow_to_wide(player->getName());
2318 std::wstring message;
2321 message += L" joined the game.";
2322 BroadcastChatMessage(message);
2326 // Warnings about protocol version can be issued here
2327 if(getClient(peer_id)->net_proto_version < SERVER_PROTOCOL_VERSION)
2329 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER!");
2336 std::ostringstream os(std::ios_base::binary);
2337 for(core::map<u16, RemoteClient*>::Iterator
2338 i = m_clients.getIterator();
2339 i.atEnd() == false; i++)
2341 RemoteClient *client = i.getNode()->getValue();
2342 assert(client->peer_id == i.getNode()->getKey());
2343 if(client->serialization_version == SER_FMT_VER_INVALID)
2346 Player *player = m_env->getPlayer(client->peer_id);
2349 // Get name of player
2350 os<<player->getName()<<" ";
2353 actionstream<<player->getName()<<" joins game. List of players: "
2354 <<os.str()<<std::endl;
2360 if(peer_ser_ver == SER_FMT_VER_INVALID)
2362 infostream<<"Server::ProcessData(): Cancelling: Peer"
2363 " serialization format invalid or not initialized."
2364 " Skipping incoming command="<<command<<std::endl;
2368 Player *player = m_env->getPlayer(peer_id);
2370 infostream<<"Server::ProcessData(): Cancelling: "
2371 "No player for peer_id="<<peer_id
2376 PlayerSAO *playersao = player->getPlayerSAO();
2377 if(playersao == NULL){
2378 infostream<<"Server::ProcessData(): Cancelling: "
2379 "No player object for peer_id="<<peer_id
2384 if(command == TOSERVER_PLAYERPOS)
2386 if(datasize < 2+12+12+4+4+4)
2390 v3s32 ps = readV3S32(&data[start+2]);
2391 v3s32 ss = readV3S32(&data[start+2+12]);
2392 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2393 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2394 u32 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2395 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2396 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2397 pitch = wrapDegrees(pitch);
2398 yaw = wrapDegrees(yaw);
2400 player->setPosition(position);
2401 player->setSpeed(speed);
2402 player->setPitch(pitch);
2403 player->setYaw(yaw);
2404 player->keyPressed=keyPressed;
2405 player->control.up = (bool)(keyPressed&1);
2406 player->control.down = (bool)(keyPressed&2);
2407 player->control.left = (bool)(keyPressed&4);
2408 player->control.right = (bool)(keyPressed&8);
2409 player->control.jump = (bool)(keyPressed&16);
2410 player->control.aux1 = (bool)(keyPressed&32);
2411 player->control.sneak = (bool)(keyPressed&64);
2412 player->control.LMB = (bool)(keyPressed&128);
2413 player->control.RMB = (bool)(keyPressed&256);
2415 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2416 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2417 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2419 else if(command == TOSERVER_GOTBLOCKS)
2432 u16 count = data[2];
2433 for(u16 i=0; i<count; i++)
2435 if((s16)datasize < 2+1+(i+1)*6)
2436 throw con::InvalidIncomingDataException
2437 ("GOTBLOCKS length is too short");
2438 v3s16 p = readV3S16(&data[2+1+i*6]);
2439 /*infostream<<"Server: GOTBLOCKS ("
2440 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2441 RemoteClient *client = getClient(peer_id);
2442 client->GotBlock(p);
2445 else if(command == TOSERVER_DELETEDBLOCKS)
2458 u16 count = data[2];
2459 for(u16 i=0; i<count; i++)
2461 if((s16)datasize < 2+1+(i+1)*6)
2462 throw con::InvalidIncomingDataException
2463 ("DELETEDBLOCKS length is too short");
2464 v3s16 p = readV3S16(&data[2+1+i*6]);
2465 /*infostream<<"Server: DELETEDBLOCKS ("
2466 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2467 RemoteClient *client = getClient(peer_id);
2468 client->SetBlockNotSent(p);
2471 else if(command == TOSERVER_CLICK_OBJECT)
2473 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2476 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2478 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2481 else if(command == TOSERVER_GROUND_ACTION)
2483 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2487 else if(command == TOSERVER_RELEASE)
2489 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2492 else if(command == TOSERVER_SIGNTEXT)
2494 infostream<<"Server: SIGNTEXT not supported anymore"
2498 else if(command == TOSERVER_SIGNNODETEXT)
2500 infostream<<"Server: SIGNNODETEXT not supported anymore"
2504 else if(command == TOSERVER_INVENTORY_ACTION)
2506 // Strip command and create a stream
2507 std::string datastring((char*)&data[2], datasize-2);
2508 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2509 std::istringstream is(datastring, std::ios_base::binary);
2511 InventoryAction *a = InventoryAction::deSerialize(is);
2514 infostream<<"TOSERVER_INVENTORY_ACTION: "
2515 <<"InventoryAction::deSerialize() returned NULL"
2520 // If something goes wrong, this player is to blame
2521 RollbackScopeActor rollback_scope(m_rollback,
2522 std::string("player:")+player->getName());
2525 Note: Always set inventory not sent, to repair cases
2526 where the client made a bad prediction.
2530 Handle restrictions and special cases of the move action
2532 if(a->getType() == IACTION_MOVE)
2534 IMoveAction *ma = (IMoveAction*)a;
2536 ma->from_inv.applyCurrentPlayer(player->getName());
2537 ma->to_inv.applyCurrentPlayer(player->getName());
2539 setInventoryModified(ma->from_inv);
2540 setInventoryModified(ma->to_inv);
2542 bool from_inv_is_current_player =
2543 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2544 (ma->from_inv.name == player->getName());
2546 bool to_inv_is_current_player =
2547 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2548 (ma->to_inv.name == player->getName());
2551 Disable moving items out of craftpreview
2553 if(ma->from_list == "craftpreview")
2555 infostream<<"Ignoring IMoveAction from "
2556 <<(ma->from_inv.dump())<<":"<<ma->from_list
2557 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2558 <<" because src is "<<ma->from_list<<std::endl;
2564 Disable moving items into craftresult and craftpreview
2566 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2568 infostream<<"Ignoring IMoveAction from "
2569 <<(ma->from_inv.dump())<<":"<<ma->from_list
2570 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2571 <<" because dst is "<<ma->to_list<<std::endl;
2576 // Disallow moving items in elsewhere than player's inventory
2577 // if not allowed to interact
2578 if(!checkPriv(player->getName(), "interact") &&
2579 (!from_inv_is_current_player ||
2580 !to_inv_is_current_player))
2582 infostream<<"Cannot move outside of player's inventory: "
2583 <<"No interact privilege"<<std::endl;
2589 Handle restrictions and special cases of the drop action
2591 else if(a->getType() == IACTION_DROP)
2593 IDropAction *da = (IDropAction*)a;
2595 da->from_inv.applyCurrentPlayer(player->getName());
2597 setInventoryModified(da->from_inv);
2599 // Disallow dropping items if not allowed to interact
2600 if(!checkPriv(player->getName(), "interact"))
2607 Handle restrictions and special cases of the craft action
2609 else if(a->getType() == IACTION_CRAFT)
2611 ICraftAction *ca = (ICraftAction*)a;
2613 ca->craft_inv.applyCurrentPlayer(player->getName());
2615 setInventoryModified(ca->craft_inv);
2617 //bool craft_inv_is_current_player =
2618 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2619 // (ca->craft_inv.name == player->getName());
2621 // Disallow crafting if not allowed to interact
2622 if(!checkPriv(player->getName(), "interact"))
2624 infostream<<"Cannot craft: "
2625 <<"No interact privilege"<<std::endl;
2632 a->apply(this, playersao, this);
2636 else if(command == TOSERVER_CHAT_MESSAGE)
2644 std::string datastring((char*)&data[2], datasize-2);
2645 std::istringstream is(datastring, std::ios_base::binary);
2648 is.read((char*)buf, 2);
2649 u16 len = readU16(buf);
2651 std::wstring message;
2652 for(u16 i=0; i<len; i++)
2654 is.read((char*)buf, 2);
2655 message += (wchar_t)readU16(buf);
2658 // If something goes wrong, this player is to blame
2659 RollbackScopeActor rollback_scope(m_rollback,
2660 std::string("player:")+player->getName());
2662 // Get player name of this client
2663 std::wstring name = narrow_to_wide(player->getName());
2666 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2667 wide_to_narrow(message));
2668 // If script ate the message, don't proceed
2672 // Line to send to players
2674 // Whether to send to the player that sent the line
2675 bool send_to_sender = false;
2676 // Whether to send to other players
2677 bool send_to_others = false;
2679 // Commands are implemented in Lua, so only catch invalid
2680 // commands that were not "eaten" and send an error back
2681 if(message[0] == L'/')
2683 message = message.substr(1);
2684 send_to_sender = true;
2685 if(message.length() == 0)
2686 line += L"-!- Empty command";
2688 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2692 if(checkPriv(player->getName(), "shout")){
2697 send_to_others = true;
2699 line += L"-!- You don't have permission to shout.";
2700 send_to_sender = true;
2707 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2710 Send the message to clients
2712 for(core::map<u16, RemoteClient*>::Iterator
2713 i = m_clients.getIterator();
2714 i.atEnd() == false; i++)
2716 // Get client and check that it is valid
2717 RemoteClient *client = i.getNode()->getValue();
2718 assert(client->peer_id == i.getNode()->getKey());
2719 if(client->serialization_version == SER_FMT_VER_INVALID)
2723 bool sender_selected = (peer_id == client->peer_id);
2724 if(sender_selected == true && send_to_sender == false)
2726 if(sender_selected == false && send_to_others == false)
2729 SendChatMessage(client->peer_id, line);
2733 else if(command == TOSERVER_DAMAGE)
2735 std::string datastring((char*)&data[2], datasize-2);
2736 std::istringstream is(datastring, std::ios_base::binary);
2737 u8 damage = readU8(is);
2739 actionstream<<player->getName()<<" damaged by "
2740 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2743 playersao->setHP(playersao->getHP() - damage);
2745 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2748 if(playersao->m_hp_not_sent)
2749 SendPlayerHP(peer_id);
2751 else if(command == TOSERVER_PASSWORD)
2754 [0] u16 TOSERVER_PASSWORD
2755 [2] u8[28] old password
2756 [30] u8[28] new password
2759 if(datasize != 2+PASSWORD_SIZE*2)
2761 /*char password[PASSWORD_SIZE];
2762 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2763 password[i] = data[2+i];
2764 password[PASSWORD_SIZE-1] = 0;*/
2766 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2774 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2776 char c = data[2+PASSWORD_SIZE+i];
2782 if(!base64_is_valid(newpwd)){
2783 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2784 // Wrong old password supplied!!
2785 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2789 infostream<<"Server: Client requests a password change from "
2790 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2792 std::string playername = player->getName();
2794 std::string checkpwd;
2795 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2797 if(oldpwd != checkpwd)
2799 infostream<<"Server: invalid old password"<<std::endl;
2800 // Wrong old password supplied!!
2801 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2805 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2807 actionstream<<player->getName()<<" changes password"<<std::endl;
2808 SendChatMessage(peer_id, L"Password change successful.");
2810 actionstream<<player->getName()<<" tries to change password but "
2811 <<"it fails"<<std::endl;
2812 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2815 else if(command == TOSERVER_PLAYERITEM)
2820 u16 item = readU16(&data[2]);
2821 playersao->setWieldIndex(item);
2823 else if(command == TOSERVER_RESPAWN)
2828 RespawnPlayer(peer_id);
2830 actionstream<<player->getName()<<" respawns at "
2831 <<PP(player->getPosition()/BS)<<std::endl;
2833 // ActiveObject is added to environment in AsyncRunStep after
2834 // the previous addition has been succesfully removed
2836 else if(command == TOSERVER_REQUEST_MEDIA) {
2837 std::string datastring((char*)&data[2], datasize-2);
2838 std::istringstream is(datastring, std::ios_base::binary);
2840 core::list<MediaRequest> tosend;
2841 u16 numfiles = readU16(is);
2843 infostream<<"Sending "<<numfiles<<" files to "
2844 <<getPlayerName(peer_id)<<std::endl;
2845 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2847 for(int i = 0; i < numfiles; i++) {
2848 std::string name = deSerializeString(is);
2849 tosend.push_back(MediaRequest(name));
2850 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2854 sendRequestedMedia(peer_id, tosend);
2856 // Now the client should know about everything
2857 // (definitions and files)
2858 getClient(peer_id)->definitions_sent = true;
2860 else if(command == TOSERVER_INTERACT)
2862 std::string datastring((char*)&data[2], datasize-2);
2863 std::istringstream is(datastring, std::ios_base::binary);
2869 [5] u32 length of the next item
2870 [9] serialized PointedThing
2872 0: start digging (from undersurface) or use
2873 1: stop digging (all parameters ignored)
2874 2: digging completed
2875 3: place block or item (to abovesurface)
2878 u8 action = readU8(is);
2879 u16 item_i = readU16(is);
2880 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2881 PointedThing pointed;
2882 pointed.deSerialize(tmp_is);
2884 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2885 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2889 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2890 <<" tried to interact, but is dead!"<<std::endl;
2894 v3f player_pos = playersao->getLastGoodPosition();
2896 // Update wielded item
2897 playersao->setWieldIndex(item_i);
2899 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2900 v3s16 p_under = pointed.node_undersurface;
2901 v3s16 p_above = pointed.node_abovesurface;
2903 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2904 ServerActiveObject *pointed_object = NULL;
2905 if(pointed.type == POINTEDTHING_OBJECT)
2907 pointed_object = m_env->getActiveObject(pointed.object_id);
2908 if(pointed_object == NULL)
2910 verbosestream<<"TOSERVER_INTERACT: "
2911 "pointed object is NULL"<<std::endl;
2917 v3f pointed_pos_under = player_pos;
2918 v3f pointed_pos_above = player_pos;
2919 if(pointed.type == POINTEDTHING_NODE)
2921 pointed_pos_under = intToFloat(p_under, BS);
2922 pointed_pos_above = intToFloat(p_above, BS);
2924 else if(pointed.type == POINTEDTHING_OBJECT)
2926 pointed_pos_under = pointed_object->getBasePosition();
2927 pointed_pos_above = pointed_pos_under;
2931 Check that target is reasonably close
2932 (only when digging or placing things)
2934 if(action == 0 || action == 2 || action == 3)
2936 float d = player_pos.getDistanceFrom(pointed_pos_under);
2937 float max_d = BS * 14; // Just some large enough value
2939 actionstream<<"Player "<<player->getName()
2940 <<" tried to access "<<pointed.dump()
2942 <<"d="<<d<<", max_d="<<max_d
2943 <<". ignoring."<<std::endl;
2944 // Re-send block to revert change on client-side
2945 RemoteClient *client = getClient(peer_id);
2946 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2947 client->SetBlockNotSent(blockpos);
2954 Make sure the player is allowed to do it
2956 if(!checkPriv(player->getName(), "interact"))
2958 actionstream<<player->getName()<<" attempted to interact with "
2959 <<pointed.dump()<<" without 'interact' privilege"
2961 // Re-send block to revert change on client-side
2962 RemoteClient *client = getClient(peer_id);
2963 // Digging completed -> under
2965 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2966 client->SetBlockNotSent(blockpos);
2968 // Placement -> above
2970 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2971 client->SetBlockNotSent(blockpos);
2977 If something goes wrong, this player is to blame
2979 RollbackScopeActor rollback_scope(m_rollback,
2980 std::string("player:")+player->getName());
2983 0: start digging or punch object
2987 if(pointed.type == POINTEDTHING_NODE)
2990 NOTE: This can be used in the future to check if
2991 somebody is cheating, by checking the timing.
2993 MapNode n(CONTENT_IGNORE);
2996 n = m_env->getMap().getNode(p_under);
2998 catch(InvalidPositionException &e)
3000 infostream<<"Server: Not punching: Node not found."
3001 <<" Adding block to emerge queue."
3003 m_emerge_queue.addBlock(peer_id,
3004 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3006 if(n.getContent() != CONTENT_IGNORE)
3007 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3009 playersao->noCheatDigStart(p_under);
3011 else if(pointed.type == POINTEDTHING_OBJECT)
3013 // Skip if object has been removed
3014 if(pointed_object->m_removed)
3017 actionstream<<player->getName()<<" punches object "
3018 <<pointed.object_id<<": "
3019 <<pointed_object->getDescription()<<std::endl;
3021 ItemStack punchitem = playersao->getWieldedItem();
3022 ToolCapabilities toolcap =
3023 punchitem.getToolCapabilities(m_itemdef);
3024 v3f dir = (pointed_object->getBasePosition() -
3025 (player->getPosition() + player->getEyeOffset())
3027 float time_from_last_punch =
3028 playersao->resetTimeFromLastPunch();
3029 pointed_object->punch(dir, &toolcap, playersao,
3030 time_from_last_punch);
3038 else if(action == 1)
3043 2: Digging completed
3045 else if(action == 2)
3047 // Only digging of nodes
3048 if(pointed.type == POINTEDTHING_NODE)
3050 MapNode n(CONTENT_IGNORE);
3053 n = m_env->getMap().getNode(p_under);
3055 catch(InvalidPositionException &e)
3057 infostream<<"Server: Not finishing digging: Node not found."
3058 <<" Adding block to emerge queue."
3060 m_emerge_queue.addBlock(peer_id,
3061 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3064 /* Cheat prevention */
3065 bool is_valid_dig = true;
3066 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3068 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3069 float nocheat_t = playersao->getNoCheatDigTime();
3070 playersao->noCheatDigEnd();
3071 // If player didn't start digging this, ignore dig
3072 if(nocheat_p != p_under){
3073 infostream<<"Server: NoCheat: "<<player->getName()
3074 <<" started digging "
3075 <<PP(nocheat_p)<<" and completed digging "
3076 <<PP(p_under)<<"; not digging."<<std::endl;
3077 is_valid_dig = false;
3079 // Get player's wielded item
3080 ItemStack playeritem;
3081 InventoryList *mlist = playersao->getInventory()->getList("main");
3083 playeritem = mlist->getItem(playersao->getWieldIndex());
3084 ToolCapabilities playeritem_toolcap =
3085 playeritem.getToolCapabilities(m_itemdef);
3086 // Get diggability and expected digging time
3087 DigParams params = getDigParams(m_nodedef->get(n).groups,
3088 &playeritem_toolcap);
3089 // If can't dig, try hand
3090 if(!params.diggable){
3091 const ItemDefinition &hand = m_itemdef->get("");
3092 const ToolCapabilities *tp = hand.tool_capabilities;
3094 params = getDigParams(m_nodedef->get(n).groups, tp);
3096 // If can't dig, ignore dig
3097 if(!params.diggable){
3098 infostream<<"Server: NoCheat: "<<player->getName()
3099 <<" completed digging "<<PP(p_under)
3100 <<", which is not diggable with tool. not digging."
3102 is_valid_dig = false;
3104 // If time is considerably too short, ignore dig
3105 // Check time only for medium and slow timed digs
3106 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3107 infostream<<"Server: NoCheat: "<<player->getName()
3108 <<" completed digging "
3109 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3110 <<params.time<<"s; not digging."<<std::endl;
3111 is_valid_dig = false;
3115 /* Actually dig node */
3117 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3118 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3120 // Send unusual result (that is, node not being removed)
3121 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3123 // Re-send block to revert change on client-side
3124 RemoteClient *client = getClient(peer_id);
3125 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3126 client->SetBlockNotSent(blockpos);
3132 3: place block or right-click object
3134 else if(action == 3)
3136 ItemStack item = playersao->getWieldedItem();
3138 // Reset build time counter
3139 if(pointed.type == POINTEDTHING_NODE &&
3140 item.getDefinition(m_itemdef).type == ITEM_NODE)
3141 getClient(peer_id)->m_time_from_building = 0.0;
3143 if(pointed.type == POINTEDTHING_OBJECT)
3145 // Right click object
3147 // Skip if object has been removed
3148 if(pointed_object->m_removed)
3151 actionstream<<player->getName()<<" right-clicks object "
3152 <<pointed.object_id<<": "
3153 <<pointed_object->getDescription()<<std::endl;
3156 pointed_object->rightClick(playersao);
3158 else if(scriptapi_item_on_place(m_lua,
3159 item, playersao, pointed))
3161 // Placement was handled in lua
3163 // Apply returned ItemStack
3164 playersao->setWieldedItem(item);
3167 // If item has node placement prediction, always send the above
3168 // node to make sure the client knows what exactly happened
3169 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3170 RemoteClient *client = getClient(peer_id);
3171 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3172 client->SetBlockNotSent(blockpos);
3179 else if(action == 4)
3181 ItemStack item = playersao->getWieldedItem();
3183 actionstream<<player->getName()<<" uses "<<item.name
3184 <<", pointing at "<<pointed.dump()<<std::endl;
3186 if(scriptapi_item_on_use(m_lua,
3187 item, playersao, pointed))
3189 // Apply returned ItemStack
3190 playersao->setWieldedItem(item);
3197 Catch invalid actions
3201 infostream<<"WARNING: Server: Invalid action "
3202 <<action<<std::endl;
3205 else if(command == TOSERVER_REMOVED_SOUNDS)
3207 std::string datastring((char*)&data[2], datasize-2);
3208 std::istringstream is(datastring, std::ios_base::binary);
3210 int num = readU16(is);
3211 for(int k=0; k<num; k++){
3212 s32 id = readS32(is);
3213 std::map<s32, ServerPlayingSound>::iterator i =
3214 m_playing_sounds.find(id);
3215 if(i == m_playing_sounds.end())
3217 ServerPlayingSound &psound = i->second;
3218 psound.clients.erase(peer_id);
3219 if(psound.clients.size() == 0)
3220 m_playing_sounds.erase(i++);
3223 else if(command == TOSERVER_NODEMETA_FIELDS)
3225 std::string datastring((char*)&data[2], datasize-2);
3226 std::istringstream is(datastring, std::ios_base::binary);
3228 v3s16 p = readV3S16(is);
3229 std::string formname = deSerializeString(is);
3230 int num = readU16(is);
3231 std::map<std::string, std::string> fields;
3232 for(int k=0; k<num; k++){
3233 std::string fieldname = deSerializeString(is);
3234 std::string fieldvalue = deSerializeLongString(is);
3235 fields[fieldname] = fieldvalue;
3238 // If something goes wrong, this player is to blame
3239 RollbackScopeActor rollback_scope(m_rollback,
3240 std::string("player:")+player->getName());
3242 // Check the target node for rollback data; leave others unnoticed
3243 RollbackNode rn_old(&m_env->getMap(), p, this);
3245 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3248 // Report rollback data
3249 RollbackNode rn_new(&m_env->getMap(), p, this);
3250 if(rollback() && rn_new != rn_old){
3251 RollbackAction action;
3252 action.setSetNode(p, rn_old, rn_new);
3253 rollback()->reportAction(action);
3256 else if(command == TOSERVER_INVENTORY_FIELDS)
3258 std::string datastring((char*)&data[2], datasize-2);
3259 std::istringstream is(datastring, std::ios_base::binary);
3261 std::string formname = deSerializeString(is);
3262 int num = readU16(is);
3263 std::map<std::string, std::string> fields;
3264 for(int k=0; k<num; k++){
3265 std::string fieldname = deSerializeString(is);
3266 std::string fieldvalue = deSerializeLongString(is);
3267 fields[fieldname] = fieldvalue;
3270 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3274 infostream<<"Server::ProcessData(): Ignoring "
3275 "unknown command "<<command<<std::endl;
3279 catch(SendFailedException &e)
3281 errorstream<<"Server::ProcessData(): SendFailedException: "
3287 void Server::onMapEditEvent(MapEditEvent *event)
3289 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3290 if(m_ignore_map_edit_events)
3292 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3294 MapEditEvent *e = event->clone();
3295 m_unsent_map_edit_queue.push_back(e);
3298 Inventory* Server::getInventory(const InventoryLocation &loc)
3301 case InventoryLocation::UNDEFINED:
3304 case InventoryLocation::CURRENT_PLAYER:
3307 case InventoryLocation::PLAYER:
3309 Player *player = m_env->getPlayer(loc.name.c_str());
3312 PlayerSAO *playersao = player->getPlayerSAO();
3315 return playersao->getInventory();
3318 case InventoryLocation::NODEMETA:
3320 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3323 return meta->getInventory();
3326 case InventoryLocation::DETACHED:
3328 if(m_detached_inventories.count(loc.name) == 0)
3330 return m_detached_inventories[loc.name];
3338 void Server::setInventoryModified(const InventoryLocation &loc)
3341 case InventoryLocation::UNDEFINED:
3344 case InventoryLocation::PLAYER:
3346 Player *player = m_env->getPlayer(loc.name.c_str());
3349 PlayerSAO *playersao = player->getPlayerSAO();
3352 playersao->m_inventory_not_sent = true;
3353 playersao->m_wielded_item_not_sent = true;
3356 case InventoryLocation::NODEMETA:
3358 v3s16 blockpos = getNodeBlockPos(loc.p);
3360 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3362 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3364 setBlockNotSent(blockpos);
3367 case InventoryLocation::DETACHED:
3369 sendDetachedInventoryToAll(loc.name);
3377 core::list<PlayerInfo> Server::getPlayerInfo()
3379 DSTACK(__FUNCTION_NAME);
3380 JMutexAutoLock envlock(m_env_mutex);
3381 JMutexAutoLock conlock(m_con_mutex);
3383 core::list<PlayerInfo> list;
3385 core::list<Player*> players = m_env->getPlayers();
3387 core::list<Player*>::Iterator i;
3388 for(i = players.begin();
3389 i != players.end(); i++)
3393 Player *player = *i;
3396 // Copy info from connection to info struct
3397 info.id = player->peer_id;
3398 info.address = m_con.GetPeerAddress(player->peer_id);
3399 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3401 catch(con::PeerNotFoundException &e)
3403 // Set dummy peer info
3405 info.address = Address(0,0,0,0,0);
3409 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3410 info.position = player->getPosition();
3412 list.push_back(info);
3419 void Server::peerAdded(con::Peer *peer)
3421 DSTACK(__FUNCTION_NAME);
3422 verbosestream<<"Server::peerAdded(): peer->id="
3423 <<peer->id<<std::endl;
3426 c.type = PEER_ADDED;
3427 c.peer_id = peer->id;
3429 m_peer_change_queue.push_back(c);
3432 void Server::deletingPeer(con::Peer *peer, bool timeout)
3434 DSTACK(__FUNCTION_NAME);
3435 verbosestream<<"Server::deletingPeer(): peer->id="
3436 <<peer->id<<", timeout="<<timeout<<std::endl;
3439 c.type = PEER_REMOVED;
3440 c.peer_id = peer->id;
3441 c.timeout = timeout;
3442 m_peer_change_queue.push_back(c);
3449 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3451 DSTACK(__FUNCTION_NAME);
3452 std::ostringstream os(std::ios_base::binary);
3454 writeU16(os, TOCLIENT_HP);
3458 std::string s = os.str();
3459 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3461 con.Send(peer_id, 0, data, true);
3464 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3465 const std::wstring &reason)
3467 DSTACK(__FUNCTION_NAME);
3468 std::ostringstream os(std::ios_base::binary);
3470 writeU16(os, TOCLIENT_ACCESS_DENIED);
3471 os<<serializeWideString(reason);
3474 std::string s = os.str();
3475 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3477 con.Send(peer_id, 0, data, true);
3480 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3481 bool set_camera_point_target, v3f camera_point_target)
3483 DSTACK(__FUNCTION_NAME);
3484 std::ostringstream os(std::ios_base::binary);
3486 writeU16(os, TOCLIENT_DEATHSCREEN);
3487 writeU8(os, set_camera_point_target);
3488 writeV3F1000(os, camera_point_target);
3491 std::string s = os.str();
3492 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3494 con.Send(peer_id, 0, data, true);
3497 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3498 IItemDefManager *itemdef)
3500 DSTACK(__FUNCTION_NAME);
3501 std::ostringstream os(std::ios_base::binary);
3505 u32 length of the next item
3506 zlib-compressed serialized ItemDefManager
3508 writeU16(os, TOCLIENT_ITEMDEF);
3509 std::ostringstream tmp_os(std::ios::binary);
3510 itemdef->serialize(tmp_os);
3511 std::ostringstream tmp_os2(std::ios::binary);
3512 compressZlib(tmp_os.str(), tmp_os2);
3513 os<<serializeLongString(tmp_os2.str());
3516 std::string s = os.str();
3517 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3518 <<"): size="<<s.size()<<std::endl;
3519 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3521 con.Send(peer_id, 0, data, true);
3524 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3525 INodeDefManager *nodedef, u16 protocol_version)
3527 DSTACK(__FUNCTION_NAME);
3528 std::ostringstream os(std::ios_base::binary);
3532 u32 length of the next item
3533 zlib-compressed serialized NodeDefManager
3535 writeU16(os, TOCLIENT_NODEDEF);
3536 std::ostringstream tmp_os(std::ios::binary);
3537 nodedef->serialize(tmp_os, protocol_version);
3538 std::ostringstream tmp_os2(std::ios::binary);
3539 compressZlib(tmp_os.str(), tmp_os2);
3540 os<<serializeLongString(tmp_os2.str());
3543 std::string s = os.str();
3544 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3545 <<"): size="<<s.size()<<std::endl;
3546 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3548 con.Send(peer_id, 0, data, true);
3552 Non-static send methods
3555 void Server::SendInventory(u16 peer_id)
3557 DSTACK(__FUNCTION_NAME);
3559 PlayerSAO *playersao = getPlayerSAO(peer_id);
3562 playersao->m_inventory_not_sent = false;
3568 std::ostringstream os;
3569 playersao->getInventory()->serialize(os);
3571 std::string s = os.str();
3573 SharedBuffer<u8> data(s.size()+2);
3574 writeU16(&data[0], TOCLIENT_INVENTORY);
3575 memcpy(&data[2], s.c_str(), s.size());
3578 m_con.Send(peer_id, 0, data, true);
3581 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3583 DSTACK(__FUNCTION_NAME);
3585 std::ostringstream os(std::ios_base::binary);
3589 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3590 os.write((char*)buf, 2);
3593 writeU16(buf, message.size());
3594 os.write((char*)buf, 2);
3597 for(u32 i=0; i<message.size(); i++)
3601 os.write((char*)buf, 2);
3605 std::string s = os.str();
3606 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3608 m_con.Send(peer_id, 0, data, true);
3611 void Server::BroadcastChatMessage(const std::wstring &message)
3613 for(core::map<u16, RemoteClient*>::Iterator
3614 i = m_clients.getIterator();
3615 i.atEnd() == false; i++)
3617 // Get client and check that it is valid
3618 RemoteClient *client = i.getNode()->getValue();
3619 assert(client->peer_id == i.getNode()->getKey());
3620 if(client->serialization_version == SER_FMT_VER_INVALID)
3623 SendChatMessage(client->peer_id, message);
3627 void Server::SendPlayerHP(u16 peer_id)
3629 DSTACK(__FUNCTION_NAME);
3630 PlayerSAO *playersao = getPlayerSAO(peer_id);
3632 playersao->m_hp_not_sent = false;
3633 SendHP(m_con, peer_id, playersao->getHP());
3636 void Server::SendMovePlayer(u16 peer_id)
3638 DSTACK(__FUNCTION_NAME);
3639 Player *player = m_env->getPlayer(peer_id);
3642 std::ostringstream os(std::ios_base::binary);
3643 writeU16(os, TOCLIENT_MOVE_PLAYER);
3644 writeV3F1000(os, player->getPosition());
3645 writeF1000(os, player->getPitch());
3646 writeF1000(os, player->getYaw());
3649 v3f pos = player->getPosition();
3650 f32 pitch = player->getPitch();
3651 f32 yaw = player->getYaw();
3652 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3653 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3660 std::string s = os.str();
3661 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3663 m_con.Send(peer_id, 0, data, true);
3666 void Server::SendPlayerPrivileges(u16 peer_id)
3668 Player *player = m_env->getPlayer(peer_id);
3670 if(player->peer_id == PEER_ID_INEXISTENT)
3673 std::set<std::string> privs;
3674 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3676 std::ostringstream os(std::ios_base::binary);
3677 writeU16(os, TOCLIENT_PRIVILEGES);
3678 writeU16(os, privs.size());
3679 for(std::set<std::string>::const_iterator i = privs.begin();
3680 i != privs.end(); i++){
3681 os<<serializeString(*i);
3685 std::string s = os.str();
3686 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3688 m_con.Send(peer_id, 0, data, true);
3691 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3693 Player *player = m_env->getPlayer(peer_id);
3695 if(player->peer_id == PEER_ID_INEXISTENT)
3698 std::ostringstream os(std::ios_base::binary);
3699 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3700 os<<serializeLongString(player->inventory_formspec);
3703 std::string s = os.str();
3704 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3706 m_con.Send(peer_id, 0, data, true);
3709 s32 Server::playSound(const SimpleSoundSpec &spec,
3710 const ServerSoundParams ¶ms)
3712 // Find out initial position of sound
3713 bool pos_exists = false;
3714 v3f pos = params.getPos(m_env, &pos_exists);
3715 // If position is not found while it should be, cancel sound
3716 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3718 // Filter destination clients
3719 std::set<RemoteClient*> dst_clients;
3720 if(params.to_player != "")
3722 Player *player = m_env->getPlayer(params.to_player.c_str());
3724 infostream<<"Server::playSound: Player \""<<params.to_player
3725 <<"\" not found"<<std::endl;
3728 if(player->peer_id == PEER_ID_INEXISTENT){
3729 infostream<<"Server::playSound: Player \""<<params.to_player
3730 <<"\" not connected"<<std::endl;
3733 RemoteClient *client = getClient(player->peer_id);
3734 dst_clients.insert(client);
3738 for(core::map<u16, RemoteClient*>::Iterator
3739 i = m_clients.getIterator(); i.atEnd() == false; i++)
3741 RemoteClient *client = i.getNode()->getValue();
3742 Player *player = m_env->getPlayer(client->peer_id);
3746 if(player->getPosition().getDistanceFrom(pos) >
3747 params.max_hear_distance)
3750 dst_clients.insert(client);
3753 if(dst_clients.size() == 0)
3756 s32 id = m_next_sound_id++;
3757 // The sound will exist as a reference in m_playing_sounds
3758 m_playing_sounds[id] = ServerPlayingSound();
3759 ServerPlayingSound &psound = m_playing_sounds[id];
3760 psound.params = params;
3761 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3762 i != dst_clients.end(); i++)
3763 psound.clients.insert((*i)->peer_id);
3765 std::ostringstream os(std::ios_base::binary);
3766 writeU16(os, TOCLIENT_PLAY_SOUND);
3768 os<<serializeString(spec.name);
3769 writeF1000(os, spec.gain * params.gain);
3770 writeU8(os, params.type);
3771 writeV3F1000(os, pos);
3772 writeU16(os, params.object);
3773 writeU8(os, params.loop);
3775 std::string s = os.str();
3776 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3778 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3779 i != dst_clients.end(); i++){
3781 m_con.Send((*i)->peer_id, 0, data, true);
3785 void Server::stopSound(s32 handle)
3787 // Get sound reference
3788 std::map<s32, ServerPlayingSound>::iterator i =
3789 m_playing_sounds.find(handle);
3790 if(i == m_playing_sounds.end())
3792 ServerPlayingSound &psound = i->second;
3794 std::ostringstream os(std::ios_base::binary);
3795 writeU16(os, TOCLIENT_STOP_SOUND);
3796 writeS32(os, handle);
3798 std::string s = os.str();
3799 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3801 for(std::set<u16>::iterator i = psound.clients.begin();
3802 i != psound.clients.end(); i++){
3804 m_con.Send(*i, 0, data, true);
3806 // Remove sound reference
3807 m_playing_sounds.erase(i);
3810 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3811 core::list<u16> *far_players, float far_d_nodes)
3813 float maxd = far_d_nodes*BS;
3814 v3f p_f = intToFloat(p, BS);
3818 SharedBuffer<u8> reply(replysize);
3819 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3820 writeS16(&reply[2], p.X);
3821 writeS16(&reply[4], p.Y);
3822 writeS16(&reply[6], p.Z);
3824 for(core::map<u16, RemoteClient*>::Iterator
3825 i = m_clients.getIterator();
3826 i.atEnd() == false; i++)
3828 // Get client and check that it is valid
3829 RemoteClient *client = i.getNode()->getValue();
3830 assert(client->peer_id == i.getNode()->getKey());
3831 if(client->serialization_version == SER_FMT_VER_INVALID)
3834 // Don't send if it's the same one
3835 if(client->peer_id == ignore_id)
3841 Player *player = m_env->getPlayer(client->peer_id);
3844 // If player is far away, only set modified blocks not sent
3845 v3f player_pos = player->getPosition();
3846 if(player_pos.getDistanceFrom(p_f) > maxd)
3848 far_players->push_back(client->peer_id);
3855 m_con.Send(client->peer_id, 0, reply, true);
3859 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3860 core::list<u16> *far_players, float far_d_nodes)
3862 float maxd = far_d_nodes*BS;
3863 v3f p_f = intToFloat(p, BS);
3865 for(core::map<u16, RemoteClient*>::Iterator
3866 i = m_clients.getIterator();
3867 i.atEnd() == false; i++)
3869 // Get client and check that it is valid
3870 RemoteClient *client = i.getNode()->getValue();
3871 assert(client->peer_id == i.getNode()->getKey());
3872 if(client->serialization_version == SER_FMT_VER_INVALID)
3875 // Don't send if it's the same one
3876 if(client->peer_id == ignore_id)
3882 Player *player = m_env->getPlayer(client->peer_id);
3885 // If player is far away, only set modified blocks not sent
3886 v3f player_pos = player->getPosition();
3887 if(player_pos.getDistanceFrom(p_f) > maxd)
3889 far_players->push_back(client->peer_id);
3896 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3897 SharedBuffer<u8> reply(replysize);
3898 writeU16(&reply[0], TOCLIENT_ADDNODE);
3899 writeS16(&reply[2], p.X);
3900 writeS16(&reply[4], p.Y);
3901 writeS16(&reply[6], p.Z);
3902 n.serialize(&reply[8], client->serialization_version);
3905 m_con.Send(client->peer_id, 0, reply, true);
3909 void Server::setBlockNotSent(v3s16 p)
3911 for(core::map<u16, RemoteClient*>::Iterator
3912 i = m_clients.getIterator();
3913 i.atEnd()==false; i++)
3915 RemoteClient *client = i.getNode()->getValue();
3916 client->SetBlockNotSent(p);
3920 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3922 DSTACK(__FUNCTION_NAME);
3924 v3s16 p = block->getPos();
3928 bool completely_air = true;
3929 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3930 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3931 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3933 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3935 completely_air = false;
3936 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3941 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3943 infostream<<"[completely air] ";
3944 infostream<<std::endl;
3948 Create a packet with the block in the right format
3951 std::ostringstream os(std::ios_base::binary);
3952 block->serialize(os, ver, false);
3953 std::string s = os.str();
3954 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3956 u32 replysize = 8 + blockdata.getSize();
3957 SharedBuffer<u8> reply(replysize);
3958 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3959 writeS16(&reply[2], p.X);
3960 writeS16(&reply[4], p.Y);
3961 writeS16(&reply[6], p.Z);
3962 memcpy(&reply[8], *blockdata, blockdata.getSize());
3964 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3965 <<": \tpacket size: "<<replysize<<std::endl;*/
3970 m_con.Send(peer_id, 1, reply, true);
3973 void Server::SendBlocks(float dtime)
3975 DSTACK(__FUNCTION_NAME);
3977 JMutexAutoLock envlock(m_env_mutex);
3978 JMutexAutoLock conlock(m_con_mutex);
3980 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3982 core::array<PrioritySortedBlockTransfer> queue;
3984 s32 total_sending = 0;
3987 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3989 for(core::map<u16, RemoteClient*>::Iterator
3990 i = m_clients.getIterator();
3991 i.atEnd() == false; i++)
3993 RemoteClient *client = i.getNode()->getValue();
3994 assert(client->peer_id == i.getNode()->getKey());
3996 // If definitions and textures have not been sent, don't
3997 // send MapBlocks either
3998 if(!client->definitions_sent)
4001 total_sending += client->SendingCount();
4003 if(client->serialization_version == SER_FMT_VER_INVALID)
4006 client->GetNextBlocks(this, dtime, queue);
4011 // Lowest priority number comes first.
4012 // Lowest is most important.
4015 for(u32 i=0; i<queue.size(); i++)
4017 //TODO: Calculate limit dynamically
4018 if(total_sending >= g_settings->getS32
4019 ("max_simultaneous_block_sends_server_total"))
4022 PrioritySortedBlockTransfer q = queue[i];
4024 MapBlock *block = NULL;
4027 block = m_env->getMap().getBlockNoCreate(q.pos);
4029 catch(InvalidPositionException &e)
4034 RemoteClient *client = getClient(q.peer_id);
4036 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4038 client->SentBlock(q.pos);
4044 void Server::fillMediaCache()
4046 DSTACK(__FUNCTION_NAME);
4048 infostream<<"Server: Calculating media file checksums"<<std::endl;
4050 // Collect all media file paths
4051 std::list<std::string> paths;
4052 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4053 i != m_mods.end(); i++){
4054 const ModSpec &mod = *i;
4055 paths.push_back(mod.path + DIR_DELIM + "textures");
4056 paths.push_back(mod.path + DIR_DELIM + "sounds");
4057 paths.push_back(mod.path + DIR_DELIM + "media");
4058 paths.push_back(mod.path + DIR_DELIM + "models");
4060 std::string path_all = "textures";
4061 paths.push_back(path_all + DIR_DELIM + "all");
4063 // Collect media file information from paths into cache
4064 for(std::list<std::string>::iterator i = paths.begin();
4065 i != paths.end(); i++)
4067 std::string mediapath = *i;
4068 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4069 for(u32 j=0; j<dirlist.size(); j++){
4070 if(dirlist[j].dir) // Ignode dirs
4072 std::string filename = dirlist[j].name;
4073 // If name contains illegal characters, ignore the file
4074 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4075 infostream<<"Server: ignoring illegal file name: \""
4076 <<filename<<"\""<<std::endl;
4079 // If name is not in a supported format, ignore it
4080 const char *supported_ext[] = {
4081 ".png", ".jpg", ".bmp", ".tga",
4082 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4084 ".x", ".b3d", ".md2", ".obj",
4087 if(removeStringEnd(filename, supported_ext) == ""){
4088 infostream<<"Server: ignoring unsupported file extension: \""
4089 <<filename<<"\""<<std::endl;
4092 // Ok, attempt to load the file and add to cache
4093 std::string filepath = mediapath + DIR_DELIM + filename;
4095 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4096 if(fis.good() == false){
4097 errorstream<<"Server::fillMediaCache(): Could not open \""
4098 <<filename<<"\" for reading"<<std::endl;
4101 std::ostringstream tmp_os(std::ios_base::binary);
4105 fis.read(buf, 1024);
4106 std::streamsize len = fis.gcount();
4107 tmp_os.write(buf, len);
4116 errorstream<<"Server::fillMediaCache(): Failed to read \""
4117 <<filename<<"\""<<std::endl;
4120 if(tmp_os.str().length() == 0){
4121 errorstream<<"Server::fillMediaCache(): Empty file \""
4122 <<filepath<<"\""<<std::endl;
4127 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4129 unsigned char *digest = sha1.getDigest();
4130 std::string sha1_base64 = base64_encode(digest, 20);
4131 std::string sha1_hex = hex_encode((char*)digest, 20);
4135 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4136 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4141 struct SendableMediaAnnouncement
4144 std::string sha1_digest;
4146 SendableMediaAnnouncement(const std::string name_="",
4147 const std::string sha1_digest_=""):
4149 sha1_digest(sha1_digest_)
4153 void Server::sendMediaAnnouncement(u16 peer_id)
4155 DSTACK(__FUNCTION_NAME);
4157 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4160 core::list<SendableMediaAnnouncement> file_announcements;
4162 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4163 i != m_media.end(); i++){
4165 file_announcements.push_back(
4166 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4170 std::ostringstream os(std::ios_base::binary);
4178 u16 length of sha1_digest
4183 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4184 writeU16(os, file_announcements.size());
4186 for(core::list<SendableMediaAnnouncement>::Iterator
4187 j = file_announcements.begin();
4188 j != file_announcements.end(); j++){
4189 os<<serializeString(j->name);
4190 os<<serializeString(j->sha1_digest);
4194 std::string s = os.str();
4195 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4198 m_con.Send(peer_id, 0, data, true);
4202 struct SendableMedia
4208 SendableMedia(const std::string &name_="", const std::string path_="",
4209 const std::string &data_=""):
4216 void Server::sendRequestedMedia(u16 peer_id,
4217 const core::list<MediaRequest> &tosend)
4219 DSTACK(__FUNCTION_NAME);
4221 verbosestream<<"Server::sendRequestedMedia(): "
4222 <<"Sending files to client"<<std::endl;
4226 // Put 5kB in one bunch (this is not accurate)
4227 u32 bytes_per_bunch = 5000;
4229 core::array< core::list<SendableMedia> > file_bunches;
4230 file_bunches.push_back(core::list<SendableMedia>());
4232 u32 file_size_bunch_total = 0;
4234 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4235 i != tosend.end(); i++)
4237 if(m_media.find(i->name) == m_media.end()){
4238 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4239 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4243 //TODO get path + name
4244 std::string tpath = m_media[(*i).name].path;
4247 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4248 if(fis.good() == false){
4249 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4250 <<tpath<<"\" for reading"<<std::endl;
4253 std::ostringstream tmp_os(std::ios_base::binary);
4257 fis.read(buf, 1024);
4258 std::streamsize len = fis.gcount();
4259 tmp_os.write(buf, len);
4260 file_size_bunch_total += len;
4269 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4270 <<(*i).name<<"\""<<std::endl;
4273 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4274 <<tname<<"\""<<std::endl;*/
4276 file_bunches[file_bunches.size()-1].push_back(
4277 SendableMedia((*i).name, tpath, tmp_os.str()));
4279 // Start next bunch if got enough data
4280 if(file_size_bunch_total >= bytes_per_bunch){
4281 file_bunches.push_back(core::list<SendableMedia>());
4282 file_size_bunch_total = 0;
4287 /* Create and send packets */
4289 u32 num_bunches = file_bunches.size();
4290 for(u32 i=0; i<num_bunches; i++)
4292 std::ostringstream os(std::ios_base::binary);
4296 u16 total number of texture bunches
4297 u16 index of this bunch
4298 u32 number of files in this bunch
4307 writeU16(os, TOCLIENT_MEDIA);
4308 writeU16(os, num_bunches);
4310 writeU32(os, file_bunches[i].size());
4312 for(core::list<SendableMedia>::Iterator
4313 j = file_bunches[i].begin();
4314 j != file_bunches[i].end(); j++){
4315 os<<serializeString(j->name);
4316 os<<serializeLongString(j->data);
4320 std::string s = os.str();
4321 verbosestream<<"Server::sendRequestedMedia(): bunch "
4322 <<i<<"/"<<num_bunches
4323 <<" files="<<file_bunches[i].size()
4324 <<" size=" <<s.size()<<std::endl;
4325 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4327 m_con.Send(peer_id, 0, data, true);
4331 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4333 if(m_detached_inventories.count(name) == 0){
4334 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4337 Inventory *inv = m_detached_inventories[name];
4339 std::ostringstream os(std::ios_base::binary);
4340 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4341 os<<serializeString(name);
4345 std::string s = os.str();
4346 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4348 m_con.Send(peer_id, 0, data, true);
4351 void Server::sendDetachedInventoryToAll(const std::string &name)
4353 DSTACK(__FUNCTION_NAME);
4355 for(core::map<u16, RemoteClient*>::Iterator
4356 i = m_clients.getIterator();
4357 i.atEnd() == false; i++){
4358 RemoteClient *client = i.getNode()->getValue();
4359 sendDetachedInventory(name, client->peer_id);
4363 void Server::sendDetachedInventories(u16 peer_id)
4365 DSTACK(__FUNCTION_NAME);
4367 for(std::map<std::string, Inventory*>::iterator
4368 i = m_detached_inventories.begin();
4369 i != m_detached_inventories.end(); i++){
4370 const std::string &name = i->first;
4371 //Inventory *inv = i->second;
4372 sendDetachedInventory(name, peer_id);
4380 void Server::DiePlayer(u16 peer_id)
4382 DSTACK(__FUNCTION_NAME);
4384 PlayerSAO *playersao = getPlayerSAO(peer_id);
4387 infostream<<"Server::DiePlayer(): Player "
4388 <<playersao->getPlayer()->getName()
4389 <<" dies"<<std::endl;
4391 playersao->setHP(0);
4393 // Trigger scripted stuff
4394 scriptapi_on_dieplayer(m_lua, playersao);
4396 SendPlayerHP(peer_id);
4397 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4400 void Server::RespawnPlayer(u16 peer_id)
4402 DSTACK(__FUNCTION_NAME);
4404 PlayerSAO *playersao = getPlayerSAO(peer_id);
4407 infostream<<"Server::RespawnPlayer(): Player "
4408 <<playersao->getPlayer()->getName()
4409 <<" respawns"<<std::endl;
4411 playersao->setHP(PLAYER_MAX_HP);
4413 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4415 v3f pos = findSpawnPos(m_env->getServerMap());
4416 playersao->setPos(pos);
4420 void Server::UpdateCrafting(u16 peer_id)
4422 DSTACK(__FUNCTION_NAME);
4424 Player* player = m_env->getPlayer(peer_id);
4427 // Get a preview for crafting
4429 getCraftingResult(&player->inventory, preview, false, this);
4431 // Put the new preview in
4432 InventoryList *plist = player->inventory.getList("craftpreview");
4434 assert(plist->getSize() >= 1);
4435 plist->changeItem(0, preview);
4438 RemoteClient* Server::getClient(u16 peer_id)
4440 DSTACK(__FUNCTION_NAME);
4441 //JMutexAutoLock lock(m_con_mutex);
4442 core::map<u16, RemoteClient*>::Node *n;
4443 n = m_clients.find(peer_id);
4444 // A client should exist for all peers
4446 return n->getValue();
4449 std::wstring Server::getStatusString()
4451 std::wostringstream os(std::ios_base::binary);
4454 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4456 os<<L", uptime="<<m_uptime.get();
4457 // Information about clients
4458 core::map<u16, RemoteClient*>::Iterator i;
4461 for(i = m_clients.getIterator(), first = true;
4462 i.atEnd() == false; i++)
4464 // Get client and check that it is valid
4465 RemoteClient *client = i.getNode()->getValue();
4466 assert(client->peer_id == i.getNode()->getKey());
4467 if(client->serialization_version == SER_FMT_VER_INVALID)
4470 Player *player = m_env->getPlayer(client->peer_id);
4471 // Get name of player
4472 std::wstring name = L"unknown";
4474 name = narrow_to_wide(player->getName());
4475 // Add name to information string
4483 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4484 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4485 if(g_settings->get("motd") != "")
4486 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4490 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4492 std::set<std::string> privs;
4493 scriptapi_get_auth(m_lua, name, NULL, &privs);
4497 bool Server::checkPriv(const std::string &name, const std::string &priv)
4499 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4500 return (privs.count(priv) != 0);
4503 void Server::reportPrivsModified(const std::string &name)
4506 for(core::map<u16, RemoteClient*>::Iterator
4507 i = m_clients.getIterator();
4508 i.atEnd() == false; i++){
4509 RemoteClient *client = i.getNode()->getValue();
4510 Player *player = m_env->getPlayer(client->peer_id);
4511 reportPrivsModified(player->getName());
4514 Player *player = m_env->getPlayer(name.c_str());
4517 SendPlayerPrivileges(player->peer_id);
4518 PlayerSAO *sao = player->getPlayerSAO();
4521 sao->updatePrivileges(
4522 getPlayerEffectivePrivs(name),
4527 void Server::reportInventoryFormspecModified(const std::string &name)
4529 Player *player = m_env->getPlayer(name.c_str());
4532 SendPlayerInventoryFormspec(player->peer_id);
4535 // Saves g_settings to configpath given at initialization
4536 void Server::saveConfig()
4538 if(m_path_config != "")
4539 g_settings->updateConfigFile(m_path_config.c_str());
4542 void Server::notifyPlayer(const char *name, const std::wstring msg)
4544 Player *player = m_env->getPlayer(name);
4547 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4550 void Server::notifyPlayers(const std::wstring msg)
4552 BroadcastChatMessage(msg);
4555 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4559 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4560 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4563 Inventory* Server::createDetachedInventory(const std::string &name)
4565 if(m_detached_inventories.count(name) > 0){
4566 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4567 delete m_detached_inventories[name];
4569 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4571 Inventory *inv = new Inventory(m_itemdef);
4573 m_detached_inventories[name] = inv;
4574 sendDetachedInventoryToAll(name);
4581 BoolScopeSet(bool *dst, bool val):
4584 m_orig_state = *m_dst;
4589 *m_dst = m_orig_state;
4596 // actions: time-reversed list
4597 // Return value: success/failure
4598 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4599 std::list<std::string> *log)
4601 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4602 ServerMap *map = (ServerMap*)(&m_env->getMap());
4603 // Disable rollback report sink while reverting
4604 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4606 // Fail if no actions to handle
4607 if(actions.empty()){
4608 log->push_back("Nothing to do.");
4615 for(std::list<RollbackAction>::const_iterator
4616 i = actions.begin();
4617 i != actions.end(); i++)
4619 const RollbackAction &action = *i;
4621 bool success = action.applyRevert(map, this, this);
4624 std::ostringstream os;
4625 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4626 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4628 log->push_back(os.str());
4630 std::ostringstream os;
4631 os<<"Succesfully reverted step ("<<num_tried<<") "<<action.toString();
4632 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4634 log->push_back(os.str());
4638 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4639 <<" failed"<<std::endl;
4641 // Call it done if less than half failed
4642 return num_failed <= num_tried/2;
4645 // IGameDef interface
4647 IItemDefManager* Server::getItemDefManager()
4651 INodeDefManager* Server::getNodeDefManager()
4655 ICraftDefManager* Server::getCraftDefManager()
4659 ITextureSource* Server::getTextureSource()
4663 u16 Server::allocateUnknownNodeId(const std::string &name)
4665 return m_nodedef->allocateDummy(name);
4667 ISoundManager* Server::getSoundManager()
4669 return &dummySoundManager;
4671 MtEventManager* Server::getEventManager()
4675 IRollbackReportSink* Server::getRollbackReportSink()
4677 if(!m_enable_rollback_recording)
4679 if(!m_rollback_sink_enabled)
4684 IWritableItemDefManager* Server::getWritableItemDefManager()
4688 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4692 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4697 const ModSpec* Server::getModSpec(const std::string &modname)
4699 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4700 i != m_mods.end(); i++){
4701 const ModSpec &mod = *i;
4702 if(mod.name == modname)
4707 void Server::getModNames(core::list<std::string> &modlist)
4709 for(core::list<ModSpec>::Iterator i = m_mods.begin(); i != m_mods.end(); i++)
4711 modlist.push_back((*i).name);
4714 std::string Server::getBuiltinLuaPath()
4716 return porting::path_share + DIR_DELIM + "builtin";
4719 v3f findSpawnPos(ServerMap &map)
4721 //return v3f(50,50,50)*BS;
4726 nodepos = v2s16(0,0);
4731 // Try to find a good place a few times
4732 for(s32 i=0; i<1000; i++)
4735 // We're going to try to throw the player to this position
4736 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4737 -range + (myrand()%(range*2)));
4738 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4739 // Get ground height at point (fallbacks to heightmap function)
4740 s16 groundheight = map.findGroundLevel(nodepos2d);
4741 // Don't go underwater
4742 if(groundheight < WATER_LEVEL)
4744 //infostream<<"-> Underwater"<<std::endl;
4747 // Don't go to high places
4748 if(groundheight > WATER_LEVEL + 4)
4750 //infostream<<"-> Underwater"<<std::endl;
4754 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4755 bool is_good = false;
4757 for(s32 i=0; i<10; i++){
4758 v3s16 blockpos = getNodeBlockPos(nodepos);
4759 map.emergeBlock(blockpos, true);
4760 MapNode n = map.getNodeNoEx(nodepos);
4761 if(n.getContent() == CONTENT_AIR){
4772 // Found a good place
4773 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4779 return intToFloat(nodepos, BS);
4782 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4784 RemotePlayer *player = NULL;
4785 bool newplayer = false;
4788 Try to get an existing player
4790 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4792 // If player is already connected, cancel
4793 if(player != NULL && player->peer_id != 0)
4795 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4800 If player with the wanted peer_id already exists, cancel.
4802 if(m_env->getPlayer(peer_id) != NULL)
4804 infostream<<"emergePlayer(): Player with wrong name but same"
4805 " peer_id already exists"<<std::endl;
4810 Create a new player if it doesn't exist yet
4815 player = new RemotePlayer(this);
4816 player->updateName(name);
4818 /* Set player position */
4819 infostream<<"Server: Finding spawn place for player \""
4820 <<name<<"\""<<std::endl;
4821 v3f pos = findSpawnPos(m_env->getServerMap());
4822 player->setPosition(pos);
4824 /* Add player to environment */
4825 m_env->addPlayer(player);
4829 Create a new player active object
4831 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4832 getPlayerEffectivePrivs(player->getName()),
4835 /* Add object to environment */
4836 m_env->addActiveObject(playersao);
4840 scriptapi_on_newplayer(m_lua, playersao);
4842 scriptapi_on_joinplayer(m_lua, playersao);
4847 void Server::handlePeerChange(PeerChange &c)
4849 JMutexAutoLock envlock(m_env_mutex);
4850 JMutexAutoLock conlock(m_con_mutex);
4852 if(c.type == PEER_ADDED)
4859 core::map<u16, RemoteClient*>::Node *n;
4860 n = m_clients.find(c.peer_id);
4861 // The client shouldn't already exist
4865 RemoteClient *client = new RemoteClient();
4866 client->peer_id = c.peer_id;
4867 m_clients.insert(client->peer_id, client);
4870 else if(c.type == PEER_REMOVED)
4877 core::map<u16, RemoteClient*>::Node *n;
4878 n = m_clients.find(c.peer_id);
4879 // The client should exist
4883 Mark objects to be not known by the client
4885 RemoteClient *client = n->getValue();
4887 for(core::map<u16, bool>::Iterator
4888 i = client->m_known_objects.getIterator();
4889 i.atEnd()==false; i++)
4892 u16 id = i.getNode()->getKey();
4893 ServerActiveObject* obj = m_env->getActiveObject(id);
4895 if(obj && obj->m_known_by_count > 0)
4896 obj->m_known_by_count--;
4900 Clear references to playing sounds
4902 for(std::map<s32, ServerPlayingSound>::iterator
4903 i = m_playing_sounds.begin();
4904 i != m_playing_sounds.end();)
4906 ServerPlayingSound &psound = i->second;
4907 psound.clients.erase(c.peer_id);
4908 if(psound.clients.size() == 0)
4909 m_playing_sounds.erase(i++);
4914 Player *player = m_env->getPlayer(c.peer_id);
4916 // Collect information about leaving in chat
4917 std::wstring message;
4921 std::wstring name = narrow_to_wide(player->getName());
4924 message += L" left the game.";
4926 message += L" (timed out)";
4930 /* Run scripts and remove from environment */
4934 PlayerSAO *playersao = player->getPlayerSAO();
4937 scriptapi_on_leaveplayer(m_lua, playersao);
4939 playersao->disconnected();
4949 std::ostringstream os(std::ios_base::binary);
4950 for(core::map<u16, RemoteClient*>::Iterator
4951 i = m_clients.getIterator();
4952 i.atEnd() == false; i++)
4954 RemoteClient *client = i.getNode()->getValue();
4955 assert(client->peer_id == i.getNode()->getKey());
4956 if(client->serialization_version == SER_FMT_VER_INVALID)
4959 Player *player = m_env->getPlayer(client->peer_id);
4962 // Get name of player
4963 os<<player->getName()<<" ";
4966 actionstream<<player->getName()<<" "
4967 <<(c.timeout?"times out.":"leaves game.")
4968 <<" List of players: "
4969 <<os.str()<<std::endl;
4974 delete m_clients[c.peer_id];
4975 m_clients.remove(c.peer_id);
4977 // Send player info to all remaining clients
4978 //SendPlayerInfos();
4980 // Send leave chat message to all remaining clients
4981 if(message.length() != 0)
4982 BroadcastChatMessage(message);
4991 void Server::handlePeerChanges()
4993 while(m_peer_change_queue.size() > 0)
4995 PeerChange c = m_peer_change_queue.pop_front();
4997 verbosestream<<"Server: Handling peer change: "
4998 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5001 handlePeerChange(c);
5005 void dedicated_server_loop(Server &server, bool &kill)
5007 DSTACK(__FUNCTION_NAME);
5009 verbosestream<<"dedicated_server_loop()"<<std::endl;
5011 IntervalLimiter m_profiler_interval;
5015 float steplen = g_settings->getFloat("dedicated_server_step");
5016 // This is kind of a hack but can be done like this
5017 // because server.step() is very light
5019 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5020 sleep_ms((int)(steplen*1000.0));
5022 server.step(steplen);
5024 if(server.getShutdownRequested() || kill)
5026 infostream<<"Dedicated server quitting"<<std::endl;
5033 float profiler_print_interval =
5034 g_settings->getFloat("profiler_print_interval");
5035 if(profiler_print_interval != 0)
5037 if(m_profiler_interval.step(steplen, profiler_print_interval))
5039 infostream<<"Profiler:"<<std::endl;
5040 g_profiler->print(infostream);
5041 g_profiler->clear();