3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "clientserver.h"
25 #include "jmutexautolock.h"
27 #include "constants.h"
32 #include "serverobject.h"
37 #include "scriptapi.h"
42 #include "content_mapnode.h"
43 #include "content_nodemeta.h"
44 #include "content_abm.h"
45 #include "content_sao.h"
50 #include "sound.h" // dummySoundManager
51 #include "event_manager.h"
53 #include "util/string.h"
54 #include "util/pointedthing.h"
55 #include "util/mathconstants.h"
57 #include "util/serialize.h"
59 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
61 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
63 class MapEditEventIgnorer
66 MapEditEventIgnorer(bool *flag):
75 ~MapEditEventIgnorer()
88 class MapEditEventAreaIgnorer
91 MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
92 m_ignorevariable(ignorevariable)
94 if(m_ignorevariable->getVolume() == 0)
95 *m_ignorevariable = a;
97 m_ignorevariable = NULL;
100 ~MapEditEventAreaIgnorer()
104 assert(m_ignorevariable->getVolume() != 0);
105 *m_ignorevariable = VoxelArea();
110 VoxelArea *m_ignorevariable;
113 void * ServerThread::Thread()
117 log_register_thread("ServerThread");
119 DSTACK(__FUNCTION_NAME);
121 BEGIN_DEBUG_EXCEPTION_HANDLER
126 //TimeTaker timer("AsyncRunStep() + Receive()");
129 //TimeTaker timer("AsyncRunStep()");
130 m_server->AsyncRunStep();
133 //infostream<<"Running m_server->Receive()"<<std::endl;
136 catch(con::NoIncomingDataException &e)
139 catch(con::PeerNotFoundException &e)
141 infostream<<"Server: PeerNotFoundException"<<std::endl;
143 catch(con::ConnectionBindFailed &e)
145 m_server->setAsyncFatalError(e.what());
149 m_server->setAsyncFatalError(e.what());
153 END_DEBUG_EXCEPTION_HANDLER(errorstream)
158 void * EmergeThread::Thread()
162 log_register_thread("EmergeThread");
164 DSTACK(__FUNCTION_NAME);
166 BEGIN_DEBUG_EXCEPTION_HANDLER
168 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
170 v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
173 Get block info from queue, emerge them and send them
176 After queue is empty, exit.
180 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
184 SharedPtr<QueuedBlockEmerge> q(qptr);
192 Do not generate over-limit
194 if(blockpos_over_limit(p))
197 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
199 //TimeTaker timer("block emerge");
202 Try to emerge it from somewhere.
204 If it is only wanted as optional, only loading from disk
209 Check if any peer wants it as non-optional. In that case it
212 Also decrement the emerge queue count in clients.
215 bool only_from_disk = true;
218 core::map<u16, u8>::Iterator i;
219 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
221 //u16 peer_id = i.getNode()->getKey();
224 u8 flags = i.getNode()->getValue();
225 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
226 only_from_disk = false;
231 if(enable_mapgen_debug_info)
232 infostream<<"EmergeThread: p="
233 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
234 <<"only_from_disk="<<only_from_disk<<std::endl;
236 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
238 MapBlock *block = NULL;
239 bool got_block = true;
240 core::map<v3s16, MapBlock*> modified_blocks;
243 Try to fetch block from memory or disk.
244 If not found and asked to generate, initialize generator.
247 bool started_generate = false;
248 mapgen::BlockMakeData data;
251 JMutexAutoLock envlock(m_server->m_env_mutex);
253 // Load sector if it isn't loaded
254 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
255 map.loadSectorMeta(p2d);
257 // Attempt to load block
258 block = map.getBlockNoCreateNoEx(p);
259 if(!block || block->isDummy() || !block->isGenerated())
261 if(enable_mapgen_debug_info)
262 infostream<<"EmergeThread: not in memory, "
263 <<"attempting to load from disk"<<std::endl;
265 block = map.loadBlock(p);
268 // If could not load and allowed to generate, start generation
269 // inside this same envlock
270 if(only_from_disk == false &&
271 (block == NULL || block->isGenerated() == false)){
272 if(enable_mapgen_debug_info)
273 infostream<<"EmergeThread: generating"<<std::endl;
274 started_generate = true;
276 map.initBlockMake(&data, p);
281 If generator was initialized, generate now when envlock is free.
286 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
288 TimeTaker t("mapgen::make_block()");
290 mapgen::make_block(&data);
292 if(enable_mapgen_debug_info == false)
293 t.stop(true); // Hide output
297 // Lock environment again to access the map
298 JMutexAutoLock envlock(m_server->m_env_mutex);
300 ScopeProfiler sp(g_profiler, "EmergeThread: after "
301 "mapgen::make_block (envlock)", SPT_AVG);
303 // Blit data back on map, update lighting, add mobs and
304 // whatever this does
305 map.finishBlockMake(&data, modified_blocks);
308 block = map.getBlockNoCreateNoEx(p);
310 // If block doesn't exist, don't try doing anything with it
311 // This happens if the block is not in generation boundaries
316 Do some post-generate stuff
319 v3s16 minp = data.blockpos_min*MAP_BLOCKSIZE;
320 v3s16 maxp = data.blockpos_max*MAP_BLOCKSIZE +
321 v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
324 Ignore map edit events, they will not need to be
325 sent to anybody because the block hasn't been sent
328 //MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
329 MapEditEventAreaIgnorer ign(
330 &m_server->m_ignore_map_edit_events_area,
331 VoxelArea(minp, maxp));
333 TimeTaker timer("on_generated");
334 scriptapi_environment_on_generated(m_server->m_lua,
335 minp, maxp, mapgen::get_blockseed(data.seed, minp));
336 /*int t = timer.stop(true);
337 dstream<<"on_generated took "<<t<<"ms"<<std::endl;*/
340 if(enable_mapgen_debug_info)
341 infostream<<"EmergeThread: ended up with: "
342 <<analyze_block(block)<<std::endl;
344 // Activate objects and stuff
345 m_server->m_env->activateBlock(block, 0);
353 Set sent status of modified blocks on clients
356 // NOTE: Server's clients are also behind the connection mutex
357 JMutexAutoLock lock(m_server->m_con_mutex);
360 Add the originally fetched block to the modified list
364 modified_blocks.insert(p, block);
368 Set the modified blocks unsent for all the clients
371 for(core::map<u16, RemoteClient*>::Iterator
372 i = m_server->m_clients.getIterator();
373 i.atEnd() == false; i++)
375 RemoteClient *client = i.getNode()->getValue();
377 if(modified_blocks.size() > 0)
379 // Remove block from sent history
380 client->SetBlocksNotSent(modified_blocks);
384 catch(VersionMismatchException &e)
386 std::ostringstream err;
387 err<<"World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl;
388 err<<"----"<<std::endl;
389 err<<"\""<<e.what()<<"\""<<std::endl;
390 err<<"See debug.txt."<<std::endl;
391 err<<"World probably saved by a newer version of Minetest."<<std::endl;
392 m_server->setAsyncFatalError(err.str());
394 catch(SerializationError &e)
396 std::ostringstream err;
397 err<<"Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl;
398 err<<"----"<<std::endl;
399 err<<"\""<<e.what()<<"\""<<std::endl;
400 err<<"See debug.txt."<<std::endl;
401 err<<"You can ignore this using [ignore_world_load_errors = true]."<<std::endl;
402 m_server->setAsyncFatalError(err.str());
405 END_DEBUG_EXCEPTION_HANDLER(errorstream)
407 log_deregister_thread();
412 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
414 if(pos_exists) *pos_exists = false;
419 if(pos_exists) *pos_exists = true;
424 ServerActiveObject *sao = env->getActiveObject(object);
427 if(pos_exists) *pos_exists = true;
428 return sao->getBasePosition(); }
433 void RemoteClient::GetNextBlocks(Server *server, float dtime,
434 core::array<PrioritySortedBlockTransfer> &dest)
436 DSTACK(__FUNCTION_NAME);
439 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
442 m_nothing_to_send_pause_timer -= dtime;
443 m_nearest_unsent_reset_timer += dtime;
445 if(m_nothing_to_send_pause_timer >= 0)
448 Player *player = server->m_env->getPlayer(peer_id);
449 // This can happen sometimes; clients and players are not in perfect sync.
453 // Won't send anything if already sending
454 if(m_blocks_sending.size() >= g_settings->getU16
455 ("max_simultaneous_block_sends_per_client"))
457 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
461 //TimeTaker timer("RemoteClient::GetNextBlocks");
463 v3f playerpos = player->getPosition();
464 v3f playerspeed = player->getSpeed();
465 v3f playerspeeddir(0,0,0);
466 if(playerspeed.getLength() > 1.0*BS)
467 playerspeeddir = playerspeed / playerspeed.getLength();
468 // Predict to next block
469 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
471 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
473 v3s16 center = getNodeBlockPos(center_nodepos);
475 // Camera position and direction
476 v3f camera_pos = player->getEyePosition();
477 v3f camera_dir = v3f(0,0,1);
478 camera_dir.rotateYZBy(player->getPitch());
479 camera_dir.rotateXZBy(player->getYaw());
481 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
482 <<camera_dir.Z<<")"<<std::endl;*/
485 Get the starting value of the block finder radius.
488 if(m_last_center != center)
490 m_nearest_unsent_d = 0;
491 m_last_center = center;
494 /*infostream<<"m_nearest_unsent_reset_timer="
495 <<m_nearest_unsent_reset_timer<<std::endl;*/
497 // Reset periodically to workaround for some bugs or stuff
498 if(m_nearest_unsent_reset_timer > 20.0)
500 m_nearest_unsent_reset_timer = 0;
501 m_nearest_unsent_d = 0;
502 //infostream<<"Resetting m_nearest_unsent_d for "
503 // <<server->getPlayerName(peer_id)<<std::endl;
506 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
507 s16 d_start = m_nearest_unsent_d;
509 //infostream<<"d_start="<<d_start<<std::endl;
511 u16 max_simul_sends_setting = g_settings->getU16
512 ("max_simultaneous_block_sends_per_client");
513 u16 max_simul_sends_usually = max_simul_sends_setting;
516 Check the time from last addNode/removeNode.
518 Decrease send rate if player is building stuff.
520 m_time_from_building += dtime;
521 if(m_time_from_building < g_settings->getFloat(
522 "full_block_send_enable_min_time_from_building"))
524 max_simul_sends_usually
525 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
529 Number of blocks sending + number of blocks selected for sending
531 u32 num_blocks_selected = m_blocks_sending.size();
534 next time d will be continued from the d from which the nearest
535 unsent block was found this time.
537 This is because not necessarily any of the blocks found this
538 time are actually sent.
540 s32 new_nearest_unsent_d = -1;
542 s16 d_max = g_settings->getS16("max_block_send_distance");
543 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
545 // Don't loop very much at a time
546 s16 max_d_increment_at_time = 2;
547 if(d_max > d_start + max_d_increment_at_time)
548 d_max = d_start + max_d_increment_at_time;
549 /*if(d_max_gen > d_start+2)
550 d_max_gen = d_start+2;*/
552 //infostream<<"Starting from "<<d_start<<std::endl;
554 s32 nearest_emerged_d = -1;
555 s32 nearest_emergefull_d = -1;
556 s32 nearest_sent_d = -1;
557 bool queue_is_full = false;
560 for(d = d_start; d <= d_max; d++)
562 /*errorstream<<"checking d="<<d<<" for "
563 <<server->getPlayerName(peer_id)<<std::endl;*/
564 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
567 If m_nearest_unsent_d was changed by the EmergeThread
568 (it can change it to 0 through SetBlockNotSent),
570 Else update m_nearest_unsent_d
572 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
574 d = m_nearest_unsent_d;
575 last_nearest_unsent_d = m_nearest_unsent_d;
579 Get the border/face dot coordinates of a "d-radiused"
582 core::list<v3s16> list;
583 getFacePositions(list, d);
585 core::list<v3s16>::Iterator li;
586 for(li=list.begin(); li!=list.end(); li++)
588 v3s16 p = *li + center;
592 - Don't allow too many simultaneous transfers
593 - EXCEPT when the blocks are very close
595 Also, don't send blocks that are already flying.
598 // Start with the usual maximum
599 u16 max_simul_dynamic = max_simul_sends_usually;
601 // If block is very close, allow full maximum
602 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
603 max_simul_dynamic = max_simul_sends_setting;
605 // Don't select too many blocks for sending
606 if(num_blocks_selected >= max_simul_dynamic)
608 queue_is_full = true;
609 goto queue_full_break;
612 // Don't send blocks that are currently being transferred
613 if(m_blocks_sending.find(p) != NULL)
619 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
620 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
621 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
622 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
623 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
624 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
627 // If this is true, inexistent block will be made from scratch
628 bool generate = d <= d_max_gen;
631 /*// Limit the generating area vertically to 2/3
632 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
635 // Limit the send area vertically to 1/2
636 if(abs(p.Y - center.Y) > d_max / 2)
642 If block is far away, don't generate it unless it is
648 // Block center y in nodes
649 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
650 // Don't generate if it's very high or very low
651 if(y < -64 || y > 64)
655 v2s16 p2d_nodes_center(
659 // Get ground height in nodes
660 s16 gh = server->m_env->getServerMap().findGroundLevel(
663 // If differs a lot, don't generate
664 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
666 // Actually, don't even send it
672 //infostream<<"d="<<d<<std::endl;
675 Don't generate or send if not in sight
676 FIXME This only works if the client uses a small enough
677 FOV setting. The default of 72 degrees is fine.
680 float camera_fov = (72.0*M_PI/180) * 4./3.;
681 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
687 Don't send already sent blocks
690 if(m_blocks_sent.find(p) != NULL)
697 Check if map has this block
699 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
701 bool surely_not_found_on_disk = false;
702 bool block_is_invalid = false;
705 // Reset usage timer, this block will be of use in the future.
706 block->resetUsageTimer();
708 // Block is dummy if data doesn't exist.
709 // It means it has been not found from disk and not generated
712 surely_not_found_on_disk = true;
715 // Block is valid if lighting is up-to-date and data exists
716 if(block->isValid() == false)
718 block_is_invalid = true;
721 /*if(block->isFullyGenerated() == false)
723 block_is_invalid = true;
728 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
729 v2s16 chunkpos = map->sector_to_chunk(p2d);
730 if(map->chunkNonVolatile(chunkpos) == false)
731 block_is_invalid = true;
733 if(block->isGenerated() == false)
734 block_is_invalid = true;
737 If block is not close, don't send it unless it is near
740 Block is near ground level if night-time mesh
741 differs from day-time mesh.
745 if(block->getDayNightDiff() == false)
752 If block has been marked to not exist on disk (dummy)
753 and generating new ones is not wanted, skip block.
755 if(generate == false && surely_not_found_on_disk == true)
762 Add inexistent block to emerge queue.
764 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
766 //TODO: Get value from somewhere
767 // Allow only one block in emerge queue
768 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
769 // Allow two blocks in queue per client
770 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
772 // Make it more responsive when needing to generate stuff
773 if(surely_not_found_on_disk)
775 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
777 //infostream<<"Adding block to emerge queue"<<std::endl;
779 // Add it to the emerge queue and trigger the thread
782 if(generate == false)
783 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
785 server->m_emerge_queue.addBlock(peer_id, p, flags);
786 server->m_emergethread.trigger();
788 if(nearest_emerged_d == -1)
789 nearest_emerged_d = d;
791 if(nearest_emergefull_d == -1)
792 nearest_emergefull_d = d;
799 if(nearest_sent_d == -1)
803 Add block to send queue
806 /*errorstream<<"sending from d="<<d<<" to "
807 <<server->getPlayerName(peer_id)<<std::endl;*/
809 PrioritySortedBlockTransfer q((float)d, p, peer_id);
813 num_blocks_selected += 1;
818 //infostream<<"Stopped at "<<d<<std::endl;
820 // If nothing was found for sending and nothing was queued for
821 // emerging, continue next time browsing from here
822 if(nearest_emerged_d != -1){
823 new_nearest_unsent_d = nearest_emerged_d;
824 } else if(nearest_emergefull_d != -1){
825 new_nearest_unsent_d = nearest_emergefull_d;
827 if(d > g_settings->getS16("max_block_send_distance")){
828 new_nearest_unsent_d = 0;
829 m_nothing_to_send_pause_timer = 2.0;
830 /*infostream<<"GetNextBlocks(): d wrapped around for "
831 <<server->getPlayerName(peer_id)
832 <<"; setting to 0 and pausing"<<std::endl;*/
834 if(nearest_sent_d != -1)
835 new_nearest_unsent_d = nearest_sent_d;
837 new_nearest_unsent_d = d;
841 if(new_nearest_unsent_d != -1)
842 m_nearest_unsent_d = new_nearest_unsent_d;
844 /*timer_result = timer.stop(true);
845 if(timer_result != 0)
846 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
849 void RemoteClient::GotBlock(v3s16 p)
851 if(m_blocks_sending.find(p) != NULL)
852 m_blocks_sending.remove(p);
855 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
856 " m_blocks_sending"<<std::endl;*/
857 m_excess_gotblocks++;
859 m_blocks_sent.insert(p, true);
862 void RemoteClient::SentBlock(v3s16 p)
864 if(m_blocks_sending.find(p) == NULL)
865 m_blocks_sending.insert(p, 0.0);
867 infostream<<"RemoteClient::SentBlock(): Sent block"
868 " already in m_blocks_sending"<<std::endl;
871 void RemoteClient::SetBlockNotSent(v3s16 p)
873 m_nearest_unsent_d = 0;
875 if(m_blocks_sending.find(p) != NULL)
876 m_blocks_sending.remove(p);
877 if(m_blocks_sent.find(p) != NULL)
878 m_blocks_sent.remove(p);
881 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
883 m_nearest_unsent_d = 0;
885 for(core::map<v3s16, MapBlock*>::Iterator
886 i = blocks.getIterator();
887 i.atEnd()==false; i++)
889 v3s16 p = i.getNode()->getKey();
891 if(m_blocks_sending.find(p) != NULL)
892 m_blocks_sending.remove(p);
893 if(m_blocks_sent.find(p) != NULL)
894 m_blocks_sent.remove(p);
902 PlayerInfo::PlayerInfo()
908 void PlayerInfo::PrintLine(std::ostream *s)
911 (*s)<<"\""<<name<<"\" ("
912 <<(position.X/10)<<","<<(position.Y/10)
913 <<","<<(position.Z/10)<<") ";
915 (*s)<<" avg_rtt="<<avg_rtt;
924 const std::string &path_world,
925 const std::string &path_config,
926 const SubgameSpec &gamespec,
927 bool simple_singleplayer_mode
929 m_path_world(path_world),
930 m_path_config(path_config),
931 m_gamespec(gamespec),
932 m_simple_singleplayer_mode(simple_singleplayer_mode),
933 m_async_fatal_error(""),
935 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
936 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
938 m_rollback_sink_enabled(true),
939 m_enable_rollback_recording(false),
941 m_itemdef(createItemDefManager()),
942 m_nodedef(createNodeDefManager()),
943 m_craftdef(createCraftDefManager()),
944 m_event(new EventManager()),
946 m_emergethread(this),
947 m_time_of_day_send_timer(0),
949 m_shutdown_requested(false),
950 m_ignore_map_edit_events(false),
951 m_ignore_map_edit_events_peer_id(0)
953 m_liquid_transform_timer = 0.0;
954 m_print_info_timer = 0.0;
955 m_objectdata_timer = 0.0;
956 m_emergethread_trigger_timer = 0.0;
957 m_savemap_timer = 0.0;
961 m_step_dtime_mutex.Init();
965 throw ServerError("Supplied empty world path");
967 if(!gamespec.isValid())
968 throw ServerError("Supplied invalid gamespec");
970 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
971 if(m_simple_singleplayer_mode)
972 infostream<<" in simple singleplayer mode"<<std::endl;
974 infostream<<std::endl;
975 infostream<<"- world: "<<m_path_world<<std::endl;
976 infostream<<"- config: "<<m_path_config<<std::endl;
977 infostream<<"- game: "<<m_gamespec.path<<std::endl;
979 // Create rollback manager
980 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
981 m_rollback = createRollbackManager(rollback_path, this);
983 // Add world mod search path
984 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
985 // Add addon mod search path
986 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
987 i != m_gamespec.mods_paths.end(); i++)
988 m_modspaths.push_front((*i));
990 // Print out mod search paths
991 for(core::list<std::string>::Iterator i = m_modspaths.begin();
992 i != m_modspaths.end(); i++){
993 std::string modspath = *i;
994 infostream<<"- mods: "<<modspath<<std::endl;
997 // Path to builtin.lua
998 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
1000 // Create world if it doesn't exist
1001 if(!initializeWorld(m_path_world, m_gamespec.id))
1002 throw ServerError("Failed to initialize world");
1005 JMutexAutoLock envlock(m_env_mutex);
1006 JMutexAutoLock conlock(m_con_mutex);
1008 // Initialize scripting
1010 infostream<<"Server: Initializing Lua"<<std::endl;
1011 m_lua = script_init();
1014 scriptapi_export(m_lua, this);
1015 // Load and run builtin.lua
1016 infostream<<"Server: Loading builtin.lua [\""
1017 <<builtinpath<<"\"]"<<std::endl;
1018 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1020 errorstream<<"Server: Failed to load and run "
1021 <<builtinpath<<std::endl;
1022 throw ModError("Failed to load and run "+builtinpath);
1024 // Find mods in mod search paths
1025 m_mods = getMods(m_modspaths);
1027 infostream<<"Server: Loading mods: ";
1028 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1029 i != m_mods.end(); i++){
1030 const ModSpec &mod = *i;
1031 infostream<<mod.name<<" ";
1033 infostream<<std::endl;
1034 // Load and run "mod" scripts
1035 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1036 i != m_mods.end(); i++){
1037 const ModSpec &mod = *i;
1038 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1039 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1040 <<scriptpath<<"\"]"<<std::endl;
1041 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1043 errorstream<<"Server: Failed to load and run "
1044 <<scriptpath<<std::endl;
1045 throw ModError("Failed to load and run "+scriptpath);
1049 // Read Textures and calculate sha1 sums
1052 // Apply item aliases in the node definition manager
1053 m_nodedef->updateAliases(m_itemdef);
1055 // Initialize Environment
1057 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
1060 // Give environment reference to scripting api
1061 scriptapi_add_environment(m_lua, m_env);
1063 // Register us to receive map edit events
1064 m_env->getMap().addEventReceiver(this);
1066 // If file exists, load environment metadata
1067 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1069 infostream<<"Server: Loading environment metadata"<<std::endl;
1070 m_env->loadMeta(m_path_world);
1074 infostream<<"Server: Loading players"<<std::endl;
1075 m_env->deSerializePlayers(m_path_world);
1078 Add some test ActiveBlockModifiers to environment
1080 add_legacy_abms(m_env, m_nodedef);
1085 infostream<<"Server destructing"<<std::endl;
1088 Send shutdown message
1091 JMutexAutoLock conlock(m_con_mutex);
1093 std::wstring line = L"*** Server shutting down";
1096 Send the message to clients
1098 for(core::map<u16, RemoteClient*>::Iterator
1099 i = m_clients.getIterator();
1100 i.atEnd() == false; i++)
1102 // Get client and check that it is valid
1103 RemoteClient *client = i.getNode()->getValue();
1104 assert(client->peer_id == i.getNode()->getKey());
1105 if(client->serialization_version == SER_FMT_VER_INVALID)
1109 SendChatMessage(client->peer_id, line);
1111 catch(con::PeerNotFoundException &e)
1117 JMutexAutoLock envlock(m_env_mutex);
1118 JMutexAutoLock conlock(m_con_mutex);
1121 Execute script shutdown hooks
1123 scriptapi_on_shutdown(m_lua);
1127 JMutexAutoLock envlock(m_env_mutex);
1132 infostream<<"Server: Saving players"<<std::endl;
1133 m_env->serializePlayers(m_path_world);
1136 Save environment metadata
1138 infostream<<"Server: Saving environment metadata"<<std::endl;
1139 m_env->saveMeta(m_path_world);
1151 JMutexAutoLock clientslock(m_con_mutex);
1153 for(core::map<u16, RemoteClient*>::Iterator
1154 i = m_clients.getIterator();
1155 i.atEnd() == false; i++)
1158 delete i.getNode()->getValue();
1162 // Delete things in the reverse order of creation
1170 // Deinitialize scripting
1171 infostream<<"Server: Deinitializing scripting"<<std::endl;
1172 script_deinit(m_lua);
1174 // Delete detached inventories
1176 for(std::map<std::string, Inventory*>::iterator
1177 i = m_detached_inventories.begin();
1178 i != m_detached_inventories.end(); i++){
1184 void Server::start(unsigned short port)
1186 DSTACK(__FUNCTION_NAME);
1187 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1189 // Stop thread if already running
1192 // Initialize connection
1193 m_con.SetTimeoutMs(30);
1197 m_thread.setRun(true);
1200 // ASCII art for the win!
1202 <<" .__ __ __ "<<std::endl
1203 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1204 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1205 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1206 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1207 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1208 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1209 actionstream<<"Server for gameid=\""<<m_gamespec.id
1210 <<"\" listening on port "<<port<<"."<<std::endl;
1215 DSTACK(__FUNCTION_NAME);
1217 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1219 // Stop threads (set run=false first so both start stopping)
1220 m_thread.setRun(false);
1221 m_emergethread.setRun(false);
1223 m_emergethread.stop();
1225 infostream<<"Server: Threads stopped"<<std::endl;
1228 void Server::step(float dtime)
1230 DSTACK(__FUNCTION_NAME);
1235 JMutexAutoLock lock(m_step_dtime_mutex);
1236 m_step_dtime += dtime;
1238 // Throw if fatal error occurred in thread
1239 std::string async_err = m_async_fatal_error.get();
1240 if(async_err != ""){
1241 throw ServerError(async_err);
1245 void Server::AsyncRunStep()
1247 DSTACK(__FUNCTION_NAME);
1249 g_profiler->add("Server::AsyncRunStep (num)", 1);
1253 JMutexAutoLock lock1(m_step_dtime_mutex);
1254 dtime = m_step_dtime;
1258 // Send blocks to clients
1265 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1267 //infostream<<"Server steps "<<dtime<<std::endl;
1268 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1271 JMutexAutoLock lock1(m_step_dtime_mutex);
1272 m_step_dtime -= dtime;
1279 m_uptime.set(m_uptime.get() + dtime);
1283 // Process connection's timeouts
1284 JMutexAutoLock lock2(m_con_mutex);
1285 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1286 m_con.RunTimeouts(dtime);
1290 // This has to be called so that the client list gets synced
1291 // with the peer list of the connection
1292 handlePeerChanges();
1296 Update time of day and overall game time
1299 JMutexAutoLock envlock(m_env_mutex);
1301 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1304 Send to clients at constant intervals
1307 m_time_of_day_send_timer -= dtime;
1308 if(m_time_of_day_send_timer < 0.0)
1310 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1312 //JMutexAutoLock envlock(m_env_mutex);
1313 JMutexAutoLock conlock(m_con_mutex);
1315 for(core::map<u16, RemoteClient*>::Iterator
1316 i = m_clients.getIterator();
1317 i.atEnd() == false; i++)
1319 RemoteClient *client = i.getNode()->getValue();
1320 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1321 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1323 m_con.Send(client->peer_id, 0, data, true);
1329 JMutexAutoLock lock(m_env_mutex);
1331 ScopeProfiler sp(g_profiler, "SEnv step");
1332 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1336 const float map_timer_and_unload_dtime = 2.92;
1337 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1339 JMutexAutoLock lock(m_env_mutex);
1340 // Run Map's timers and unload unused data
1341 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1342 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1343 g_settings->getFloat("server_unload_unused_data_timeout"));
1354 JMutexAutoLock lock(m_env_mutex);
1355 JMutexAutoLock lock2(m_con_mutex);
1357 ScopeProfiler sp(g_profiler, "Server: handle players");
1359 for(core::map<u16, RemoteClient*>::Iterator
1360 i = m_clients.getIterator();
1361 i.atEnd() == false; i++)
1363 RemoteClient *client = i.getNode()->getValue();
1364 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1365 if(playersao == NULL)
1369 Handle player HPs (die if hp=0)
1371 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1373 if(playersao->getHP() == 0)
1374 DiePlayer(client->peer_id);
1376 SendPlayerHP(client->peer_id);
1380 Send player inventories if necessary
1382 if(playersao->m_moved){
1383 SendMovePlayer(client->peer_id);
1384 playersao->m_moved = false;
1386 if(playersao->m_inventory_not_sent){
1387 UpdateCrafting(client->peer_id);
1388 SendInventory(client->peer_id);
1393 /* Transform liquids */
1394 m_liquid_transform_timer += dtime;
1395 if(m_liquid_transform_timer >= 1.00)
1397 m_liquid_transform_timer -= 1.00;
1399 JMutexAutoLock lock(m_env_mutex);
1401 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1403 core::map<v3s16, MapBlock*> modified_blocks;
1404 m_env->getMap().transformLiquids(modified_blocks);
1409 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1410 ServerMap &map = ((ServerMap&)m_env->getMap());
1411 map.updateLighting(modified_blocks, lighting_modified_blocks);
1413 // Add blocks modified by lighting to modified_blocks
1414 for(core::map<v3s16, MapBlock*>::Iterator
1415 i = lighting_modified_blocks.getIterator();
1416 i.atEnd() == false; i++)
1418 MapBlock *block = i.getNode()->getValue();
1419 modified_blocks.insert(block->getPos(), block);
1423 Set the modified blocks unsent for all the clients
1426 JMutexAutoLock lock2(m_con_mutex);
1428 for(core::map<u16, RemoteClient*>::Iterator
1429 i = m_clients.getIterator();
1430 i.atEnd() == false; i++)
1432 RemoteClient *client = i.getNode()->getValue();
1434 if(modified_blocks.size() > 0)
1436 // Remove block from sent history
1437 client->SetBlocksNotSent(modified_blocks);
1442 // Periodically print some info
1444 float &counter = m_print_info_timer;
1450 JMutexAutoLock lock2(m_con_mutex);
1452 if(m_clients.size() != 0)
1453 infostream<<"Players:"<<std::endl;
1454 for(core::map<u16, RemoteClient*>::Iterator
1455 i = m_clients.getIterator();
1456 i.atEnd() == false; i++)
1458 //u16 peer_id = i.getNode()->getKey();
1459 RemoteClient *client = i.getNode()->getValue();
1460 Player *player = m_env->getPlayer(client->peer_id);
1463 infostream<<"* "<<player->getName()<<"\t";
1464 client->PrintInfo(infostream);
1469 //if(g_settings->getBool("enable_experimental"))
1473 Check added and deleted active objects
1476 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1477 JMutexAutoLock envlock(m_env_mutex);
1478 JMutexAutoLock conlock(m_con_mutex);
1480 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1482 // Radius inside which objects are active
1483 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1484 radius *= MAP_BLOCKSIZE;
1486 for(core::map<u16, RemoteClient*>::Iterator
1487 i = m_clients.getIterator();
1488 i.atEnd() == false; i++)
1490 RemoteClient *client = i.getNode()->getValue();
1492 // If definitions and textures have not been sent, don't
1493 // send objects either
1494 if(!client->definitions_sent)
1497 Player *player = m_env->getPlayer(client->peer_id);
1500 // This can happen if the client timeouts somehow
1501 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1503 <<" has no associated player"<<std::endl;*/
1506 v3s16 pos = floatToInt(player->getPosition(), BS);
1508 core::map<u16, bool> removed_objects;
1509 core::map<u16, bool> added_objects;
1510 m_env->getRemovedActiveObjects(pos, radius,
1511 client->m_known_objects, removed_objects);
1512 m_env->getAddedActiveObjects(pos, radius,
1513 client->m_known_objects, added_objects);
1515 // Ignore if nothing happened
1516 if(removed_objects.size() == 0 && added_objects.size() == 0)
1518 //infostream<<"active objects: none changed"<<std::endl;
1522 std::string data_buffer;
1526 // Handle removed objects
1527 writeU16((u8*)buf, removed_objects.size());
1528 data_buffer.append(buf, 2);
1529 for(core::map<u16, bool>::Iterator
1530 i = removed_objects.getIterator();
1531 i.atEnd()==false; i++)
1534 u16 id = i.getNode()->getKey();
1535 ServerActiveObject* obj = m_env->getActiveObject(id);
1537 // Add to data buffer for sending
1538 writeU16((u8*)buf, i.getNode()->getKey());
1539 data_buffer.append(buf, 2);
1541 // Remove from known objects
1542 client->m_known_objects.remove(i.getNode()->getKey());
1544 if(obj && obj->m_known_by_count > 0)
1545 obj->m_known_by_count--;
1548 // Handle added objects
1549 writeU16((u8*)buf, added_objects.size());
1550 data_buffer.append(buf, 2);
1551 for(core::map<u16, bool>::Iterator
1552 i = added_objects.getIterator();
1553 i.atEnd()==false; i++)
1556 u16 id = i.getNode()->getKey();
1557 ServerActiveObject* obj = m_env->getActiveObject(id);
1560 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1562 infostream<<"WARNING: "<<__FUNCTION_NAME
1563 <<": NULL object"<<std::endl;
1565 type = obj->getSendType();
1567 // Add to data buffer for sending
1568 writeU16((u8*)buf, id);
1569 data_buffer.append(buf, 2);
1570 writeU8((u8*)buf, type);
1571 data_buffer.append(buf, 1);
1574 data_buffer.append(serializeLongString(
1575 obj->getClientInitializationData(client->net_proto_version)));
1577 data_buffer.append(serializeLongString(""));
1579 // Add to known objects
1580 client->m_known_objects.insert(i.getNode()->getKey(), false);
1583 obj->m_known_by_count++;
1587 SharedBuffer<u8> reply(2 + data_buffer.size());
1588 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1589 memcpy((char*)&reply[2], data_buffer.c_str(),
1590 data_buffer.size());
1592 m_con.Send(client->peer_id, 0, reply, true);
1594 verbosestream<<"Server: Sent object remove/add: "
1595 <<removed_objects.size()<<" removed, "
1596 <<added_objects.size()<<" added, "
1597 <<"packet size is "<<reply.getSize()<<std::endl;
1602 Collect a list of all the objects known by the clients
1603 and report it back to the environment.
1606 core::map<u16, bool> all_known_objects;
1608 for(core::map<u16, RemoteClient*>::Iterator
1609 i = m_clients.getIterator();
1610 i.atEnd() == false; i++)
1612 RemoteClient *client = i.getNode()->getValue();
1613 // Go through all known objects of client
1614 for(core::map<u16, bool>::Iterator
1615 i = client->m_known_objects.getIterator();
1616 i.atEnd()==false; i++)
1618 u16 id = i.getNode()->getKey();
1619 all_known_objects[id] = true;
1623 m_env->setKnownActiveObjects(whatever);
1629 Send object messages
1632 JMutexAutoLock envlock(m_env_mutex);
1633 JMutexAutoLock conlock(m_con_mutex);
1635 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1638 // Value = data sent by object
1639 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1641 // Get active object messages from environment
1644 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1648 core::list<ActiveObjectMessage>* message_list = NULL;
1649 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1650 n = buffered_messages.find(aom.id);
1653 message_list = new core::list<ActiveObjectMessage>;
1654 buffered_messages.insert(aom.id, message_list);
1658 message_list = n->getValue();
1660 message_list->push_back(aom);
1663 // Route data to every client
1664 for(core::map<u16, RemoteClient*>::Iterator
1665 i = m_clients.getIterator();
1666 i.atEnd()==false; i++)
1668 RemoteClient *client = i.getNode()->getValue();
1669 std::string reliable_data;
1670 std::string unreliable_data;
1671 // Go through all objects in message buffer
1672 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1673 j = buffered_messages.getIterator();
1674 j.atEnd()==false; j++)
1676 // If object is not known by client, skip it
1677 u16 id = j.getNode()->getKey();
1678 if(client->m_known_objects.find(id) == NULL)
1680 // Get message list of object
1681 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1682 // Go through every message
1683 for(core::list<ActiveObjectMessage>::Iterator
1684 k = list->begin(); k != list->end(); k++)
1686 // Compose the full new data with header
1687 ActiveObjectMessage aom = *k;
1688 std::string new_data;
1691 writeU16((u8*)&buf[0], aom.id);
1692 new_data.append(buf, 2);
1694 new_data += serializeString(aom.datastring);
1695 // Add data to buffer
1697 reliable_data += new_data;
1699 unreliable_data += new_data;
1703 reliable_data and unreliable_data are now ready.
1706 if(reliable_data.size() > 0)
1708 SharedBuffer<u8> reply(2 + reliable_data.size());
1709 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1710 memcpy((char*)&reply[2], reliable_data.c_str(),
1711 reliable_data.size());
1713 m_con.Send(client->peer_id, 0, reply, true);
1715 if(unreliable_data.size() > 0)
1717 SharedBuffer<u8> reply(2 + unreliable_data.size());
1718 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1719 memcpy((char*)&reply[2], unreliable_data.c_str(),
1720 unreliable_data.size());
1721 // Send as unreliable
1722 m_con.Send(client->peer_id, 0, reply, false);
1725 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1727 infostream<<"Server: Size of object message data: "
1728 <<"reliable: "<<reliable_data.size()
1729 <<", unreliable: "<<unreliable_data.size()
1734 // Clear buffered_messages
1735 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1736 i = buffered_messages.getIterator();
1737 i.atEnd()==false; i++)
1739 delete i.getNode()->getValue();
1743 } // enable_experimental
1746 Send queued-for-sending map edit events.
1749 // We will be accessing the environment and the connection
1750 JMutexAutoLock lock(m_env_mutex);
1751 JMutexAutoLock conlock(m_con_mutex);
1753 // Don't send too many at a time
1756 // Single change sending is disabled if queue size is not small
1757 bool disable_single_change_sending = false;
1758 if(m_unsent_map_edit_queue.size() >= 4)
1759 disable_single_change_sending = true;
1761 int event_count = m_unsent_map_edit_queue.size();
1763 // We'll log the amount of each
1766 while(m_unsent_map_edit_queue.size() != 0)
1768 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1770 // Players far away from the change are stored here.
1771 // Instead of sending the changes, MapBlocks are set not sent
1773 core::list<u16> far_players;
1775 if(event->type == MEET_ADDNODE)
1777 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1778 prof.add("MEET_ADDNODE", 1);
1779 if(disable_single_change_sending)
1780 sendAddNode(event->p, event->n, event->already_known_by_peer,
1783 sendAddNode(event->p, event->n, event->already_known_by_peer,
1786 else if(event->type == MEET_REMOVENODE)
1788 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1789 prof.add("MEET_REMOVENODE", 1);
1790 if(disable_single_change_sending)
1791 sendRemoveNode(event->p, event->already_known_by_peer,
1794 sendRemoveNode(event->p, event->already_known_by_peer,
1797 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1799 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1800 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1801 setBlockNotSent(event->p);
1803 else if(event->type == MEET_OTHER)
1805 infostream<<"Server: MEET_OTHER"<<std::endl;
1806 prof.add("MEET_OTHER", 1);
1807 for(core::map<v3s16, bool>::Iterator
1808 i = event->modified_blocks.getIterator();
1809 i.atEnd()==false; i++)
1811 v3s16 p = i.getNode()->getKey();
1817 prof.add("unknown", 1);
1818 infostream<<"WARNING: Server: Unknown MapEditEvent "
1819 <<((u32)event->type)<<std::endl;
1823 Set blocks not sent to far players
1825 if(far_players.size() > 0)
1827 // Convert list format to that wanted by SetBlocksNotSent
1828 core::map<v3s16, MapBlock*> modified_blocks2;
1829 for(core::map<v3s16, bool>::Iterator
1830 i = event->modified_blocks.getIterator();
1831 i.atEnd()==false; i++)
1833 v3s16 p = i.getNode()->getKey();
1834 modified_blocks2.insert(p,
1835 m_env->getMap().getBlockNoCreateNoEx(p));
1837 // Set blocks not sent
1838 for(core::list<u16>::Iterator
1839 i = far_players.begin();
1840 i != far_players.end(); i++)
1843 RemoteClient *client = getClient(peer_id);
1846 client->SetBlocksNotSent(modified_blocks2);
1852 /*// Don't send too many at a time
1854 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1858 if(event_count >= 5){
1859 infostream<<"Server: MapEditEvents:"<<std::endl;
1860 prof.print(infostream);
1861 } else if(event_count != 0){
1862 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1863 prof.print(verbosestream);
1869 Trigger emergethread (it somehow gets to a non-triggered but
1870 bysy state sometimes)
1873 float &counter = m_emergethread_trigger_timer;
1879 m_emergethread.trigger();
1881 // Update m_enable_rollback_recording here too
1882 m_enable_rollback_recording =
1883 g_settings->getBool("enable_rollback_recording");
1887 // Save map, players and auth stuff
1889 float &counter = m_savemap_timer;
1891 if(counter >= g_settings->getFloat("server_map_save_interval"))
1894 JMutexAutoLock lock(m_env_mutex);
1896 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1899 if(m_banmanager.isModified())
1900 m_banmanager.save();
1902 // Save changed parts of map
1903 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1906 m_env->serializePlayers(m_path_world);
1908 // Save environment metadata
1909 m_env->saveMeta(m_path_world);
1914 void Server::Receive()
1916 DSTACK(__FUNCTION_NAME);
1917 SharedBuffer<u8> data;
1922 JMutexAutoLock conlock(m_con_mutex);
1923 datasize = m_con.Receive(peer_id, data);
1926 // This has to be called so that the client list gets synced
1927 // with the peer list of the connection
1928 handlePeerChanges();
1930 ProcessData(*data, datasize, peer_id);
1932 catch(con::InvalidIncomingDataException &e)
1934 infostream<<"Server::Receive(): "
1935 "InvalidIncomingDataException: what()="
1936 <<e.what()<<std::endl;
1938 catch(con::PeerNotFoundException &e)
1940 //NOTE: This is not needed anymore
1942 // The peer has been disconnected.
1943 // Find the associated player and remove it.
1945 /*JMutexAutoLock envlock(m_env_mutex);
1947 infostream<<"ServerThread: peer_id="<<peer_id
1948 <<" has apparently closed connection. "
1949 <<"Removing player."<<std::endl;
1951 m_env->removePlayer(peer_id);*/
1955 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1957 DSTACK(__FUNCTION_NAME);
1958 // Environment is locked first.
1959 JMutexAutoLock envlock(m_env_mutex);
1960 JMutexAutoLock conlock(m_con_mutex);
1962 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1965 Address address = m_con.GetPeerAddress(peer_id);
1966 std::string addr_s = address.serializeString();
1968 // drop player if is ip is banned
1969 if(m_banmanager.isIpBanned(addr_s)){
1970 infostream<<"Server: A banned client tried to connect from "
1971 <<addr_s<<"; banned name was "
1972 <<m_banmanager.getBanName(addr_s)<<std::endl;
1973 // This actually doesn't seem to transfer to the client
1974 SendAccessDenied(m_con, peer_id,
1975 L"Your ip is banned. Banned name was "
1976 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1977 m_con.DeletePeer(peer_id);
1981 catch(con::PeerNotFoundException &e)
1983 infostream<<"Server::ProcessData(): Cancelling: peer "
1984 <<peer_id<<" not found"<<std::endl;
1988 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1990 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1998 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
2000 if(command == TOSERVER_INIT)
2002 // [0] u16 TOSERVER_INIT
2003 // [2] u8 SER_FMT_VER_HIGHEST
2004 // [3] u8[20] player_name
2005 // [23] u8[28] password <--- can be sent without this, from old versions
2007 if(datasize < 2+1+PLAYERNAME_SIZE)
2010 verbosestream<<"Server: Got TOSERVER_INIT from "
2011 <<peer_id<<std::endl;
2013 // First byte after command is maximum supported
2014 // serialization version
2015 u8 client_max = data[2];
2016 u8 our_max = SER_FMT_VER_HIGHEST;
2017 // Use the highest version supported by both
2018 u8 deployed = core::min_(client_max, our_max);
2019 // If it's lower than the lowest supported, give up.
2020 if(deployed < SER_FMT_VER_LOWEST)
2021 deployed = SER_FMT_VER_INVALID;
2023 //peer->serialization_version = deployed;
2024 getClient(peer_id)->pending_serialization_version = deployed;
2026 if(deployed == SER_FMT_VER_INVALID)
2028 actionstream<<"Server: A mismatched client tried to connect from "
2029 <<addr_s<<std::endl;
2030 infostream<<"Server: Cannot negotiate "
2031 "serialization version with peer "
2032 <<peer_id<<std::endl;
2033 SendAccessDenied(m_con, peer_id, std::wstring(
2034 L"Your client's version is not supported.\n"
2035 L"Server version is ")
2036 + narrow_to_wide(VERSION_STRING) + L"."
2042 Read and check network protocol version
2045 u16 min_net_proto_version = 0;
2046 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2047 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2049 // Use same version as minimum and maximum if maximum version field
2050 // doesn't exist (backwards compatibility)
2051 u16 max_net_proto_version = min_net_proto_version;
2052 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
2053 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
2055 // Start with client's maximum version
2056 u16 net_proto_version = max_net_proto_version;
2058 // Figure out a working version if it is possible at all
2059 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
2060 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
2062 // If maximum is larger than our maximum, go with our maximum
2063 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2064 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
2065 // Else go with client's maximum
2067 net_proto_version = max_net_proto_version;
2070 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
2071 <<min_net_proto_version<<", max: "<<max_net_proto_version
2072 <<", chosen: "<<net_proto_version<<std::endl;
2074 getClient(peer_id)->net_proto_version = net_proto_version;
2076 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
2077 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2079 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
2081 SendAccessDenied(m_con, peer_id, std::wstring(
2082 L"Your client's version is not supported.\n"
2083 L"Server version is ")
2084 + narrow_to_wide(VERSION_STRING) + L",\n"
2085 + L"server's PROTOCOL_VERSION is "
2086 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
2088 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
2089 + L", client's PROTOCOL_VERSION is "
2090 + narrow_to_wide(itos(min_net_proto_version))
2092 + narrow_to_wide(itos(max_net_proto_version))
2097 if(g_settings->getBool("strict_protocol_version_checking"))
2099 if(net_proto_version != LATEST_PROTOCOL_VERSION)
2101 actionstream<<"Server: A mismatched (strict) client tried to "
2102 <<"connect from "<<addr_s<<std::endl;
2103 SendAccessDenied(m_con, peer_id, std::wstring(
2104 L"Your client's version is not supported.\n"
2105 L"Server version is ")
2106 + narrow_to_wide(VERSION_STRING) + L",\n"
2107 + L"server's PROTOCOL_VERSION (strict) is "
2108 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
2109 + L", client's PROTOCOL_VERSION is "
2110 + narrow_to_wide(itos(min_net_proto_version))
2112 + narrow_to_wide(itos(max_net_proto_version))
2123 char playername[PLAYERNAME_SIZE];
2124 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2126 playername[i] = data[3+i];
2128 playername[PLAYERNAME_SIZE-1] = 0;
2130 if(playername[0]=='\0')
2132 actionstream<<"Server: Player with an empty name "
2133 <<"tried to connect from "<<addr_s<<std::endl;
2134 SendAccessDenied(m_con, peer_id,
2139 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2141 actionstream<<"Server: Player with an invalid name "
2142 <<"tried to connect from "<<addr_s<<std::endl;
2143 SendAccessDenied(m_con, peer_id,
2144 L"Name contains unallowed characters");
2148 infostream<<"Server: New connection: \""<<playername<<"\" from "
2149 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2152 char given_password[PASSWORD_SIZE];
2153 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2155 // old version - assume blank password
2156 given_password[0] = 0;
2160 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2162 given_password[i] = data[23+i];
2164 given_password[PASSWORD_SIZE-1] = 0;
2167 if(!base64_is_valid(given_password)){
2168 infostream<<"Server: "<<playername
2169 <<" supplied invalid password hash"<<std::endl;
2170 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2174 std::string checkpwd; // Password hash to check against
2175 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2177 // If no authentication info exists for user, create it
2179 if(!isSingleplayer() &&
2180 g_settings->getBool("disallow_empty_password") &&
2181 std::string(given_password) == ""){
2182 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2183 L"disallowed. Set a password and try again.");
2186 std::wstring raw_default_password =
2187 narrow_to_wide(g_settings->get("default_password"));
2188 std::string initial_password =
2189 translatePassword(playername, raw_default_password);
2191 // If default_password is empty, allow any initial password
2192 if (raw_default_password.length() == 0)
2193 initial_password = given_password;
2195 scriptapi_create_auth(m_lua, playername, initial_password);
2198 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2201 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2205 if(given_password != checkpwd){
2206 infostream<<"Server: peer_id="<<peer_id
2207 <<": supplied invalid password for "
2208 <<playername<<std::endl;
2209 SendAccessDenied(m_con, peer_id, L"Invalid password");
2213 // Do not allow multiple players in simple singleplayer mode.
2214 // This isn't a perfect way to do it, but will suffice for now.
2215 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2216 infostream<<"Server: Not allowing another client to connect in"
2217 <<" simple singleplayer mode"<<std::endl;
2218 SendAccessDenied(m_con, peer_id,
2219 L"Running in simple singleplayer mode.");
2223 // Enforce user limit.
2224 // Don't enforce for users that have some admin right
2225 if(m_clients.size() >= g_settings->getU16("max_users") &&
2226 !checkPriv(playername, "server") &&
2227 !checkPriv(playername, "ban") &&
2228 !checkPriv(playername, "privs") &&
2229 !checkPriv(playername, "password") &&
2230 playername != g_settings->get("name"))
2232 actionstream<<"Server: "<<playername<<" tried to join, but there"
2233 <<" are already max_users="
2234 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2235 SendAccessDenied(m_con, peer_id, L"Too many users.");
2240 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2242 // If failed, cancel
2243 if(playersao == NULL)
2245 errorstream<<"Server: peer_id="<<peer_id
2246 <<": failed to emerge player"<<std::endl;
2251 Answer with a TOCLIENT_INIT
2254 SharedBuffer<u8> reply(2+1+6+8+4);
2255 writeU16(&reply[0], TOCLIENT_INIT);
2256 writeU8(&reply[2], deployed);
2257 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2258 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2259 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2262 m_con.Send(peer_id, 0, reply, true);
2266 Send complete position information
2268 SendMovePlayer(peer_id);
2273 if(command == TOSERVER_INIT2)
2275 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2276 <<peer_id<<std::endl;
2278 Player *player = m_env->getPlayer(peer_id);
2280 verbosestream<<"Server: TOSERVER_INIT2: "
2281 <<"Player not found; ignoring."<<std::endl;
2285 RemoteClient *client = getClient(peer_id);
2286 client->serialization_version =
2287 getClient(peer_id)->pending_serialization_version;
2290 Send some initialization data
2293 infostream<<"Server: Sending content to "
2294 <<getPlayerName(peer_id)<<std::endl;
2296 // Send item definitions
2297 SendItemDef(m_con, peer_id, m_itemdef);
2299 // Send node definitions
2300 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2302 // Send media announcement
2303 sendMediaAnnouncement(peer_id);
2306 SendPlayerPrivileges(peer_id);
2308 // Send inventory formspec
2309 SendPlayerInventoryFormspec(peer_id);
2312 UpdateCrafting(peer_id);
2313 SendInventory(peer_id);
2316 if(g_settings->getBool("enable_damage"))
2317 SendPlayerHP(peer_id);
2319 // Send detached inventories
2320 sendDetachedInventories(peer_id);
2322 // Show death screen if necessary
2324 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2328 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2329 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2330 m_con.Send(peer_id, 0, data, true);
2333 // Note things in chat if not in simple singleplayer mode
2334 if(!m_simple_singleplayer_mode)
2336 // Send information about server to player in chat
2337 SendChatMessage(peer_id, getStatusString());
2339 // Send information about joining in chat
2341 std::wstring name = L"unknown";
2342 Player *player = m_env->getPlayer(peer_id);
2344 name = narrow_to_wide(player->getName());
2346 std::wstring message;
2349 message += L" joined the game.";
2350 BroadcastChatMessage(message);
2354 // Warnings about protocol version can be issued here
2355 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2357 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2358 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2365 std::ostringstream os(std::ios_base::binary);
2366 for(core::map<u16, RemoteClient*>::Iterator
2367 i = m_clients.getIterator();
2368 i.atEnd() == false; i++)
2370 RemoteClient *client = i.getNode()->getValue();
2371 assert(client->peer_id == i.getNode()->getKey());
2372 if(client->serialization_version == SER_FMT_VER_INVALID)
2375 Player *player = m_env->getPlayer(client->peer_id);
2378 // Get name of player
2379 os<<player->getName()<<" ";
2382 actionstream<<player->getName()<<" joins game. List of players: "
2383 <<os.str()<<std::endl;
2389 if(peer_ser_ver == SER_FMT_VER_INVALID)
2391 infostream<<"Server::ProcessData(): Cancelling: Peer"
2392 " serialization format invalid or not initialized."
2393 " Skipping incoming command="<<command<<std::endl;
2397 Player *player = m_env->getPlayer(peer_id);
2399 infostream<<"Server::ProcessData(): Cancelling: "
2400 "No player for peer_id="<<peer_id
2405 PlayerSAO *playersao = player->getPlayerSAO();
2406 if(playersao == NULL){
2407 infostream<<"Server::ProcessData(): Cancelling: "
2408 "No player object for peer_id="<<peer_id
2413 if(command == TOSERVER_PLAYERPOS)
2415 if(datasize < 2+12+12+4+4)
2419 v3s32 ps = readV3S32(&data[start+2]);
2420 v3s32 ss = readV3S32(&data[start+2+12]);
2421 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2422 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2424 if(datasize >= 2+12+12+4+4+4)
2425 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2426 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2427 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2428 pitch = wrapDegrees(pitch);
2429 yaw = wrapDegrees(yaw);
2431 player->setPosition(position);
2432 player->setSpeed(speed);
2433 player->setPitch(pitch);
2434 player->setYaw(yaw);
2435 player->keyPressed=keyPressed;
2436 player->control.up = (bool)(keyPressed&1);
2437 player->control.down = (bool)(keyPressed&2);
2438 player->control.left = (bool)(keyPressed&4);
2439 player->control.right = (bool)(keyPressed&8);
2440 player->control.jump = (bool)(keyPressed&16);
2441 player->control.aux1 = (bool)(keyPressed&32);
2442 player->control.sneak = (bool)(keyPressed&64);
2443 player->control.LMB = (bool)(keyPressed&128);
2444 player->control.RMB = (bool)(keyPressed&256);
2446 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2447 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2448 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2450 else if(command == TOSERVER_GOTBLOCKS)
2463 u16 count = data[2];
2464 for(u16 i=0; i<count; i++)
2466 if((s16)datasize < 2+1+(i+1)*6)
2467 throw con::InvalidIncomingDataException
2468 ("GOTBLOCKS length is too short");
2469 v3s16 p = readV3S16(&data[2+1+i*6]);
2470 /*infostream<<"Server: GOTBLOCKS ("
2471 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2472 RemoteClient *client = getClient(peer_id);
2473 client->GotBlock(p);
2476 else if(command == TOSERVER_DELETEDBLOCKS)
2489 u16 count = data[2];
2490 for(u16 i=0; i<count; i++)
2492 if((s16)datasize < 2+1+(i+1)*6)
2493 throw con::InvalidIncomingDataException
2494 ("DELETEDBLOCKS length is too short");
2495 v3s16 p = readV3S16(&data[2+1+i*6]);
2496 /*infostream<<"Server: DELETEDBLOCKS ("
2497 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2498 RemoteClient *client = getClient(peer_id);
2499 client->SetBlockNotSent(p);
2502 else if(command == TOSERVER_CLICK_OBJECT)
2504 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2507 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2509 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2512 else if(command == TOSERVER_GROUND_ACTION)
2514 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2518 else if(command == TOSERVER_RELEASE)
2520 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2523 else if(command == TOSERVER_SIGNTEXT)
2525 infostream<<"Server: SIGNTEXT not supported anymore"
2529 else if(command == TOSERVER_SIGNNODETEXT)
2531 infostream<<"Server: SIGNNODETEXT not supported anymore"
2535 else if(command == TOSERVER_INVENTORY_ACTION)
2537 // Strip command and create a stream
2538 std::string datastring((char*)&data[2], datasize-2);
2539 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2540 std::istringstream is(datastring, std::ios_base::binary);
2542 InventoryAction *a = InventoryAction::deSerialize(is);
2545 infostream<<"TOSERVER_INVENTORY_ACTION: "
2546 <<"InventoryAction::deSerialize() returned NULL"
2551 // If something goes wrong, this player is to blame
2552 RollbackScopeActor rollback_scope(m_rollback,
2553 std::string("player:")+player->getName());
2556 Note: Always set inventory not sent, to repair cases
2557 where the client made a bad prediction.
2561 Handle restrictions and special cases of the move action
2563 if(a->getType() == IACTION_MOVE)
2565 IMoveAction *ma = (IMoveAction*)a;
2567 ma->from_inv.applyCurrentPlayer(player->getName());
2568 ma->to_inv.applyCurrentPlayer(player->getName());
2570 setInventoryModified(ma->from_inv);
2571 setInventoryModified(ma->to_inv);
2573 bool from_inv_is_current_player =
2574 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2575 (ma->from_inv.name == player->getName());
2577 bool to_inv_is_current_player =
2578 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2579 (ma->to_inv.name == player->getName());
2582 Disable moving items out of craftpreview
2584 if(ma->from_list == "craftpreview")
2586 infostream<<"Ignoring IMoveAction from "
2587 <<(ma->from_inv.dump())<<":"<<ma->from_list
2588 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2589 <<" because src is "<<ma->from_list<<std::endl;
2595 Disable moving items into craftresult and craftpreview
2597 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2599 infostream<<"Ignoring IMoveAction from "
2600 <<(ma->from_inv.dump())<<":"<<ma->from_list
2601 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2602 <<" because dst is "<<ma->to_list<<std::endl;
2607 // Disallow moving items in elsewhere than player's inventory
2608 // if not allowed to interact
2609 if(!checkPriv(player->getName(), "interact") &&
2610 (!from_inv_is_current_player ||
2611 !to_inv_is_current_player))
2613 infostream<<"Cannot move outside of player's inventory: "
2614 <<"No interact privilege"<<std::endl;
2620 Handle restrictions and special cases of the drop action
2622 else if(a->getType() == IACTION_DROP)
2624 IDropAction *da = (IDropAction*)a;
2626 da->from_inv.applyCurrentPlayer(player->getName());
2628 setInventoryModified(da->from_inv);
2630 // Disallow dropping items if not allowed to interact
2631 if(!checkPriv(player->getName(), "interact"))
2638 Handle restrictions and special cases of the craft action
2640 else if(a->getType() == IACTION_CRAFT)
2642 ICraftAction *ca = (ICraftAction*)a;
2644 ca->craft_inv.applyCurrentPlayer(player->getName());
2646 setInventoryModified(ca->craft_inv);
2648 //bool craft_inv_is_current_player =
2649 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2650 // (ca->craft_inv.name == player->getName());
2652 // Disallow crafting if not allowed to interact
2653 if(!checkPriv(player->getName(), "interact"))
2655 infostream<<"Cannot craft: "
2656 <<"No interact privilege"<<std::endl;
2663 a->apply(this, playersao, this);
2667 else if(command == TOSERVER_CHAT_MESSAGE)
2675 std::string datastring((char*)&data[2], datasize-2);
2676 std::istringstream is(datastring, std::ios_base::binary);
2679 is.read((char*)buf, 2);
2680 u16 len = readU16(buf);
2682 std::wstring message;
2683 for(u16 i=0; i<len; i++)
2685 is.read((char*)buf, 2);
2686 message += (wchar_t)readU16(buf);
2689 // If something goes wrong, this player is to blame
2690 RollbackScopeActor rollback_scope(m_rollback,
2691 std::string("player:")+player->getName());
2693 // Get player name of this client
2694 std::wstring name = narrow_to_wide(player->getName());
2697 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2698 wide_to_narrow(message));
2699 // If script ate the message, don't proceed
2703 // Line to send to players
2705 // Whether to send to the player that sent the line
2706 bool send_to_sender = false;
2707 // Whether to send to other players
2708 bool send_to_others = false;
2710 // Commands are implemented in Lua, so only catch invalid
2711 // commands that were not "eaten" and send an error back
2712 if(message[0] == L'/')
2714 message = message.substr(1);
2715 send_to_sender = true;
2716 if(message.length() == 0)
2717 line += L"-!- Empty command";
2719 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2723 if(checkPriv(player->getName(), "shout")){
2728 send_to_others = true;
2730 line += L"-!- You don't have permission to shout.";
2731 send_to_sender = true;
2738 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2741 Send the message to clients
2743 for(core::map<u16, RemoteClient*>::Iterator
2744 i = m_clients.getIterator();
2745 i.atEnd() == false; i++)
2747 // Get client and check that it is valid
2748 RemoteClient *client = i.getNode()->getValue();
2749 assert(client->peer_id == i.getNode()->getKey());
2750 if(client->serialization_version == SER_FMT_VER_INVALID)
2754 bool sender_selected = (peer_id == client->peer_id);
2755 if(sender_selected == true && send_to_sender == false)
2757 if(sender_selected == false && send_to_others == false)
2760 SendChatMessage(client->peer_id, line);
2764 else if(command == TOSERVER_DAMAGE)
2766 std::string datastring((char*)&data[2], datasize-2);
2767 std::istringstream is(datastring, std::ios_base::binary);
2768 u8 damage = readU8(is);
2770 if(g_settings->getBool("enable_damage"))
2772 actionstream<<player->getName()<<" damaged by "
2773 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2776 playersao->setHP(playersao->getHP() - damage);
2778 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2781 if(playersao->m_hp_not_sent)
2782 SendPlayerHP(peer_id);
2785 else if(command == TOSERVER_PASSWORD)
2788 [0] u16 TOSERVER_PASSWORD
2789 [2] u8[28] old password
2790 [30] u8[28] new password
2793 if(datasize != 2+PASSWORD_SIZE*2)
2795 /*char password[PASSWORD_SIZE];
2796 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2797 password[i] = data[2+i];
2798 password[PASSWORD_SIZE-1] = 0;*/
2800 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2808 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2810 char c = data[2+PASSWORD_SIZE+i];
2816 if(!base64_is_valid(newpwd)){
2817 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2818 // Wrong old password supplied!!
2819 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2823 infostream<<"Server: Client requests a password change from "
2824 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2826 std::string playername = player->getName();
2828 std::string checkpwd;
2829 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2831 if(oldpwd != checkpwd)
2833 infostream<<"Server: invalid old password"<<std::endl;
2834 // Wrong old password supplied!!
2835 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2839 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2841 actionstream<<player->getName()<<" changes password"<<std::endl;
2842 SendChatMessage(peer_id, L"Password change successful.");
2844 actionstream<<player->getName()<<" tries to change password but "
2845 <<"it fails"<<std::endl;
2846 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2849 else if(command == TOSERVER_PLAYERITEM)
2854 u16 item = readU16(&data[2]);
2855 playersao->setWieldIndex(item);
2857 else if(command == TOSERVER_RESPAWN)
2859 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2862 RespawnPlayer(peer_id);
2864 actionstream<<player->getName()<<" respawns at "
2865 <<PP(player->getPosition()/BS)<<std::endl;
2867 // ActiveObject is added to environment in AsyncRunStep after
2868 // the previous addition has been succesfully removed
2870 else if(command == TOSERVER_REQUEST_MEDIA) {
2871 std::string datastring((char*)&data[2], datasize-2);
2872 std::istringstream is(datastring, std::ios_base::binary);
2874 core::list<MediaRequest> tosend;
2875 u16 numfiles = readU16(is);
2877 infostream<<"Sending "<<numfiles<<" files to "
2878 <<getPlayerName(peer_id)<<std::endl;
2879 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2881 for(int i = 0; i < numfiles; i++) {
2882 std::string name = deSerializeString(is);
2883 tosend.push_back(MediaRequest(name));
2884 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2888 sendRequestedMedia(peer_id, tosend);
2890 // Now the client should know about everything
2891 // (definitions and files)
2892 getClient(peer_id)->definitions_sent = true;
2894 else if(command == TOSERVER_RECEIVED_MEDIA) {
2895 getClient(peer_id)->definitions_sent = true;
2897 else if(command == TOSERVER_INTERACT)
2899 std::string datastring((char*)&data[2], datasize-2);
2900 std::istringstream is(datastring, std::ios_base::binary);
2906 [5] u32 length of the next item
2907 [9] serialized PointedThing
2909 0: start digging (from undersurface) or use
2910 1: stop digging (all parameters ignored)
2911 2: digging completed
2912 3: place block or item (to abovesurface)
2915 u8 action = readU8(is);
2916 u16 item_i = readU16(is);
2917 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2918 PointedThing pointed;
2919 pointed.deSerialize(tmp_is);
2921 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2922 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2926 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2927 <<" tried to interact, but is dead!"<<std::endl;
2931 v3f player_pos = playersao->getLastGoodPosition();
2933 // Update wielded item
2934 playersao->setWieldIndex(item_i);
2936 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2937 v3s16 p_under = pointed.node_undersurface;
2938 v3s16 p_above = pointed.node_abovesurface;
2940 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2941 ServerActiveObject *pointed_object = NULL;
2942 if(pointed.type == POINTEDTHING_OBJECT)
2944 pointed_object = m_env->getActiveObject(pointed.object_id);
2945 if(pointed_object == NULL)
2947 verbosestream<<"TOSERVER_INTERACT: "
2948 "pointed object is NULL"<<std::endl;
2954 v3f pointed_pos_under = player_pos;
2955 v3f pointed_pos_above = player_pos;
2956 if(pointed.type == POINTEDTHING_NODE)
2958 pointed_pos_under = intToFloat(p_under, BS);
2959 pointed_pos_above = intToFloat(p_above, BS);
2961 else if(pointed.type == POINTEDTHING_OBJECT)
2963 pointed_pos_under = pointed_object->getBasePosition();
2964 pointed_pos_above = pointed_pos_under;
2968 Check that target is reasonably close
2969 (only when digging or placing things)
2971 if(action == 0 || action == 2 || action == 3)
2973 float d = player_pos.getDistanceFrom(pointed_pos_under);
2974 float max_d = BS * 14; // Just some large enough value
2976 actionstream<<"Player "<<player->getName()
2977 <<" tried to access "<<pointed.dump()
2979 <<"d="<<d<<", max_d="<<max_d
2980 <<". ignoring."<<std::endl;
2981 // Re-send block to revert change on client-side
2982 RemoteClient *client = getClient(peer_id);
2983 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2984 client->SetBlockNotSent(blockpos);
2991 Make sure the player is allowed to do it
2993 if(!checkPriv(player->getName(), "interact"))
2995 actionstream<<player->getName()<<" attempted to interact with "
2996 <<pointed.dump()<<" without 'interact' privilege"
2998 // Re-send block to revert change on client-side
2999 RemoteClient *client = getClient(peer_id);
3000 // Digging completed -> under
3002 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3003 client->SetBlockNotSent(blockpos);
3005 // Placement -> above
3007 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3008 client->SetBlockNotSent(blockpos);
3014 If something goes wrong, this player is to blame
3016 RollbackScopeActor rollback_scope(m_rollback,
3017 std::string("player:")+player->getName());
3020 0: start digging or punch object
3024 if(pointed.type == POINTEDTHING_NODE)
3027 NOTE: This can be used in the future to check if
3028 somebody is cheating, by checking the timing.
3030 MapNode n(CONTENT_IGNORE);
3033 n = m_env->getMap().getNode(p_under);
3035 catch(InvalidPositionException &e)
3037 infostream<<"Server: Not punching: Node not found."
3038 <<" Adding block to emerge queue."
3040 m_emerge_queue.addBlock(peer_id,
3041 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3043 if(n.getContent() != CONTENT_IGNORE)
3044 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3046 playersao->noCheatDigStart(p_under);
3048 else if(pointed.type == POINTEDTHING_OBJECT)
3050 // Skip if object has been removed
3051 if(pointed_object->m_removed)
3054 actionstream<<player->getName()<<" punches object "
3055 <<pointed.object_id<<": "
3056 <<pointed_object->getDescription()<<std::endl;
3058 ItemStack punchitem = playersao->getWieldedItem();
3059 ToolCapabilities toolcap =
3060 punchitem.getToolCapabilities(m_itemdef);
3061 v3f dir = (pointed_object->getBasePosition() -
3062 (player->getPosition() + player->getEyeOffset())
3064 float time_from_last_punch =
3065 playersao->resetTimeFromLastPunch();
3066 pointed_object->punch(dir, &toolcap, playersao,
3067 time_from_last_punch);
3075 else if(action == 1)
3080 2: Digging completed
3082 else if(action == 2)
3084 // Only digging of nodes
3085 if(pointed.type == POINTEDTHING_NODE)
3087 MapNode n(CONTENT_IGNORE);
3090 n = m_env->getMap().getNode(p_under);
3092 catch(InvalidPositionException &e)
3094 infostream<<"Server: Not finishing digging: Node not found."
3095 <<" Adding block to emerge queue."
3097 m_emerge_queue.addBlock(peer_id,
3098 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3101 /* Cheat prevention */
3102 bool is_valid_dig = true;
3103 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3105 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3106 float nocheat_t = playersao->getNoCheatDigTime();
3107 playersao->noCheatDigEnd();
3108 // If player didn't start digging this, ignore dig
3109 if(nocheat_p != p_under){
3110 infostream<<"Server: NoCheat: "<<player->getName()
3111 <<" started digging "
3112 <<PP(nocheat_p)<<" and completed digging "
3113 <<PP(p_under)<<"; not digging."<<std::endl;
3114 is_valid_dig = false;
3116 // Get player's wielded item
3117 ItemStack playeritem;
3118 InventoryList *mlist = playersao->getInventory()->getList("main");
3120 playeritem = mlist->getItem(playersao->getWieldIndex());
3121 ToolCapabilities playeritem_toolcap =
3122 playeritem.getToolCapabilities(m_itemdef);
3123 // Get diggability and expected digging time
3124 DigParams params = getDigParams(m_nodedef->get(n).groups,
3125 &playeritem_toolcap);
3126 // If can't dig, try hand
3127 if(!params.diggable){
3128 const ItemDefinition &hand = m_itemdef->get("");
3129 const ToolCapabilities *tp = hand.tool_capabilities;
3131 params = getDigParams(m_nodedef->get(n).groups, tp);
3133 // If can't dig, ignore dig
3134 if(!params.diggable){
3135 infostream<<"Server: NoCheat: "<<player->getName()
3136 <<" completed digging "<<PP(p_under)
3137 <<", which is not diggable with tool. not digging."
3139 is_valid_dig = false;
3141 // If time is considerably too short, ignore dig
3142 // Check time only for medium and slow timed digs
3143 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3144 infostream<<"Server: NoCheat: "<<player->getName()
3145 <<" completed digging "
3146 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3147 <<params.time<<"s; not digging."<<std::endl;
3148 is_valid_dig = false;
3152 /* Actually dig node */
3154 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3155 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3157 // Send unusual result (that is, node not being removed)
3158 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3160 // Re-send block to revert change on client-side
3161 RemoteClient *client = getClient(peer_id);
3162 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3163 client->SetBlockNotSent(blockpos);
3169 3: place block or right-click object
3171 else if(action == 3)
3173 ItemStack item = playersao->getWieldedItem();
3175 // Reset build time counter
3176 if(pointed.type == POINTEDTHING_NODE &&
3177 item.getDefinition(m_itemdef).type == ITEM_NODE)
3178 getClient(peer_id)->m_time_from_building = 0.0;
3180 if(pointed.type == POINTEDTHING_OBJECT)
3182 // Right click object
3184 // Skip if object has been removed
3185 if(pointed_object->m_removed)
3188 actionstream<<player->getName()<<" right-clicks object "
3189 <<pointed.object_id<<": "
3190 <<pointed_object->getDescription()<<std::endl;
3193 pointed_object->rightClick(playersao);
3195 else if(scriptapi_item_on_place(m_lua,
3196 item, playersao, pointed))
3198 // Placement was handled in lua
3200 // Apply returned ItemStack
3201 playersao->setWieldedItem(item);
3204 // If item has node placement prediction, always send the above
3205 // node to make sure the client knows what exactly happened
3206 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3207 RemoteClient *client = getClient(peer_id);
3208 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3209 client->SetBlockNotSent(blockpos);
3216 else if(action == 4)
3218 ItemStack item = playersao->getWieldedItem();
3220 actionstream<<player->getName()<<" uses "<<item.name
3221 <<", pointing at "<<pointed.dump()<<std::endl;
3223 if(scriptapi_item_on_use(m_lua,
3224 item, playersao, pointed))
3226 // Apply returned ItemStack
3227 playersao->setWieldedItem(item);
3234 Catch invalid actions
3238 infostream<<"WARNING: Server: Invalid action "
3239 <<action<<std::endl;
3242 else if(command == TOSERVER_REMOVED_SOUNDS)
3244 std::string datastring((char*)&data[2], datasize-2);
3245 std::istringstream is(datastring, std::ios_base::binary);
3247 int num = readU16(is);
3248 for(int k=0; k<num; k++){
3249 s32 id = readS32(is);
3250 std::map<s32, ServerPlayingSound>::iterator i =
3251 m_playing_sounds.find(id);
3252 if(i == m_playing_sounds.end())
3254 ServerPlayingSound &psound = i->second;
3255 psound.clients.erase(peer_id);
3256 if(psound.clients.size() == 0)
3257 m_playing_sounds.erase(i++);
3260 else if(command == TOSERVER_NODEMETA_FIELDS)
3262 std::string datastring((char*)&data[2], datasize-2);
3263 std::istringstream is(datastring, std::ios_base::binary);
3265 v3s16 p = readV3S16(is);
3266 std::string formname = deSerializeString(is);
3267 int num = readU16(is);
3268 std::map<std::string, std::string> fields;
3269 for(int k=0; k<num; k++){
3270 std::string fieldname = deSerializeString(is);
3271 std::string fieldvalue = deSerializeLongString(is);
3272 fields[fieldname] = fieldvalue;
3275 // If something goes wrong, this player is to blame
3276 RollbackScopeActor rollback_scope(m_rollback,
3277 std::string("player:")+player->getName());
3279 // Check the target node for rollback data; leave others unnoticed
3280 RollbackNode rn_old(&m_env->getMap(), p, this);
3282 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3285 // Report rollback data
3286 RollbackNode rn_new(&m_env->getMap(), p, this);
3287 if(rollback() && rn_new != rn_old){
3288 RollbackAction action;
3289 action.setSetNode(p, rn_old, rn_new);
3290 rollback()->reportAction(action);
3293 else if(command == TOSERVER_INVENTORY_FIELDS)
3295 std::string datastring((char*)&data[2], datasize-2);
3296 std::istringstream is(datastring, std::ios_base::binary);
3298 std::string formname = deSerializeString(is);
3299 int num = readU16(is);
3300 std::map<std::string, std::string> fields;
3301 for(int k=0; k<num; k++){
3302 std::string fieldname = deSerializeString(is);
3303 std::string fieldvalue = deSerializeLongString(is);
3304 fields[fieldname] = fieldvalue;
3307 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3311 infostream<<"Server::ProcessData(): Ignoring "
3312 "unknown command "<<command<<std::endl;
3316 catch(SendFailedException &e)
3318 errorstream<<"Server::ProcessData(): SendFailedException: "
3324 void Server::onMapEditEvent(MapEditEvent *event)
3326 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3327 if(m_ignore_map_edit_events)
3329 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3331 MapEditEvent *e = event->clone();
3332 m_unsent_map_edit_queue.push_back(e);
3335 Inventory* Server::getInventory(const InventoryLocation &loc)
3338 case InventoryLocation::UNDEFINED:
3341 case InventoryLocation::CURRENT_PLAYER:
3344 case InventoryLocation::PLAYER:
3346 Player *player = m_env->getPlayer(loc.name.c_str());
3349 PlayerSAO *playersao = player->getPlayerSAO();
3352 return playersao->getInventory();
3355 case InventoryLocation::NODEMETA:
3357 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3360 return meta->getInventory();
3363 case InventoryLocation::DETACHED:
3365 if(m_detached_inventories.count(loc.name) == 0)
3367 return m_detached_inventories[loc.name];
3375 void Server::setInventoryModified(const InventoryLocation &loc)
3378 case InventoryLocation::UNDEFINED:
3381 case InventoryLocation::PLAYER:
3383 Player *player = m_env->getPlayer(loc.name.c_str());
3386 PlayerSAO *playersao = player->getPlayerSAO();
3389 playersao->m_inventory_not_sent = true;
3390 playersao->m_wielded_item_not_sent = true;
3393 case InventoryLocation::NODEMETA:
3395 v3s16 blockpos = getNodeBlockPos(loc.p);
3397 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3399 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3401 setBlockNotSent(blockpos);
3404 case InventoryLocation::DETACHED:
3406 sendDetachedInventoryToAll(loc.name);
3414 core::list<PlayerInfo> Server::getPlayerInfo()
3416 DSTACK(__FUNCTION_NAME);
3417 JMutexAutoLock envlock(m_env_mutex);
3418 JMutexAutoLock conlock(m_con_mutex);
3420 core::list<PlayerInfo> list;
3422 core::list<Player*> players = m_env->getPlayers();
3424 core::list<Player*>::Iterator i;
3425 for(i = players.begin();
3426 i != players.end(); i++)
3430 Player *player = *i;
3433 // Copy info from connection to info struct
3434 info.id = player->peer_id;
3435 info.address = m_con.GetPeerAddress(player->peer_id);
3436 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3438 catch(con::PeerNotFoundException &e)
3440 // Set dummy peer info
3442 info.address = Address(0,0,0,0,0);
3446 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3447 info.position = player->getPosition();
3449 list.push_back(info);
3456 void Server::peerAdded(con::Peer *peer)
3458 DSTACK(__FUNCTION_NAME);
3459 verbosestream<<"Server::peerAdded(): peer->id="
3460 <<peer->id<<std::endl;
3463 c.type = PEER_ADDED;
3464 c.peer_id = peer->id;
3466 m_peer_change_queue.push_back(c);
3469 void Server::deletingPeer(con::Peer *peer, bool timeout)
3471 DSTACK(__FUNCTION_NAME);
3472 verbosestream<<"Server::deletingPeer(): peer->id="
3473 <<peer->id<<", timeout="<<timeout<<std::endl;
3476 c.type = PEER_REMOVED;
3477 c.peer_id = peer->id;
3478 c.timeout = timeout;
3479 m_peer_change_queue.push_back(c);
3486 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3488 DSTACK(__FUNCTION_NAME);
3489 std::ostringstream os(std::ios_base::binary);
3491 writeU16(os, TOCLIENT_HP);
3495 std::string s = os.str();
3496 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3498 con.Send(peer_id, 0, data, true);
3501 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3502 const std::wstring &reason)
3504 DSTACK(__FUNCTION_NAME);
3505 std::ostringstream os(std::ios_base::binary);
3507 writeU16(os, TOCLIENT_ACCESS_DENIED);
3508 os<<serializeWideString(reason);
3511 std::string s = os.str();
3512 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3514 con.Send(peer_id, 0, data, true);
3517 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3518 bool set_camera_point_target, v3f camera_point_target)
3520 DSTACK(__FUNCTION_NAME);
3521 std::ostringstream os(std::ios_base::binary);
3523 writeU16(os, TOCLIENT_DEATHSCREEN);
3524 writeU8(os, set_camera_point_target);
3525 writeV3F1000(os, camera_point_target);
3528 std::string s = os.str();
3529 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3531 con.Send(peer_id, 0, data, true);
3534 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3535 IItemDefManager *itemdef)
3537 DSTACK(__FUNCTION_NAME);
3538 std::ostringstream os(std::ios_base::binary);
3542 u32 length of the next item
3543 zlib-compressed serialized ItemDefManager
3545 writeU16(os, TOCLIENT_ITEMDEF);
3546 std::ostringstream tmp_os(std::ios::binary);
3547 itemdef->serialize(tmp_os);
3548 std::ostringstream tmp_os2(std::ios::binary);
3549 compressZlib(tmp_os.str(), tmp_os2);
3550 os<<serializeLongString(tmp_os2.str());
3553 std::string s = os.str();
3554 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3555 <<"): size="<<s.size()<<std::endl;
3556 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3558 con.Send(peer_id, 0, data, true);
3561 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3562 INodeDefManager *nodedef, u16 protocol_version)
3564 DSTACK(__FUNCTION_NAME);
3565 std::ostringstream os(std::ios_base::binary);
3569 u32 length of the next item
3570 zlib-compressed serialized NodeDefManager
3572 writeU16(os, TOCLIENT_NODEDEF);
3573 std::ostringstream tmp_os(std::ios::binary);
3574 nodedef->serialize(tmp_os, protocol_version);
3575 std::ostringstream tmp_os2(std::ios::binary);
3576 compressZlib(tmp_os.str(), tmp_os2);
3577 os<<serializeLongString(tmp_os2.str());
3580 std::string s = os.str();
3581 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3582 <<"): size="<<s.size()<<std::endl;
3583 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3585 con.Send(peer_id, 0, data, true);
3589 Non-static send methods
3592 void Server::SendInventory(u16 peer_id)
3594 DSTACK(__FUNCTION_NAME);
3596 PlayerSAO *playersao = getPlayerSAO(peer_id);
3599 playersao->m_inventory_not_sent = false;
3605 std::ostringstream os;
3606 playersao->getInventory()->serialize(os);
3608 std::string s = os.str();
3610 SharedBuffer<u8> data(s.size()+2);
3611 writeU16(&data[0], TOCLIENT_INVENTORY);
3612 memcpy(&data[2], s.c_str(), s.size());
3615 m_con.Send(peer_id, 0, data, true);
3618 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3620 DSTACK(__FUNCTION_NAME);
3622 std::ostringstream os(std::ios_base::binary);
3626 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3627 os.write((char*)buf, 2);
3630 writeU16(buf, message.size());
3631 os.write((char*)buf, 2);
3634 for(u32 i=0; i<message.size(); i++)
3638 os.write((char*)buf, 2);
3642 std::string s = os.str();
3643 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3645 m_con.Send(peer_id, 0, data, true);
3647 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3649 DSTACK(__FUNCTION_NAME);
3651 std::ostringstream os(std::ios_base::binary);
3655 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3656 os.write((char*)buf, 2);
3657 os<<serializeLongString(formspec);
3658 os<<serializeString(formname);
3661 std::string s = os.str();
3662 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3664 m_con.Send(peer_id, 0, data, true);
3667 void Server::BroadcastChatMessage(const std::wstring &message)
3669 for(core::map<u16, RemoteClient*>::Iterator
3670 i = m_clients.getIterator();
3671 i.atEnd() == false; i++)
3673 // Get client and check that it is valid
3674 RemoteClient *client = i.getNode()->getValue();
3675 assert(client->peer_id == i.getNode()->getKey());
3676 if(client->serialization_version == SER_FMT_VER_INVALID)
3679 SendChatMessage(client->peer_id, message);
3683 void Server::SendPlayerHP(u16 peer_id)
3685 DSTACK(__FUNCTION_NAME);
3686 PlayerSAO *playersao = getPlayerSAO(peer_id);
3688 playersao->m_hp_not_sent = false;
3689 SendHP(m_con, peer_id, playersao->getHP());
3692 void Server::SendMovePlayer(u16 peer_id)
3694 DSTACK(__FUNCTION_NAME);
3695 Player *player = m_env->getPlayer(peer_id);
3698 std::ostringstream os(std::ios_base::binary);
3699 writeU16(os, TOCLIENT_MOVE_PLAYER);
3700 writeV3F1000(os, player->getPosition());
3701 writeF1000(os, player->getPitch());
3702 writeF1000(os, player->getYaw());
3705 v3f pos = player->getPosition();
3706 f32 pitch = player->getPitch();
3707 f32 yaw = player->getYaw();
3708 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3709 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3716 std::string s = os.str();
3717 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3719 m_con.Send(peer_id, 0, data, true);
3722 void Server::SendPlayerPrivileges(u16 peer_id)
3724 Player *player = m_env->getPlayer(peer_id);
3726 if(player->peer_id == PEER_ID_INEXISTENT)
3729 std::set<std::string> privs;
3730 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3732 std::ostringstream os(std::ios_base::binary);
3733 writeU16(os, TOCLIENT_PRIVILEGES);
3734 writeU16(os, privs.size());
3735 for(std::set<std::string>::const_iterator i = privs.begin();
3736 i != privs.end(); i++){
3737 os<<serializeString(*i);
3741 std::string s = os.str();
3742 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3744 m_con.Send(peer_id, 0, data, true);
3747 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3749 Player *player = m_env->getPlayer(peer_id);
3751 if(player->peer_id == PEER_ID_INEXISTENT)
3754 std::ostringstream os(std::ios_base::binary);
3755 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3756 os<<serializeLongString(player->inventory_formspec);
3759 std::string s = os.str();
3760 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3762 m_con.Send(peer_id, 0, data, true);
3765 s32 Server::playSound(const SimpleSoundSpec &spec,
3766 const ServerSoundParams ¶ms)
3768 // Find out initial position of sound
3769 bool pos_exists = false;
3770 v3f pos = params.getPos(m_env, &pos_exists);
3771 // If position is not found while it should be, cancel sound
3772 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3774 // Filter destination clients
3775 std::set<RemoteClient*> dst_clients;
3776 if(params.to_player != "")
3778 Player *player = m_env->getPlayer(params.to_player.c_str());
3780 infostream<<"Server::playSound: Player \""<<params.to_player
3781 <<"\" not found"<<std::endl;
3784 if(player->peer_id == PEER_ID_INEXISTENT){
3785 infostream<<"Server::playSound: Player \""<<params.to_player
3786 <<"\" not connected"<<std::endl;
3789 RemoteClient *client = getClient(player->peer_id);
3790 dst_clients.insert(client);
3794 for(core::map<u16, RemoteClient*>::Iterator
3795 i = m_clients.getIterator(); i.atEnd() == false; i++)
3797 RemoteClient *client = i.getNode()->getValue();
3798 Player *player = m_env->getPlayer(client->peer_id);
3802 if(player->getPosition().getDistanceFrom(pos) >
3803 params.max_hear_distance)
3806 dst_clients.insert(client);
3809 if(dst_clients.size() == 0)
3812 s32 id = m_next_sound_id++;
3813 // The sound will exist as a reference in m_playing_sounds
3814 m_playing_sounds[id] = ServerPlayingSound();
3815 ServerPlayingSound &psound = m_playing_sounds[id];
3816 psound.params = params;
3817 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3818 i != dst_clients.end(); i++)
3819 psound.clients.insert((*i)->peer_id);
3821 std::ostringstream os(std::ios_base::binary);
3822 writeU16(os, TOCLIENT_PLAY_SOUND);
3824 os<<serializeString(spec.name);
3825 writeF1000(os, spec.gain * params.gain);
3826 writeU8(os, params.type);
3827 writeV3F1000(os, pos);
3828 writeU16(os, params.object);
3829 writeU8(os, params.loop);
3831 std::string s = os.str();
3832 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3834 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3835 i != dst_clients.end(); i++){
3837 m_con.Send((*i)->peer_id, 0, data, true);
3841 void Server::stopSound(s32 handle)
3843 // Get sound reference
3844 std::map<s32, ServerPlayingSound>::iterator i =
3845 m_playing_sounds.find(handle);
3846 if(i == m_playing_sounds.end())
3848 ServerPlayingSound &psound = i->second;
3850 std::ostringstream os(std::ios_base::binary);
3851 writeU16(os, TOCLIENT_STOP_SOUND);
3852 writeS32(os, handle);
3854 std::string s = os.str();
3855 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3857 for(std::set<u16>::iterator i = psound.clients.begin();
3858 i != psound.clients.end(); i++){
3860 m_con.Send(*i, 0, data, true);
3862 // Remove sound reference
3863 m_playing_sounds.erase(i);
3866 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3867 core::list<u16> *far_players, float far_d_nodes)
3869 float maxd = far_d_nodes*BS;
3870 v3f p_f = intToFloat(p, BS);
3874 SharedBuffer<u8> reply(replysize);
3875 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3876 writeS16(&reply[2], p.X);
3877 writeS16(&reply[4], p.Y);
3878 writeS16(&reply[6], p.Z);
3880 for(core::map<u16, RemoteClient*>::Iterator
3881 i = m_clients.getIterator();
3882 i.atEnd() == false; i++)
3884 // Get client and check that it is valid
3885 RemoteClient *client = i.getNode()->getValue();
3886 assert(client->peer_id == i.getNode()->getKey());
3887 if(client->serialization_version == SER_FMT_VER_INVALID)
3890 // Don't send if it's the same one
3891 if(client->peer_id == ignore_id)
3897 Player *player = m_env->getPlayer(client->peer_id);
3900 // If player is far away, only set modified blocks not sent
3901 v3f player_pos = player->getPosition();
3902 if(player_pos.getDistanceFrom(p_f) > maxd)
3904 far_players->push_back(client->peer_id);
3911 m_con.Send(client->peer_id, 0, reply, true);
3915 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3916 core::list<u16> *far_players, float far_d_nodes)
3918 float maxd = far_d_nodes*BS;
3919 v3f p_f = intToFloat(p, BS);
3921 for(core::map<u16, RemoteClient*>::Iterator
3922 i = m_clients.getIterator();
3923 i.atEnd() == false; i++)
3925 // Get client and check that it is valid
3926 RemoteClient *client = i.getNode()->getValue();
3927 assert(client->peer_id == i.getNode()->getKey());
3928 if(client->serialization_version == SER_FMT_VER_INVALID)
3931 // Don't send if it's the same one
3932 if(client->peer_id == ignore_id)
3938 Player *player = m_env->getPlayer(client->peer_id);
3941 // If player is far away, only set modified blocks not sent
3942 v3f player_pos = player->getPosition();
3943 if(player_pos.getDistanceFrom(p_f) > maxd)
3945 far_players->push_back(client->peer_id);
3952 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3953 SharedBuffer<u8> reply(replysize);
3954 writeU16(&reply[0], TOCLIENT_ADDNODE);
3955 writeS16(&reply[2], p.X);
3956 writeS16(&reply[4], p.Y);
3957 writeS16(&reply[6], p.Z);
3958 n.serialize(&reply[8], client->serialization_version);
3961 m_con.Send(client->peer_id, 0, reply, true);
3965 void Server::setBlockNotSent(v3s16 p)
3967 for(core::map<u16, RemoteClient*>::Iterator
3968 i = m_clients.getIterator();
3969 i.atEnd()==false; i++)
3971 RemoteClient *client = i.getNode()->getValue();
3972 client->SetBlockNotSent(p);
3976 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3978 DSTACK(__FUNCTION_NAME);
3980 v3s16 p = block->getPos();
3984 bool completely_air = true;
3985 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3986 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3987 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3989 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3991 completely_air = false;
3992 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3997 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3999 infostream<<"[completely air] ";
4000 infostream<<std::endl;
4004 Create a packet with the block in the right format
4007 std::ostringstream os(std::ios_base::binary);
4008 block->serialize(os, ver, false);
4009 std::string s = os.str();
4010 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4012 u32 replysize = 8 + blockdata.getSize();
4013 SharedBuffer<u8> reply(replysize);
4014 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4015 writeS16(&reply[2], p.X);
4016 writeS16(&reply[4], p.Y);
4017 writeS16(&reply[6], p.Z);
4018 memcpy(&reply[8], *blockdata, blockdata.getSize());
4020 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4021 <<": \tpacket size: "<<replysize<<std::endl;*/
4026 m_con.Send(peer_id, 1, reply, true);
4029 void Server::SendBlocks(float dtime)
4031 DSTACK(__FUNCTION_NAME);
4033 JMutexAutoLock envlock(m_env_mutex);
4034 JMutexAutoLock conlock(m_con_mutex);
4036 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4038 core::array<PrioritySortedBlockTransfer> queue;
4040 s32 total_sending = 0;
4043 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4045 for(core::map<u16, RemoteClient*>::Iterator
4046 i = m_clients.getIterator();
4047 i.atEnd() == false; i++)
4049 RemoteClient *client = i.getNode()->getValue();
4050 assert(client->peer_id == i.getNode()->getKey());
4052 // If definitions and textures have not been sent, don't
4053 // send MapBlocks either
4054 if(!client->definitions_sent)
4057 total_sending += client->SendingCount();
4059 if(client->serialization_version == SER_FMT_VER_INVALID)
4062 client->GetNextBlocks(this, dtime, queue);
4067 // Lowest priority number comes first.
4068 // Lowest is most important.
4071 for(u32 i=0; i<queue.size(); i++)
4073 //TODO: Calculate limit dynamically
4074 if(total_sending >= g_settings->getS32
4075 ("max_simultaneous_block_sends_server_total"))
4078 PrioritySortedBlockTransfer q = queue[i];
4080 MapBlock *block = NULL;
4083 block = m_env->getMap().getBlockNoCreate(q.pos);
4085 catch(InvalidPositionException &e)
4090 RemoteClient *client = getClient(q.peer_id);
4092 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4094 client->SentBlock(q.pos);
4100 void Server::fillMediaCache()
4102 DSTACK(__FUNCTION_NAME);
4104 infostream<<"Server: Calculating media file checksums"<<std::endl;
4106 // Collect all media file paths
4107 std::list<std::string> paths;
4108 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4109 i != m_mods.end(); i++){
4110 const ModSpec &mod = *i;
4111 paths.push_back(mod.path + DIR_DELIM + "textures");
4112 paths.push_back(mod.path + DIR_DELIM + "sounds");
4113 paths.push_back(mod.path + DIR_DELIM + "media");
4114 paths.push_back(mod.path + DIR_DELIM + "models");
4116 std::string path_all = "textures";
4117 paths.push_back(path_all + DIR_DELIM + "all");
4119 // Collect media file information from paths into cache
4120 for(std::list<std::string>::iterator i = paths.begin();
4121 i != paths.end(); i++)
4123 std::string mediapath = *i;
4124 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4125 for(u32 j=0; j<dirlist.size(); j++){
4126 if(dirlist[j].dir) // Ignode dirs
4128 std::string filename = dirlist[j].name;
4129 // If name contains illegal characters, ignore the file
4130 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4131 infostream<<"Server: ignoring illegal file name: \""
4132 <<filename<<"\""<<std::endl;
4135 // If name is not in a supported format, ignore it
4136 const char *supported_ext[] = {
4137 ".png", ".jpg", ".bmp", ".tga",
4138 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4140 ".x", ".b3d", ".md2", ".obj",
4143 if(removeStringEnd(filename, supported_ext) == ""){
4144 infostream<<"Server: ignoring unsupported file extension: \""
4145 <<filename<<"\""<<std::endl;
4148 // Ok, attempt to load the file and add to cache
4149 std::string filepath = mediapath + DIR_DELIM + filename;
4151 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4152 if(fis.good() == false){
4153 errorstream<<"Server::fillMediaCache(): Could not open \""
4154 <<filename<<"\" for reading"<<std::endl;
4157 std::ostringstream tmp_os(std::ios_base::binary);
4161 fis.read(buf, 1024);
4162 std::streamsize len = fis.gcount();
4163 tmp_os.write(buf, len);
4172 errorstream<<"Server::fillMediaCache(): Failed to read \""
4173 <<filename<<"\""<<std::endl;
4176 if(tmp_os.str().length() == 0){
4177 errorstream<<"Server::fillMediaCache(): Empty file \""
4178 <<filepath<<"\""<<std::endl;
4183 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4185 unsigned char *digest = sha1.getDigest();
4186 std::string sha1_base64 = base64_encode(digest, 20);
4187 std::string sha1_hex = hex_encode((char*)digest, 20);
4191 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4192 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4197 struct SendableMediaAnnouncement
4200 std::string sha1_digest;
4202 SendableMediaAnnouncement(const std::string name_="",
4203 const std::string sha1_digest_=""):
4205 sha1_digest(sha1_digest_)
4209 void Server::sendMediaAnnouncement(u16 peer_id)
4211 DSTACK(__FUNCTION_NAME);
4213 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4216 core::list<SendableMediaAnnouncement> file_announcements;
4218 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4219 i != m_media.end(); i++){
4221 file_announcements.push_back(
4222 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4226 std::ostringstream os(std::ios_base::binary);
4234 u16 length of sha1_digest
4239 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4240 writeU16(os, file_announcements.size());
4242 for(core::list<SendableMediaAnnouncement>::Iterator
4243 j = file_announcements.begin();
4244 j != file_announcements.end(); j++){
4245 os<<serializeString(j->name);
4246 os<<serializeString(j->sha1_digest);
4248 os<<serializeString(g_settings->get("remote_media"));
4251 std::string s = os.str();
4252 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4255 m_con.Send(peer_id, 0, data, true);
4258 struct SendableMedia
4264 SendableMedia(const std::string &name_="", const std::string path_="",
4265 const std::string &data_=""):
4272 void Server::sendRequestedMedia(u16 peer_id,
4273 const core::list<MediaRequest> &tosend)
4275 DSTACK(__FUNCTION_NAME);
4277 verbosestream<<"Server::sendRequestedMedia(): "
4278 <<"Sending files to client"<<std::endl;
4282 // Put 5kB in one bunch (this is not accurate)
4283 u32 bytes_per_bunch = 5000;
4285 core::array< core::list<SendableMedia> > file_bunches;
4286 file_bunches.push_back(core::list<SendableMedia>());
4288 u32 file_size_bunch_total = 0;
4290 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4291 i != tosend.end(); i++)
4293 if(m_media.find(i->name) == m_media.end()){
4294 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4295 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4299 //TODO get path + name
4300 std::string tpath = m_media[(*i).name].path;
4303 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4304 if(fis.good() == false){
4305 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4306 <<tpath<<"\" for reading"<<std::endl;
4309 std::ostringstream tmp_os(std::ios_base::binary);
4313 fis.read(buf, 1024);
4314 std::streamsize len = fis.gcount();
4315 tmp_os.write(buf, len);
4316 file_size_bunch_total += len;
4325 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4326 <<(*i).name<<"\""<<std::endl;
4329 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4330 <<tname<<"\""<<std::endl;*/
4332 file_bunches[file_bunches.size()-1].push_back(
4333 SendableMedia((*i).name, tpath, tmp_os.str()));
4335 // Start next bunch if got enough data
4336 if(file_size_bunch_total >= bytes_per_bunch){
4337 file_bunches.push_back(core::list<SendableMedia>());
4338 file_size_bunch_total = 0;
4343 /* Create and send packets */
4345 u32 num_bunches = file_bunches.size();
4346 for(u32 i=0; i<num_bunches; i++)
4348 std::ostringstream os(std::ios_base::binary);
4352 u16 total number of texture bunches
4353 u16 index of this bunch
4354 u32 number of files in this bunch
4363 writeU16(os, TOCLIENT_MEDIA);
4364 writeU16(os, num_bunches);
4366 writeU32(os, file_bunches[i].size());
4368 for(core::list<SendableMedia>::Iterator
4369 j = file_bunches[i].begin();
4370 j != file_bunches[i].end(); j++){
4371 os<<serializeString(j->name);
4372 os<<serializeLongString(j->data);
4376 std::string s = os.str();
4377 verbosestream<<"Server::sendRequestedMedia(): bunch "
4378 <<i<<"/"<<num_bunches
4379 <<" files="<<file_bunches[i].size()
4380 <<" size=" <<s.size()<<std::endl;
4381 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4383 m_con.Send(peer_id, 0, data, true);
4387 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4389 if(m_detached_inventories.count(name) == 0){
4390 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4393 Inventory *inv = m_detached_inventories[name];
4395 std::ostringstream os(std::ios_base::binary);
4396 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4397 os<<serializeString(name);
4401 std::string s = os.str();
4402 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4404 m_con.Send(peer_id, 0, data, true);
4407 void Server::sendDetachedInventoryToAll(const std::string &name)
4409 DSTACK(__FUNCTION_NAME);
4411 for(core::map<u16, RemoteClient*>::Iterator
4412 i = m_clients.getIterator();
4413 i.atEnd() == false; i++){
4414 RemoteClient *client = i.getNode()->getValue();
4415 sendDetachedInventory(name, client->peer_id);
4419 void Server::sendDetachedInventories(u16 peer_id)
4421 DSTACK(__FUNCTION_NAME);
4423 for(std::map<std::string, Inventory*>::iterator
4424 i = m_detached_inventories.begin();
4425 i != m_detached_inventories.end(); i++){
4426 const std::string &name = i->first;
4427 //Inventory *inv = i->second;
4428 sendDetachedInventory(name, peer_id);
4436 void Server::DiePlayer(u16 peer_id)
4438 DSTACK(__FUNCTION_NAME);
4440 PlayerSAO *playersao = getPlayerSAO(peer_id);
4443 infostream<<"Server::DiePlayer(): Player "
4444 <<playersao->getPlayer()->getName()
4445 <<" dies"<<std::endl;
4447 playersao->setHP(0);
4449 // Trigger scripted stuff
4450 scriptapi_on_dieplayer(m_lua, playersao);
4452 SendPlayerHP(peer_id);
4453 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4456 void Server::RespawnPlayer(u16 peer_id)
4458 DSTACK(__FUNCTION_NAME);
4460 PlayerSAO *playersao = getPlayerSAO(peer_id);
4463 infostream<<"Server::RespawnPlayer(): Player "
4464 <<playersao->getPlayer()->getName()
4465 <<" respawns"<<std::endl;
4467 playersao->setHP(PLAYER_MAX_HP);
4469 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4471 v3f pos = findSpawnPos(m_env->getServerMap());
4472 playersao->setPos(pos);
4476 void Server::UpdateCrafting(u16 peer_id)
4478 DSTACK(__FUNCTION_NAME);
4480 Player* player = m_env->getPlayer(peer_id);
4483 // Get a preview for crafting
4485 getCraftingResult(&player->inventory, preview, false, this);
4487 // Put the new preview in
4488 InventoryList *plist = player->inventory.getList("craftpreview");
4490 assert(plist->getSize() >= 1);
4491 plist->changeItem(0, preview);
4494 RemoteClient* Server::getClient(u16 peer_id)
4496 DSTACK(__FUNCTION_NAME);
4497 //JMutexAutoLock lock(m_con_mutex);
4498 core::map<u16, RemoteClient*>::Node *n;
4499 n = m_clients.find(peer_id);
4500 // A client should exist for all peers
4502 return n->getValue();
4505 std::wstring Server::getStatusString()
4507 std::wostringstream os(std::ios_base::binary);
4510 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4512 os<<L", uptime="<<m_uptime.get();
4513 // Information about clients
4514 core::map<u16, RemoteClient*>::Iterator i;
4517 for(i = m_clients.getIterator(), first = true;
4518 i.atEnd() == false; i++)
4520 // Get client and check that it is valid
4521 RemoteClient *client = i.getNode()->getValue();
4522 assert(client->peer_id == i.getNode()->getKey());
4523 if(client->serialization_version == SER_FMT_VER_INVALID)
4526 Player *player = m_env->getPlayer(client->peer_id);
4527 // Get name of player
4528 std::wstring name = L"unknown";
4530 name = narrow_to_wide(player->getName());
4531 // Add name to information string
4539 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4540 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4541 if(g_settings->get("motd") != "")
4542 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4546 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4548 std::set<std::string> privs;
4549 scriptapi_get_auth(m_lua, name, NULL, &privs);
4553 bool Server::checkPriv(const std::string &name, const std::string &priv)
4555 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4556 return (privs.count(priv) != 0);
4559 void Server::reportPrivsModified(const std::string &name)
4562 for(core::map<u16, RemoteClient*>::Iterator
4563 i = m_clients.getIterator();
4564 i.atEnd() == false; i++){
4565 RemoteClient *client = i.getNode()->getValue();
4566 Player *player = m_env->getPlayer(client->peer_id);
4567 reportPrivsModified(player->getName());
4570 Player *player = m_env->getPlayer(name.c_str());
4573 SendPlayerPrivileges(player->peer_id);
4574 PlayerSAO *sao = player->getPlayerSAO();
4577 sao->updatePrivileges(
4578 getPlayerEffectivePrivs(name),
4583 void Server::reportInventoryFormspecModified(const std::string &name)
4585 Player *player = m_env->getPlayer(name.c_str());
4588 SendPlayerInventoryFormspec(player->peer_id);
4591 // Saves g_settings to configpath given at initialization
4592 void Server::saveConfig()
4594 if(m_path_config != "")
4595 g_settings->updateConfigFile(m_path_config.c_str());
4598 void Server::notifyPlayer(const char *name, const std::wstring msg)
4600 Player *player = m_env->getPlayer(name);
4603 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4606 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4608 Player *player = m_env->getPlayer(playername);
4612 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4616 SendShowFormspecMessage(player->peer_id, formspec, formname);
4620 void Server::notifyPlayers(const std::wstring msg)
4622 BroadcastChatMessage(msg);
4625 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4629 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4630 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4633 Inventory* Server::createDetachedInventory(const std::string &name)
4635 if(m_detached_inventories.count(name) > 0){
4636 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4637 delete m_detached_inventories[name];
4639 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4641 Inventory *inv = new Inventory(m_itemdef);
4643 m_detached_inventories[name] = inv;
4644 sendDetachedInventoryToAll(name);
4651 BoolScopeSet(bool *dst, bool val):
4654 m_orig_state = *m_dst;
4659 *m_dst = m_orig_state;
4666 // actions: time-reversed list
4667 // Return value: success/failure
4668 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4669 std::list<std::string> *log)
4671 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4672 ServerMap *map = (ServerMap*)(&m_env->getMap());
4673 // Disable rollback report sink while reverting
4674 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4676 // Fail if no actions to handle
4677 if(actions.empty()){
4678 log->push_back("Nothing to do.");
4685 for(std::list<RollbackAction>::const_iterator
4686 i = actions.begin();
4687 i != actions.end(); i++)
4689 const RollbackAction &action = *i;
4691 bool success = action.applyRevert(map, this, this);
4694 std::ostringstream os;
4695 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4696 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4698 log->push_back(os.str());
4700 std::ostringstream os;
4701 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4702 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4704 log->push_back(os.str());
4708 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4709 <<" failed"<<std::endl;
4711 // Call it done if less than half failed
4712 return num_failed <= num_tried/2;
4715 // IGameDef interface
4717 IItemDefManager* Server::getItemDefManager()
4721 INodeDefManager* Server::getNodeDefManager()
4725 ICraftDefManager* Server::getCraftDefManager()
4729 ITextureSource* Server::getTextureSource()
4733 IShaderSource* Server::getShaderSource()
4737 u16 Server::allocateUnknownNodeId(const std::string &name)
4739 return m_nodedef->allocateDummy(name);
4741 ISoundManager* Server::getSoundManager()
4743 return &dummySoundManager;
4745 MtEventManager* Server::getEventManager()
4749 IRollbackReportSink* Server::getRollbackReportSink()
4751 if(!m_enable_rollback_recording)
4753 if(!m_rollback_sink_enabled)
4758 IWritableItemDefManager* Server::getWritableItemDefManager()
4762 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4766 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4771 const ModSpec* Server::getModSpec(const std::string &modname)
4773 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4774 i != m_mods.end(); i++){
4775 const ModSpec &mod = *i;
4776 if(mod.name == modname)
4781 void Server::getModNames(core::list<std::string> &modlist)
4783 for(core::list<ModSpec>::Iterator i = m_mods.begin(); i != m_mods.end(); i++)
4785 modlist.push_back((*i).name);
4788 std::string Server::getBuiltinLuaPath()
4790 return porting::path_share + DIR_DELIM + "builtin";
4793 v3f findSpawnPos(ServerMap &map)
4795 //return v3f(50,50,50)*BS;
4800 nodepos = v2s16(0,0);
4805 // Try to find a good place a few times
4806 for(s32 i=0; i<1000; i++)
4809 // We're going to try to throw the player to this position
4810 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4811 -range + (myrand()%(range*2)));
4812 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4813 // Get ground height at point (fallbacks to heightmap function)
4814 s16 groundheight = map.findGroundLevel(nodepos2d);
4815 // Don't go underwater
4816 if(groundheight < WATER_LEVEL)
4818 //infostream<<"-> Underwater"<<std::endl;
4821 // Don't go to high places
4822 if(groundheight > WATER_LEVEL + 4)
4824 //infostream<<"-> Underwater"<<std::endl;
4828 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4829 bool is_good = false;
4831 for(s32 i=0; i<10; i++){
4832 v3s16 blockpos = getNodeBlockPos(nodepos);
4833 map.emergeBlock(blockpos, true);
4834 MapNode n = map.getNodeNoEx(nodepos);
4835 if(n.getContent() == CONTENT_AIR){
4846 // Found a good place
4847 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4853 return intToFloat(nodepos, BS);
4856 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4858 RemotePlayer *player = NULL;
4859 bool newplayer = false;
4862 Try to get an existing player
4864 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4866 // If player is already connected, cancel
4867 if(player != NULL && player->peer_id != 0)
4869 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4874 If player with the wanted peer_id already exists, cancel.
4876 if(m_env->getPlayer(peer_id) != NULL)
4878 infostream<<"emergePlayer(): Player with wrong name but same"
4879 " peer_id already exists"<<std::endl;
4884 Create a new player if it doesn't exist yet
4889 player = new RemotePlayer(this);
4890 player->updateName(name);
4892 /* Set player position */
4893 infostream<<"Server: Finding spawn place for player \""
4894 <<name<<"\""<<std::endl;
4895 v3f pos = findSpawnPos(m_env->getServerMap());
4896 player->setPosition(pos);
4898 /* Add player to environment */
4899 m_env->addPlayer(player);
4903 Create a new player active object
4905 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4906 getPlayerEffectivePrivs(player->getName()),
4909 /* Add object to environment */
4910 m_env->addActiveObject(playersao);
4914 scriptapi_on_newplayer(m_lua, playersao);
4916 scriptapi_on_joinplayer(m_lua, playersao);
4921 void Server::handlePeerChange(PeerChange &c)
4923 JMutexAutoLock envlock(m_env_mutex);
4924 JMutexAutoLock conlock(m_con_mutex);
4926 if(c.type == PEER_ADDED)
4933 core::map<u16, RemoteClient*>::Node *n;
4934 n = m_clients.find(c.peer_id);
4935 // The client shouldn't already exist
4939 RemoteClient *client = new RemoteClient();
4940 client->peer_id = c.peer_id;
4941 m_clients.insert(client->peer_id, client);
4944 else if(c.type == PEER_REMOVED)
4951 core::map<u16, RemoteClient*>::Node *n;
4952 n = m_clients.find(c.peer_id);
4953 // The client should exist
4957 Mark objects to be not known by the client
4959 RemoteClient *client = n->getValue();
4961 for(core::map<u16, bool>::Iterator
4962 i = client->m_known_objects.getIterator();
4963 i.atEnd()==false; i++)
4966 u16 id = i.getNode()->getKey();
4967 ServerActiveObject* obj = m_env->getActiveObject(id);
4969 if(obj && obj->m_known_by_count > 0)
4970 obj->m_known_by_count--;
4974 Clear references to playing sounds
4976 for(std::map<s32, ServerPlayingSound>::iterator
4977 i = m_playing_sounds.begin();
4978 i != m_playing_sounds.end();)
4980 ServerPlayingSound &psound = i->second;
4981 psound.clients.erase(c.peer_id);
4982 if(psound.clients.size() == 0)
4983 m_playing_sounds.erase(i++);
4988 Player *player = m_env->getPlayer(c.peer_id);
4990 // Collect information about leaving in chat
4991 std::wstring message;
4995 std::wstring name = narrow_to_wide(player->getName());
4998 message += L" left the game.";
5000 message += L" (timed out)";
5004 /* Run scripts and remove from environment */
5008 PlayerSAO *playersao = player->getPlayerSAO();
5011 scriptapi_on_leaveplayer(m_lua, playersao);
5013 playersao->disconnected();
5023 std::ostringstream os(std::ios_base::binary);
5024 for(core::map<u16, RemoteClient*>::Iterator
5025 i = m_clients.getIterator();
5026 i.atEnd() == false; i++)
5028 RemoteClient *client = i.getNode()->getValue();
5029 assert(client->peer_id == i.getNode()->getKey());
5030 if(client->serialization_version == SER_FMT_VER_INVALID)
5033 Player *player = m_env->getPlayer(client->peer_id);
5036 // Get name of player
5037 os<<player->getName()<<" ";
5040 actionstream<<player->getName()<<" "
5041 <<(c.timeout?"times out.":"leaves game.")
5042 <<" List of players: "
5043 <<os.str()<<std::endl;
5048 delete m_clients[c.peer_id];
5049 m_clients.remove(c.peer_id);
5051 // Send player info to all remaining clients
5052 //SendPlayerInfos();
5054 // Send leave chat message to all remaining clients
5055 if(message.length() != 0)
5056 BroadcastChatMessage(message);
5065 void Server::handlePeerChanges()
5067 while(m_peer_change_queue.size() > 0)
5069 PeerChange c = m_peer_change_queue.pop_front();
5071 verbosestream<<"Server: Handling peer change: "
5072 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5075 handlePeerChange(c);
5079 void dedicated_server_loop(Server &server, bool &kill)
5081 DSTACK(__FUNCTION_NAME);
5083 verbosestream<<"dedicated_server_loop()"<<std::endl;
5085 IntervalLimiter m_profiler_interval;
5089 float steplen = g_settings->getFloat("dedicated_server_step");
5090 // This is kind of a hack but can be done like this
5091 // because server.step() is very light
5093 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5094 sleep_ms((int)(steplen*1000.0));
5096 server.step(steplen);
5098 if(server.getShutdownRequested() || kill)
5100 infostream<<"Dedicated server quitting"<<std::endl;
5107 float profiler_print_interval =
5108 g_settings->getFloat("profiler_print_interval");
5109 if(profiler_print_interval != 0)
5111 if(m_profiler_interval.step(steplen, profiler_print_interval))
5113 infostream<<"Profiler:"<<std::endl;
5114 g_profiler->print(infostream);
5115 g_profiler->clear();