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 // Create world if it doesn't exist
984 if(!initializeWorld(m_path_world, m_gamespec.id))
985 throw ServerError("Failed to initialize world");
987 ModConfiguration modconf(m_path_world);
988 m_mods = modconf.getMods();
989 // complain about mods with unsatisfied dependencies
990 if(!modconf.isConsistent())
992 errorstream << "The following mods have unsatisfied dependencies: ";
993 std::list<ModSpec> modlist = modconf.getUnsatisfiedMods();
994 for(std::list<ModSpec>::iterator it = modlist.begin();
995 it != modlist.end(); ++it)
997 errorstream << (*it).name << " ";
999 errorstream << std::endl;
1002 Settings worldmt_settings;
1003 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
1004 worldmt_settings.readConfigFile(worldmt.c_str());
1005 std::vector<std::string> names = worldmt_settings.getNames();
1006 std::set<std::string> exclude_mod_names;
1007 std::set<std::string> load_mod_names;
1008 for(std::vector<std::string>::iterator it = names.begin();
1009 it != names.end(); ++it)
1011 std::string name = *it;
1012 if (name.compare(0,9,"load_mod_")==0)
1014 if(worldmt_settings.getBool(name))
1015 load_mod_names.insert(name.substr(9));
1017 exclude_mod_names.insert(name.substr(9));
1020 // complain about mods declared to be loaded, but not found
1021 for(std::vector<ModSpec>::iterator it = m_mods.begin();
1022 it != m_mods.end(); ++it)
1023 load_mod_names.erase((*it).name);
1024 if(!load_mod_names.empty())
1026 errorstream << "The following mods could not be found: ";
1027 for(std::set<std::string>::iterator it = load_mod_names.begin();
1028 it != load_mod_names.end(); ++it)
1029 errorstream << (*it) << " ";
1030 errorstream << std::endl;
1033 // Path to builtin.lua
1034 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
1037 JMutexAutoLock envlock(m_env_mutex);
1038 JMutexAutoLock conlock(m_con_mutex);
1040 // Initialize scripting
1042 infostream<<"Server: Initializing Lua"<<std::endl;
1043 m_lua = script_init();
1046 scriptapi_export(m_lua, this);
1047 // Load and run builtin.lua
1048 infostream<<"Server: Loading builtin.lua [\""
1049 <<builtinpath<<"\"]"<<std::endl;
1050 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1052 errorstream<<"Server: Failed to load and run "
1053 <<builtinpath<<std::endl;
1054 throw ModError("Failed to load and run "+builtinpath);
1057 infostream<<"Server: Loading mods: ";
1058 for(std::vector<ModSpec>::iterator i = m_mods.begin();
1059 i != m_mods.end(); i++){
1060 const ModSpec &mod = *i;
1061 infostream<<mod.name<<" ";
1063 infostream<<std::endl;
1064 // Load and run "mod" scripts
1065 for(std::vector<ModSpec>::iterator i = m_mods.begin();
1066 i != m_mods.end(); i++){
1067 const ModSpec &mod = *i;
1068 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1069 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1070 <<scriptpath<<"\"]"<<std::endl;
1071 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1073 errorstream<<"Server: Failed to load and run "
1074 <<scriptpath<<std::endl;
1075 throw ModError("Failed to load and run "+scriptpath);
1079 // Read Textures and calculate sha1 sums
1082 // Apply item aliases in the node definition manager
1083 m_nodedef->updateAliases(m_itemdef);
1085 // Initialize Environment
1087 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
1090 // Give environment reference to scripting api
1091 scriptapi_add_environment(m_lua, m_env);
1093 // Register us to receive map edit events
1094 m_env->getMap().addEventReceiver(this);
1096 // If file exists, load environment metadata
1097 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1099 infostream<<"Server: Loading environment metadata"<<std::endl;
1100 m_env->loadMeta(m_path_world);
1104 infostream<<"Server: Loading players"<<std::endl;
1105 m_env->deSerializePlayers(m_path_world);
1108 Add some test ActiveBlockModifiers to environment
1110 add_legacy_abms(m_env, m_nodedef);
1115 infostream<<"Server destructing"<<std::endl;
1118 Send shutdown message
1121 JMutexAutoLock conlock(m_con_mutex);
1123 std::wstring line = L"*** Server shutting down";
1126 Send the message to clients
1128 for(core::map<u16, RemoteClient*>::Iterator
1129 i = m_clients.getIterator();
1130 i.atEnd() == false; i++)
1132 // Get client and check that it is valid
1133 RemoteClient *client = i.getNode()->getValue();
1134 assert(client->peer_id == i.getNode()->getKey());
1135 if(client->serialization_version == SER_FMT_VER_INVALID)
1139 SendChatMessage(client->peer_id, line);
1141 catch(con::PeerNotFoundException &e)
1147 JMutexAutoLock envlock(m_env_mutex);
1148 JMutexAutoLock conlock(m_con_mutex);
1151 Execute script shutdown hooks
1153 scriptapi_on_shutdown(m_lua);
1157 JMutexAutoLock envlock(m_env_mutex);
1162 infostream<<"Server: Saving players"<<std::endl;
1163 m_env->serializePlayers(m_path_world);
1166 Save environment metadata
1168 infostream<<"Server: Saving environment metadata"<<std::endl;
1169 m_env->saveMeta(m_path_world);
1181 JMutexAutoLock clientslock(m_con_mutex);
1183 for(core::map<u16, RemoteClient*>::Iterator
1184 i = m_clients.getIterator();
1185 i.atEnd() == false; i++)
1188 delete i.getNode()->getValue();
1192 // Delete things in the reverse order of creation
1200 // Deinitialize scripting
1201 infostream<<"Server: Deinitializing scripting"<<std::endl;
1202 script_deinit(m_lua);
1204 // Delete detached inventories
1206 for(std::map<std::string, Inventory*>::iterator
1207 i = m_detached_inventories.begin();
1208 i != m_detached_inventories.end(); i++){
1214 void Server::start(unsigned short port)
1216 DSTACK(__FUNCTION_NAME);
1217 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1219 // Stop thread if already running
1222 // Initialize connection
1223 m_con.SetTimeoutMs(30);
1227 m_thread.setRun(true);
1230 // ASCII art for the win!
1232 <<" .__ __ __ "<<std::endl
1233 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1234 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1235 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1236 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1237 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1238 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1239 actionstream<<"Server for gameid=\""<<m_gamespec.id
1240 <<"\" listening on port "<<port<<"."<<std::endl;
1245 DSTACK(__FUNCTION_NAME);
1247 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1249 // Stop threads (set run=false first so both start stopping)
1250 m_thread.setRun(false);
1251 m_emergethread.setRun(false);
1253 m_emergethread.stop();
1255 infostream<<"Server: Threads stopped"<<std::endl;
1258 void Server::step(float dtime)
1260 DSTACK(__FUNCTION_NAME);
1265 JMutexAutoLock lock(m_step_dtime_mutex);
1266 m_step_dtime += dtime;
1268 // Throw if fatal error occurred in thread
1269 std::string async_err = m_async_fatal_error.get();
1270 if(async_err != ""){
1271 throw ServerError(async_err);
1275 void Server::AsyncRunStep()
1277 DSTACK(__FUNCTION_NAME);
1279 g_profiler->add("Server::AsyncRunStep (num)", 1);
1283 JMutexAutoLock lock1(m_step_dtime_mutex);
1284 dtime = m_step_dtime;
1288 // Send blocks to clients
1295 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1297 //infostream<<"Server steps "<<dtime<<std::endl;
1298 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1301 JMutexAutoLock lock1(m_step_dtime_mutex);
1302 m_step_dtime -= dtime;
1309 m_uptime.set(m_uptime.get() + dtime);
1313 // Process connection's timeouts
1314 JMutexAutoLock lock2(m_con_mutex);
1315 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1316 m_con.RunTimeouts(dtime);
1320 // This has to be called so that the client list gets synced
1321 // with the peer list of the connection
1322 handlePeerChanges();
1326 Update time of day and overall game time
1329 JMutexAutoLock envlock(m_env_mutex);
1331 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1334 Send to clients at constant intervals
1337 m_time_of_day_send_timer -= dtime;
1338 if(m_time_of_day_send_timer < 0.0)
1340 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1342 //JMutexAutoLock envlock(m_env_mutex);
1343 JMutexAutoLock conlock(m_con_mutex);
1345 for(core::map<u16, RemoteClient*>::Iterator
1346 i = m_clients.getIterator();
1347 i.atEnd() == false; i++)
1349 RemoteClient *client = i.getNode()->getValue();
1350 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1351 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1353 m_con.Send(client->peer_id, 0, data, true);
1359 JMutexAutoLock lock(m_env_mutex);
1361 ScopeProfiler sp(g_profiler, "SEnv step");
1362 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1366 const float map_timer_and_unload_dtime = 2.92;
1367 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1369 JMutexAutoLock lock(m_env_mutex);
1370 // Run Map's timers and unload unused data
1371 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1372 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1373 g_settings->getFloat("server_unload_unused_data_timeout"));
1384 JMutexAutoLock lock(m_env_mutex);
1385 JMutexAutoLock lock2(m_con_mutex);
1387 ScopeProfiler sp(g_profiler, "Server: handle players");
1389 for(core::map<u16, RemoteClient*>::Iterator
1390 i = m_clients.getIterator();
1391 i.atEnd() == false; i++)
1393 RemoteClient *client = i.getNode()->getValue();
1394 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1395 if(playersao == NULL)
1399 Handle player HPs (die if hp=0)
1401 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1403 if(playersao->getHP() == 0)
1404 DiePlayer(client->peer_id);
1406 SendPlayerHP(client->peer_id);
1410 Send player inventories if necessary
1412 if(playersao->m_moved){
1413 SendMovePlayer(client->peer_id);
1414 playersao->m_moved = false;
1416 if(playersao->m_inventory_not_sent){
1417 UpdateCrafting(client->peer_id);
1418 SendInventory(client->peer_id);
1423 /* Transform liquids */
1424 m_liquid_transform_timer += dtime;
1425 if(m_liquid_transform_timer >= 1.00)
1427 m_liquid_transform_timer -= 1.00;
1429 JMutexAutoLock lock(m_env_mutex);
1431 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1433 core::map<v3s16, MapBlock*> modified_blocks;
1434 m_env->getMap().transformLiquids(modified_blocks);
1439 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1440 ServerMap &map = ((ServerMap&)m_env->getMap());
1441 map.updateLighting(modified_blocks, lighting_modified_blocks);
1443 // Add blocks modified by lighting to modified_blocks
1444 for(core::map<v3s16, MapBlock*>::Iterator
1445 i = lighting_modified_blocks.getIterator();
1446 i.atEnd() == false; i++)
1448 MapBlock *block = i.getNode()->getValue();
1449 modified_blocks.insert(block->getPos(), block);
1453 Set the modified blocks unsent for all the clients
1456 JMutexAutoLock lock2(m_con_mutex);
1458 for(core::map<u16, RemoteClient*>::Iterator
1459 i = m_clients.getIterator();
1460 i.atEnd() == false; i++)
1462 RemoteClient *client = i.getNode()->getValue();
1464 if(modified_blocks.size() > 0)
1466 // Remove block from sent history
1467 client->SetBlocksNotSent(modified_blocks);
1472 // Periodically print some info
1474 float &counter = m_print_info_timer;
1480 JMutexAutoLock lock2(m_con_mutex);
1482 if(m_clients.size() != 0)
1483 infostream<<"Players:"<<std::endl;
1484 for(core::map<u16, RemoteClient*>::Iterator
1485 i = m_clients.getIterator();
1486 i.atEnd() == false; i++)
1488 //u16 peer_id = i.getNode()->getKey();
1489 RemoteClient *client = i.getNode()->getValue();
1490 Player *player = m_env->getPlayer(client->peer_id);
1493 infostream<<"* "<<player->getName()<<"\t";
1494 client->PrintInfo(infostream);
1499 //if(g_settings->getBool("enable_experimental"))
1503 Check added and deleted active objects
1506 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1507 JMutexAutoLock envlock(m_env_mutex);
1508 JMutexAutoLock conlock(m_con_mutex);
1510 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1512 // Radius inside which objects are active
1513 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1514 radius *= MAP_BLOCKSIZE;
1516 for(core::map<u16, RemoteClient*>::Iterator
1517 i = m_clients.getIterator();
1518 i.atEnd() == false; i++)
1520 RemoteClient *client = i.getNode()->getValue();
1522 // If definitions and textures have not been sent, don't
1523 // send objects either
1524 if(!client->definitions_sent)
1527 Player *player = m_env->getPlayer(client->peer_id);
1530 // This can happen if the client timeouts somehow
1531 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1533 <<" has no associated player"<<std::endl;*/
1536 v3s16 pos = floatToInt(player->getPosition(), BS);
1538 core::map<u16, bool> removed_objects;
1539 core::map<u16, bool> added_objects;
1540 m_env->getRemovedActiveObjects(pos, radius,
1541 client->m_known_objects, removed_objects);
1542 m_env->getAddedActiveObjects(pos, radius,
1543 client->m_known_objects, added_objects);
1545 // Ignore if nothing happened
1546 if(removed_objects.size() == 0 && added_objects.size() == 0)
1548 //infostream<<"active objects: none changed"<<std::endl;
1552 std::string data_buffer;
1556 // Handle removed objects
1557 writeU16((u8*)buf, removed_objects.size());
1558 data_buffer.append(buf, 2);
1559 for(core::map<u16, bool>::Iterator
1560 i = removed_objects.getIterator();
1561 i.atEnd()==false; i++)
1564 u16 id = i.getNode()->getKey();
1565 ServerActiveObject* obj = m_env->getActiveObject(id);
1567 // Add to data buffer for sending
1568 writeU16((u8*)buf, i.getNode()->getKey());
1569 data_buffer.append(buf, 2);
1571 // Remove from known objects
1572 client->m_known_objects.remove(i.getNode()->getKey());
1574 if(obj && obj->m_known_by_count > 0)
1575 obj->m_known_by_count--;
1578 // Handle added objects
1579 writeU16((u8*)buf, added_objects.size());
1580 data_buffer.append(buf, 2);
1581 for(core::map<u16, bool>::Iterator
1582 i = added_objects.getIterator();
1583 i.atEnd()==false; i++)
1586 u16 id = i.getNode()->getKey();
1587 ServerActiveObject* obj = m_env->getActiveObject(id);
1590 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1592 infostream<<"WARNING: "<<__FUNCTION_NAME
1593 <<": NULL object"<<std::endl;
1595 type = obj->getSendType();
1597 // Add to data buffer for sending
1598 writeU16((u8*)buf, id);
1599 data_buffer.append(buf, 2);
1600 writeU8((u8*)buf, type);
1601 data_buffer.append(buf, 1);
1604 data_buffer.append(serializeLongString(
1605 obj->getClientInitializationData(client->net_proto_version)));
1607 data_buffer.append(serializeLongString(""));
1609 // Add to known objects
1610 client->m_known_objects.insert(i.getNode()->getKey(), false);
1613 obj->m_known_by_count++;
1617 SharedBuffer<u8> reply(2 + data_buffer.size());
1618 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1619 memcpy((char*)&reply[2], data_buffer.c_str(),
1620 data_buffer.size());
1622 m_con.Send(client->peer_id, 0, reply, true);
1624 verbosestream<<"Server: Sent object remove/add: "
1625 <<removed_objects.size()<<" removed, "
1626 <<added_objects.size()<<" added, "
1627 <<"packet size is "<<reply.getSize()<<std::endl;
1632 Collect a list of all the objects known by the clients
1633 and report it back to the environment.
1636 core::map<u16, bool> all_known_objects;
1638 for(core::map<u16, RemoteClient*>::Iterator
1639 i = m_clients.getIterator();
1640 i.atEnd() == false; i++)
1642 RemoteClient *client = i.getNode()->getValue();
1643 // Go through all known objects of client
1644 for(core::map<u16, bool>::Iterator
1645 i = client->m_known_objects.getIterator();
1646 i.atEnd()==false; i++)
1648 u16 id = i.getNode()->getKey();
1649 all_known_objects[id] = true;
1653 m_env->setKnownActiveObjects(whatever);
1659 Send object messages
1662 JMutexAutoLock envlock(m_env_mutex);
1663 JMutexAutoLock conlock(m_con_mutex);
1665 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1668 // Value = data sent by object
1669 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1671 // Get active object messages from environment
1674 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1678 core::list<ActiveObjectMessage>* message_list = NULL;
1679 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1680 n = buffered_messages.find(aom.id);
1683 message_list = new core::list<ActiveObjectMessage>;
1684 buffered_messages.insert(aom.id, message_list);
1688 message_list = n->getValue();
1690 message_list->push_back(aom);
1693 // Route data to every client
1694 for(core::map<u16, RemoteClient*>::Iterator
1695 i = m_clients.getIterator();
1696 i.atEnd()==false; i++)
1698 RemoteClient *client = i.getNode()->getValue();
1699 std::string reliable_data;
1700 std::string unreliable_data;
1701 // Go through all objects in message buffer
1702 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1703 j = buffered_messages.getIterator();
1704 j.atEnd()==false; j++)
1706 // If object is not known by client, skip it
1707 u16 id = j.getNode()->getKey();
1708 if(client->m_known_objects.find(id) == NULL)
1710 // Get message list of object
1711 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1712 // Go through every message
1713 for(core::list<ActiveObjectMessage>::Iterator
1714 k = list->begin(); k != list->end(); k++)
1716 // Compose the full new data with header
1717 ActiveObjectMessage aom = *k;
1718 std::string new_data;
1721 writeU16((u8*)&buf[0], aom.id);
1722 new_data.append(buf, 2);
1724 new_data += serializeString(aom.datastring);
1725 // Add data to buffer
1727 reliable_data += new_data;
1729 unreliable_data += new_data;
1733 reliable_data and unreliable_data are now ready.
1736 if(reliable_data.size() > 0)
1738 SharedBuffer<u8> reply(2 + reliable_data.size());
1739 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1740 memcpy((char*)&reply[2], reliable_data.c_str(),
1741 reliable_data.size());
1743 m_con.Send(client->peer_id, 0, reply, true);
1745 if(unreliable_data.size() > 0)
1747 SharedBuffer<u8> reply(2 + unreliable_data.size());
1748 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1749 memcpy((char*)&reply[2], unreliable_data.c_str(),
1750 unreliable_data.size());
1751 // Send as unreliable
1752 m_con.Send(client->peer_id, 0, reply, false);
1755 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1757 infostream<<"Server: Size of object message data: "
1758 <<"reliable: "<<reliable_data.size()
1759 <<", unreliable: "<<unreliable_data.size()
1764 // Clear buffered_messages
1765 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1766 i = buffered_messages.getIterator();
1767 i.atEnd()==false; i++)
1769 delete i.getNode()->getValue();
1773 } // enable_experimental
1776 Send queued-for-sending map edit events.
1779 // We will be accessing the environment and the connection
1780 JMutexAutoLock lock(m_env_mutex);
1781 JMutexAutoLock conlock(m_con_mutex);
1783 // Don't send too many at a time
1786 // Single change sending is disabled if queue size is not small
1787 bool disable_single_change_sending = false;
1788 if(m_unsent_map_edit_queue.size() >= 4)
1789 disable_single_change_sending = true;
1791 int event_count = m_unsent_map_edit_queue.size();
1793 // We'll log the amount of each
1796 while(m_unsent_map_edit_queue.size() != 0)
1798 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1800 // Players far away from the change are stored here.
1801 // Instead of sending the changes, MapBlocks are set not sent
1803 core::list<u16> far_players;
1805 if(event->type == MEET_ADDNODE)
1807 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1808 prof.add("MEET_ADDNODE", 1);
1809 if(disable_single_change_sending)
1810 sendAddNode(event->p, event->n, event->already_known_by_peer,
1813 sendAddNode(event->p, event->n, event->already_known_by_peer,
1816 else if(event->type == MEET_REMOVENODE)
1818 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1819 prof.add("MEET_REMOVENODE", 1);
1820 if(disable_single_change_sending)
1821 sendRemoveNode(event->p, event->already_known_by_peer,
1824 sendRemoveNode(event->p, event->already_known_by_peer,
1827 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1829 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1830 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1831 setBlockNotSent(event->p);
1833 else if(event->type == MEET_OTHER)
1835 infostream<<"Server: MEET_OTHER"<<std::endl;
1836 prof.add("MEET_OTHER", 1);
1837 for(core::map<v3s16, bool>::Iterator
1838 i = event->modified_blocks.getIterator();
1839 i.atEnd()==false; i++)
1841 v3s16 p = i.getNode()->getKey();
1847 prof.add("unknown", 1);
1848 infostream<<"WARNING: Server: Unknown MapEditEvent "
1849 <<((u32)event->type)<<std::endl;
1853 Set blocks not sent to far players
1855 if(far_players.size() > 0)
1857 // Convert list format to that wanted by SetBlocksNotSent
1858 core::map<v3s16, MapBlock*> modified_blocks2;
1859 for(core::map<v3s16, bool>::Iterator
1860 i = event->modified_blocks.getIterator();
1861 i.atEnd()==false; i++)
1863 v3s16 p = i.getNode()->getKey();
1864 modified_blocks2.insert(p,
1865 m_env->getMap().getBlockNoCreateNoEx(p));
1867 // Set blocks not sent
1868 for(core::list<u16>::Iterator
1869 i = far_players.begin();
1870 i != far_players.end(); i++)
1873 RemoteClient *client = getClient(peer_id);
1876 client->SetBlocksNotSent(modified_blocks2);
1882 /*// Don't send too many at a time
1884 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1888 if(event_count >= 5){
1889 infostream<<"Server: MapEditEvents:"<<std::endl;
1890 prof.print(infostream);
1891 } else if(event_count != 0){
1892 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1893 prof.print(verbosestream);
1899 Trigger emergethread (it somehow gets to a non-triggered but
1900 bysy state sometimes)
1903 float &counter = m_emergethread_trigger_timer;
1909 m_emergethread.trigger();
1911 // Update m_enable_rollback_recording here too
1912 m_enable_rollback_recording =
1913 g_settings->getBool("enable_rollback_recording");
1917 // Save map, players and auth stuff
1919 float &counter = m_savemap_timer;
1921 if(counter >= g_settings->getFloat("server_map_save_interval"))
1924 JMutexAutoLock lock(m_env_mutex);
1926 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1929 if(m_banmanager.isModified())
1930 m_banmanager.save();
1932 // Save changed parts of map
1933 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1936 m_env->serializePlayers(m_path_world);
1938 // Save environment metadata
1939 m_env->saveMeta(m_path_world);
1944 void Server::Receive()
1946 DSTACK(__FUNCTION_NAME);
1947 SharedBuffer<u8> data;
1952 JMutexAutoLock conlock(m_con_mutex);
1953 datasize = m_con.Receive(peer_id, data);
1956 // This has to be called so that the client list gets synced
1957 // with the peer list of the connection
1958 handlePeerChanges();
1960 ProcessData(*data, datasize, peer_id);
1962 catch(con::InvalidIncomingDataException &e)
1964 infostream<<"Server::Receive(): "
1965 "InvalidIncomingDataException: what()="
1966 <<e.what()<<std::endl;
1968 catch(con::PeerNotFoundException &e)
1970 //NOTE: This is not needed anymore
1972 // The peer has been disconnected.
1973 // Find the associated player and remove it.
1975 /*JMutexAutoLock envlock(m_env_mutex);
1977 infostream<<"ServerThread: peer_id="<<peer_id
1978 <<" has apparently closed connection. "
1979 <<"Removing player."<<std::endl;
1981 m_env->removePlayer(peer_id);*/
1985 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1987 DSTACK(__FUNCTION_NAME);
1988 // Environment is locked first.
1989 JMutexAutoLock envlock(m_env_mutex);
1990 JMutexAutoLock conlock(m_con_mutex);
1992 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1995 Address address = m_con.GetPeerAddress(peer_id);
1996 std::string addr_s = address.serializeString();
1998 // drop player if is ip is banned
1999 if(m_banmanager.isIpBanned(addr_s)){
2000 infostream<<"Server: A banned client tried to connect from "
2001 <<addr_s<<"; banned name was "
2002 <<m_banmanager.getBanName(addr_s)<<std::endl;
2003 // This actually doesn't seem to transfer to the client
2004 SendAccessDenied(m_con, peer_id,
2005 L"Your ip is banned. Banned name was "
2006 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
2007 m_con.DeletePeer(peer_id);
2011 catch(con::PeerNotFoundException &e)
2013 infostream<<"Server::ProcessData(): Cancelling: peer "
2014 <<peer_id<<" not found"<<std::endl;
2018 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
2020 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
2028 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
2030 if(command == TOSERVER_INIT)
2032 // [0] u16 TOSERVER_INIT
2033 // [2] u8 SER_FMT_VER_HIGHEST
2034 // [3] u8[20] player_name
2035 // [23] u8[28] password <--- can be sent without this, from old versions
2037 if(datasize < 2+1+PLAYERNAME_SIZE)
2040 verbosestream<<"Server: Got TOSERVER_INIT from "
2041 <<peer_id<<std::endl;
2043 // First byte after command is maximum supported
2044 // serialization version
2045 u8 client_max = data[2];
2046 u8 our_max = SER_FMT_VER_HIGHEST;
2047 // Use the highest version supported by both
2048 u8 deployed = core::min_(client_max, our_max);
2049 // If it's lower than the lowest supported, give up.
2050 if(deployed < SER_FMT_VER_LOWEST)
2051 deployed = SER_FMT_VER_INVALID;
2053 //peer->serialization_version = deployed;
2054 getClient(peer_id)->pending_serialization_version = deployed;
2056 if(deployed == SER_FMT_VER_INVALID)
2058 actionstream<<"Server: A mismatched client tried to connect from "
2059 <<addr_s<<std::endl;
2060 infostream<<"Server: Cannot negotiate "
2061 "serialization version with peer "
2062 <<peer_id<<std::endl;
2063 SendAccessDenied(m_con, peer_id, std::wstring(
2064 L"Your client's version is not supported.\n"
2065 L"Server version is ")
2066 + narrow_to_wide(VERSION_STRING) + L"."
2072 Read and check network protocol version
2075 u16 min_net_proto_version = 0;
2076 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2077 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2079 // Use same version as minimum and maximum if maximum version field
2080 // doesn't exist (backwards compatibility)
2081 u16 max_net_proto_version = min_net_proto_version;
2082 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
2083 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
2085 // Start with client's maximum version
2086 u16 net_proto_version = max_net_proto_version;
2088 // Figure out a working version if it is possible at all
2089 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
2090 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
2092 // If maximum is larger than our maximum, go with our maximum
2093 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2094 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
2095 // Else go with client's maximum
2097 net_proto_version = max_net_proto_version;
2100 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
2101 <<min_net_proto_version<<", max: "<<max_net_proto_version
2102 <<", chosen: "<<net_proto_version<<std::endl;
2104 getClient(peer_id)->net_proto_version = net_proto_version;
2106 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
2107 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2109 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
2111 SendAccessDenied(m_con, peer_id, std::wstring(
2112 L"Your client's version is not supported.\n"
2113 L"Server version is ")
2114 + narrow_to_wide(VERSION_STRING) + L",\n"
2115 + L"server's PROTOCOL_VERSION is "
2116 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
2118 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
2119 + L", client's PROTOCOL_VERSION is "
2120 + narrow_to_wide(itos(min_net_proto_version))
2122 + narrow_to_wide(itos(max_net_proto_version))
2127 if(g_settings->getBool("strict_protocol_version_checking"))
2129 if(net_proto_version != LATEST_PROTOCOL_VERSION)
2131 actionstream<<"Server: A mismatched (strict) client tried to "
2132 <<"connect from "<<addr_s<<std::endl;
2133 SendAccessDenied(m_con, peer_id, std::wstring(
2134 L"Your client's version is not supported.\n"
2135 L"Server version is ")
2136 + narrow_to_wide(VERSION_STRING) + L",\n"
2137 + L"server's PROTOCOL_VERSION (strict) is "
2138 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
2139 + L", client's PROTOCOL_VERSION is "
2140 + narrow_to_wide(itos(min_net_proto_version))
2142 + narrow_to_wide(itos(max_net_proto_version))
2153 char playername[PLAYERNAME_SIZE];
2154 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2156 playername[i] = data[3+i];
2158 playername[PLAYERNAME_SIZE-1] = 0;
2160 if(playername[0]=='\0')
2162 actionstream<<"Server: Player with an empty name "
2163 <<"tried to connect from "<<addr_s<<std::endl;
2164 SendAccessDenied(m_con, peer_id,
2169 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2171 actionstream<<"Server: Player with an invalid name "
2172 <<"tried to connect from "<<addr_s<<std::endl;
2173 SendAccessDenied(m_con, peer_id,
2174 L"Name contains unallowed characters");
2178 infostream<<"Server: New connection: \""<<playername<<"\" from "
2179 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2182 char given_password[PASSWORD_SIZE];
2183 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2185 // old version - assume blank password
2186 given_password[0] = 0;
2190 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2192 given_password[i] = data[23+i];
2194 given_password[PASSWORD_SIZE-1] = 0;
2197 if(!base64_is_valid(given_password)){
2198 infostream<<"Server: "<<playername
2199 <<" supplied invalid password hash"<<std::endl;
2200 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2204 std::string checkpwd; // Password hash to check against
2205 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2207 // If no authentication info exists for user, create it
2209 if(!isSingleplayer() &&
2210 g_settings->getBool("disallow_empty_password") &&
2211 std::string(given_password) == ""){
2212 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2213 L"disallowed. Set a password and try again.");
2216 std::wstring raw_default_password =
2217 narrow_to_wide(g_settings->get("default_password"));
2218 std::string initial_password =
2219 translatePassword(playername, raw_default_password);
2221 // If default_password is empty, allow any initial password
2222 if (raw_default_password.length() == 0)
2223 initial_password = given_password;
2225 scriptapi_create_auth(m_lua, playername, initial_password);
2228 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2231 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2235 if(given_password != checkpwd){
2236 infostream<<"Server: peer_id="<<peer_id
2237 <<": supplied invalid password for "
2238 <<playername<<std::endl;
2239 SendAccessDenied(m_con, peer_id, L"Invalid password");
2243 // Do not allow multiple players in simple singleplayer mode.
2244 // This isn't a perfect way to do it, but will suffice for now.
2245 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2246 infostream<<"Server: Not allowing another client to connect in"
2247 <<" simple singleplayer mode"<<std::endl;
2248 SendAccessDenied(m_con, peer_id,
2249 L"Running in simple singleplayer mode.");
2253 // Enforce user limit.
2254 // Don't enforce for users that have some admin right
2255 if(m_clients.size() >= g_settings->getU16("max_users") &&
2256 !checkPriv(playername, "server") &&
2257 !checkPriv(playername, "ban") &&
2258 !checkPriv(playername, "privs") &&
2259 !checkPriv(playername, "password") &&
2260 playername != g_settings->get("name"))
2262 actionstream<<"Server: "<<playername<<" tried to join, but there"
2263 <<" are already max_users="
2264 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2265 SendAccessDenied(m_con, peer_id, L"Too many users.");
2270 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2272 // If failed, cancel
2273 if(playersao == NULL)
2275 errorstream<<"Server: peer_id="<<peer_id
2276 <<": failed to emerge player"<<std::endl;
2281 Answer with a TOCLIENT_INIT
2284 SharedBuffer<u8> reply(2+1+6+8+4);
2285 writeU16(&reply[0], TOCLIENT_INIT);
2286 writeU8(&reply[2], deployed);
2287 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2288 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2289 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2292 m_con.Send(peer_id, 0, reply, true);
2296 Send complete position information
2298 SendMovePlayer(peer_id);
2303 if(command == TOSERVER_INIT2)
2305 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2306 <<peer_id<<std::endl;
2308 Player *player = m_env->getPlayer(peer_id);
2310 verbosestream<<"Server: TOSERVER_INIT2: "
2311 <<"Player not found; ignoring."<<std::endl;
2315 RemoteClient *client = getClient(peer_id);
2316 client->serialization_version =
2317 getClient(peer_id)->pending_serialization_version;
2320 Send some initialization data
2323 infostream<<"Server: Sending content to "
2324 <<getPlayerName(peer_id)<<std::endl;
2326 // Send item definitions
2327 SendItemDef(m_con, peer_id, m_itemdef);
2329 // Send node definitions
2330 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2332 // Send media announcement
2333 sendMediaAnnouncement(peer_id);
2336 SendPlayerPrivileges(peer_id);
2338 // Send inventory formspec
2339 SendPlayerInventoryFormspec(peer_id);
2342 UpdateCrafting(peer_id);
2343 SendInventory(peer_id);
2346 if(g_settings->getBool("enable_damage"))
2347 SendPlayerHP(peer_id);
2349 // Send detached inventories
2350 sendDetachedInventories(peer_id);
2352 // Show death screen if necessary
2354 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2358 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2359 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2360 m_con.Send(peer_id, 0, data, true);
2363 // Note things in chat if not in simple singleplayer mode
2364 if(!m_simple_singleplayer_mode)
2366 // Send information about server to player in chat
2367 SendChatMessage(peer_id, getStatusString());
2369 // Send information about joining in chat
2371 std::wstring name = L"unknown";
2372 Player *player = m_env->getPlayer(peer_id);
2374 name = narrow_to_wide(player->getName());
2376 std::wstring message;
2379 message += L" joined the game.";
2380 BroadcastChatMessage(message);
2384 // Warnings about protocol version can be issued here
2385 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2387 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2388 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2395 std::ostringstream os(std::ios_base::binary);
2396 for(core::map<u16, RemoteClient*>::Iterator
2397 i = m_clients.getIterator();
2398 i.atEnd() == false; i++)
2400 RemoteClient *client = i.getNode()->getValue();
2401 assert(client->peer_id == i.getNode()->getKey());
2402 if(client->serialization_version == SER_FMT_VER_INVALID)
2405 Player *player = m_env->getPlayer(client->peer_id);
2408 // Get name of player
2409 os<<player->getName()<<" ";
2412 actionstream<<player->getName()<<" joins game. List of players: "
2413 <<os.str()<<std::endl;
2419 if(peer_ser_ver == SER_FMT_VER_INVALID)
2421 infostream<<"Server::ProcessData(): Cancelling: Peer"
2422 " serialization format invalid or not initialized."
2423 " Skipping incoming command="<<command<<std::endl;
2427 Player *player = m_env->getPlayer(peer_id);
2429 infostream<<"Server::ProcessData(): Cancelling: "
2430 "No player for peer_id="<<peer_id
2435 PlayerSAO *playersao = player->getPlayerSAO();
2436 if(playersao == NULL){
2437 infostream<<"Server::ProcessData(): Cancelling: "
2438 "No player object for peer_id="<<peer_id
2443 if(command == TOSERVER_PLAYERPOS)
2445 if(datasize < 2+12+12+4+4)
2449 v3s32 ps = readV3S32(&data[start+2]);
2450 v3s32 ss = readV3S32(&data[start+2+12]);
2451 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2452 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2454 if(datasize >= 2+12+12+4+4+4)
2455 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2456 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2457 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2458 pitch = wrapDegrees(pitch);
2459 yaw = wrapDegrees(yaw);
2461 player->setPosition(position);
2462 player->setSpeed(speed);
2463 player->setPitch(pitch);
2464 player->setYaw(yaw);
2465 player->keyPressed=keyPressed;
2466 player->control.up = (bool)(keyPressed&1);
2467 player->control.down = (bool)(keyPressed&2);
2468 player->control.left = (bool)(keyPressed&4);
2469 player->control.right = (bool)(keyPressed&8);
2470 player->control.jump = (bool)(keyPressed&16);
2471 player->control.aux1 = (bool)(keyPressed&32);
2472 player->control.sneak = (bool)(keyPressed&64);
2473 player->control.LMB = (bool)(keyPressed&128);
2474 player->control.RMB = (bool)(keyPressed&256);
2476 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2477 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2478 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2480 else if(command == TOSERVER_GOTBLOCKS)
2493 u16 count = data[2];
2494 for(u16 i=0; i<count; i++)
2496 if((s16)datasize < 2+1+(i+1)*6)
2497 throw con::InvalidIncomingDataException
2498 ("GOTBLOCKS length is too short");
2499 v3s16 p = readV3S16(&data[2+1+i*6]);
2500 /*infostream<<"Server: GOTBLOCKS ("
2501 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2502 RemoteClient *client = getClient(peer_id);
2503 client->GotBlock(p);
2506 else if(command == TOSERVER_DELETEDBLOCKS)
2519 u16 count = data[2];
2520 for(u16 i=0; i<count; i++)
2522 if((s16)datasize < 2+1+(i+1)*6)
2523 throw con::InvalidIncomingDataException
2524 ("DELETEDBLOCKS length is too short");
2525 v3s16 p = readV3S16(&data[2+1+i*6]);
2526 /*infostream<<"Server: DELETEDBLOCKS ("
2527 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2528 RemoteClient *client = getClient(peer_id);
2529 client->SetBlockNotSent(p);
2532 else if(command == TOSERVER_CLICK_OBJECT)
2534 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2537 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2539 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2542 else if(command == TOSERVER_GROUND_ACTION)
2544 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2548 else if(command == TOSERVER_RELEASE)
2550 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2553 else if(command == TOSERVER_SIGNTEXT)
2555 infostream<<"Server: SIGNTEXT not supported anymore"
2559 else if(command == TOSERVER_SIGNNODETEXT)
2561 infostream<<"Server: SIGNNODETEXT not supported anymore"
2565 else if(command == TOSERVER_INVENTORY_ACTION)
2567 // Strip command and create a stream
2568 std::string datastring((char*)&data[2], datasize-2);
2569 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2570 std::istringstream is(datastring, std::ios_base::binary);
2572 InventoryAction *a = InventoryAction::deSerialize(is);
2575 infostream<<"TOSERVER_INVENTORY_ACTION: "
2576 <<"InventoryAction::deSerialize() returned NULL"
2581 // If something goes wrong, this player is to blame
2582 RollbackScopeActor rollback_scope(m_rollback,
2583 std::string("player:")+player->getName());
2586 Note: Always set inventory not sent, to repair cases
2587 where the client made a bad prediction.
2591 Handle restrictions and special cases of the move action
2593 if(a->getType() == IACTION_MOVE)
2595 IMoveAction *ma = (IMoveAction*)a;
2597 ma->from_inv.applyCurrentPlayer(player->getName());
2598 ma->to_inv.applyCurrentPlayer(player->getName());
2600 setInventoryModified(ma->from_inv);
2601 setInventoryModified(ma->to_inv);
2603 bool from_inv_is_current_player =
2604 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2605 (ma->from_inv.name == player->getName());
2607 bool to_inv_is_current_player =
2608 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2609 (ma->to_inv.name == player->getName());
2612 Disable moving items out of craftpreview
2614 if(ma->from_list == "craftpreview")
2616 infostream<<"Ignoring IMoveAction from "
2617 <<(ma->from_inv.dump())<<":"<<ma->from_list
2618 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2619 <<" because src is "<<ma->from_list<<std::endl;
2625 Disable moving items into craftresult and craftpreview
2627 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2629 infostream<<"Ignoring IMoveAction from "
2630 <<(ma->from_inv.dump())<<":"<<ma->from_list
2631 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2632 <<" because dst is "<<ma->to_list<<std::endl;
2637 // Disallow moving items in elsewhere than player's inventory
2638 // if not allowed to interact
2639 if(!checkPriv(player->getName(), "interact") &&
2640 (!from_inv_is_current_player ||
2641 !to_inv_is_current_player))
2643 infostream<<"Cannot move outside of player's inventory: "
2644 <<"No interact privilege"<<std::endl;
2650 Handle restrictions and special cases of the drop action
2652 else if(a->getType() == IACTION_DROP)
2654 IDropAction *da = (IDropAction*)a;
2656 da->from_inv.applyCurrentPlayer(player->getName());
2658 setInventoryModified(da->from_inv);
2660 // Disallow dropping items if not allowed to interact
2661 if(!checkPriv(player->getName(), "interact"))
2668 Handle restrictions and special cases of the craft action
2670 else if(a->getType() == IACTION_CRAFT)
2672 ICraftAction *ca = (ICraftAction*)a;
2674 ca->craft_inv.applyCurrentPlayer(player->getName());
2676 setInventoryModified(ca->craft_inv);
2678 //bool craft_inv_is_current_player =
2679 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2680 // (ca->craft_inv.name == player->getName());
2682 // Disallow crafting if not allowed to interact
2683 if(!checkPriv(player->getName(), "interact"))
2685 infostream<<"Cannot craft: "
2686 <<"No interact privilege"<<std::endl;
2693 a->apply(this, playersao, this);
2697 else if(command == TOSERVER_CHAT_MESSAGE)
2705 std::string datastring((char*)&data[2], datasize-2);
2706 std::istringstream is(datastring, std::ios_base::binary);
2709 is.read((char*)buf, 2);
2710 u16 len = readU16(buf);
2712 std::wstring message;
2713 for(u16 i=0; i<len; i++)
2715 is.read((char*)buf, 2);
2716 message += (wchar_t)readU16(buf);
2719 // If something goes wrong, this player is to blame
2720 RollbackScopeActor rollback_scope(m_rollback,
2721 std::string("player:")+player->getName());
2723 // Get player name of this client
2724 std::wstring name = narrow_to_wide(player->getName());
2727 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2728 wide_to_narrow(message));
2729 // If script ate the message, don't proceed
2733 // Line to send to players
2735 // Whether to send to the player that sent the line
2736 bool send_to_sender = false;
2737 // Whether to send to other players
2738 bool send_to_others = false;
2740 // Commands are implemented in Lua, so only catch invalid
2741 // commands that were not "eaten" and send an error back
2742 if(message[0] == L'/')
2744 message = message.substr(1);
2745 send_to_sender = true;
2746 if(message.length() == 0)
2747 line += L"-!- Empty command";
2749 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2753 if(checkPriv(player->getName(), "shout")){
2758 send_to_others = true;
2760 line += L"-!- You don't have permission to shout.";
2761 send_to_sender = true;
2768 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2771 Send the message to clients
2773 for(core::map<u16, RemoteClient*>::Iterator
2774 i = m_clients.getIterator();
2775 i.atEnd() == false; i++)
2777 // Get client and check that it is valid
2778 RemoteClient *client = i.getNode()->getValue();
2779 assert(client->peer_id == i.getNode()->getKey());
2780 if(client->serialization_version == SER_FMT_VER_INVALID)
2784 bool sender_selected = (peer_id == client->peer_id);
2785 if(sender_selected == true && send_to_sender == false)
2787 if(sender_selected == false && send_to_others == false)
2790 SendChatMessage(client->peer_id, line);
2794 else if(command == TOSERVER_DAMAGE)
2796 std::string datastring((char*)&data[2], datasize-2);
2797 std::istringstream is(datastring, std::ios_base::binary);
2798 u8 damage = readU8(is);
2800 if(g_settings->getBool("enable_damage"))
2802 actionstream<<player->getName()<<" damaged by "
2803 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2806 playersao->setHP(playersao->getHP() - damage);
2808 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2811 if(playersao->m_hp_not_sent)
2812 SendPlayerHP(peer_id);
2815 else if(command == TOSERVER_PASSWORD)
2818 [0] u16 TOSERVER_PASSWORD
2819 [2] u8[28] old password
2820 [30] u8[28] new password
2823 if(datasize != 2+PASSWORD_SIZE*2)
2825 /*char password[PASSWORD_SIZE];
2826 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2827 password[i] = data[2+i];
2828 password[PASSWORD_SIZE-1] = 0;*/
2830 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2838 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2840 char c = data[2+PASSWORD_SIZE+i];
2846 if(!base64_is_valid(newpwd)){
2847 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2848 // Wrong old password supplied!!
2849 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2853 infostream<<"Server: Client requests a password change from "
2854 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2856 std::string playername = player->getName();
2858 std::string checkpwd;
2859 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2861 if(oldpwd != checkpwd)
2863 infostream<<"Server: invalid old password"<<std::endl;
2864 // Wrong old password supplied!!
2865 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2869 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2871 actionstream<<player->getName()<<" changes password"<<std::endl;
2872 SendChatMessage(peer_id, L"Password change successful.");
2874 actionstream<<player->getName()<<" tries to change password but "
2875 <<"it fails"<<std::endl;
2876 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2879 else if(command == TOSERVER_PLAYERITEM)
2884 u16 item = readU16(&data[2]);
2885 playersao->setWieldIndex(item);
2887 else if(command == TOSERVER_RESPAWN)
2889 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2892 RespawnPlayer(peer_id);
2894 actionstream<<player->getName()<<" respawns at "
2895 <<PP(player->getPosition()/BS)<<std::endl;
2897 // ActiveObject is added to environment in AsyncRunStep after
2898 // the previous addition has been succesfully removed
2900 else if(command == TOSERVER_REQUEST_MEDIA) {
2901 std::string datastring((char*)&data[2], datasize-2);
2902 std::istringstream is(datastring, std::ios_base::binary);
2904 core::list<MediaRequest> tosend;
2905 u16 numfiles = readU16(is);
2907 infostream<<"Sending "<<numfiles<<" files to "
2908 <<getPlayerName(peer_id)<<std::endl;
2909 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2911 for(int i = 0; i < numfiles; i++) {
2912 std::string name = deSerializeString(is);
2913 tosend.push_back(MediaRequest(name));
2914 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2918 sendRequestedMedia(peer_id, tosend);
2920 // Now the client should know about everything
2921 // (definitions and files)
2922 getClient(peer_id)->definitions_sent = true;
2924 else if(command == TOSERVER_RECEIVED_MEDIA) {
2925 getClient(peer_id)->definitions_sent = true;
2927 else if(command == TOSERVER_INTERACT)
2929 std::string datastring((char*)&data[2], datasize-2);
2930 std::istringstream is(datastring, std::ios_base::binary);
2936 [5] u32 length of the next item
2937 [9] serialized PointedThing
2939 0: start digging (from undersurface) or use
2940 1: stop digging (all parameters ignored)
2941 2: digging completed
2942 3: place block or item (to abovesurface)
2945 u8 action = readU8(is);
2946 u16 item_i = readU16(is);
2947 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2948 PointedThing pointed;
2949 pointed.deSerialize(tmp_is);
2951 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2952 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2956 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2957 <<" tried to interact, but is dead!"<<std::endl;
2961 v3f player_pos = playersao->getLastGoodPosition();
2963 // Update wielded item
2964 playersao->setWieldIndex(item_i);
2966 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2967 v3s16 p_under = pointed.node_undersurface;
2968 v3s16 p_above = pointed.node_abovesurface;
2970 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2971 ServerActiveObject *pointed_object = NULL;
2972 if(pointed.type == POINTEDTHING_OBJECT)
2974 pointed_object = m_env->getActiveObject(pointed.object_id);
2975 if(pointed_object == NULL)
2977 verbosestream<<"TOSERVER_INTERACT: "
2978 "pointed object is NULL"<<std::endl;
2984 v3f pointed_pos_under = player_pos;
2985 v3f pointed_pos_above = player_pos;
2986 if(pointed.type == POINTEDTHING_NODE)
2988 pointed_pos_under = intToFloat(p_under, BS);
2989 pointed_pos_above = intToFloat(p_above, BS);
2991 else if(pointed.type == POINTEDTHING_OBJECT)
2993 pointed_pos_under = pointed_object->getBasePosition();
2994 pointed_pos_above = pointed_pos_under;
2998 Check that target is reasonably close
2999 (only when digging or placing things)
3001 if(action == 0 || action == 2 || action == 3)
3003 float d = player_pos.getDistanceFrom(pointed_pos_under);
3004 float max_d = BS * 14; // Just some large enough value
3006 actionstream<<"Player "<<player->getName()
3007 <<" tried to access "<<pointed.dump()
3009 <<"d="<<d<<", max_d="<<max_d
3010 <<". ignoring."<<std::endl;
3011 // Re-send block to revert change on client-side
3012 RemoteClient *client = getClient(peer_id);
3013 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3014 client->SetBlockNotSent(blockpos);
3021 Make sure the player is allowed to do it
3023 if(!checkPriv(player->getName(), "interact"))
3025 actionstream<<player->getName()<<" attempted to interact with "
3026 <<pointed.dump()<<" without 'interact' privilege"
3028 // Re-send block to revert change on client-side
3029 RemoteClient *client = getClient(peer_id);
3030 // Digging completed -> under
3032 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3033 client->SetBlockNotSent(blockpos);
3035 // Placement -> above
3037 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3038 client->SetBlockNotSent(blockpos);
3044 If something goes wrong, this player is to blame
3046 RollbackScopeActor rollback_scope(m_rollback,
3047 std::string("player:")+player->getName());
3050 0: start digging or punch object
3054 if(pointed.type == POINTEDTHING_NODE)
3057 NOTE: This can be used in the future to check if
3058 somebody is cheating, by checking the timing.
3060 MapNode n(CONTENT_IGNORE);
3063 n = m_env->getMap().getNode(p_under);
3065 catch(InvalidPositionException &e)
3067 infostream<<"Server: Not punching: Node not found."
3068 <<" Adding block to emerge queue."
3070 m_emerge_queue.addBlock(peer_id,
3071 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3073 if(n.getContent() != CONTENT_IGNORE)
3074 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3076 playersao->noCheatDigStart(p_under);
3078 else if(pointed.type == POINTEDTHING_OBJECT)
3080 // Skip if object has been removed
3081 if(pointed_object->m_removed)
3084 actionstream<<player->getName()<<" punches object "
3085 <<pointed.object_id<<": "
3086 <<pointed_object->getDescription()<<std::endl;
3088 ItemStack punchitem = playersao->getWieldedItem();
3089 ToolCapabilities toolcap =
3090 punchitem.getToolCapabilities(m_itemdef);
3091 v3f dir = (pointed_object->getBasePosition() -
3092 (player->getPosition() + player->getEyeOffset())
3094 float time_from_last_punch =
3095 playersao->resetTimeFromLastPunch();
3096 pointed_object->punch(dir, &toolcap, playersao,
3097 time_from_last_punch);
3105 else if(action == 1)
3110 2: Digging completed
3112 else if(action == 2)
3114 // Only digging of nodes
3115 if(pointed.type == POINTEDTHING_NODE)
3117 MapNode n(CONTENT_IGNORE);
3120 n = m_env->getMap().getNode(p_under);
3122 catch(InvalidPositionException &e)
3124 infostream<<"Server: Not finishing digging: Node not found."
3125 <<" Adding block to emerge queue."
3127 m_emerge_queue.addBlock(peer_id,
3128 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3131 /* Cheat prevention */
3132 bool is_valid_dig = true;
3133 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3135 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3136 float nocheat_t = playersao->getNoCheatDigTime();
3137 playersao->noCheatDigEnd();
3138 // If player didn't start digging this, ignore dig
3139 if(nocheat_p != p_under){
3140 infostream<<"Server: NoCheat: "<<player->getName()
3141 <<" started digging "
3142 <<PP(nocheat_p)<<" and completed digging "
3143 <<PP(p_under)<<"; not digging."<<std::endl;
3144 is_valid_dig = false;
3146 // Get player's wielded item
3147 ItemStack playeritem;
3148 InventoryList *mlist = playersao->getInventory()->getList("main");
3150 playeritem = mlist->getItem(playersao->getWieldIndex());
3151 ToolCapabilities playeritem_toolcap =
3152 playeritem.getToolCapabilities(m_itemdef);
3153 // Get diggability and expected digging time
3154 DigParams params = getDigParams(m_nodedef->get(n).groups,
3155 &playeritem_toolcap);
3156 // If can't dig, try hand
3157 if(!params.diggable){
3158 const ItemDefinition &hand = m_itemdef->get("");
3159 const ToolCapabilities *tp = hand.tool_capabilities;
3161 params = getDigParams(m_nodedef->get(n).groups, tp);
3163 // If can't dig, ignore dig
3164 if(!params.diggable){
3165 infostream<<"Server: NoCheat: "<<player->getName()
3166 <<" completed digging "<<PP(p_under)
3167 <<", which is not diggable with tool. not digging."
3169 is_valid_dig = false;
3171 // If time is considerably too short, ignore dig
3172 // Check time only for medium and slow timed digs
3173 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3174 infostream<<"Server: NoCheat: "<<player->getName()
3175 <<" completed digging "
3176 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3177 <<params.time<<"s; not digging."<<std::endl;
3178 is_valid_dig = false;
3182 /* Actually dig node */
3184 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3185 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3187 // Send unusual result (that is, node not being removed)
3188 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3190 // Re-send block to revert change on client-side
3191 RemoteClient *client = getClient(peer_id);
3192 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3193 client->SetBlockNotSent(blockpos);
3199 3: place block or right-click object
3201 else if(action == 3)
3203 ItemStack item = playersao->getWieldedItem();
3205 // Reset build time counter
3206 if(pointed.type == POINTEDTHING_NODE &&
3207 item.getDefinition(m_itemdef).type == ITEM_NODE)
3208 getClient(peer_id)->m_time_from_building = 0.0;
3210 if(pointed.type == POINTEDTHING_OBJECT)
3212 // Right click object
3214 // Skip if object has been removed
3215 if(pointed_object->m_removed)
3218 actionstream<<player->getName()<<" right-clicks object "
3219 <<pointed.object_id<<": "
3220 <<pointed_object->getDescription()<<std::endl;
3223 pointed_object->rightClick(playersao);
3225 else if(scriptapi_item_on_place(m_lua,
3226 item, playersao, pointed))
3228 // Placement was handled in lua
3230 // Apply returned ItemStack
3231 playersao->setWieldedItem(item);
3234 // If item has node placement prediction, always send the above
3235 // node to make sure the client knows what exactly happened
3236 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3237 RemoteClient *client = getClient(peer_id);
3238 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3239 client->SetBlockNotSent(blockpos);
3246 else if(action == 4)
3248 ItemStack item = playersao->getWieldedItem();
3250 actionstream<<player->getName()<<" uses "<<item.name
3251 <<", pointing at "<<pointed.dump()<<std::endl;
3253 if(scriptapi_item_on_use(m_lua,
3254 item, playersao, pointed))
3256 // Apply returned ItemStack
3257 playersao->setWieldedItem(item);
3264 Catch invalid actions
3268 infostream<<"WARNING: Server: Invalid action "
3269 <<action<<std::endl;
3272 else if(command == TOSERVER_REMOVED_SOUNDS)
3274 std::string datastring((char*)&data[2], datasize-2);
3275 std::istringstream is(datastring, std::ios_base::binary);
3277 int num = readU16(is);
3278 for(int k=0; k<num; k++){
3279 s32 id = readS32(is);
3280 std::map<s32, ServerPlayingSound>::iterator i =
3281 m_playing_sounds.find(id);
3282 if(i == m_playing_sounds.end())
3284 ServerPlayingSound &psound = i->second;
3285 psound.clients.erase(peer_id);
3286 if(psound.clients.size() == 0)
3287 m_playing_sounds.erase(i++);
3290 else if(command == TOSERVER_NODEMETA_FIELDS)
3292 std::string datastring((char*)&data[2], datasize-2);
3293 std::istringstream is(datastring, std::ios_base::binary);
3295 v3s16 p = readV3S16(is);
3296 std::string formname = deSerializeString(is);
3297 int num = readU16(is);
3298 std::map<std::string, std::string> fields;
3299 for(int k=0; k<num; k++){
3300 std::string fieldname = deSerializeString(is);
3301 std::string fieldvalue = deSerializeLongString(is);
3302 fields[fieldname] = fieldvalue;
3305 // If something goes wrong, this player is to blame
3306 RollbackScopeActor rollback_scope(m_rollback,
3307 std::string("player:")+player->getName());
3309 // Check the target node for rollback data; leave others unnoticed
3310 RollbackNode rn_old(&m_env->getMap(), p, this);
3312 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3315 // Report rollback data
3316 RollbackNode rn_new(&m_env->getMap(), p, this);
3317 if(rollback() && rn_new != rn_old){
3318 RollbackAction action;
3319 action.setSetNode(p, rn_old, rn_new);
3320 rollback()->reportAction(action);
3323 else if(command == TOSERVER_INVENTORY_FIELDS)
3325 std::string datastring((char*)&data[2], datasize-2);
3326 std::istringstream is(datastring, std::ios_base::binary);
3328 std::string formname = deSerializeString(is);
3329 int num = readU16(is);
3330 std::map<std::string, std::string> fields;
3331 for(int k=0; k<num; k++){
3332 std::string fieldname = deSerializeString(is);
3333 std::string fieldvalue = deSerializeLongString(is);
3334 fields[fieldname] = fieldvalue;
3337 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3341 infostream<<"Server::ProcessData(): Ignoring "
3342 "unknown command "<<command<<std::endl;
3346 catch(SendFailedException &e)
3348 errorstream<<"Server::ProcessData(): SendFailedException: "
3354 void Server::onMapEditEvent(MapEditEvent *event)
3356 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3357 if(m_ignore_map_edit_events)
3359 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3361 MapEditEvent *e = event->clone();
3362 m_unsent_map_edit_queue.push_back(e);
3365 Inventory* Server::getInventory(const InventoryLocation &loc)
3368 case InventoryLocation::UNDEFINED:
3371 case InventoryLocation::CURRENT_PLAYER:
3374 case InventoryLocation::PLAYER:
3376 Player *player = m_env->getPlayer(loc.name.c_str());
3379 PlayerSAO *playersao = player->getPlayerSAO();
3382 return playersao->getInventory();
3385 case InventoryLocation::NODEMETA:
3387 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3390 return meta->getInventory();
3393 case InventoryLocation::DETACHED:
3395 if(m_detached_inventories.count(loc.name) == 0)
3397 return m_detached_inventories[loc.name];
3405 void Server::setInventoryModified(const InventoryLocation &loc)
3408 case InventoryLocation::UNDEFINED:
3411 case InventoryLocation::PLAYER:
3413 Player *player = m_env->getPlayer(loc.name.c_str());
3416 PlayerSAO *playersao = player->getPlayerSAO();
3419 playersao->m_inventory_not_sent = true;
3420 playersao->m_wielded_item_not_sent = true;
3423 case InventoryLocation::NODEMETA:
3425 v3s16 blockpos = getNodeBlockPos(loc.p);
3427 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3429 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3431 setBlockNotSent(blockpos);
3434 case InventoryLocation::DETACHED:
3436 sendDetachedInventoryToAll(loc.name);
3444 core::list<PlayerInfo> Server::getPlayerInfo()
3446 DSTACK(__FUNCTION_NAME);
3447 JMutexAutoLock envlock(m_env_mutex);
3448 JMutexAutoLock conlock(m_con_mutex);
3450 core::list<PlayerInfo> list;
3452 core::list<Player*> players = m_env->getPlayers();
3454 core::list<Player*>::Iterator i;
3455 for(i = players.begin();
3456 i != players.end(); i++)
3460 Player *player = *i;
3463 // Copy info from connection to info struct
3464 info.id = player->peer_id;
3465 info.address = m_con.GetPeerAddress(player->peer_id);
3466 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3468 catch(con::PeerNotFoundException &e)
3470 // Set dummy peer info
3472 info.address = Address(0,0,0,0,0);
3476 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3477 info.position = player->getPosition();
3479 list.push_back(info);
3486 void Server::peerAdded(con::Peer *peer)
3488 DSTACK(__FUNCTION_NAME);
3489 verbosestream<<"Server::peerAdded(): peer->id="
3490 <<peer->id<<std::endl;
3493 c.type = PEER_ADDED;
3494 c.peer_id = peer->id;
3496 m_peer_change_queue.push_back(c);
3499 void Server::deletingPeer(con::Peer *peer, bool timeout)
3501 DSTACK(__FUNCTION_NAME);
3502 verbosestream<<"Server::deletingPeer(): peer->id="
3503 <<peer->id<<", timeout="<<timeout<<std::endl;
3506 c.type = PEER_REMOVED;
3507 c.peer_id = peer->id;
3508 c.timeout = timeout;
3509 m_peer_change_queue.push_back(c);
3516 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3518 DSTACK(__FUNCTION_NAME);
3519 std::ostringstream os(std::ios_base::binary);
3521 writeU16(os, TOCLIENT_HP);
3525 std::string s = os.str();
3526 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3528 con.Send(peer_id, 0, data, true);
3531 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3532 const std::wstring &reason)
3534 DSTACK(__FUNCTION_NAME);
3535 std::ostringstream os(std::ios_base::binary);
3537 writeU16(os, TOCLIENT_ACCESS_DENIED);
3538 os<<serializeWideString(reason);
3541 std::string s = os.str();
3542 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3544 con.Send(peer_id, 0, data, true);
3547 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3548 bool set_camera_point_target, v3f camera_point_target)
3550 DSTACK(__FUNCTION_NAME);
3551 std::ostringstream os(std::ios_base::binary);
3553 writeU16(os, TOCLIENT_DEATHSCREEN);
3554 writeU8(os, set_camera_point_target);
3555 writeV3F1000(os, camera_point_target);
3558 std::string s = os.str();
3559 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3561 con.Send(peer_id, 0, data, true);
3564 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3565 IItemDefManager *itemdef)
3567 DSTACK(__FUNCTION_NAME);
3568 std::ostringstream os(std::ios_base::binary);
3572 u32 length of the next item
3573 zlib-compressed serialized ItemDefManager
3575 writeU16(os, TOCLIENT_ITEMDEF);
3576 std::ostringstream tmp_os(std::ios::binary);
3577 itemdef->serialize(tmp_os);
3578 std::ostringstream tmp_os2(std::ios::binary);
3579 compressZlib(tmp_os.str(), tmp_os2);
3580 os<<serializeLongString(tmp_os2.str());
3583 std::string s = os.str();
3584 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3585 <<"): size="<<s.size()<<std::endl;
3586 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3588 con.Send(peer_id, 0, data, true);
3591 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3592 INodeDefManager *nodedef, u16 protocol_version)
3594 DSTACK(__FUNCTION_NAME);
3595 std::ostringstream os(std::ios_base::binary);
3599 u32 length of the next item
3600 zlib-compressed serialized NodeDefManager
3602 writeU16(os, TOCLIENT_NODEDEF);
3603 std::ostringstream tmp_os(std::ios::binary);
3604 nodedef->serialize(tmp_os, protocol_version);
3605 std::ostringstream tmp_os2(std::ios::binary);
3606 compressZlib(tmp_os.str(), tmp_os2);
3607 os<<serializeLongString(tmp_os2.str());
3610 std::string s = os.str();
3611 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3612 <<"): size="<<s.size()<<std::endl;
3613 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3615 con.Send(peer_id, 0, data, true);
3619 Non-static send methods
3622 void Server::SendInventory(u16 peer_id)
3624 DSTACK(__FUNCTION_NAME);
3626 PlayerSAO *playersao = getPlayerSAO(peer_id);
3629 playersao->m_inventory_not_sent = false;
3635 std::ostringstream os;
3636 playersao->getInventory()->serialize(os);
3638 std::string s = os.str();
3640 SharedBuffer<u8> data(s.size()+2);
3641 writeU16(&data[0], TOCLIENT_INVENTORY);
3642 memcpy(&data[2], s.c_str(), s.size());
3645 m_con.Send(peer_id, 0, data, true);
3648 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3650 DSTACK(__FUNCTION_NAME);
3652 std::ostringstream os(std::ios_base::binary);
3656 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3657 os.write((char*)buf, 2);
3660 writeU16(buf, message.size());
3661 os.write((char*)buf, 2);
3664 for(u32 i=0; i<message.size(); i++)
3668 os.write((char*)buf, 2);
3672 std::string s = os.str();
3673 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3675 m_con.Send(peer_id, 0, data, true);
3677 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3679 DSTACK(__FUNCTION_NAME);
3681 std::ostringstream os(std::ios_base::binary);
3685 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3686 os.write((char*)buf, 2);
3687 os<<serializeLongString(formspec);
3688 os<<serializeString(formname);
3691 std::string s = os.str();
3692 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3694 m_con.Send(peer_id, 0, data, true);
3697 void Server::BroadcastChatMessage(const std::wstring &message)
3699 for(core::map<u16, RemoteClient*>::Iterator
3700 i = m_clients.getIterator();
3701 i.atEnd() == false; i++)
3703 // Get client and check that it is valid
3704 RemoteClient *client = i.getNode()->getValue();
3705 assert(client->peer_id == i.getNode()->getKey());
3706 if(client->serialization_version == SER_FMT_VER_INVALID)
3709 SendChatMessage(client->peer_id, message);
3713 void Server::SendPlayerHP(u16 peer_id)
3715 DSTACK(__FUNCTION_NAME);
3716 PlayerSAO *playersao = getPlayerSAO(peer_id);
3718 playersao->m_hp_not_sent = false;
3719 SendHP(m_con, peer_id, playersao->getHP());
3722 void Server::SendMovePlayer(u16 peer_id)
3724 DSTACK(__FUNCTION_NAME);
3725 Player *player = m_env->getPlayer(peer_id);
3728 std::ostringstream os(std::ios_base::binary);
3729 writeU16(os, TOCLIENT_MOVE_PLAYER);
3730 writeV3F1000(os, player->getPosition());
3731 writeF1000(os, player->getPitch());
3732 writeF1000(os, player->getYaw());
3735 v3f pos = player->getPosition();
3736 f32 pitch = player->getPitch();
3737 f32 yaw = player->getYaw();
3738 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3739 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3746 std::string s = os.str();
3747 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3749 m_con.Send(peer_id, 0, data, true);
3752 void Server::SendPlayerPrivileges(u16 peer_id)
3754 Player *player = m_env->getPlayer(peer_id);
3756 if(player->peer_id == PEER_ID_INEXISTENT)
3759 std::set<std::string> privs;
3760 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3762 std::ostringstream os(std::ios_base::binary);
3763 writeU16(os, TOCLIENT_PRIVILEGES);
3764 writeU16(os, privs.size());
3765 for(std::set<std::string>::const_iterator i = privs.begin();
3766 i != privs.end(); i++){
3767 os<<serializeString(*i);
3771 std::string s = os.str();
3772 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3774 m_con.Send(peer_id, 0, data, true);
3777 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3779 Player *player = m_env->getPlayer(peer_id);
3781 if(player->peer_id == PEER_ID_INEXISTENT)
3784 std::ostringstream os(std::ios_base::binary);
3785 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3786 os<<serializeLongString(player->inventory_formspec);
3789 std::string s = os.str();
3790 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3792 m_con.Send(peer_id, 0, data, true);
3795 s32 Server::playSound(const SimpleSoundSpec &spec,
3796 const ServerSoundParams ¶ms)
3798 // Find out initial position of sound
3799 bool pos_exists = false;
3800 v3f pos = params.getPos(m_env, &pos_exists);
3801 // If position is not found while it should be, cancel sound
3802 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3804 // Filter destination clients
3805 std::set<RemoteClient*> dst_clients;
3806 if(params.to_player != "")
3808 Player *player = m_env->getPlayer(params.to_player.c_str());
3810 infostream<<"Server::playSound: Player \""<<params.to_player
3811 <<"\" not found"<<std::endl;
3814 if(player->peer_id == PEER_ID_INEXISTENT){
3815 infostream<<"Server::playSound: Player \""<<params.to_player
3816 <<"\" not connected"<<std::endl;
3819 RemoteClient *client = getClient(player->peer_id);
3820 dst_clients.insert(client);
3824 for(core::map<u16, RemoteClient*>::Iterator
3825 i = m_clients.getIterator(); i.atEnd() == false; i++)
3827 RemoteClient *client = i.getNode()->getValue();
3828 Player *player = m_env->getPlayer(client->peer_id);
3832 if(player->getPosition().getDistanceFrom(pos) >
3833 params.max_hear_distance)
3836 dst_clients.insert(client);
3839 if(dst_clients.size() == 0)
3842 s32 id = m_next_sound_id++;
3843 // The sound will exist as a reference in m_playing_sounds
3844 m_playing_sounds[id] = ServerPlayingSound();
3845 ServerPlayingSound &psound = m_playing_sounds[id];
3846 psound.params = params;
3847 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3848 i != dst_clients.end(); i++)
3849 psound.clients.insert((*i)->peer_id);
3851 std::ostringstream os(std::ios_base::binary);
3852 writeU16(os, TOCLIENT_PLAY_SOUND);
3854 os<<serializeString(spec.name);
3855 writeF1000(os, spec.gain * params.gain);
3856 writeU8(os, params.type);
3857 writeV3F1000(os, pos);
3858 writeU16(os, params.object);
3859 writeU8(os, params.loop);
3861 std::string s = os.str();
3862 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3864 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3865 i != dst_clients.end(); i++){
3867 m_con.Send((*i)->peer_id, 0, data, true);
3871 void Server::stopSound(s32 handle)
3873 // Get sound reference
3874 std::map<s32, ServerPlayingSound>::iterator i =
3875 m_playing_sounds.find(handle);
3876 if(i == m_playing_sounds.end())
3878 ServerPlayingSound &psound = i->second;
3880 std::ostringstream os(std::ios_base::binary);
3881 writeU16(os, TOCLIENT_STOP_SOUND);
3882 writeS32(os, handle);
3884 std::string s = os.str();
3885 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3887 for(std::set<u16>::iterator i = psound.clients.begin();
3888 i != psound.clients.end(); i++){
3890 m_con.Send(*i, 0, data, true);
3892 // Remove sound reference
3893 m_playing_sounds.erase(i);
3896 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3897 core::list<u16> *far_players, float far_d_nodes)
3899 float maxd = far_d_nodes*BS;
3900 v3f p_f = intToFloat(p, BS);
3904 SharedBuffer<u8> reply(replysize);
3905 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3906 writeS16(&reply[2], p.X);
3907 writeS16(&reply[4], p.Y);
3908 writeS16(&reply[6], p.Z);
3910 for(core::map<u16, RemoteClient*>::Iterator
3911 i = m_clients.getIterator();
3912 i.atEnd() == false; i++)
3914 // Get client and check that it is valid
3915 RemoteClient *client = i.getNode()->getValue();
3916 assert(client->peer_id == i.getNode()->getKey());
3917 if(client->serialization_version == SER_FMT_VER_INVALID)
3920 // Don't send if it's the same one
3921 if(client->peer_id == ignore_id)
3927 Player *player = m_env->getPlayer(client->peer_id);
3930 // If player is far away, only set modified blocks not sent
3931 v3f player_pos = player->getPosition();
3932 if(player_pos.getDistanceFrom(p_f) > maxd)
3934 far_players->push_back(client->peer_id);
3941 m_con.Send(client->peer_id, 0, reply, true);
3945 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3946 core::list<u16> *far_players, float far_d_nodes)
3948 float maxd = far_d_nodes*BS;
3949 v3f p_f = intToFloat(p, BS);
3951 for(core::map<u16, RemoteClient*>::Iterator
3952 i = m_clients.getIterator();
3953 i.atEnd() == false; i++)
3955 // Get client and check that it is valid
3956 RemoteClient *client = i.getNode()->getValue();
3957 assert(client->peer_id == i.getNode()->getKey());
3958 if(client->serialization_version == SER_FMT_VER_INVALID)
3961 // Don't send if it's the same one
3962 if(client->peer_id == ignore_id)
3968 Player *player = m_env->getPlayer(client->peer_id);
3971 // If player is far away, only set modified blocks not sent
3972 v3f player_pos = player->getPosition();
3973 if(player_pos.getDistanceFrom(p_f) > maxd)
3975 far_players->push_back(client->peer_id);
3982 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3983 SharedBuffer<u8> reply(replysize);
3984 writeU16(&reply[0], TOCLIENT_ADDNODE);
3985 writeS16(&reply[2], p.X);
3986 writeS16(&reply[4], p.Y);
3987 writeS16(&reply[6], p.Z);
3988 n.serialize(&reply[8], client->serialization_version);
3991 m_con.Send(client->peer_id, 0, reply, true);
3995 void Server::setBlockNotSent(v3s16 p)
3997 for(core::map<u16, RemoteClient*>::Iterator
3998 i = m_clients.getIterator();
3999 i.atEnd()==false; i++)
4001 RemoteClient *client = i.getNode()->getValue();
4002 client->SetBlockNotSent(p);
4006 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4008 DSTACK(__FUNCTION_NAME);
4010 v3s16 p = block->getPos();
4014 bool completely_air = true;
4015 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4016 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4017 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4019 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4021 completely_air = false;
4022 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4027 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4029 infostream<<"[completely air] ";
4030 infostream<<std::endl;
4034 Create a packet with the block in the right format
4037 std::ostringstream os(std::ios_base::binary);
4038 block->serialize(os, ver, false);
4039 std::string s = os.str();
4040 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4042 u32 replysize = 8 + blockdata.getSize();
4043 SharedBuffer<u8> reply(replysize);
4044 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4045 writeS16(&reply[2], p.X);
4046 writeS16(&reply[4], p.Y);
4047 writeS16(&reply[6], p.Z);
4048 memcpy(&reply[8], *blockdata, blockdata.getSize());
4050 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4051 <<": \tpacket size: "<<replysize<<std::endl;*/
4056 m_con.Send(peer_id, 1, reply, true);
4059 void Server::SendBlocks(float dtime)
4061 DSTACK(__FUNCTION_NAME);
4063 JMutexAutoLock envlock(m_env_mutex);
4064 JMutexAutoLock conlock(m_con_mutex);
4066 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4068 core::array<PrioritySortedBlockTransfer> queue;
4070 s32 total_sending = 0;
4073 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4075 for(core::map<u16, RemoteClient*>::Iterator
4076 i = m_clients.getIterator();
4077 i.atEnd() == false; i++)
4079 RemoteClient *client = i.getNode()->getValue();
4080 assert(client->peer_id == i.getNode()->getKey());
4082 // If definitions and textures have not been sent, don't
4083 // send MapBlocks either
4084 if(!client->definitions_sent)
4087 total_sending += client->SendingCount();
4089 if(client->serialization_version == SER_FMT_VER_INVALID)
4092 client->GetNextBlocks(this, dtime, queue);
4097 // Lowest priority number comes first.
4098 // Lowest is most important.
4101 for(u32 i=0; i<queue.size(); i++)
4103 //TODO: Calculate limit dynamically
4104 if(total_sending >= g_settings->getS32
4105 ("max_simultaneous_block_sends_server_total"))
4108 PrioritySortedBlockTransfer q = queue[i];
4110 MapBlock *block = NULL;
4113 block = m_env->getMap().getBlockNoCreate(q.pos);
4115 catch(InvalidPositionException &e)
4120 RemoteClient *client = getClient(q.peer_id);
4122 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4124 client->SentBlock(q.pos);
4130 void Server::fillMediaCache()
4132 DSTACK(__FUNCTION_NAME);
4134 infostream<<"Server: Calculating media file checksums"<<std::endl;
4136 // Collect all media file paths
4137 std::list<std::string> paths;
4138 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4139 i != m_mods.end(); i++){
4140 const ModSpec &mod = *i;
4141 paths.push_back(mod.path + DIR_DELIM + "textures");
4142 paths.push_back(mod.path + DIR_DELIM + "sounds");
4143 paths.push_back(mod.path + DIR_DELIM + "media");
4144 paths.push_back(mod.path + DIR_DELIM + "models");
4146 std::string path_all = "textures";
4147 paths.push_back(path_all + DIR_DELIM + "all");
4149 // Collect media file information from paths into cache
4150 for(std::list<std::string>::iterator i = paths.begin();
4151 i != paths.end(); i++)
4153 std::string mediapath = *i;
4154 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4155 for(u32 j=0; j<dirlist.size(); j++){
4156 if(dirlist[j].dir) // Ignode dirs
4158 std::string filename = dirlist[j].name;
4159 // If name contains illegal characters, ignore the file
4160 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4161 infostream<<"Server: ignoring illegal file name: \""
4162 <<filename<<"\""<<std::endl;
4165 // If name is not in a supported format, ignore it
4166 const char *supported_ext[] = {
4167 ".png", ".jpg", ".bmp", ".tga",
4168 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4170 ".x", ".b3d", ".md2", ".obj",
4173 if(removeStringEnd(filename, supported_ext) == ""){
4174 infostream<<"Server: ignoring unsupported file extension: \""
4175 <<filename<<"\""<<std::endl;
4178 // Ok, attempt to load the file and add to cache
4179 std::string filepath = mediapath + DIR_DELIM + filename;
4181 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4182 if(fis.good() == false){
4183 errorstream<<"Server::fillMediaCache(): Could not open \""
4184 <<filename<<"\" for reading"<<std::endl;
4187 std::ostringstream tmp_os(std::ios_base::binary);
4191 fis.read(buf, 1024);
4192 std::streamsize len = fis.gcount();
4193 tmp_os.write(buf, len);
4202 errorstream<<"Server::fillMediaCache(): Failed to read \""
4203 <<filename<<"\""<<std::endl;
4206 if(tmp_os.str().length() == 0){
4207 errorstream<<"Server::fillMediaCache(): Empty file \""
4208 <<filepath<<"\""<<std::endl;
4213 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4215 unsigned char *digest = sha1.getDigest();
4216 std::string sha1_base64 = base64_encode(digest, 20);
4217 std::string sha1_hex = hex_encode((char*)digest, 20);
4221 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4222 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4227 struct SendableMediaAnnouncement
4230 std::string sha1_digest;
4232 SendableMediaAnnouncement(const std::string name_="",
4233 const std::string sha1_digest_=""):
4235 sha1_digest(sha1_digest_)
4239 void Server::sendMediaAnnouncement(u16 peer_id)
4241 DSTACK(__FUNCTION_NAME);
4243 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4246 core::list<SendableMediaAnnouncement> file_announcements;
4248 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4249 i != m_media.end(); i++){
4251 file_announcements.push_back(
4252 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4256 std::ostringstream os(std::ios_base::binary);
4264 u16 length of sha1_digest
4269 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4270 writeU16(os, file_announcements.size());
4272 for(core::list<SendableMediaAnnouncement>::Iterator
4273 j = file_announcements.begin();
4274 j != file_announcements.end(); j++){
4275 os<<serializeString(j->name);
4276 os<<serializeString(j->sha1_digest);
4278 os<<serializeString(g_settings->get("remote_media"));
4281 std::string s = os.str();
4282 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4285 m_con.Send(peer_id, 0, data, true);
4288 struct SendableMedia
4294 SendableMedia(const std::string &name_="", const std::string path_="",
4295 const std::string &data_=""):
4302 void Server::sendRequestedMedia(u16 peer_id,
4303 const core::list<MediaRequest> &tosend)
4305 DSTACK(__FUNCTION_NAME);
4307 verbosestream<<"Server::sendRequestedMedia(): "
4308 <<"Sending files to client"<<std::endl;
4312 // Put 5kB in one bunch (this is not accurate)
4313 u32 bytes_per_bunch = 5000;
4315 core::array< core::list<SendableMedia> > file_bunches;
4316 file_bunches.push_back(core::list<SendableMedia>());
4318 u32 file_size_bunch_total = 0;
4320 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4321 i != tosend.end(); i++)
4323 if(m_media.find(i->name) == m_media.end()){
4324 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4325 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4329 //TODO get path + name
4330 std::string tpath = m_media[(*i).name].path;
4333 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4334 if(fis.good() == false){
4335 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4336 <<tpath<<"\" for reading"<<std::endl;
4339 std::ostringstream tmp_os(std::ios_base::binary);
4343 fis.read(buf, 1024);
4344 std::streamsize len = fis.gcount();
4345 tmp_os.write(buf, len);
4346 file_size_bunch_total += len;
4355 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4356 <<(*i).name<<"\""<<std::endl;
4359 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4360 <<tname<<"\""<<std::endl;*/
4362 file_bunches[file_bunches.size()-1].push_back(
4363 SendableMedia((*i).name, tpath, tmp_os.str()));
4365 // Start next bunch if got enough data
4366 if(file_size_bunch_total >= bytes_per_bunch){
4367 file_bunches.push_back(core::list<SendableMedia>());
4368 file_size_bunch_total = 0;
4373 /* Create and send packets */
4375 u32 num_bunches = file_bunches.size();
4376 for(u32 i=0; i<num_bunches; i++)
4378 std::ostringstream os(std::ios_base::binary);
4382 u16 total number of texture bunches
4383 u16 index of this bunch
4384 u32 number of files in this bunch
4393 writeU16(os, TOCLIENT_MEDIA);
4394 writeU16(os, num_bunches);
4396 writeU32(os, file_bunches[i].size());
4398 for(core::list<SendableMedia>::Iterator
4399 j = file_bunches[i].begin();
4400 j != file_bunches[i].end(); j++){
4401 os<<serializeString(j->name);
4402 os<<serializeLongString(j->data);
4406 std::string s = os.str();
4407 verbosestream<<"Server::sendRequestedMedia(): bunch "
4408 <<i<<"/"<<num_bunches
4409 <<" files="<<file_bunches[i].size()
4410 <<" size=" <<s.size()<<std::endl;
4411 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4413 m_con.Send(peer_id, 0, data, true);
4417 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4419 if(m_detached_inventories.count(name) == 0){
4420 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4423 Inventory *inv = m_detached_inventories[name];
4425 std::ostringstream os(std::ios_base::binary);
4426 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4427 os<<serializeString(name);
4431 std::string s = os.str();
4432 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4434 m_con.Send(peer_id, 0, data, true);
4437 void Server::sendDetachedInventoryToAll(const std::string &name)
4439 DSTACK(__FUNCTION_NAME);
4441 for(core::map<u16, RemoteClient*>::Iterator
4442 i = m_clients.getIterator();
4443 i.atEnd() == false; i++){
4444 RemoteClient *client = i.getNode()->getValue();
4445 sendDetachedInventory(name, client->peer_id);
4449 void Server::sendDetachedInventories(u16 peer_id)
4451 DSTACK(__FUNCTION_NAME);
4453 for(std::map<std::string, Inventory*>::iterator
4454 i = m_detached_inventories.begin();
4455 i != m_detached_inventories.end(); i++){
4456 const std::string &name = i->first;
4457 //Inventory *inv = i->second;
4458 sendDetachedInventory(name, peer_id);
4466 void Server::DiePlayer(u16 peer_id)
4468 DSTACK(__FUNCTION_NAME);
4470 PlayerSAO *playersao = getPlayerSAO(peer_id);
4473 infostream<<"Server::DiePlayer(): Player "
4474 <<playersao->getPlayer()->getName()
4475 <<" dies"<<std::endl;
4477 playersao->setHP(0);
4479 // Trigger scripted stuff
4480 scriptapi_on_dieplayer(m_lua, playersao);
4482 SendPlayerHP(peer_id);
4483 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4486 void Server::RespawnPlayer(u16 peer_id)
4488 DSTACK(__FUNCTION_NAME);
4490 PlayerSAO *playersao = getPlayerSAO(peer_id);
4493 infostream<<"Server::RespawnPlayer(): Player "
4494 <<playersao->getPlayer()->getName()
4495 <<" respawns"<<std::endl;
4497 playersao->setHP(PLAYER_MAX_HP);
4499 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4501 v3f pos = findSpawnPos(m_env->getServerMap());
4502 playersao->setPos(pos);
4506 void Server::UpdateCrafting(u16 peer_id)
4508 DSTACK(__FUNCTION_NAME);
4510 Player* player = m_env->getPlayer(peer_id);
4513 // Get a preview for crafting
4515 getCraftingResult(&player->inventory, preview, false, this);
4517 // Put the new preview in
4518 InventoryList *plist = player->inventory.getList("craftpreview");
4520 assert(plist->getSize() >= 1);
4521 plist->changeItem(0, preview);
4524 RemoteClient* Server::getClient(u16 peer_id)
4526 DSTACK(__FUNCTION_NAME);
4527 //JMutexAutoLock lock(m_con_mutex);
4528 core::map<u16, RemoteClient*>::Node *n;
4529 n = m_clients.find(peer_id);
4530 // A client should exist for all peers
4532 return n->getValue();
4535 std::wstring Server::getStatusString()
4537 std::wostringstream os(std::ios_base::binary);
4540 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4542 os<<L", uptime="<<m_uptime.get();
4543 // Information about clients
4544 core::map<u16, RemoteClient*>::Iterator i;
4547 for(i = m_clients.getIterator(), first = true;
4548 i.atEnd() == false; i++)
4550 // Get client and check that it is valid
4551 RemoteClient *client = i.getNode()->getValue();
4552 assert(client->peer_id == i.getNode()->getKey());
4553 if(client->serialization_version == SER_FMT_VER_INVALID)
4556 Player *player = m_env->getPlayer(client->peer_id);
4557 // Get name of player
4558 std::wstring name = L"unknown";
4560 name = narrow_to_wide(player->getName());
4561 // Add name to information string
4569 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4570 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4571 if(g_settings->get("motd") != "")
4572 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4576 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4578 std::set<std::string> privs;
4579 scriptapi_get_auth(m_lua, name, NULL, &privs);
4583 bool Server::checkPriv(const std::string &name, const std::string &priv)
4585 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4586 return (privs.count(priv) != 0);
4589 void Server::reportPrivsModified(const std::string &name)
4592 for(core::map<u16, RemoteClient*>::Iterator
4593 i = m_clients.getIterator();
4594 i.atEnd() == false; i++){
4595 RemoteClient *client = i.getNode()->getValue();
4596 Player *player = m_env->getPlayer(client->peer_id);
4597 reportPrivsModified(player->getName());
4600 Player *player = m_env->getPlayer(name.c_str());
4603 SendPlayerPrivileges(player->peer_id);
4604 PlayerSAO *sao = player->getPlayerSAO();
4607 sao->updatePrivileges(
4608 getPlayerEffectivePrivs(name),
4613 void Server::reportInventoryFormspecModified(const std::string &name)
4615 Player *player = m_env->getPlayer(name.c_str());
4618 SendPlayerInventoryFormspec(player->peer_id);
4621 // Saves g_settings to configpath given at initialization
4622 void Server::saveConfig()
4624 if(m_path_config != "")
4625 g_settings->updateConfigFile(m_path_config.c_str());
4628 void Server::notifyPlayer(const char *name, const std::wstring msg)
4630 Player *player = m_env->getPlayer(name);
4633 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4636 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4638 Player *player = m_env->getPlayer(playername);
4642 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4646 SendShowFormspecMessage(player->peer_id, formspec, formname);
4650 void Server::notifyPlayers(const std::wstring msg)
4652 BroadcastChatMessage(msg);
4655 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4659 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4660 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4663 Inventory* Server::createDetachedInventory(const std::string &name)
4665 if(m_detached_inventories.count(name) > 0){
4666 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4667 delete m_detached_inventories[name];
4669 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4671 Inventory *inv = new Inventory(m_itemdef);
4673 m_detached_inventories[name] = inv;
4674 sendDetachedInventoryToAll(name);
4681 BoolScopeSet(bool *dst, bool val):
4684 m_orig_state = *m_dst;
4689 *m_dst = m_orig_state;
4696 // actions: time-reversed list
4697 // Return value: success/failure
4698 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4699 std::list<std::string> *log)
4701 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4702 ServerMap *map = (ServerMap*)(&m_env->getMap());
4703 // Disable rollback report sink while reverting
4704 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4706 // Fail if no actions to handle
4707 if(actions.empty()){
4708 log->push_back("Nothing to do.");
4715 for(std::list<RollbackAction>::const_iterator
4716 i = actions.begin();
4717 i != actions.end(); i++)
4719 const RollbackAction &action = *i;
4721 bool success = action.applyRevert(map, this, this);
4724 std::ostringstream os;
4725 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4726 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4728 log->push_back(os.str());
4730 std::ostringstream os;
4731 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4732 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4734 log->push_back(os.str());
4738 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4739 <<" failed"<<std::endl;
4741 // Call it done if less than half failed
4742 return num_failed <= num_tried/2;
4745 // IGameDef interface
4747 IItemDefManager* Server::getItemDefManager()
4751 INodeDefManager* Server::getNodeDefManager()
4755 ICraftDefManager* Server::getCraftDefManager()
4759 ITextureSource* Server::getTextureSource()
4763 IShaderSource* Server::getShaderSource()
4767 u16 Server::allocateUnknownNodeId(const std::string &name)
4769 return m_nodedef->allocateDummy(name);
4771 ISoundManager* Server::getSoundManager()
4773 return &dummySoundManager;
4775 MtEventManager* Server::getEventManager()
4779 IRollbackReportSink* Server::getRollbackReportSink()
4781 if(!m_enable_rollback_recording)
4783 if(!m_rollback_sink_enabled)
4788 IWritableItemDefManager* Server::getWritableItemDefManager()
4792 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4796 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4801 const ModSpec* Server::getModSpec(const std::string &modname)
4803 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4804 i != m_mods.end(); i++){
4805 const ModSpec &mod = *i;
4806 if(mod.name == modname)
4811 void Server::getModNames(core::list<std::string> &modlist)
4813 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4815 modlist.push_back((*i).name);
4818 std::string Server::getBuiltinLuaPath()
4820 return porting::path_share + DIR_DELIM + "builtin";
4823 v3f findSpawnPos(ServerMap &map)
4825 //return v3f(50,50,50)*BS;
4830 nodepos = v2s16(0,0);
4835 // Try to find a good place a few times
4836 for(s32 i=0; i<1000; i++)
4839 // We're going to try to throw the player to this position
4840 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4841 -range + (myrand()%(range*2)));
4842 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4843 // Get ground height at point (fallbacks to heightmap function)
4844 s16 groundheight = map.findGroundLevel(nodepos2d);
4845 // Don't go underwater
4846 if(groundheight < WATER_LEVEL)
4848 //infostream<<"-> Underwater"<<std::endl;
4851 // Don't go to high places
4852 if(groundheight > WATER_LEVEL + 4)
4854 //infostream<<"-> Underwater"<<std::endl;
4858 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4859 bool is_good = false;
4861 for(s32 i=0; i<10; i++){
4862 v3s16 blockpos = getNodeBlockPos(nodepos);
4863 map.emergeBlock(blockpos, true);
4864 MapNode n = map.getNodeNoEx(nodepos);
4865 if(n.getContent() == CONTENT_AIR){
4876 // Found a good place
4877 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4883 return intToFloat(nodepos, BS);
4886 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4888 RemotePlayer *player = NULL;
4889 bool newplayer = false;
4892 Try to get an existing player
4894 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4896 // If player is already connected, cancel
4897 if(player != NULL && player->peer_id != 0)
4899 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4904 If player with the wanted peer_id already exists, cancel.
4906 if(m_env->getPlayer(peer_id) != NULL)
4908 infostream<<"emergePlayer(): Player with wrong name but same"
4909 " peer_id already exists"<<std::endl;
4914 Create a new player if it doesn't exist yet
4919 player = new RemotePlayer(this);
4920 player->updateName(name);
4922 /* Set player position */
4923 infostream<<"Server: Finding spawn place for player \""
4924 <<name<<"\""<<std::endl;
4925 v3f pos = findSpawnPos(m_env->getServerMap());
4926 player->setPosition(pos);
4928 /* Add player to environment */
4929 m_env->addPlayer(player);
4933 Create a new player active object
4935 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4936 getPlayerEffectivePrivs(player->getName()),
4939 /* Add object to environment */
4940 m_env->addActiveObject(playersao);
4944 scriptapi_on_newplayer(m_lua, playersao);
4946 scriptapi_on_joinplayer(m_lua, playersao);
4951 void Server::handlePeerChange(PeerChange &c)
4953 JMutexAutoLock envlock(m_env_mutex);
4954 JMutexAutoLock conlock(m_con_mutex);
4956 if(c.type == PEER_ADDED)
4963 core::map<u16, RemoteClient*>::Node *n;
4964 n = m_clients.find(c.peer_id);
4965 // The client shouldn't already exist
4969 RemoteClient *client = new RemoteClient();
4970 client->peer_id = c.peer_id;
4971 m_clients.insert(client->peer_id, client);
4974 else if(c.type == PEER_REMOVED)
4981 core::map<u16, RemoteClient*>::Node *n;
4982 n = m_clients.find(c.peer_id);
4983 // The client should exist
4987 Mark objects to be not known by the client
4989 RemoteClient *client = n->getValue();
4991 for(core::map<u16, bool>::Iterator
4992 i = client->m_known_objects.getIterator();
4993 i.atEnd()==false; i++)
4996 u16 id = i.getNode()->getKey();
4997 ServerActiveObject* obj = m_env->getActiveObject(id);
4999 if(obj && obj->m_known_by_count > 0)
5000 obj->m_known_by_count--;
5004 Clear references to playing sounds
5006 for(std::map<s32, ServerPlayingSound>::iterator
5007 i = m_playing_sounds.begin();
5008 i != m_playing_sounds.end();)
5010 ServerPlayingSound &psound = i->second;
5011 psound.clients.erase(c.peer_id);
5012 if(psound.clients.size() == 0)
5013 m_playing_sounds.erase(i++);
5018 Player *player = m_env->getPlayer(c.peer_id);
5020 // Collect information about leaving in chat
5021 std::wstring message;
5025 std::wstring name = narrow_to_wide(player->getName());
5028 message += L" left the game.";
5030 message += L" (timed out)";
5034 /* Run scripts and remove from environment */
5038 PlayerSAO *playersao = player->getPlayerSAO();
5041 scriptapi_on_leaveplayer(m_lua, playersao);
5043 playersao->disconnected();
5053 std::ostringstream os(std::ios_base::binary);
5054 for(core::map<u16, RemoteClient*>::Iterator
5055 i = m_clients.getIterator();
5056 i.atEnd() == false; i++)
5058 RemoteClient *client = i.getNode()->getValue();
5059 assert(client->peer_id == i.getNode()->getKey());
5060 if(client->serialization_version == SER_FMT_VER_INVALID)
5063 Player *player = m_env->getPlayer(client->peer_id);
5066 // Get name of player
5067 os<<player->getName()<<" ";
5070 actionstream<<player->getName()<<" "
5071 <<(c.timeout?"times out.":"leaves game.")
5072 <<" List of players: "
5073 <<os.str()<<std::endl;
5078 delete m_clients[c.peer_id];
5079 m_clients.remove(c.peer_id);
5081 // Send player info to all remaining clients
5082 //SendPlayerInfos();
5084 // Send leave chat message to all remaining clients
5085 if(message.length() != 0)
5086 BroadcastChatMessage(message);
5095 void Server::handlePeerChanges()
5097 while(m_peer_change_queue.size() > 0)
5099 PeerChange c = m_peer_change_queue.pop_front();
5101 verbosestream<<"Server: Handling peer change: "
5102 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5105 handlePeerChange(c);
5109 void dedicated_server_loop(Server &server, bool &kill)
5111 DSTACK(__FUNCTION_NAME);
5113 verbosestream<<"dedicated_server_loop()"<<std::endl;
5115 IntervalLimiter m_profiler_interval;
5119 float steplen = g_settings->getFloat("dedicated_server_step");
5120 // This is kind of a hack but can be done like this
5121 // because server.step() is very light
5123 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5124 sleep_ms((int)(steplen*1000.0));
5126 server.step(steplen);
5128 if(server.getShutdownRequested() || kill)
5130 infostream<<"Dedicated server quitting"<<std::endl;
5137 float profiler_print_interval =
5138 g_settings->getFloat("profiler_print_interval");
5139 if(profiler_print_interval != 0)
5141 if(m_profiler_interval.step(steplen, profiler_print_interval))
5143 infostream<<"Profiler:"<<std::endl;
5144 g_profiler->print(infostream);
5145 g_profiler->clear();