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"
43 #include "content_mapnode.h"
44 #include "content_nodemeta.h"
45 #include "content_abm.h"
46 #include "content_sao.h"
51 #include "sound.h" // dummySoundManager
52 #include "event_manager.h"
54 #include "serverlist.h"
55 #include "util/string.h"
56 #include "util/pointedthing.h"
57 #include "util/mathconstants.h"
59 #include "util/serialize.h"
61 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
63 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
65 class MapEditEventIgnorer
68 MapEditEventIgnorer(bool *flag):
77 ~MapEditEventIgnorer()
90 class MapEditEventAreaIgnorer
93 MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
94 m_ignorevariable(ignorevariable)
96 if(m_ignorevariable->getVolume() == 0)
97 *m_ignorevariable = a;
99 m_ignorevariable = NULL;
102 ~MapEditEventAreaIgnorer()
106 assert(m_ignorevariable->getVolume() != 0);
107 *m_ignorevariable = VoxelArea();
112 VoxelArea *m_ignorevariable;
115 void * ServerThread::Thread()
119 log_register_thread("ServerThread");
121 DSTACK(__FUNCTION_NAME);
123 BEGIN_DEBUG_EXCEPTION_HANDLER
128 //TimeTaker timer("AsyncRunStep() + Receive()");
131 //TimeTaker timer("AsyncRunStep()");
132 m_server->AsyncRunStep();
135 //infostream<<"Running m_server->Receive()"<<std::endl;
138 catch(con::NoIncomingDataException &e)
141 catch(con::PeerNotFoundException &e)
143 infostream<<"Server: PeerNotFoundException"<<std::endl;
145 catch(con::ConnectionBindFailed &e)
147 m_server->setAsyncFatalError(e.what());
151 m_server->setAsyncFatalError(e.what());
155 END_DEBUG_EXCEPTION_HANDLER(errorstream)
160 void * EmergeThread::Thread()
164 log_register_thread("EmergeThread");
166 DSTACK(__FUNCTION_NAME);
168 BEGIN_DEBUG_EXCEPTION_HANDLER
170 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
172 v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
174 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
175 EmergeManager *emerge = m_server->m_emerge;
176 Mapgen *mapgen = emerge->getMapgen();
179 Get block info from queue, emerge them and send them
182 After queue is empty, exit.
186 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
190 SharedPtr<QueuedBlockEmerge> q(qptr);
198 Do not generate over-limit
200 if(blockpos_over_limit(p))
203 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
205 //TimeTaker timer("block emerge");
208 Try to emerge it from somewhere.
210 If it is only wanted as optional, only loading from disk
215 Check if any peer wants it as non-optional. In that case it
218 Also decrement the emerge queue count in clients.
221 bool only_from_disk = true;
224 core::map<u16, u8>::Iterator i;
225 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
227 //u16 peer_id = i.getNode()->getKey();
230 u8 flags = i.getNode()->getValue();
231 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
232 only_from_disk = false;
237 if(enable_mapgen_debug_info)
238 infostream<<"EmergeThread: p="
239 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
240 <<"only_from_disk="<<only_from_disk<<std::endl;
244 MapBlock *block = NULL;
245 bool got_block = true;
246 core::map<v3s16, MapBlock*> modified_blocks;
249 Try to fetch block from memory or disk.
250 If not found and asked to generate, initialize generator.
253 bool started_generate = false;
257 JMutexAutoLock envlock(m_server->m_env_mutex);
259 // Load sector if it isn't loaded
260 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
261 map.loadSectorMeta(p2d);
263 // Attempt to load block
264 block = map.getBlockNoCreateNoEx(p);
265 if(!block || block->isDummy() || !block->isGenerated())
267 if(enable_mapgen_debug_info)
268 infostream<<"EmergeThread: not in memory, "
269 <<"attempting to load from disk"<<std::endl;
271 block = map.loadBlock(p);
274 // If could not load and allowed to generate, start generation
275 // inside this same envlock
276 if(only_from_disk == false &&
277 (block == NULL || block->isGenerated() == false)){
278 if(enable_mapgen_debug_info)
279 infostream<<"EmergeThread: generating"<<std::endl;
280 started_generate = true;
282 map.initBlockMake(&data, p);
287 If generator was initialized, generate now when envlock is free.
292 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
294 TimeTaker t("mapgen::make_block()");
296 mapgen->makeChunk(&data);
297 //mapgen::make_block(&data);
299 if(enable_mapgen_debug_info == false)
300 t.stop(true); // Hide output
304 // Lock environment again to access the map
305 JMutexAutoLock envlock(m_server->m_env_mutex);
307 ScopeProfiler sp(g_profiler, "EmergeThread: after "
308 "mapgen::make_block (envlock)", SPT_AVG);
310 // Blit data back on map, update lighting, add mobs and
311 // whatever this does
312 map.finishBlockMake(&data, modified_blocks);
315 block = map.getBlockNoCreateNoEx(p);
317 // If block doesn't exist, don't try doing anything with it
318 // This happens if the block is not in generation boundaries
323 Do some post-generate stuff
326 v3s16 minp = data.blockpos_min*MAP_BLOCKSIZE;
327 v3s16 maxp = data.blockpos_max*MAP_BLOCKSIZE +
328 v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
331 Ignore map edit events, they will not need to be
332 sent to anybody because the block hasn't been sent
335 //MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
336 MapEditEventAreaIgnorer ign(
337 &m_server->m_ignore_map_edit_events_area,
338 VoxelArea(minp, maxp));
340 TimeTaker timer("on_generated");
341 scriptapi_environment_on_generated(m_server->m_lua,
342 minp, maxp, emerge->getBlockSeed(minp));
343 /*int t = timer.stop(true);
344 dstream<<"on_generated took "<<t<<"ms"<<std::endl;*/
347 if(enable_mapgen_debug_info)
348 infostream<<"EmergeThread: ended up with: "
349 <<analyze_block(block)<<std::endl;
351 // Activate objects and stuff
352 m_server->m_env->activateBlock(block, 0);
360 Set sent status of modified blocks on clients
363 // NOTE: Server's clients are also behind the connection mutex
364 JMutexAutoLock lock(m_server->m_con_mutex);
367 Add the originally fetched block to the modified list
371 modified_blocks.insert(p, block);
375 Set the modified blocks unsent for all the clients
378 for(core::map<u16, RemoteClient*>::Iterator
379 i = m_server->m_clients.getIterator();
380 i.atEnd() == false; i++)
382 RemoteClient *client = i.getNode()->getValue();
384 if(modified_blocks.size() > 0)
386 // Remove block from sent history
387 client->SetBlocksNotSent(modified_blocks);
391 catch(VersionMismatchException &e)
393 std::ostringstream err;
394 err<<"World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl;
395 err<<"----"<<std::endl;
396 err<<"\""<<e.what()<<"\""<<std::endl;
397 err<<"See debug.txt."<<std::endl;
398 err<<"World probably saved by a newer version of Minetest."<<std::endl;
399 m_server->setAsyncFatalError(err.str());
401 catch(SerializationError &e)
403 std::ostringstream err;
404 err<<"Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl;
405 err<<"----"<<std::endl;
406 err<<"\""<<e.what()<<"\""<<std::endl;
407 err<<"See debug.txt."<<std::endl;
408 err<<"You can ignore this using [ignore_world_load_errors = true]."<<std::endl;
409 m_server->setAsyncFatalError(err.str());
412 END_DEBUG_EXCEPTION_HANDLER(errorstream)
414 log_deregister_thread();
419 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
421 if(pos_exists) *pos_exists = false;
426 if(pos_exists) *pos_exists = true;
431 ServerActiveObject *sao = env->getActiveObject(object);
434 if(pos_exists) *pos_exists = true;
435 return sao->getBasePosition(); }
440 void RemoteClient::GetNextBlocks(Server *server, float dtime,
441 core::array<PrioritySortedBlockTransfer> &dest)
443 DSTACK(__FUNCTION_NAME);
446 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
449 m_nothing_to_send_pause_timer -= dtime;
450 m_nearest_unsent_reset_timer += dtime;
452 if(m_nothing_to_send_pause_timer >= 0)
455 Player *player = server->m_env->getPlayer(peer_id);
456 // This can happen sometimes; clients and players are not in perfect sync.
460 // Won't send anything if already sending
461 if(m_blocks_sending.size() >= g_settings->getU16
462 ("max_simultaneous_block_sends_per_client"))
464 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
468 //TimeTaker timer("RemoteClient::GetNextBlocks");
470 v3f playerpos = player->getPosition();
471 v3f playerspeed = player->getSpeed();
472 v3f playerspeeddir(0,0,0);
473 if(playerspeed.getLength() > 1.0*BS)
474 playerspeeddir = playerspeed / playerspeed.getLength();
475 // Predict to next block
476 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
478 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
480 v3s16 center = getNodeBlockPos(center_nodepos);
482 // Camera position and direction
483 v3f camera_pos = player->getEyePosition();
484 v3f camera_dir = v3f(0,0,1);
485 camera_dir.rotateYZBy(player->getPitch());
486 camera_dir.rotateXZBy(player->getYaw());
488 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
489 <<camera_dir.Z<<")"<<std::endl;*/
492 Get the starting value of the block finder radius.
495 if(m_last_center != center)
497 m_nearest_unsent_d = 0;
498 m_last_center = center;
501 /*infostream<<"m_nearest_unsent_reset_timer="
502 <<m_nearest_unsent_reset_timer<<std::endl;*/
504 // Reset periodically to workaround for some bugs or stuff
505 if(m_nearest_unsent_reset_timer > 20.0)
507 m_nearest_unsent_reset_timer = 0;
508 m_nearest_unsent_d = 0;
509 //infostream<<"Resetting m_nearest_unsent_d for "
510 // <<server->getPlayerName(peer_id)<<std::endl;
513 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
514 s16 d_start = m_nearest_unsent_d;
516 //infostream<<"d_start="<<d_start<<std::endl;
518 u16 max_simul_sends_setting = g_settings->getU16
519 ("max_simultaneous_block_sends_per_client");
520 u16 max_simul_sends_usually = max_simul_sends_setting;
523 Check the time from last addNode/removeNode.
525 Decrease send rate if player is building stuff.
527 m_time_from_building += dtime;
528 if(m_time_from_building < g_settings->getFloat(
529 "full_block_send_enable_min_time_from_building"))
531 max_simul_sends_usually
532 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
536 Number of blocks sending + number of blocks selected for sending
538 u32 num_blocks_selected = m_blocks_sending.size();
541 next time d will be continued from the d from which the nearest
542 unsent block was found this time.
544 This is because not necessarily any of the blocks found this
545 time are actually sent.
547 s32 new_nearest_unsent_d = -1;
549 s16 d_max = g_settings->getS16("max_block_send_distance");
550 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
552 // Don't loop very much at a time
553 s16 max_d_increment_at_time = 2;
554 if(d_max > d_start + max_d_increment_at_time)
555 d_max = d_start + max_d_increment_at_time;
556 /*if(d_max_gen > d_start+2)
557 d_max_gen = d_start+2;*/
559 //infostream<<"Starting from "<<d_start<<std::endl;
561 s32 nearest_emerged_d = -1;
562 s32 nearest_emergefull_d = -1;
563 s32 nearest_sent_d = -1;
564 bool queue_is_full = false;
567 for(d = d_start; d <= d_max; d++)
569 /*errorstream<<"checking d="<<d<<" for "
570 <<server->getPlayerName(peer_id)<<std::endl;*/
571 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
574 If m_nearest_unsent_d was changed by the EmergeThread
575 (it can change it to 0 through SetBlockNotSent),
577 Else update m_nearest_unsent_d
579 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
581 d = m_nearest_unsent_d;
582 last_nearest_unsent_d = m_nearest_unsent_d;
586 Get the border/face dot coordinates of a "d-radiused"
589 core::list<v3s16> list;
590 getFacePositions(list, d);
592 core::list<v3s16>::Iterator li;
593 for(li=list.begin(); li!=list.end(); li++)
595 v3s16 p = *li + center;
599 - Don't allow too many simultaneous transfers
600 - EXCEPT when the blocks are very close
602 Also, don't send blocks that are already flying.
605 // Start with the usual maximum
606 u16 max_simul_dynamic = max_simul_sends_usually;
608 // If block is very close, allow full maximum
609 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
610 max_simul_dynamic = max_simul_sends_setting;
612 // Don't select too many blocks for sending
613 if(num_blocks_selected >= max_simul_dynamic)
615 queue_is_full = true;
616 goto queue_full_break;
619 // Don't send blocks that are currently being transferred
620 if(m_blocks_sending.find(p) != NULL)
626 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
627 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
628 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
629 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
630 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
631 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
634 // If this is true, inexistent block will be made from scratch
635 bool generate = d <= d_max_gen;
638 /*// Limit the generating area vertically to 2/3
639 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
642 // Limit the send area vertically to 1/2
643 if(abs(p.Y - center.Y) > d_max / 2)
649 If block is far away, don't generate it unless it is
655 // Block center y in nodes
656 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
657 // Don't generate if it's very high or very low
658 if(y < -64 || y > 64)
662 v2s16 p2d_nodes_center(
666 // Get ground height in nodes
667 s16 gh = server->m_env->getServerMap().findGroundLevel(
670 // If differs a lot, don't generate
671 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
673 // Actually, don't even send it
679 //infostream<<"d="<<d<<std::endl;
682 Don't generate or send if not in sight
683 FIXME This only works if the client uses a small enough
684 FOV setting. The default of 72 degrees is fine.
687 float camera_fov = (72.0*M_PI/180) * 4./3.;
688 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
694 Don't send already sent blocks
697 if(m_blocks_sent.find(p) != NULL)
704 Check if map has this block
706 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
708 bool surely_not_found_on_disk = false;
709 bool block_is_invalid = false;
712 // Reset usage timer, this block will be of use in the future.
713 block->resetUsageTimer();
715 // Block is dummy if data doesn't exist.
716 // It means it has been not found from disk and not generated
719 surely_not_found_on_disk = true;
722 // Block is valid if lighting is up-to-date and data exists
723 if(block->isValid() == false)
725 block_is_invalid = true;
728 /*if(block->isFullyGenerated() == false)
730 block_is_invalid = true;
735 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
736 v2s16 chunkpos = map->sector_to_chunk(p2d);
737 if(map->chunkNonVolatile(chunkpos) == false)
738 block_is_invalid = true;
740 if(block->isGenerated() == false)
741 block_is_invalid = true;
744 If block is not close, don't send it unless it is near
747 Block is near ground level if night-time mesh
748 differs from day-time mesh.
752 if(block->getDayNightDiff() == false)
759 If block has been marked to not exist on disk (dummy)
760 and generating new ones is not wanted, skip block.
762 if(generate == false && surely_not_found_on_disk == true)
769 Add inexistent block to emerge queue.
771 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
773 //TODO: Get value from somewhere
774 // Allow only one block in emerge queue
775 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
776 // Allow two blocks in queue per client
777 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
779 // Make it more responsive when needing to generate stuff
780 if(surely_not_found_on_disk)
782 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
784 //infostream<<"Adding block to emerge queue"<<std::endl;
786 // Add it to the emerge queue and trigger the thread
789 if(generate == false)
790 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
792 server->m_emerge_queue.addBlock(peer_id, p, flags);
793 server->m_emergethread.trigger();
795 if(nearest_emerged_d == -1)
796 nearest_emerged_d = d;
798 if(nearest_emergefull_d == -1)
799 nearest_emergefull_d = d;
800 goto queue_full_break;
807 if(nearest_sent_d == -1)
811 Add block to send queue
814 /*errorstream<<"sending from d="<<d<<" to "
815 <<server->getPlayerName(peer_id)<<std::endl;*/
817 PrioritySortedBlockTransfer q((float)d, p, peer_id);
821 num_blocks_selected += 1;
826 //infostream<<"Stopped at "<<d<<std::endl;
828 // If nothing was found for sending and nothing was queued for
829 // emerging, continue next time browsing from here
830 if(nearest_emerged_d != -1){
831 new_nearest_unsent_d = nearest_emerged_d;
832 } else if(nearest_emergefull_d != -1){
833 new_nearest_unsent_d = nearest_emergefull_d;
835 if(d > g_settings->getS16("max_block_send_distance")){
836 new_nearest_unsent_d = 0;
837 m_nothing_to_send_pause_timer = 2.0;
838 /*infostream<<"GetNextBlocks(): d wrapped around for "
839 <<server->getPlayerName(peer_id)
840 <<"; setting to 0 and pausing"<<std::endl;*/
842 if(nearest_sent_d != -1)
843 new_nearest_unsent_d = nearest_sent_d;
845 new_nearest_unsent_d = d;
849 if(new_nearest_unsent_d != -1)
850 m_nearest_unsent_d = new_nearest_unsent_d;
852 /*timer_result = timer.stop(true);
853 if(timer_result != 0)
854 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
857 void RemoteClient::GotBlock(v3s16 p)
859 if(m_blocks_sending.find(p) != NULL)
860 m_blocks_sending.remove(p);
863 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
864 " m_blocks_sending"<<std::endl;*/
865 m_excess_gotblocks++;
867 m_blocks_sent.insert(p, true);
870 void RemoteClient::SentBlock(v3s16 p)
872 if(m_blocks_sending.find(p) == NULL)
873 m_blocks_sending.insert(p, 0.0);
875 infostream<<"RemoteClient::SentBlock(): Sent block"
876 " already in m_blocks_sending"<<std::endl;
879 void RemoteClient::SetBlockNotSent(v3s16 p)
881 m_nearest_unsent_d = 0;
883 if(m_blocks_sending.find(p) != NULL)
884 m_blocks_sending.remove(p);
885 if(m_blocks_sent.find(p) != NULL)
886 m_blocks_sent.remove(p);
889 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
891 m_nearest_unsent_d = 0;
893 for(core::map<v3s16, MapBlock*>::Iterator
894 i = blocks.getIterator();
895 i.atEnd()==false; i++)
897 v3s16 p = i.getNode()->getKey();
899 if(m_blocks_sending.find(p) != NULL)
900 m_blocks_sending.remove(p);
901 if(m_blocks_sent.find(p) != NULL)
902 m_blocks_sent.remove(p);
910 PlayerInfo::PlayerInfo()
916 void PlayerInfo::PrintLine(std::ostream *s)
919 (*s)<<"\""<<name<<"\" ("
920 <<(position.X/10)<<","<<(position.Y/10)
921 <<","<<(position.Z/10)<<") ";
923 (*s)<<" avg_rtt="<<avg_rtt;
932 const std::string &path_world,
933 const std::string &path_config,
934 const SubgameSpec &gamespec,
935 bool simple_singleplayer_mode
937 m_path_world(path_world),
938 m_path_config(path_config),
939 m_gamespec(gamespec),
940 m_simple_singleplayer_mode(simple_singleplayer_mode),
941 m_async_fatal_error(""),
943 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
944 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
946 m_rollback_sink_enabled(true),
947 m_enable_rollback_recording(false),
951 m_itemdef(createItemDefManager()),
952 m_nodedef(createNodeDefManager()),
953 m_craftdef(createCraftDefManager()),
954 m_event(new EventManager()),
956 m_emergethread(this),
957 m_time_of_day_send_timer(0),
959 m_shutdown_requested(false),
960 m_ignore_map_edit_events(false),
961 m_ignore_map_edit_events_peer_id(0)
963 m_liquid_transform_timer = 0.0;
964 m_liquid_transform_every = 1.0;
965 m_print_info_timer = 0.0;
966 m_masterserver_timer = 0.0;
967 m_objectdata_timer = 0.0;
968 m_emergethread_trigger_timer = 0.0;
969 m_savemap_timer = 0.0;
970 m_clients_number = 0;
974 m_step_dtime_mutex.Init();
978 throw ServerError("Supplied empty world path");
980 if(!gamespec.isValid())
981 throw ServerError("Supplied invalid gamespec");
983 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
984 if(m_simple_singleplayer_mode)
985 infostream<<" in simple singleplayer mode"<<std::endl;
987 infostream<<std::endl;
988 infostream<<"- world: "<<m_path_world<<std::endl;
989 infostream<<"- config: "<<m_path_config<<std::endl;
990 infostream<<"- game: "<<m_gamespec.path<<std::endl;
992 // Create biome definition manager
993 m_biomedef = new BiomeDefManager(this);
995 // Create rollback manager
996 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
997 m_rollback = createRollbackManager(rollback_path, this);
999 // Create world if it doesn't exist
1000 if(!initializeWorld(m_path_world, m_gamespec.id))
1001 throw ServerError("Failed to initialize world");
1003 ModConfiguration modconf(m_path_world);
1004 m_mods = modconf.getMods();
1005 std::list<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
1006 // complain about mods with unsatisfied dependencies
1007 if(!modconf.isConsistent())
1009 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
1010 it != unsatisfied_mods.end(); ++it)
1013 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
1014 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
1015 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
1016 errorstream << " \"" << *dep_it << "\"";
1017 errorstream << std::endl;
1021 Settings worldmt_settings;
1022 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
1023 worldmt_settings.readConfigFile(worldmt.c_str());
1024 std::vector<std::string> names = worldmt_settings.getNames();
1025 std::set<std::string> exclude_mod_names;
1026 std::set<std::string> load_mod_names;
1027 for(std::vector<std::string>::iterator it = names.begin();
1028 it != names.end(); ++it)
1030 std::string name = *it;
1031 if (name.compare(0,9,"load_mod_")==0)
1033 if(worldmt_settings.getBool(name))
1034 load_mod_names.insert(name.substr(9));
1036 exclude_mod_names.insert(name.substr(9));
1039 // complain about mods declared to be loaded, but not found
1040 for(std::vector<ModSpec>::iterator it = m_mods.begin();
1041 it != m_mods.end(); ++it)
1042 load_mod_names.erase((*it).name);
1043 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
1044 it != unsatisfied_mods.end(); ++it)
1045 load_mod_names.erase((*it).name);
1046 if(!load_mod_names.empty())
1048 errorstream << "The following mods could not be found:";
1049 for(std::set<std::string>::iterator it = load_mod_names.begin();
1050 it != load_mod_names.end(); ++it)
1051 errorstream << " \"" << (*it) << "\"";
1052 errorstream << std::endl;
1055 // Path to builtin.lua
1056 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
1059 JMutexAutoLock envlock(m_env_mutex);
1060 JMutexAutoLock conlock(m_con_mutex);
1062 // Initialize scripting
1064 infostream<<"Server: Initializing Lua"<<std::endl;
1065 m_lua = script_init();
1068 scriptapi_export(m_lua, this);
1069 // Load and run builtin.lua
1070 infostream<<"Server: Loading builtin.lua [\""
1071 <<builtinpath<<"\"]"<<std::endl;
1072 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1074 errorstream<<"Server: Failed to load and run "
1075 <<builtinpath<<std::endl;
1076 throw ModError("Failed to load and run "+builtinpath);
1079 infostream<<"Server: Loading mods: ";
1080 for(std::vector<ModSpec>::iterator i = m_mods.begin();
1081 i != m_mods.end(); i++){
1082 const ModSpec &mod = *i;
1083 infostream<<mod.name<<" ";
1085 infostream<<std::endl;
1086 // Load and run "mod" scripts
1087 for(std::vector<ModSpec>::iterator i = m_mods.begin();
1088 i != m_mods.end(); i++){
1089 const ModSpec &mod = *i;
1090 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1091 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1092 <<scriptpath<<"\"]"<<std::endl;
1093 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1095 errorstream<<"Server: Failed to load and run "
1096 <<scriptpath<<std::endl;
1097 throw ModError("Failed to load and run "+scriptpath);
1101 // Read Textures and calculate sha1 sums
1104 // Apply item aliases in the node definition manager
1105 m_nodedef->updateAliases(m_itemdef);
1107 // Add default biomes after nodedef had its aliases added
1108 m_biomedef->addDefaultBiomes();
1110 // Create emerge manager
1111 m_emerge = new EmergeManager(this, m_biomedef);
1113 // Initialize Environment
1114 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
1115 m_env = new ServerEnvironment(servermap, m_lua, this, this);
1117 m_emerge->initMapgens(servermap->getMapgenParams());
1119 // Give environment reference to scripting api
1120 scriptapi_add_environment(m_lua, m_env);
1122 // Register us to receive map edit events
1123 servermap->addEventReceiver(this);
1125 // If file exists, load environment metadata
1126 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1128 infostream<<"Server: Loading environment metadata"<<std::endl;
1129 m_env->loadMeta(m_path_world);
1133 infostream<<"Server: Loading players"<<std::endl;
1134 m_env->deSerializePlayers(m_path_world);
1137 Add some test ActiveBlockModifiers to environment
1139 add_legacy_abms(m_env, m_nodedef);
1141 m_liquid_transform_every = g_settings->getFloat("liquid_update");
1146 infostream<<"Server destructing"<<std::endl;
1149 Send shutdown message
1152 JMutexAutoLock conlock(m_con_mutex);
1154 std::wstring line = L"*** Server shutting down";
1157 Send the message to clients
1159 for(core::map<u16, RemoteClient*>::Iterator
1160 i = m_clients.getIterator();
1161 i.atEnd() == false; i++)
1163 // Get client and check that it is valid
1164 RemoteClient *client = i.getNode()->getValue();
1165 assert(client->peer_id == i.getNode()->getKey());
1166 if(client->serialization_version == SER_FMT_VER_INVALID)
1170 SendChatMessage(client->peer_id, line);
1172 catch(con::PeerNotFoundException &e)
1178 JMutexAutoLock envlock(m_env_mutex);
1179 JMutexAutoLock conlock(m_con_mutex);
1182 Execute script shutdown hooks
1184 scriptapi_on_shutdown(m_lua);
1188 JMutexAutoLock envlock(m_env_mutex);
1193 infostream<<"Server: Saving players"<<std::endl;
1194 m_env->serializePlayers(m_path_world);
1197 Save environment metadata
1199 infostream<<"Server: Saving environment metadata"<<std::endl;
1200 m_env->saveMeta(m_path_world);
1212 JMutexAutoLock clientslock(m_con_mutex);
1214 for(core::map<u16, RemoteClient*>::Iterator
1215 i = m_clients.getIterator();
1216 i.atEnd() == false; i++)
1220 delete i.getNode()->getValue();
1224 // Delete things in the reverse order of creation
1233 // Deinitialize scripting
1234 infostream<<"Server: Deinitializing scripting"<<std::endl;
1235 script_deinit(m_lua);
1237 // Delete detached inventories
1239 for(std::map<std::string, Inventory*>::iterator
1240 i = m_detached_inventories.begin();
1241 i != m_detached_inventories.end(); i++){
1247 void Server::start(unsigned short port)
1249 DSTACK(__FUNCTION_NAME);
1250 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1252 // Stop thread if already running
1255 // Initialize connection
1256 m_con.SetTimeoutMs(30);
1260 m_thread.setRun(true);
1263 // ASCII art for the win!
1265 <<" .__ __ __ "<<std::endl
1266 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1267 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1268 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1269 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1270 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1271 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1272 actionstream<<"Server for gameid=\""<<m_gamespec.id
1273 <<"\" listening on port "<<port<<"."<<std::endl;
1278 DSTACK(__FUNCTION_NAME);
1280 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1282 // Stop threads (set run=false first so both start stopping)
1283 m_thread.setRun(false);
1284 m_emergethread.setRun(false);
1286 m_emergethread.stop();
1288 infostream<<"Server: Threads stopped"<<std::endl;
1291 void Server::step(float dtime)
1293 DSTACK(__FUNCTION_NAME);
1298 JMutexAutoLock lock(m_step_dtime_mutex);
1299 m_step_dtime += dtime;
1301 // Throw if fatal error occurred in thread
1302 std::string async_err = m_async_fatal_error.get();
1303 if(async_err != ""){
1304 throw ServerError(async_err);
1308 void Server::AsyncRunStep()
1310 DSTACK(__FUNCTION_NAME);
1312 g_profiler->add("Server::AsyncRunStep (num)", 1);
1316 JMutexAutoLock lock1(m_step_dtime_mutex);
1317 dtime = m_step_dtime;
1321 // Send blocks to clients
1328 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1330 //infostream<<"Server steps "<<dtime<<std::endl;
1331 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1334 JMutexAutoLock lock1(m_step_dtime_mutex);
1335 m_step_dtime -= dtime;
1342 m_uptime.set(m_uptime.get() + dtime);
1346 // Process connection's timeouts
1347 JMutexAutoLock lock2(m_con_mutex);
1348 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1349 m_con.RunTimeouts(dtime);
1353 // This has to be called so that the client list gets synced
1354 // with the peer list of the connection
1355 handlePeerChanges();
1359 Update time of day and overall game time
1362 JMutexAutoLock envlock(m_env_mutex);
1364 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1367 Send to clients at constant intervals
1370 m_time_of_day_send_timer -= dtime;
1371 if(m_time_of_day_send_timer < 0.0)
1373 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1375 //JMutexAutoLock envlock(m_env_mutex);
1376 JMutexAutoLock conlock(m_con_mutex);
1378 for(core::map<u16, RemoteClient*>::Iterator
1379 i = m_clients.getIterator();
1380 i.atEnd() == false; i++)
1382 RemoteClient *client = i.getNode()->getValue();
1383 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1384 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1386 m_con.Send(client->peer_id, 0, data, true);
1392 JMutexAutoLock lock(m_env_mutex);
1394 ScopeProfiler sp(g_profiler, "SEnv step");
1395 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1399 const float map_timer_and_unload_dtime = 2.92;
1400 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1402 JMutexAutoLock lock(m_env_mutex);
1403 // Run Map's timers and unload unused data
1404 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1405 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1406 g_settings->getFloat("server_unload_unused_data_timeout"));
1417 JMutexAutoLock lock(m_env_mutex);
1418 JMutexAutoLock lock2(m_con_mutex);
1420 ScopeProfiler sp(g_profiler, "Server: handle players");
1422 for(core::map<u16, RemoteClient*>::Iterator
1423 i = m_clients.getIterator();
1424 i.atEnd() == false; i++)
1426 RemoteClient *client = i.getNode()->getValue();
1427 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1428 if(playersao == NULL)
1432 Handle player HPs (die if hp=0)
1434 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1436 if(playersao->getHP() == 0)
1437 DiePlayer(client->peer_id);
1439 SendPlayerHP(client->peer_id);
1443 Send player inventories if necessary
1445 if(playersao->m_moved){
1446 SendMovePlayer(client->peer_id);
1447 playersao->m_moved = false;
1449 if(playersao->m_inventory_not_sent){
1450 UpdateCrafting(client->peer_id);
1451 SendInventory(client->peer_id);
1456 /* Transform liquids */
1457 m_liquid_transform_timer += dtime;
1458 if(m_liquid_transform_timer >= m_liquid_transform_every)
1460 m_liquid_transform_timer -= m_liquid_transform_every;
1462 JMutexAutoLock lock(m_env_mutex);
1464 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1466 core::map<v3s16, MapBlock*> modified_blocks;
1467 m_env->getMap().transformLiquids(modified_blocks);
1472 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1473 ServerMap &map = ((ServerMap&)m_env->getMap());
1474 map.updateLighting(modified_blocks, lighting_modified_blocks);
1476 // Add blocks modified by lighting to modified_blocks
1477 for(core::map<v3s16, MapBlock*>::Iterator
1478 i = lighting_modified_blocks.getIterator();
1479 i.atEnd() == false; i++)
1481 MapBlock *block = i.getNode()->getValue();
1482 modified_blocks.insert(block->getPos(), block);
1486 Set the modified blocks unsent for all the clients
1489 JMutexAutoLock lock2(m_con_mutex);
1491 for(core::map<u16, RemoteClient*>::Iterator
1492 i = m_clients.getIterator();
1493 i.atEnd() == false; i++)
1495 RemoteClient *client = i.getNode()->getValue();
1497 if(modified_blocks.size() > 0)
1499 // Remove block from sent history
1500 client->SetBlocksNotSent(modified_blocks);
1505 // Periodically print some info
1507 float &counter = m_print_info_timer;
1513 JMutexAutoLock lock2(m_con_mutex);
1514 m_clients_number = 0;
1515 if(m_clients.size() != 0)
1516 infostream<<"Players:"<<std::endl;
1517 for(core::map<u16, RemoteClient*>::Iterator
1518 i = m_clients.getIterator();
1519 i.atEnd() == false; i++)
1521 //u16 peer_id = i.getNode()->getKey();
1522 RemoteClient *client = i.getNode()->getValue();
1523 Player *player = m_env->getPlayer(client->peer_id);
1526 infostream<<"* "<<player->getName()<<"\t";
1527 client->PrintInfo(infostream);
1535 // send masterserver announce
1537 float &counter = m_masterserver_timer;
1538 if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1540 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number);
1547 //if(g_settings->getBool("enable_experimental"))
1551 Check added and deleted active objects
1554 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1555 JMutexAutoLock envlock(m_env_mutex);
1556 JMutexAutoLock conlock(m_con_mutex);
1558 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1560 // Radius inside which objects are active
1561 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1562 radius *= MAP_BLOCKSIZE;
1564 for(core::map<u16, RemoteClient*>::Iterator
1565 i = m_clients.getIterator();
1566 i.atEnd() == false; i++)
1568 RemoteClient *client = i.getNode()->getValue();
1570 // If definitions and textures have not been sent, don't
1571 // send objects either
1572 if(!client->definitions_sent)
1575 Player *player = m_env->getPlayer(client->peer_id);
1578 // This can happen if the client timeouts somehow
1579 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1581 <<" has no associated player"<<std::endl;*/
1584 v3s16 pos = floatToInt(player->getPosition(), BS);
1586 core::map<u16, bool> removed_objects;
1587 core::map<u16, bool> added_objects;
1588 m_env->getRemovedActiveObjects(pos, radius,
1589 client->m_known_objects, removed_objects);
1590 m_env->getAddedActiveObjects(pos, radius,
1591 client->m_known_objects, added_objects);
1593 // Ignore if nothing happened
1594 if(removed_objects.size() == 0 && added_objects.size() == 0)
1596 //infostream<<"active objects: none changed"<<std::endl;
1600 std::string data_buffer;
1604 // Handle removed objects
1605 writeU16((u8*)buf, removed_objects.size());
1606 data_buffer.append(buf, 2);
1607 for(core::map<u16, bool>::Iterator
1608 i = removed_objects.getIterator();
1609 i.atEnd()==false; i++)
1612 u16 id = i.getNode()->getKey();
1613 ServerActiveObject* obj = m_env->getActiveObject(id);
1615 // Add to data buffer for sending
1616 writeU16((u8*)buf, i.getNode()->getKey());
1617 data_buffer.append(buf, 2);
1619 // Remove from known objects
1620 client->m_known_objects.remove(i.getNode()->getKey());
1622 if(obj && obj->m_known_by_count > 0)
1623 obj->m_known_by_count--;
1626 // Handle added objects
1627 writeU16((u8*)buf, added_objects.size());
1628 data_buffer.append(buf, 2);
1629 for(core::map<u16, bool>::Iterator
1630 i = added_objects.getIterator();
1631 i.atEnd()==false; i++)
1634 u16 id = i.getNode()->getKey();
1635 ServerActiveObject* obj = m_env->getActiveObject(id);
1638 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1640 infostream<<"WARNING: "<<__FUNCTION_NAME
1641 <<": NULL object"<<std::endl;
1643 type = obj->getSendType();
1645 // Add to data buffer for sending
1646 writeU16((u8*)buf, id);
1647 data_buffer.append(buf, 2);
1648 writeU8((u8*)buf, type);
1649 data_buffer.append(buf, 1);
1652 data_buffer.append(serializeLongString(
1653 obj->getClientInitializationData(client->net_proto_version)));
1655 data_buffer.append(serializeLongString(""));
1657 // Add to known objects
1658 client->m_known_objects.insert(i.getNode()->getKey(), false);
1661 obj->m_known_by_count++;
1665 SharedBuffer<u8> reply(2 + data_buffer.size());
1666 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1667 memcpy((char*)&reply[2], data_buffer.c_str(),
1668 data_buffer.size());
1670 m_con.Send(client->peer_id, 0, reply, true);
1672 verbosestream<<"Server: Sent object remove/add: "
1673 <<removed_objects.size()<<" removed, "
1674 <<added_objects.size()<<" added, "
1675 <<"packet size is "<<reply.getSize()<<std::endl;
1680 Collect a list of all the objects known by the clients
1681 and report it back to the environment.
1684 core::map<u16, bool> all_known_objects;
1686 for(core::map<u16, RemoteClient*>::Iterator
1687 i = m_clients.getIterator();
1688 i.atEnd() == false; i++)
1690 RemoteClient *client = i.getNode()->getValue();
1691 // Go through all known objects of client
1692 for(core::map<u16, bool>::Iterator
1693 i = client->m_known_objects.getIterator();
1694 i.atEnd()==false; i++)
1696 u16 id = i.getNode()->getKey();
1697 all_known_objects[id] = true;
1701 m_env->setKnownActiveObjects(whatever);
1707 Send object messages
1710 JMutexAutoLock envlock(m_env_mutex);
1711 JMutexAutoLock conlock(m_con_mutex);
1713 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1716 // Value = data sent by object
1717 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1719 // Get active object messages from environment
1722 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1726 core::list<ActiveObjectMessage>* message_list = NULL;
1727 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1728 n = buffered_messages.find(aom.id);
1731 message_list = new core::list<ActiveObjectMessage>;
1732 buffered_messages.insert(aom.id, message_list);
1736 message_list = n->getValue();
1738 message_list->push_back(aom);
1741 // Route data to every client
1742 for(core::map<u16, RemoteClient*>::Iterator
1743 i = m_clients.getIterator();
1744 i.atEnd()==false; i++)
1746 RemoteClient *client = i.getNode()->getValue();
1747 std::string reliable_data;
1748 std::string unreliable_data;
1749 // Go through all objects in message buffer
1750 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1751 j = buffered_messages.getIterator();
1752 j.atEnd()==false; j++)
1754 // If object is not known by client, skip it
1755 u16 id = j.getNode()->getKey();
1756 if(client->m_known_objects.find(id) == NULL)
1758 // Get message list of object
1759 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1760 // Go through every message
1761 for(core::list<ActiveObjectMessage>::Iterator
1762 k = list->begin(); k != list->end(); k++)
1764 // Compose the full new data with header
1765 ActiveObjectMessage aom = *k;
1766 std::string new_data;
1769 writeU16((u8*)&buf[0], aom.id);
1770 new_data.append(buf, 2);
1772 new_data += serializeString(aom.datastring);
1773 // Add data to buffer
1775 reliable_data += new_data;
1777 unreliable_data += new_data;
1781 reliable_data and unreliable_data are now ready.
1784 if(reliable_data.size() > 0)
1786 SharedBuffer<u8> reply(2 + reliable_data.size());
1787 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1788 memcpy((char*)&reply[2], reliable_data.c_str(),
1789 reliable_data.size());
1791 m_con.Send(client->peer_id, 0, reply, true);
1793 if(unreliable_data.size() > 0)
1795 SharedBuffer<u8> reply(2 + unreliable_data.size());
1796 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1797 memcpy((char*)&reply[2], unreliable_data.c_str(),
1798 unreliable_data.size());
1799 // Send as unreliable
1800 m_con.Send(client->peer_id, 0, reply, false);
1803 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1805 infostream<<"Server: Size of object message data: "
1806 <<"reliable: "<<reliable_data.size()
1807 <<", unreliable: "<<unreliable_data.size()
1812 // Clear buffered_messages
1813 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1814 i = buffered_messages.getIterator();
1815 i.atEnd()==false; i++)
1817 delete i.getNode()->getValue();
1821 } // enable_experimental
1824 Send queued-for-sending map edit events.
1827 // We will be accessing the environment and the connection
1828 JMutexAutoLock lock(m_env_mutex);
1829 JMutexAutoLock conlock(m_con_mutex);
1831 // Don't send too many at a time
1834 // Single change sending is disabled if queue size is not small
1835 bool disable_single_change_sending = false;
1836 if(m_unsent_map_edit_queue.size() >= 4)
1837 disable_single_change_sending = true;
1839 int event_count = m_unsent_map_edit_queue.size();
1841 // We'll log the amount of each
1844 while(m_unsent_map_edit_queue.size() != 0)
1846 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1848 // Players far away from the change are stored here.
1849 // Instead of sending the changes, MapBlocks are set not sent
1851 core::list<u16> far_players;
1853 if(event->type == MEET_ADDNODE)
1855 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1856 prof.add("MEET_ADDNODE", 1);
1857 if(disable_single_change_sending)
1858 sendAddNode(event->p, event->n, event->already_known_by_peer,
1861 sendAddNode(event->p, event->n, event->already_known_by_peer,
1864 else if(event->type == MEET_REMOVENODE)
1866 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1867 prof.add("MEET_REMOVENODE", 1);
1868 if(disable_single_change_sending)
1869 sendRemoveNode(event->p, event->already_known_by_peer,
1872 sendRemoveNode(event->p, event->already_known_by_peer,
1875 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1877 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1878 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1879 setBlockNotSent(event->p);
1881 else if(event->type == MEET_OTHER)
1883 infostream<<"Server: MEET_OTHER"<<std::endl;
1884 prof.add("MEET_OTHER", 1);
1885 for(core::map<v3s16, bool>::Iterator
1886 i = event->modified_blocks.getIterator();
1887 i.atEnd()==false; i++)
1889 v3s16 p = i.getNode()->getKey();
1895 prof.add("unknown", 1);
1896 infostream<<"WARNING: Server: Unknown MapEditEvent "
1897 <<((u32)event->type)<<std::endl;
1901 Set blocks not sent to far players
1903 if(far_players.size() > 0)
1905 // Convert list format to that wanted by SetBlocksNotSent
1906 core::map<v3s16, MapBlock*> modified_blocks2;
1907 for(core::map<v3s16, bool>::Iterator
1908 i = event->modified_blocks.getIterator();
1909 i.atEnd()==false; i++)
1911 v3s16 p = i.getNode()->getKey();
1912 modified_blocks2.insert(p,
1913 m_env->getMap().getBlockNoCreateNoEx(p));
1915 // Set blocks not sent
1916 for(core::list<u16>::Iterator
1917 i = far_players.begin();
1918 i != far_players.end(); i++)
1921 RemoteClient *client = getClient(peer_id);
1924 client->SetBlocksNotSent(modified_blocks2);
1930 /*// Don't send too many at a time
1932 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1936 if(event_count >= 5){
1937 infostream<<"Server: MapEditEvents:"<<std::endl;
1938 prof.print(infostream);
1939 } else if(event_count != 0){
1940 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1941 prof.print(verbosestream);
1947 Trigger emergethread (it somehow gets to a non-triggered but
1948 bysy state sometimes)
1951 float &counter = m_emergethread_trigger_timer;
1957 m_emergethread.trigger();
1959 // Update m_enable_rollback_recording here too
1960 m_enable_rollback_recording =
1961 g_settings->getBool("enable_rollback_recording");
1965 // Save map, players and auth stuff
1967 float &counter = m_savemap_timer;
1969 if(counter >= g_settings->getFloat("server_map_save_interval"))
1972 JMutexAutoLock lock(m_env_mutex);
1974 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1977 if(m_banmanager.isModified())
1978 m_banmanager.save();
1980 // Save changed parts of map
1981 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1984 m_env->serializePlayers(m_path_world);
1986 // Save environment metadata
1987 m_env->saveMeta(m_path_world);
1992 void Server::Receive()
1994 DSTACK(__FUNCTION_NAME);
1995 SharedBuffer<u8> data;
2000 JMutexAutoLock conlock(m_con_mutex);
2001 datasize = m_con.Receive(peer_id, data);
2004 // This has to be called so that the client list gets synced
2005 // with the peer list of the connection
2006 handlePeerChanges();
2008 ProcessData(*data, datasize, peer_id);
2010 catch(con::InvalidIncomingDataException &e)
2012 infostream<<"Server::Receive(): "
2013 "InvalidIncomingDataException: what()="
2014 <<e.what()<<std::endl;
2016 catch(con::PeerNotFoundException &e)
2018 //NOTE: This is not needed anymore
2020 // The peer has been disconnected.
2021 // Find the associated player and remove it.
2023 /*JMutexAutoLock envlock(m_env_mutex);
2025 infostream<<"ServerThread: peer_id="<<peer_id
2026 <<" has apparently closed connection. "
2027 <<"Removing player."<<std::endl;
2029 m_env->removePlayer(peer_id);*/
2033 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
2035 DSTACK(__FUNCTION_NAME);
2036 // Environment is locked first.
2037 JMutexAutoLock envlock(m_env_mutex);
2038 JMutexAutoLock conlock(m_con_mutex);
2040 ScopeProfiler sp(g_profiler, "Server::ProcessData");
2043 Address address = m_con.GetPeerAddress(peer_id);
2044 std::string addr_s = address.serializeString();
2046 // drop player if is ip is banned
2047 if(m_banmanager.isIpBanned(addr_s)){
2048 infostream<<"Server: A banned client tried to connect from "
2049 <<addr_s<<"; banned name was "
2050 <<m_banmanager.getBanName(addr_s)<<std::endl;
2051 // This actually doesn't seem to transfer to the client
2052 SendAccessDenied(m_con, peer_id,
2053 L"Your ip is banned. Banned name was "
2054 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
2055 m_con.DeletePeer(peer_id);
2059 catch(con::PeerNotFoundException &e)
2061 infostream<<"Server::ProcessData(): Cancelling: peer "
2062 <<peer_id<<" not found"<<std::endl;
2066 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
2068 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
2076 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
2078 if(command == TOSERVER_INIT)
2080 // [0] u16 TOSERVER_INIT
2081 // [2] u8 SER_FMT_VER_HIGHEST
2082 // [3] u8[20] player_name
2083 // [23] u8[28] password <--- can be sent without this, from old versions
2085 if(datasize < 2+1+PLAYERNAME_SIZE)
2088 verbosestream<<"Server: Got TOSERVER_INIT from "
2089 <<peer_id<<std::endl;
2091 // First byte after command is maximum supported
2092 // serialization version
2093 u8 client_max = data[2];
2094 u8 our_max = SER_FMT_VER_HIGHEST;
2095 // Use the highest version supported by both
2096 u8 deployed = core::min_(client_max, our_max);
2097 // If it's lower than the lowest supported, give up.
2098 if(deployed < SER_FMT_VER_LOWEST)
2099 deployed = SER_FMT_VER_INVALID;
2101 //peer->serialization_version = deployed;
2102 getClient(peer_id)->pending_serialization_version = deployed;
2104 if(deployed == SER_FMT_VER_INVALID)
2106 actionstream<<"Server: A mismatched client tried to connect from "
2107 <<addr_s<<std::endl;
2108 infostream<<"Server: Cannot negotiate "
2109 "serialization version with peer "
2110 <<peer_id<<std::endl;
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"."
2120 Read and check network protocol version
2123 u16 min_net_proto_version = 0;
2124 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2125 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2127 // Use same version as minimum and maximum if maximum version field
2128 // doesn't exist (backwards compatibility)
2129 u16 max_net_proto_version = min_net_proto_version;
2130 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
2131 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
2133 // Start with client's maximum version
2134 u16 net_proto_version = max_net_proto_version;
2136 // Figure out a working version if it is possible at all
2137 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
2138 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
2140 // If maximum is larger than our maximum, go with our maximum
2141 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2142 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
2143 // Else go with client's maximum
2145 net_proto_version = max_net_proto_version;
2148 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
2149 <<min_net_proto_version<<", max: "<<max_net_proto_version
2150 <<", chosen: "<<net_proto_version<<std::endl;
2152 getClient(peer_id)->net_proto_version = net_proto_version;
2154 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
2155 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
2157 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
2159 SendAccessDenied(m_con, peer_id, std::wstring(
2160 L"Your client's version is not supported.\n"
2161 L"Server version is ")
2162 + narrow_to_wide(VERSION_STRING) + L",\n"
2163 + L"server's PROTOCOL_VERSION is "
2164 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
2166 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
2167 + L", client's PROTOCOL_VERSION is "
2168 + narrow_to_wide(itos(min_net_proto_version))
2170 + narrow_to_wide(itos(max_net_proto_version))
2175 if(g_settings->getBool("strict_protocol_version_checking"))
2177 if(net_proto_version != LATEST_PROTOCOL_VERSION)
2179 actionstream<<"Server: A mismatched (strict) client tried to "
2180 <<"connect from "<<addr_s<<std::endl;
2181 SendAccessDenied(m_con, peer_id, std::wstring(
2182 L"Your client's version is not supported.\n"
2183 L"Server version is ")
2184 + narrow_to_wide(VERSION_STRING) + L",\n"
2185 + L"server's PROTOCOL_VERSION (strict) is "
2186 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
2187 + L", client's PROTOCOL_VERSION is "
2188 + narrow_to_wide(itos(min_net_proto_version))
2190 + narrow_to_wide(itos(max_net_proto_version))
2201 char playername[PLAYERNAME_SIZE];
2202 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2204 playername[i] = data[3+i];
2206 playername[PLAYERNAME_SIZE-1] = 0;
2208 if(playername[0]=='\0')
2210 actionstream<<"Server: Player with an empty name "
2211 <<"tried to connect from "<<addr_s<<std::endl;
2212 SendAccessDenied(m_con, peer_id,
2217 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2219 actionstream<<"Server: Player with an invalid name "
2220 <<"tried to connect from "<<addr_s<<std::endl;
2221 SendAccessDenied(m_con, peer_id,
2222 L"Name contains unallowed characters");
2226 infostream<<"Server: New connection: \""<<playername<<"\" from "
2227 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2230 char given_password[PASSWORD_SIZE];
2231 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2233 // old version - assume blank password
2234 given_password[0] = 0;
2238 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2240 given_password[i] = data[23+i];
2242 given_password[PASSWORD_SIZE-1] = 0;
2245 if(!base64_is_valid(given_password)){
2246 infostream<<"Server: "<<playername
2247 <<" supplied invalid password hash"<<std::endl;
2248 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2252 std::string checkpwd; // Password hash to check against
2253 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2255 // If no authentication info exists for user, create it
2257 if(!isSingleplayer() &&
2258 g_settings->getBool("disallow_empty_password") &&
2259 std::string(given_password) == ""){
2260 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2261 L"disallowed. Set a password and try again.");
2264 std::wstring raw_default_password =
2265 narrow_to_wide(g_settings->get("default_password"));
2266 std::string initial_password =
2267 translatePassword(playername, raw_default_password);
2269 // If default_password is empty, allow any initial password
2270 if (raw_default_password.length() == 0)
2271 initial_password = given_password;
2273 scriptapi_create_auth(m_lua, playername, initial_password);
2276 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2279 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2283 if(given_password != checkpwd){
2284 infostream<<"Server: peer_id="<<peer_id
2285 <<": supplied invalid password for "
2286 <<playername<<std::endl;
2287 SendAccessDenied(m_con, peer_id, L"Invalid password");
2291 // Do not allow multiple players in simple singleplayer mode.
2292 // This isn't a perfect way to do it, but will suffice for now.
2293 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2294 infostream<<"Server: Not allowing another client to connect in"
2295 <<" simple singleplayer mode"<<std::endl;
2296 SendAccessDenied(m_con, peer_id,
2297 L"Running in simple singleplayer mode.");
2301 // Enforce user limit.
2302 // Don't enforce for users that have some admin right
2303 if(m_clients.size() >= g_settings->getU16("max_users") &&
2304 !checkPriv(playername, "server") &&
2305 !checkPriv(playername, "ban") &&
2306 !checkPriv(playername, "privs") &&
2307 !checkPriv(playername, "password") &&
2308 playername != g_settings->get("name"))
2310 actionstream<<"Server: "<<playername<<" tried to join, but there"
2311 <<" are already max_users="
2312 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2313 SendAccessDenied(m_con, peer_id, L"Too many users.");
2318 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2320 // If failed, cancel
2321 if(playersao == NULL)
2323 errorstream<<"Server: peer_id="<<peer_id
2324 <<": failed to emerge player"<<std::endl;
2329 Answer with a TOCLIENT_INIT
2332 SharedBuffer<u8> reply(2+1+6+8+4);
2333 writeU16(&reply[0], TOCLIENT_INIT);
2334 writeU8(&reply[2], deployed);
2335 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2336 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2337 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2340 m_con.Send(peer_id, 0, reply, true);
2344 Send complete position information
2346 SendMovePlayer(peer_id);
2351 if(command == TOSERVER_INIT2)
2353 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2354 <<peer_id<<std::endl;
2356 Player *player = m_env->getPlayer(peer_id);
2358 verbosestream<<"Server: TOSERVER_INIT2: "
2359 <<"Player not found; ignoring."<<std::endl;
2363 RemoteClient *client = getClient(peer_id);
2364 client->serialization_version =
2365 getClient(peer_id)->pending_serialization_version;
2368 Send some initialization data
2371 infostream<<"Server: Sending content to "
2372 <<getPlayerName(peer_id)<<std::endl;
2374 // Send player movement settings
2375 SendMovement(m_con, peer_id);
2377 // Send item definitions
2378 SendItemDef(m_con, peer_id, m_itemdef);
2380 // Send node definitions
2381 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2383 // Send media announcement
2384 sendMediaAnnouncement(peer_id);
2387 SendPlayerPrivileges(peer_id);
2389 // Send inventory formspec
2390 SendPlayerInventoryFormspec(peer_id);
2393 UpdateCrafting(peer_id);
2394 SendInventory(peer_id);
2397 if(g_settings->getBool("enable_damage"))
2398 SendPlayerHP(peer_id);
2400 // Send detached inventories
2401 sendDetachedInventories(peer_id);
2403 // Show death screen if necessary
2405 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2409 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2410 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2411 m_con.Send(peer_id, 0, data, true);
2414 // Note things in chat if not in simple singleplayer mode
2415 if(!m_simple_singleplayer_mode)
2417 // Send information about server to player in chat
2418 SendChatMessage(peer_id, getStatusString());
2420 // Send information about joining in chat
2422 std::wstring name = L"unknown";
2423 Player *player = m_env->getPlayer(peer_id);
2425 name = narrow_to_wide(player->getName());
2427 std::wstring message;
2430 message += L" joined the game.";
2431 BroadcastChatMessage(message);
2435 // Warnings about protocol version can be issued here
2436 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2438 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2439 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2446 std::ostringstream os(std::ios_base::binary);
2447 for(core::map<u16, RemoteClient*>::Iterator
2448 i = m_clients.getIterator();
2449 i.atEnd() == false; i++)
2451 RemoteClient *client = i.getNode()->getValue();
2452 assert(client->peer_id == i.getNode()->getKey());
2453 if(client->serialization_version == SER_FMT_VER_INVALID)
2456 Player *player = m_env->getPlayer(client->peer_id);
2459 // Get name of player
2460 os<<player->getName()<<" ";
2463 actionstream<<player->getName()<<" joins game. List of players: "
2464 <<os.str()<<std::endl;
2470 if(peer_ser_ver == SER_FMT_VER_INVALID)
2472 infostream<<"Server::ProcessData(): Cancelling: Peer"
2473 " serialization format invalid or not initialized."
2474 " Skipping incoming command="<<command<<std::endl;
2478 Player *player = m_env->getPlayer(peer_id);
2480 infostream<<"Server::ProcessData(): Cancelling: "
2481 "No player for peer_id="<<peer_id
2486 PlayerSAO *playersao = player->getPlayerSAO();
2487 if(playersao == NULL){
2488 infostream<<"Server::ProcessData(): Cancelling: "
2489 "No player object for peer_id="<<peer_id
2494 if(command == TOSERVER_PLAYERPOS)
2496 if(datasize < 2+12+12+4+4)
2500 v3s32 ps = readV3S32(&data[start+2]);
2501 v3s32 ss = readV3S32(&data[start+2+12]);
2502 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2503 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2505 if(datasize >= 2+12+12+4+4+4)
2506 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2507 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2508 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2509 pitch = wrapDegrees(pitch);
2510 yaw = wrapDegrees(yaw);
2512 player->setPosition(position);
2513 player->setSpeed(speed);
2514 player->setPitch(pitch);
2515 player->setYaw(yaw);
2516 player->keyPressed=keyPressed;
2517 player->control.up = (bool)(keyPressed&1);
2518 player->control.down = (bool)(keyPressed&2);
2519 player->control.left = (bool)(keyPressed&4);
2520 player->control.right = (bool)(keyPressed&8);
2521 player->control.jump = (bool)(keyPressed&16);
2522 player->control.aux1 = (bool)(keyPressed&32);
2523 player->control.sneak = (bool)(keyPressed&64);
2524 player->control.LMB = (bool)(keyPressed&128);
2525 player->control.RMB = (bool)(keyPressed&256);
2527 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2528 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2529 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2531 else if(command == TOSERVER_GOTBLOCKS)
2544 u16 count = data[2];
2545 for(u16 i=0; i<count; i++)
2547 if((s16)datasize < 2+1+(i+1)*6)
2548 throw con::InvalidIncomingDataException
2549 ("GOTBLOCKS length is too short");
2550 v3s16 p = readV3S16(&data[2+1+i*6]);
2551 /*infostream<<"Server: GOTBLOCKS ("
2552 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2553 RemoteClient *client = getClient(peer_id);
2554 client->GotBlock(p);
2557 else if(command == TOSERVER_DELETEDBLOCKS)
2570 u16 count = data[2];
2571 for(u16 i=0; i<count; i++)
2573 if((s16)datasize < 2+1+(i+1)*6)
2574 throw con::InvalidIncomingDataException
2575 ("DELETEDBLOCKS length is too short");
2576 v3s16 p = readV3S16(&data[2+1+i*6]);
2577 /*infostream<<"Server: DELETEDBLOCKS ("
2578 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2579 RemoteClient *client = getClient(peer_id);
2580 client->SetBlockNotSent(p);
2583 else if(command == TOSERVER_CLICK_OBJECT)
2585 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2588 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2590 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2593 else if(command == TOSERVER_GROUND_ACTION)
2595 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2599 else if(command == TOSERVER_RELEASE)
2601 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2604 else if(command == TOSERVER_SIGNTEXT)
2606 infostream<<"Server: SIGNTEXT not supported anymore"
2610 else if(command == TOSERVER_SIGNNODETEXT)
2612 infostream<<"Server: SIGNNODETEXT not supported anymore"
2616 else if(command == TOSERVER_INVENTORY_ACTION)
2618 // Strip command and create a stream
2619 std::string datastring((char*)&data[2], datasize-2);
2620 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2621 std::istringstream is(datastring, std::ios_base::binary);
2623 InventoryAction *a = InventoryAction::deSerialize(is);
2626 infostream<<"TOSERVER_INVENTORY_ACTION: "
2627 <<"InventoryAction::deSerialize() returned NULL"
2632 // If something goes wrong, this player is to blame
2633 RollbackScopeActor rollback_scope(m_rollback,
2634 std::string("player:")+player->getName());
2637 Note: Always set inventory not sent, to repair cases
2638 where the client made a bad prediction.
2642 Handle restrictions and special cases of the move action
2644 if(a->getType() == IACTION_MOVE)
2646 IMoveAction *ma = (IMoveAction*)a;
2648 ma->from_inv.applyCurrentPlayer(player->getName());
2649 ma->to_inv.applyCurrentPlayer(player->getName());
2651 setInventoryModified(ma->from_inv);
2652 setInventoryModified(ma->to_inv);
2654 bool from_inv_is_current_player =
2655 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2656 (ma->from_inv.name == player->getName());
2658 bool to_inv_is_current_player =
2659 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2660 (ma->to_inv.name == player->getName());
2663 Disable moving items out of craftpreview
2665 if(ma->from_list == "craftpreview")
2667 infostream<<"Ignoring IMoveAction from "
2668 <<(ma->from_inv.dump())<<":"<<ma->from_list
2669 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2670 <<" because src is "<<ma->from_list<<std::endl;
2676 Disable moving items into craftresult and craftpreview
2678 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2680 infostream<<"Ignoring IMoveAction from "
2681 <<(ma->from_inv.dump())<<":"<<ma->from_list
2682 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2683 <<" because dst is "<<ma->to_list<<std::endl;
2688 // Disallow moving items in elsewhere than player's inventory
2689 // if not allowed to interact
2690 if(!checkPriv(player->getName(), "interact") &&
2691 (!from_inv_is_current_player ||
2692 !to_inv_is_current_player))
2694 infostream<<"Cannot move outside of player's inventory: "
2695 <<"No interact privilege"<<std::endl;
2701 Handle restrictions and special cases of the drop action
2703 else if(a->getType() == IACTION_DROP)
2705 IDropAction *da = (IDropAction*)a;
2707 da->from_inv.applyCurrentPlayer(player->getName());
2709 setInventoryModified(da->from_inv);
2711 // Disallow dropping items if not allowed to interact
2712 if(!checkPriv(player->getName(), "interact"))
2719 Handle restrictions and special cases of the craft action
2721 else if(a->getType() == IACTION_CRAFT)
2723 ICraftAction *ca = (ICraftAction*)a;
2725 ca->craft_inv.applyCurrentPlayer(player->getName());
2727 setInventoryModified(ca->craft_inv);
2729 //bool craft_inv_is_current_player =
2730 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2731 // (ca->craft_inv.name == player->getName());
2733 // Disallow crafting if not allowed to interact
2734 if(!checkPriv(player->getName(), "interact"))
2736 infostream<<"Cannot craft: "
2737 <<"No interact privilege"<<std::endl;
2744 a->apply(this, playersao, this);
2748 else if(command == TOSERVER_CHAT_MESSAGE)
2756 std::string datastring((char*)&data[2], datasize-2);
2757 std::istringstream is(datastring, std::ios_base::binary);
2760 is.read((char*)buf, 2);
2761 u16 len = readU16(buf);
2763 std::wstring message;
2764 for(u16 i=0; i<len; i++)
2766 is.read((char*)buf, 2);
2767 message += (wchar_t)readU16(buf);
2770 // If something goes wrong, this player is to blame
2771 RollbackScopeActor rollback_scope(m_rollback,
2772 std::string("player:")+player->getName());
2774 // Get player name of this client
2775 std::wstring name = narrow_to_wide(player->getName());
2778 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2779 wide_to_narrow(message));
2780 // If script ate the message, don't proceed
2784 // Line to send to players
2786 // Whether to send to the player that sent the line
2787 bool send_to_sender = false;
2788 // Whether to send to other players
2789 bool send_to_others = false;
2791 // Commands are implemented in Lua, so only catch invalid
2792 // commands that were not "eaten" and send an error back
2793 if(message[0] == L'/')
2795 message = message.substr(1);
2796 send_to_sender = true;
2797 if(message.length() == 0)
2798 line += L"-!- Empty command";
2800 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2804 if(checkPriv(player->getName(), "shout")){
2809 send_to_others = true;
2811 line += L"-!- You don't have permission to shout.";
2812 send_to_sender = true;
2819 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2822 Send the message to clients
2824 for(core::map<u16, RemoteClient*>::Iterator
2825 i = m_clients.getIterator();
2826 i.atEnd() == false; i++)
2828 // Get client and check that it is valid
2829 RemoteClient *client = i.getNode()->getValue();
2830 assert(client->peer_id == i.getNode()->getKey());
2831 if(client->serialization_version == SER_FMT_VER_INVALID)
2835 bool sender_selected = (peer_id == client->peer_id);
2836 if(sender_selected == true && send_to_sender == false)
2838 if(sender_selected == false && send_to_others == false)
2841 SendChatMessage(client->peer_id, line);
2845 else if(command == TOSERVER_DAMAGE)
2847 std::string datastring((char*)&data[2], datasize-2);
2848 std::istringstream is(datastring, std::ios_base::binary);
2849 u8 damage = readU8(is);
2851 if(g_settings->getBool("enable_damage"))
2853 actionstream<<player->getName()<<" damaged by "
2854 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2857 playersao->setHP(playersao->getHP() - damage);
2859 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2862 if(playersao->m_hp_not_sent)
2863 SendPlayerHP(peer_id);
2866 else if(command == TOSERVER_PASSWORD)
2869 [0] u16 TOSERVER_PASSWORD
2870 [2] u8[28] old password
2871 [30] u8[28] new password
2874 if(datasize != 2+PASSWORD_SIZE*2)
2876 /*char password[PASSWORD_SIZE];
2877 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2878 password[i] = data[2+i];
2879 password[PASSWORD_SIZE-1] = 0;*/
2881 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2889 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2891 char c = data[2+PASSWORD_SIZE+i];
2897 if(!base64_is_valid(newpwd)){
2898 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2899 // Wrong old password supplied!!
2900 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2904 infostream<<"Server: Client requests a password change from "
2905 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2907 std::string playername = player->getName();
2909 std::string checkpwd;
2910 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2912 if(oldpwd != checkpwd)
2914 infostream<<"Server: invalid old password"<<std::endl;
2915 // Wrong old password supplied!!
2916 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2920 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2922 actionstream<<player->getName()<<" changes password"<<std::endl;
2923 SendChatMessage(peer_id, L"Password change successful.");
2925 actionstream<<player->getName()<<" tries to change password but "
2926 <<"it fails"<<std::endl;
2927 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2930 else if(command == TOSERVER_PLAYERITEM)
2935 u16 item = readU16(&data[2]);
2936 playersao->setWieldIndex(item);
2938 else if(command == TOSERVER_RESPAWN)
2940 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2943 RespawnPlayer(peer_id);
2945 actionstream<<player->getName()<<" respawns at "
2946 <<PP(player->getPosition()/BS)<<std::endl;
2948 // ActiveObject is added to environment in AsyncRunStep after
2949 // the previous addition has been succesfully removed
2951 else if(command == TOSERVER_REQUEST_MEDIA) {
2952 std::string datastring((char*)&data[2], datasize-2);
2953 std::istringstream is(datastring, std::ios_base::binary);
2955 core::list<MediaRequest> tosend;
2956 u16 numfiles = readU16(is);
2958 infostream<<"Sending "<<numfiles<<" files to "
2959 <<getPlayerName(peer_id)<<std::endl;
2960 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2962 for(int i = 0; i < numfiles; i++) {
2963 std::string name = deSerializeString(is);
2964 tosend.push_back(MediaRequest(name));
2965 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2969 sendRequestedMedia(peer_id, tosend);
2971 // Now the client should know about everything
2972 // (definitions and files)
2973 getClient(peer_id)->definitions_sent = true;
2975 else if(command == TOSERVER_RECEIVED_MEDIA) {
2976 getClient(peer_id)->definitions_sent = true;
2978 else if(command == TOSERVER_INTERACT)
2980 std::string datastring((char*)&data[2], datasize-2);
2981 std::istringstream is(datastring, std::ios_base::binary);
2987 [5] u32 length of the next item
2988 [9] serialized PointedThing
2990 0: start digging (from undersurface) or use
2991 1: stop digging (all parameters ignored)
2992 2: digging completed
2993 3: place block or item (to abovesurface)
2996 u8 action = readU8(is);
2997 u16 item_i = readU16(is);
2998 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2999 PointedThing pointed;
3000 pointed.deSerialize(tmp_is);
3002 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
3003 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
3007 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
3008 <<" tried to interact, but is dead!"<<std::endl;
3012 v3f player_pos = playersao->getLastGoodPosition();
3014 // Update wielded item
3015 playersao->setWieldIndex(item_i);
3017 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
3018 v3s16 p_under = pointed.node_undersurface;
3019 v3s16 p_above = pointed.node_abovesurface;
3021 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
3022 ServerActiveObject *pointed_object = NULL;
3023 if(pointed.type == POINTEDTHING_OBJECT)
3025 pointed_object = m_env->getActiveObject(pointed.object_id);
3026 if(pointed_object == NULL)
3028 verbosestream<<"TOSERVER_INTERACT: "
3029 "pointed object is NULL"<<std::endl;
3035 v3f pointed_pos_under = player_pos;
3036 v3f pointed_pos_above = player_pos;
3037 if(pointed.type == POINTEDTHING_NODE)
3039 pointed_pos_under = intToFloat(p_under, BS);
3040 pointed_pos_above = intToFloat(p_above, BS);
3042 else if(pointed.type == POINTEDTHING_OBJECT)
3044 pointed_pos_under = pointed_object->getBasePosition();
3045 pointed_pos_above = pointed_pos_under;
3049 Check that target is reasonably close
3050 (only when digging or placing things)
3052 if(action == 0 || action == 2 || action == 3)
3054 float d = player_pos.getDistanceFrom(pointed_pos_under);
3055 float max_d = BS * 14; // Just some large enough value
3057 actionstream<<"Player "<<player->getName()
3058 <<" tried to access "<<pointed.dump()
3060 <<"d="<<d<<", max_d="<<max_d
3061 <<". ignoring."<<std::endl;
3062 // Re-send block to revert change on client-side
3063 RemoteClient *client = getClient(peer_id);
3064 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3065 client->SetBlockNotSent(blockpos);
3072 Make sure the player is allowed to do it
3074 if(!checkPriv(player->getName(), "interact"))
3076 actionstream<<player->getName()<<" attempted to interact with "
3077 <<pointed.dump()<<" without 'interact' privilege"
3079 // Re-send block to revert change on client-side
3080 RemoteClient *client = getClient(peer_id);
3081 // Digging completed -> under
3083 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3084 client->SetBlockNotSent(blockpos);
3086 // Placement -> above
3088 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3089 client->SetBlockNotSent(blockpos);
3095 If something goes wrong, this player is to blame
3097 RollbackScopeActor rollback_scope(m_rollback,
3098 std::string("player:")+player->getName());
3101 0: start digging or punch object
3105 if(pointed.type == POINTEDTHING_NODE)
3108 NOTE: This can be used in the future to check if
3109 somebody is cheating, by checking the timing.
3111 MapNode n(CONTENT_IGNORE);
3114 n = m_env->getMap().getNode(p_under);
3116 catch(InvalidPositionException &e)
3118 infostream<<"Server: Not punching: Node not found."
3119 <<" Adding block to emerge queue."
3121 m_emerge_queue.addBlock(peer_id,
3122 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3124 if(n.getContent() != CONTENT_IGNORE)
3125 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3127 playersao->noCheatDigStart(p_under);
3129 else if(pointed.type == POINTEDTHING_OBJECT)
3131 // Skip if object has been removed
3132 if(pointed_object->m_removed)
3135 actionstream<<player->getName()<<" punches object "
3136 <<pointed.object_id<<": "
3137 <<pointed_object->getDescription()<<std::endl;
3139 ItemStack punchitem = playersao->getWieldedItem();
3140 ToolCapabilities toolcap =
3141 punchitem.getToolCapabilities(m_itemdef);
3142 v3f dir = (pointed_object->getBasePosition() -
3143 (player->getPosition() + player->getEyeOffset())
3145 float time_from_last_punch =
3146 playersao->resetTimeFromLastPunch();
3147 pointed_object->punch(dir, &toolcap, playersao,
3148 time_from_last_punch);
3156 else if(action == 1)
3161 2: Digging completed
3163 else if(action == 2)
3165 // Only digging of nodes
3166 if(pointed.type == POINTEDTHING_NODE)
3168 MapNode n(CONTENT_IGNORE);
3171 n = m_env->getMap().getNode(p_under);
3173 catch(InvalidPositionException &e)
3175 infostream<<"Server: Not finishing digging: Node not found."
3176 <<" Adding block to emerge queue."
3178 m_emerge_queue.addBlock(peer_id,
3179 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3182 /* Cheat prevention */
3183 bool is_valid_dig = true;
3184 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
3186 v3s16 nocheat_p = playersao->getNoCheatDigPos();
3187 float nocheat_t = playersao->getNoCheatDigTime();
3188 playersao->noCheatDigEnd();
3189 // If player didn't start digging this, ignore dig
3190 if(nocheat_p != p_under){
3191 infostream<<"Server: NoCheat: "<<player->getName()
3192 <<" started digging "
3193 <<PP(nocheat_p)<<" and completed digging "
3194 <<PP(p_under)<<"; not digging."<<std::endl;
3195 is_valid_dig = false;
3197 // Get player's wielded item
3198 ItemStack playeritem;
3199 InventoryList *mlist = playersao->getInventory()->getList("main");
3201 playeritem = mlist->getItem(playersao->getWieldIndex());
3202 ToolCapabilities playeritem_toolcap =
3203 playeritem.getToolCapabilities(m_itemdef);
3204 // Get diggability and expected digging time
3205 DigParams params = getDigParams(m_nodedef->get(n).groups,
3206 &playeritem_toolcap);
3207 // If can't dig, try hand
3208 if(!params.diggable){
3209 const ItemDefinition &hand = m_itemdef->get("");
3210 const ToolCapabilities *tp = hand.tool_capabilities;
3212 params = getDigParams(m_nodedef->get(n).groups, tp);
3214 // If can't dig, ignore dig
3215 if(!params.diggable){
3216 infostream<<"Server: NoCheat: "<<player->getName()
3217 <<" completed digging "<<PP(p_under)
3218 <<", which is not diggable with tool. not digging."
3220 is_valid_dig = false;
3222 // If time is considerably too short, ignore dig
3223 // Check time only for medium and slow timed digs
3224 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
3225 infostream<<"Server: NoCheat: "<<player->getName()
3226 <<" completed digging "
3227 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
3228 <<params.time<<"s; not digging."<<std::endl;
3229 is_valid_dig = false;
3233 /* Actually dig node */
3235 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3236 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3238 // Send unusual result (that is, node not being removed)
3239 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3241 // Re-send block to revert change on client-side
3242 RemoteClient *client = getClient(peer_id);
3243 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3244 client->SetBlockNotSent(blockpos);
3250 3: place block or right-click object
3252 else if(action == 3)
3254 ItemStack item = playersao->getWieldedItem();
3256 // Reset build time counter
3257 if(pointed.type == POINTEDTHING_NODE &&
3258 item.getDefinition(m_itemdef).type == ITEM_NODE)
3259 getClient(peer_id)->m_time_from_building = 0.0;
3261 if(pointed.type == POINTEDTHING_OBJECT)
3263 // Right click object
3265 // Skip if object has been removed
3266 if(pointed_object->m_removed)
3269 actionstream<<player->getName()<<" right-clicks object "
3270 <<pointed.object_id<<": "
3271 <<pointed_object->getDescription()<<std::endl;
3274 pointed_object->rightClick(playersao);
3276 else if(scriptapi_item_on_place(m_lua,
3277 item, playersao, pointed))
3279 // Placement was handled in lua
3281 // Apply returned ItemStack
3282 playersao->setWieldedItem(item);
3285 // If item has node placement prediction, always send the above
3286 // node to make sure the client knows what exactly happened
3287 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3288 RemoteClient *client = getClient(peer_id);
3289 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3290 client->SetBlockNotSent(blockpos);
3297 else if(action == 4)
3299 ItemStack item = playersao->getWieldedItem();
3301 actionstream<<player->getName()<<" uses "<<item.name
3302 <<", pointing at "<<pointed.dump()<<std::endl;
3304 if(scriptapi_item_on_use(m_lua,
3305 item, playersao, pointed))
3307 // Apply returned ItemStack
3308 playersao->setWieldedItem(item);
3315 Catch invalid actions
3319 infostream<<"WARNING: Server: Invalid action "
3320 <<action<<std::endl;
3323 else if(command == TOSERVER_REMOVED_SOUNDS)
3325 std::string datastring((char*)&data[2], datasize-2);
3326 std::istringstream is(datastring, std::ios_base::binary);
3328 int num = readU16(is);
3329 for(int k=0; k<num; k++){
3330 s32 id = readS32(is);
3331 std::map<s32, ServerPlayingSound>::iterator i =
3332 m_playing_sounds.find(id);
3333 if(i == m_playing_sounds.end())
3335 ServerPlayingSound &psound = i->second;
3336 psound.clients.erase(peer_id);
3337 if(psound.clients.size() == 0)
3338 m_playing_sounds.erase(i++);
3341 else if(command == TOSERVER_NODEMETA_FIELDS)
3343 std::string datastring((char*)&data[2], datasize-2);
3344 std::istringstream is(datastring, std::ios_base::binary);
3346 v3s16 p = readV3S16(is);
3347 std::string formname = deSerializeString(is);
3348 int num = readU16(is);
3349 std::map<std::string, std::string> fields;
3350 for(int k=0; k<num; k++){
3351 std::string fieldname = deSerializeString(is);
3352 std::string fieldvalue = deSerializeLongString(is);
3353 fields[fieldname] = fieldvalue;
3356 // If something goes wrong, this player is to blame
3357 RollbackScopeActor rollback_scope(m_rollback,
3358 std::string("player:")+player->getName());
3360 // Check the target node for rollback data; leave others unnoticed
3361 RollbackNode rn_old(&m_env->getMap(), p, this);
3363 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3366 // Report rollback data
3367 RollbackNode rn_new(&m_env->getMap(), p, this);
3368 if(rollback() && rn_new != rn_old){
3369 RollbackAction action;
3370 action.setSetNode(p, rn_old, rn_new);
3371 rollback()->reportAction(action);
3374 else if(command == TOSERVER_INVENTORY_FIELDS)
3376 std::string datastring((char*)&data[2], datasize-2);
3377 std::istringstream is(datastring, std::ios_base::binary);
3379 std::string formname = deSerializeString(is);
3380 int num = readU16(is);
3381 std::map<std::string, std::string> fields;
3382 for(int k=0; k<num; k++){
3383 std::string fieldname = deSerializeString(is);
3384 std::string fieldvalue = deSerializeLongString(is);
3385 fields[fieldname] = fieldvalue;
3388 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3392 infostream<<"Server::ProcessData(): Ignoring "
3393 "unknown command "<<command<<std::endl;
3397 catch(SendFailedException &e)
3399 errorstream<<"Server::ProcessData(): SendFailedException: "
3405 void Server::onMapEditEvent(MapEditEvent *event)
3407 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3408 if(m_ignore_map_edit_events)
3410 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3412 MapEditEvent *e = event->clone();
3413 m_unsent_map_edit_queue.push_back(e);
3416 Inventory* Server::getInventory(const InventoryLocation &loc)
3419 case InventoryLocation::UNDEFINED:
3422 case InventoryLocation::CURRENT_PLAYER:
3425 case InventoryLocation::PLAYER:
3427 Player *player = m_env->getPlayer(loc.name.c_str());
3430 PlayerSAO *playersao = player->getPlayerSAO();
3433 return playersao->getInventory();
3436 case InventoryLocation::NODEMETA:
3438 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3441 return meta->getInventory();
3444 case InventoryLocation::DETACHED:
3446 if(m_detached_inventories.count(loc.name) == 0)
3448 return m_detached_inventories[loc.name];
3456 void Server::setInventoryModified(const InventoryLocation &loc)
3459 case InventoryLocation::UNDEFINED:
3462 case InventoryLocation::PLAYER:
3464 Player *player = m_env->getPlayer(loc.name.c_str());
3467 PlayerSAO *playersao = player->getPlayerSAO();
3470 playersao->m_inventory_not_sent = true;
3471 playersao->m_wielded_item_not_sent = true;
3474 case InventoryLocation::NODEMETA:
3476 v3s16 blockpos = getNodeBlockPos(loc.p);
3478 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3480 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3482 setBlockNotSent(blockpos);
3485 case InventoryLocation::DETACHED:
3487 sendDetachedInventoryToAll(loc.name);
3495 core::list<PlayerInfo> Server::getPlayerInfo()
3497 DSTACK(__FUNCTION_NAME);
3498 JMutexAutoLock envlock(m_env_mutex);
3499 JMutexAutoLock conlock(m_con_mutex);
3501 core::list<PlayerInfo> list;
3503 core::list<Player*> players = m_env->getPlayers();
3505 core::list<Player*>::Iterator i;
3506 for(i = players.begin();
3507 i != players.end(); i++)
3511 Player *player = *i;
3514 // Copy info from connection to info struct
3515 info.id = player->peer_id;
3516 info.address = m_con.GetPeerAddress(player->peer_id);
3517 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3519 catch(con::PeerNotFoundException &e)
3521 // Set dummy peer info
3523 info.address = Address(0,0,0,0,0);
3527 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3528 info.position = player->getPosition();
3530 list.push_back(info);
3537 void Server::peerAdded(con::Peer *peer)
3539 DSTACK(__FUNCTION_NAME);
3540 verbosestream<<"Server::peerAdded(): peer->id="
3541 <<peer->id<<std::endl;
3544 c.type = PEER_ADDED;
3545 c.peer_id = peer->id;
3547 m_peer_change_queue.push_back(c);
3550 void Server::deletingPeer(con::Peer *peer, bool timeout)
3552 DSTACK(__FUNCTION_NAME);
3553 verbosestream<<"Server::deletingPeer(): peer->id="
3554 <<peer->id<<", timeout="<<timeout<<std::endl;
3557 c.type = PEER_REMOVED;
3558 c.peer_id = peer->id;
3559 c.timeout = timeout;
3560 m_peer_change_queue.push_back(c);
3567 void Server::SendMovement(con::Connection &con, u16 peer_id)
3569 DSTACK(__FUNCTION_NAME);
3570 std::ostringstream os(std::ios_base::binary);
3572 writeU16(os, TOCLIENT_MOVEMENT);
3573 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3574 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3575 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3576 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3577 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3578 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3579 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3580 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3581 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3582 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3583 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3584 writeF1000(os, g_settings->getFloat("movement_gravity"));
3587 std::string s = os.str();
3588 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3590 con.Send(peer_id, 0, data, true);
3593 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3595 DSTACK(__FUNCTION_NAME);
3596 std::ostringstream os(std::ios_base::binary);
3598 writeU16(os, TOCLIENT_HP);
3602 std::string s = os.str();
3603 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3605 con.Send(peer_id, 0, data, true);
3608 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3609 const std::wstring &reason)
3611 DSTACK(__FUNCTION_NAME);
3612 std::ostringstream os(std::ios_base::binary);
3614 writeU16(os, TOCLIENT_ACCESS_DENIED);
3615 os<<serializeWideString(reason);
3618 std::string s = os.str();
3619 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3621 con.Send(peer_id, 0, data, true);
3624 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3625 bool set_camera_point_target, v3f camera_point_target)
3627 DSTACK(__FUNCTION_NAME);
3628 std::ostringstream os(std::ios_base::binary);
3630 writeU16(os, TOCLIENT_DEATHSCREEN);
3631 writeU8(os, set_camera_point_target);
3632 writeV3F1000(os, camera_point_target);
3635 std::string s = os.str();
3636 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3638 con.Send(peer_id, 0, data, true);
3641 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3642 IItemDefManager *itemdef)
3644 DSTACK(__FUNCTION_NAME);
3645 std::ostringstream os(std::ios_base::binary);
3649 u32 length of the next item
3650 zlib-compressed serialized ItemDefManager
3652 writeU16(os, TOCLIENT_ITEMDEF);
3653 std::ostringstream tmp_os(std::ios::binary);
3654 itemdef->serialize(tmp_os);
3655 std::ostringstream tmp_os2(std::ios::binary);
3656 compressZlib(tmp_os.str(), tmp_os2);
3657 os<<serializeLongString(tmp_os2.str());
3660 std::string s = os.str();
3661 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3662 <<"): size="<<s.size()<<std::endl;
3663 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3665 con.Send(peer_id, 0, data, true);
3668 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3669 INodeDefManager *nodedef, u16 protocol_version)
3671 DSTACK(__FUNCTION_NAME);
3672 std::ostringstream os(std::ios_base::binary);
3676 u32 length of the next item
3677 zlib-compressed serialized NodeDefManager
3679 writeU16(os, TOCLIENT_NODEDEF);
3680 std::ostringstream tmp_os(std::ios::binary);
3681 nodedef->serialize(tmp_os, protocol_version);
3682 std::ostringstream tmp_os2(std::ios::binary);
3683 compressZlib(tmp_os.str(), tmp_os2);
3684 os<<serializeLongString(tmp_os2.str());
3687 std::string s = os.str();
3688 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3689 <<"): size="<<s.size()<<std::endl;
3690 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3692 con.Send(peer_id, 0, data, true);
3696 Non-static send methods
3699 void Server::SendInventory(u16 peer_id)
3701 DSTACK(__FUNCTION_NAME);
3703 PlayerSAO *playersao = getPlayerSAO(peer_id);
3706 playersao->m_inventory_not_sent = false;
3712 std::ostringstream os;
3713 playersao->getInventory()->serialize(os);
3715 std::string s = os.str();
3717 SharedBuffer<u8> data(s.size()+2);
3718 writeU16(&data[0], TOCLIENT_INVENTORY);
3719 memcpy(&data[2], s.c_str(), s.size());
3722 m_con.Send(peer_id, 0, data, true);
3725 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3727 DSTACK(__FUNCTION_NAME);
3729 std::ostringstream os(std::ios_base::binary);
3733 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3734 os.write((char*)buf, 2);
3737 writeU16(buf, message.size());
3738 os.write((char*)buf, 2);
3741 for(u32 i=0; i<message.size(); i++)
3745 os.write((char*)buf, 2);
3749 std::string s = os.str();
3750 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3752 m_con.Send(peer_id, 0, data, true);
3754 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3756 DSTACK(__FUNCTION_NAME);
3758 std::ostringstream os(std::ios_base::binary);
3762 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3763 os.write((char*)buf, 2);
3764 os<<serializeLongString(formspec);
3765 os<<serializeString(formname);
3768 std::string s = os.str();
3769 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3771 m_con.Send(peer_id, 0, data, true);
3774 void Server::BroadcastChatMessage(const std::wstring &message)
3776 for(core::map<u16, RemoteClient*>::Iterator
3777 i = m_clients.getIterator();
3778 i.atEnd() == false; i++)
3780 // Get client and check that it is valid
3781 RemoteClient *client = i.getNode()->getValue();
3782 assert(client->peer_id == i.getNode()->getKey());
3783 if(client->serialization_version == SER_FMT_VER_INVALID)
3786 SendChatMessage(client->peer_id, message);
3790 void Server::SendPlayerHP(u16 peer_id)
3792 DSTACK(__FUNCTION_NAME);
3793 PlayerSAO *playersao = getPlayerSAO(peer_id);
3795 playersao->m_hp_not_sent = false;
3796 SendHP(m_con, peer_id, playersao->getHP());
3799 void Server::SendMovePlayer(u16 peer_id)
3801 DSTACK(__FUNCTION_NAME);
3802 Player *player = m_env->getPlayer(peer_id);
3805 std::ostringstream os(std::ios_base::binary);
3806 writeU16(os, TOCLIENT_MOVE_PLAYER);
3807 writeV3F1000(os, player->getPosition());
3808 writeF1000(os, player->getPitch());
3809 writeF1000(os, player->getYaw());
3812 v3f pos = player->getPosition();
3813 f32 pitch = player->getPitch();
3814 f32 yaw = player->getYaw();
3815 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3816 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3823 std::string s = os.str();
3824 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3826 m_con.Send(peer_id, 0, data, true);
3829 void Server::SendPlayerPrivileges(u16 peer_id)
3831 Player *player = m_env->getPlayer(peer_id);
3833 if(player->peer_id == PEER_ID_INEXISTENT)
3836 std::set<std::string> privs;
3837 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3839 std::ostringstream os(std::ios_base::binary);
3840 writeU16(os, TOCLIENT_PRIVILEGES);
3841 writeU16(os, privs.size());
3842 for(std::set<std::string>::const_iterator i = privs.begin();
3843 i != privs.end(); i++){
3844 os<<serializeString(*i);
3848 std::string s = os.str();
3849 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3851 m_con.Send(peer_id, 0, data, true);
3854 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3856 Player *player = m_env->getPlayer(peer_id);
3858 if(player->peer_id == PEER_ID_INEXISTENT)
3861 std::ostringstream os(std::ios_base::binary);
3862 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3863 os<<serializeLongString(player->inventory_formspec);
3866 std::string s = os.str();
3867 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3869 m_con.Send(peer_id, 0, data, true);
3872 s32 Server::playSound(const SimpleSoundSpec &spec,
3873 const ServerSoundParams ¶ms)
3875 // Find out initial position of sound
3876 bool pos_exists = false;
3877 v3f pos = params.getPos(m_env, &pos_exists);
3878 // If position is not found while it should be, cancel sound
3879 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3881 // Filter destination clients
3882 std::set<RemoteClient*> dst_clients;
3883 if(params.to_player != "")
3885 Player *player = m_env->getPlayer(params.to_player.c_str());
3887 infostream<<"Server::playSound: Player \""<<params.to_player
3888 <<"\" not found"<<std::endl;
3891 if(player->peer_id == PEER_ID_INEXISTENT){
3892 infostream<<"Server::playSound: Player \""<<params.to_player
3893 <<"\" not connected"<<std::endl;
3896 RemoteClient *client = getClient(player->peer_id);
3897 dst_clients.insert(client);
3901 for(core::map<u16, RemoteClient*>::Iterator
3902 i = m_clients.getIterator(); i.atEnd() == false; i++)
3904 RemoteClient *client = i.getNode()->getValue();
3905 Player *player = m_env->getPlayer(client->peer_id);
3909 if(player->getPosition().getDistanceFrom(pos) >
3910 params.max_hear_distance)
3913 dst_clients.insert(client);
3916 if(dst_clients.size() == 0)
3919 s32 id = m_next_sound_id++;
3920 // The sound will exist as a reference in m_playing_sounds
3921 m_playing_sounds[id] = ServerPlayingSound();
3922 ServerPlayingSound &psound = m_playing_sounds[id];
3923 psound.params = params;
3924 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3925 i != dst_clients.end(); i++)
3926 psound.clients.insert((*i)->peer_id);
3928 std::ostringstream os(std::ios_base::binary);
3929 writeU16(os, TOCLIENT_PLAY_SOUND);
3931 os<<serializeString(spec.name);
3932 writeF1000(os, spec.gain * params.gain);
3933 writeU8(os, params.type);
3934 writeV3F1000(os, pos);
3935 writeU16(os, params.object);
3936 writeU8(os, params.loop);
3938 std::string s = os.str();
3939 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3941 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3942 i != dst_clients.end(); i++){
3944 m_con.Send((*i)->peer_id, 0, data, true);
3948 void Server::stopSound(s32 handle)
3950 // Get sound reference
3951 std::map<s32, ServerPlayingSound>::iterator i =
3952 m_playing_sounds.find(handle);
3953 if(i == m_playing_sounds.end())
3955 ServerPlayingSound &psound = i->second;
3957 std::ostringstream os(std::ios_base::binary);
3958 writeU16(os, TOCLIENT_STOP_SOUND);
3959 writeS32(os, handle);
3961 std::string s = os.str();
3962 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3964 for(std::set<u16>::iterator i = psound.clients.begin();
3965 i != psound.clients.end(); i++){
3967 m_con.Send(*i, 0, data, true);
3969 // Remove sound reference
3970 m_playing_sounds.erase(i);
3973 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3974 core::list<u16> *far_players, float far_d_nodes)
3976 float maxd = far_d_nodes*BS;
3977 v3f p_f = intToFloat(p, BS);
3981 SharedBuffer<u8> reply(replysize);
3982 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3983 writeS16(&reply[2], p.X);
3984 writeS16(&reply[4], p.Y);
3985 writeS16(&reply[6], p.Z);
3987 for(core::map<u16, RemoteClient*>::Iterator
3988 i = m_clients.getIterator();
3989 i.atEnd() == false; i++)
3991 // Get client and check that it is valid
3992 RemoteClient *client = i.getNode()->getValue();
3993 assert(client->peer_id == i.getNode()->getKey());
3994 if(client->serialization_version == SER_FMT_VER_INVALID)
3997 // Don't send if it's the same one
3998 if(client->peer_id == ignore_id)
4004 Player *player = m_env->getPlayer(client->peer_id);
4007 // If player is far away, only set modified blocks not sent
4008 v3f player_pos = player->getPosition();
4009 if(player_pos.getDistanceFrom(p_f) > maxd)
4011 far_players->push_back(client->peer_id);
4018 m_con.Send(client->peer_id, 0, reply, true);
4022 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4023 core::list<u16> *far_players, float far_d_nodes)
4025 float maxd = far_d_nodes*BS;
4026 v3f p_f = intToFloat(p, BS);
4028 for(core::map<u16, RemoteClient*>::Iterator
4029 i = m_clients.getIterator();
4030 i.atEnd() == false; i++)
4032 // Get client and check that it is valid
4033 RemoteClient *client = i.getNode()->getValue();
4034 assert(client->peer_id == i.getNode()->getKey());
4035 if(client->serialization_version == SER_FMT_VER_INVALID)
4038 // Don't send if it's the same one
4039 if(client->peer_id == ignore_id)
4045 Player *player = m_env->getPlayer(client->peer_id);
4048 // If player is far away, only set modified blocks not sent
4049 v3f player_pos = player->getPosition();
4050 if(player_pos.getDistanceFrom(p_f) > maxd)
4052 far_players->push_back(client->peer_id);
4059 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4060 SharedBuffer<u8> reply(replysize);
4061 writeU16(&reply[0], TOCLIENT_ADDNODE);
4062 writeS16(&reply[2], p.X);
4063 writeS16(&reply[4], p.Y);
4064 writeS16(&reply[6], p.Z);
4065 n.serialize(&reply[8], client->serialization_version);
4068 m_con.Send(client->peer_id, 0, reply, true);
4072 void Server::setBlockNotSent(v3s16 p)
4074 for(core::map<u16, RemoteClient*>::Iterator
4075 i = m_clients.getIterator();
4076 i.atEnd()==false; i++)
4078 RemoteClient *client = i.getNode()->getValue();
4079 client->SetBlockNotSent(p);
4083 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4085 DSTACK(__FUNCTION_NAME);
4087 v3s16 p = block->getPos();
4091 bool completely_air = true;
4092 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4093 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4094 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4096 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4098 completely_air = false;
4099 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4104 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4106 infostream<<"[completely air] ";
4107 infostream<<std::endl;
4111 Create a packet with the block in the right format
4114 std::ostringstream os(std::ios_base::binary);
4115 block->serialize(os, ver, false);
4116 std::string s = os.str();
4117 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4119 u32 replysize = 8 + blockdata.getSize();
4120 SharedBuffer<u8> reply(replysize);
4121 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4122 writeS16(&reply[2], p.X);
4123 writeS16(&reply[4], p.Y);
4124 writeS16(&reply[6], p.Z);
4125 memcpy(&reply[8], *blockdata, blockdata.getSize());
4127 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4128 <<": \tpacket size: "<<replysize<<std::endl;*/
4133 m_con.Send(peer_id, 1, reply, true);
4136 void Server::SendBlocks(float dtime)
4138 DSTACK(__FUNCTION_NAME);
4140 JMutexAutoLock envlock(m_env_mutex);
4141 JMutexAutoLock conlock(m_con_mutex);
4143 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4145 core::array<PrioritySortedBlockTransfer> queue;
4147 s32 total_sending = 0;
4150 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4152 for(core::map<u16, RemoteClient*>::Iterator
4153 i = m_clients.getIterator();
4154 i.atEnd() == false; i++)
4156 RemoteClient *client = i.getNode()->getValue();
4157 assert(client->peer_id == i.getNode()->getKey());
4159 // If definitions and textures have not been sent, don't
4160 // send MapBlocks either
4161 if(!client->definitions_sent)
4164 total_sending += client->SendingCount();
4166 if(client->serialization_version == SER_FMT_VER_INVALID)
4169 client->GetNextBlocks(this, dtime, queue);
4174 // Lowest priority number comes first.
4175 // Lowest is most important.
4178 for(u32 i=0; i<queue.size(); i++)
4180 //TODO: Calculate limit dynamically
4181 if(total_sending >= g_settings->getS32
4182 ("max_simultaneous_block_sends_server_total"))
4185 PrioritySortedBlockTransfer q = queue[i];
4187 MapBlock *block = NULL;
4190 block = m_env->getMap().getBlockNoCreate(q.pos);
4192 catch(InvalidPositionException &e)
4197 RemoteClient *client = getClient(q.peer_id);
4199 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4201 client->SentBlock(q.pos);
4207 void Server::fillMediaCache()
4209 DSTACK(__FUNCTION_NAME);
4211 infostream<<"Server: Calculating media file checksums"<<std::endl;
4213 // Collect all media file paths
4214 std::list<std::string> paths;
4215 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4216 i != m_mods.end(); i++){
4217 const ModSpec &mod = *i;
4218 paths.push_back(mod.path + DIR_DELIM + "textures");
4219 paths.push_back(mod.path + DIR_DELIM + "sounds");
4220 paths.push_back(mod.path + DIR_DELIM + "media");
4221 paths.push_back(mod.path + DIR_DELIM + "models");
4223 std::string path_all = "textures";
4224 paths.push_back(path_all + DIR_DELIM + "all");
4226 // Collect media file information from paths into cache
4227 for(std::list<std::string>::iterator i = paths.begin();
4228 i != paths.end(); i++)
4230 std::string mediapath = *i;
4231 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4232 for(u32 j=0; j<dirlist.size(); j++){
4233 if(dirlist[j].dir) // Ignode dirs
4235 std::string filename = dirlist[j].name;
4236 // If name contains illegal characters, ignore the file
4237 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4238 infostream<<"Server: ignoring illegal file name: \""
4239 <<filename<<"\""<<std::endl;
4242 // If name is not in a supported format, ignore it
4243 const char *supported_ext[] = {
4244 ".png", ".jpg", ".bmp", ".tga",
4245 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4247 ".x", ".b3d", ".md2", ".obj",
4250 if(removeStringEnd(filename, supported_ext) == ""){
4251 infostream<<"Server: ignoring unsupported file extension: \""
4252 <<filename<<"\""<<std::endl;
4255 // Ok, attempt to load the file and add to cache
4256 std::string filepath = mediapath + DIR_DELIM + filename;
4258 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4259 if(fis.good() == false){
4260 errorstream<<"Server::fillMediaCache(): Could not open \""
4261 <<filename<<"\" for reading"<<std::endl;
4264 std::ostringstream tmp_os(std::ios_base::binary);
4268 fis.read(buf, 1024);
4269 std::streamsize len = fis.gcount();
4270 tmp_os.write(buf, len);
4279 errorstream<<"Server::fillMediaCache(): Failed to read \""
4280 <<filename<<"\""<<std::endl;
4283 if(tmp_os.str().length() == 0){
4284 errorstream<<"Server::fillMediaCache(): Empty file \""
4285 <<filepath<<"\""<<std::endl;
4290 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4292 unsigned char *digest = sha1.getDigest();
4293 std::string sha1_base64 = base64_encode(digest, 20);
4294 std::string sha1_hex = hex_encode((char*)digest, 20);
4298 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4299 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4304 struct SendableMediaAnnouncement
4307 std::string sha1_digest;
4309 SendableMediaAnnouncement(const std::string name_="",
4310 const std::string sha1_digest_=""):
4312 sha1_digest(sha1_digest_)
4316 void Server::sendMediaAnnouncement(u16 peer_id)
4318 DSTACK(__FUNCTION_NAME);
4320 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4323 core::list<SendableMediaAnnouncement> file_announcements;
4325 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4326 i != m_media.end(); i++){
4328 file_announcements.push_back(
4329 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4333 std::ostringstream os(std::ios_base::binary);
4341 u16 length of sha1_digest
4346 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4347 writeU16(os, file_announcements.size());
4349 for(core::list<SendableMediaAnnouncement>::Iterator
4350 j = file_announcements.begin();
4351 j != file_announcements.end(); j++){
4352 os<<serializeString(j->name);
4353 os<<serializeString(j->sha1_digest);
4355 os<<serializeString(g_settings->get("remote_media"));
4358 std::string s = os.str();
4359 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4362 m_con.Send(peer_id, 0, data, true);
4365 struct SendableMedia
4371 SendableMedia(const std::string &name_="", const std::string path_="",
4372 const std::string &data_=""):
4379 void Server::sendRequestedMedia(u16 peer_id,
4380 const core::list<MediaRequest> &tosend)
4382 DSTACK(__FUNCTION_NAME);
4384 verbosestream<<"Server::sendRequestedMedia(): "
4385 <<"Sending files to client"<<std::endl;
4389 // Put 5kB in one bunch (this is not accurate)
4390 u32 bytes_per_bunch = 5000;
4392 core::array< core::list<SendableMedia> > file_bunches;
4393 file_bunches.push_back(core::list<SendableMedia>());
4395 u32 file_size_bunch_total = 0;
4397 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4398 i != tosend.end(); i++)
4400 if(m_media.find(i->name) == m_media.end()){
4401 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4402 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4406 //TODO get path + name
4407 std::string tpath = m_media[(*i).name].path;
4410 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4411 if(fis.good() == false){
4412 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4413 <<tpath<<"\" for reading"<<std::endl;
4416 std::ostringstream tmp_os(std::ios_base::binary);
4420 fis.read(buf, 1024);
4421 std::streamsize len = fis.gcount();
4422 tmp_os.write(buf, len);
4423 file_size_bunch_total += len;
4432 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4433 <<(*i).name<<"\""<<std::endl;
4436 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4437 <<tname<<"\""<<std::endl;*/
4439 file_bunches[file_bunches.size()-1].push_back(
4440 SendableMedia((*i).name, tpath, tmp_os.str()));
4442 // Start next bunch if got enough data
4443 if(file_size_bunch_total >= bytes_per_bunch){
4444 file_bunches.push_back(core::list<SendableMedia>());
4445 file_size_bunch_total = 0;
4450 /* Create and send packets */
4452 u32 num_bunches = file_bunches.size();
4453 for(u32 i=0; i<num_bunches; i++)
4455 std::ostringstream os(std::ios_base::binary);
4459 u16 total number of texture bunches
4460 u16 index of this bunch
4461 u32 number of files in this bunch
4470 writeU16(os, TOCLIENT_MEDIA);
4471 writeU16(os, num_bunches);
4473 writeU32(os, file_bunches[i].size());
4475 for(core::list<SendableMedia>::Iterator
4476 j = file_bunches[i].begin();
4477 j != file_bunches[i].end(); j++){
4478 os<<serializeString(j->name);
4479 os<<serializeLongString(j->data);
4483 std::string s = os.str();
4484 verbosestream<<"Server::sendRequestedMedia(): bunch "
4485 <<i<<"/"<<num_bunches
4486 <<" files="<<file_bunches[i].size()
4487 <<" size=" <<s.size()<<std::endl;
4488 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4490 m_con.Send(peer_id, 0, data, true);
4494 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4496 if(m_detached_inventories.count(name) == 0){
4497 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4500 Inventory *inv = m_detached_inventories[name];
4502 std::ostringstream os(std::ios_base::binary);
4503 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4504 os<<serializeString(name);
4508 std::string s = os.str();
4509 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4511 m_con.Send(peer_id, 0, data, true);
4514 void Server::sendDetachedInventoryToAll(const std::string &name)
4516 DSTACK(__FUNCTION_NAME);
4518 for(core::map<u16, RemoteClient*>::Iterator
4519 i = m_clients.getIterator();
4520 i.atEnd() == false; i++){
4521 RemoteClient *client = i.getNode()->getValue();
4522 sendDetachedInventory(name, client->peer_id);
4526 void Server::sendDetachedInventories(u16 peer_id)
4528 DSTACK(__FUNCTION_NAME);
4530 for(std::map<std::string, Inventory*>::iterator
4531 i = m_detached_inventories.begin();
4532 i != m_detached_inventories.end(); i++){
4533 const std::string &name = i->first;
4534 //Inventory *inv = i->second;
4535 sendDetachedInventory(name, peer_id);
4543 void Server::DiePlayer(u16 peer_id)
4545 DSTACK(__FUNCTION_NAME);
4547 PlayerSAO *playersao = getPlayerSAO(peer_id);
4550 infostream<<"Server::DiePlayer(): Player "
4551 <<playersao->getPlayer()->getName()
4552 <<" dies"<<std::endl;
4554 playersao->setHP(0);
4556 // Trigger scripted stuff
4557 scriptapi_on_dieplayer(m_lua, playersao);
4559 SendPlayerHP(peer_id);
4560 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4563 void Server::RespawnPlayer(u16 peer_id)
4565 DSTACK(__FUNCTION_NAME);
4567 PlayerSAO *playersao = getPlayerSAO(peer_id);
4570 infostream<<"Server::RespawnPlayer(): Player "
4571 <<playersao->getPlayer()->getName()
4572 <<" respawns"<<std::endl;
4574 playersao->setHP(PLAYER_MAX_HP);
4576 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4578 v3f pos = findSpawnPos(m_env->getServerMap());
4579 playersao->setPos(pos);
4583 void Server::UpdateCrafting(u16 peer_id)
4585 DSTACK(__FUNCTION_NAME);
4587 Player* player = m_env->getPlayer(peer_id);
4590 // Get a preview for crafting
4592 getCraftingResult(&player->inventory, preview, false, this);
4594 // Put the new preview in
4595 InventoryList *plist = player->inventory.getList("craftpreview");
4597 assert(plist->getSize() >= 1);
4598 plist->changeItem(0, preview);
4601 RemoteClient* Server::getClient(u16 peer_id)
4603 DSTACK(__FUNCTION_NAME);
4604 //JMutexAutoLock lock(m_con_mutex);
4605 core::map<u16, RemoteClient*>::Node *n;
4606 n = m_clients.find(peer_id);
4607 // A client should exist for all peers
4609 return n->getValue();
4612 std::wstring Server::getStatusString()
4614 std::wostringstream os(std::ios_base::binary);
4617 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4619 os<<L", uptime="<<m_uptime.get();
4620 // Information about clients
4621 core::map<u16, RemoteClient*>::Iterator i;
4624 for(i = m_clients.getIterator(), first = true;
4625 i.atEnd() == false; i++)
4627 // Get client and check that it is valid
4628 RemoteClient *client = i.getNode()->getValue();
4629 assert(client->peer_id == i.getNode()->getKey());
4630 if(client->serialization_version == SER_FMT_VER_INVALID)
4633 Player *player = m_env->getPlayer(client->peer_id);
4634 // Get name of player
4635 std::wstring name = L"unknown";
4637 name = narrow_to_wide(player->getName());
4638 // Add name to information string
4646 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4647 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4648 if(g_settings->get("motd") != "")
4649 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4653 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4655 std::set<std::string> privs;
4656 scriptapi_get_auth(m_lua, name, NULL, &privs);
4660 bool Server::checkPriv(const std::string &name, const std::string &priv)
4662 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4663 return (privs.count(priv) != 0);
4666 void Server::reportPrivsModified(const std::string &name)
4669 for(core::map<u16, RemoteClient*>::Iterator
4670 i = m_clients.getIterator();
4671 i.atEnd() == false; i++){
4672 RemoteClient *client = i.getNode()->getValue();
4673 Player *player = m_env->getPlayer(client->peer_id);
4674 reportPrivsModified(player->getName());
4677 Player *player = m_env->getPlayer(name.c_str());
4680 SendPlayerPrivileges(player->peer_id);
4681 PlayerSAO *sao = player->getPlayerSAO();
4684 sao->updatePrivileges(
4685 getPlayerEffectivePrivs(name),
4690 void Server::reportInventoryFormspecModified(const std::string &name)
4692 Player *player = m_env->getPlayer(name.c_str());
4695 SendPlayerInventoryFormspec(player->peer_id);
4698 // Saves g_settings to configpath given at initialization
4699 void Server::saveConfig()
4701 if(m_path_config != "")
4702 g_settings->updateConfigFile(m_path_config.c_str());
4705 void Server::notifyPlayer(const char *name, const std::wstring msg)
4707 Player *player = m_env->getPlayer(name);
4710 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4713 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4715 Player *player = m_env->getPlayer(playername);
4719 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4723 SendShowFormspecMessage(player->peer_id, formspec, formname);
4727 void Server::notifyPlayers(const std::wstring msg)
4729 BroadcastChatMessage(msg);
4732 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4736 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4737 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4740 Inventory* Server::createDetachedInventory(const std::string &name)
4742 if(m_detached_inventories.count(name) > 0){
4743 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4744 delete m_detached_inventories[name];
4746 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4748 Inventory *inv = new Inventory(m_itemdef);
4750 m_detached_inventories[name] = inv;
4751 sendDetachedInventoryToAll(name);
4758 BoolScopeSet(bool *dst, bool val):
4761 m_orig_state = *m_dst;
4766 *m_dst = m_orig_state;
4773 // actions: time-reversed list
4774 // Return value: success/failure
4775 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4776 std::list<std::string> *log)
4778 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4779 ServerMap *map = (ServerMap*)(&m_env->getMap());
4780 // Disable rollback report sink while reverting
4781 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4783 // Fail if no actions to handle
4784 if(actions.empty()){
4785 log->push_back("Nothing to do.");
4792 for(std::list<RollbackAction>::const_iterator
4793 i = actions.begin();
4794 i != actions.end(); i++)
4796 const RollbackAction &action = *i;
4798 bool success = action.applyRevert(map, this, this);
4801 std::ostringstream os;
4802 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4803 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4805 log->push_back(os.str());
4807 std::ostringstream os;
4808 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4809 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4811 log->push_back(os.str());
4815 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4816 <<" failed"<<std::endl;
4818 // Call it done if less than half failed
4819 return num_failed <= num_tried/2;
4822 // IGameDef interface
4824 IItemDefManager* Server::getItemDefManager()
4828 INodeDefManager* Server::getNodeDefManager()
4832 ICraftDefManager* Server::getCraftDefManager()
4836 ITextureSource* Server::getTextureSource()
4840 IShaderSource* Server::getShaderSource()
4844 u16 Server::allocateUnknownNodeId(const std::string &name)
4846 return m_nodedef->allocateDummy(name);
4848 ISoundManager* Server::getSoundManager()
4850 return &dummySoundManager;
4852 MtEventManager* Server::getEventManager()
4856 IRollbackReportSink* Server::getRollbackReportSink()
4858 if(!m_enable_rollback_recording)
4860 if(!m_rollback_sink_enabled)
4865 IWritableItemDefManager* Server::getWritableItemDefManager()
4869 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4873 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4878 const ModSpec* Server::getModSpec(const std::string &modname)
4880 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4881 i != m_mods.end(); i++){
4882 const ModSpec &mod = *i;
4883 if(mod.name == modname)
4888 void Server::getModNames(core::list<std::string> &modlist)
4890 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4892 modlist.push_back((*i).name);
4895 std::string Server::getBuiltinLuaPath()
4897 return porting::path_share + DIR_DELIM + "builtin";
4900 v3f findSpawnPos(ServerMap &map)
4902 //return v3f(50,50,50)*BS;
4907 nodepos = v2s16(0,0);
4912 s16 water_level = map.m_mgparams->water_level;
4914 // Try to find a good place a few times
4915 for(s32 i=0; i<1000; i++)
4918 // We're going to try to throw the player to this position
4919 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4920 -range + (myrand()%(range*2)));
4921 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4922 // Get ground height at point (fallbacks to heightmap function)
4923 s16 groundheight = map.findGroundLevel(nodepos2d);
4924 // Don't go underwater
4925 if(groundheight <= water_level)
4927 //infostream<<"-> Underwater"<<std::endl;
4930 // Don't go to high places
4931 if(groundheight > water_level + 6)
4933 //infostream<<"-> Underwater"<<std::endl;
4937 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4938 bool is_good = false;
4940 for(s32 i=0; i<10; i++){
4941 v3s16 blockpos = getNodeBlockPos(nodepos);
4942 map.emergeBlock(blockpos, true);
4943 MapNode n = map.getNodeNoEx(nodepos);
4944 if(n.getContent() == CONTENT_AIR){
4955 // Found a good place
4956 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4962 return intToFloat(nodepos, BS);
4965 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4967 RemotePlayer *player = NULL;
4968 bool newplayer = false;
4971 Try to get an existing player
4973 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4975 // If player is already connected, cancel
4976 if(player != NULL && player->peer_id != 0)
4978 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4983 If player with the wanted peer_id already exists, cancel.
4985 if(m_env->getPlayer(peer_id) != NULL)
4987 infostream<<"emergePlayer(): Player with wrong name but same"
4988 " peer_id already exists"<<std::endl;
4993 Create a new player if it doesn't exist yet
4998 player = new RemotePlayer(this);
4999 player->updateName(name);
5001 /* Set player position */
5002 infostream<<"Server: Finding spawn place for player \""
5003 <<name<<"\""<<std::endl;
5004 v3f pos = findSpawnPos(m_env->getServerMap());
5005 player->setPosition(pos);
5007 /* Add player to environment */
5008 m_env->addPlayer(player);
5012 Create a new player active object
5014 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5015 getPlayerEffectivePrivs(player->getName()),
5018 /* Add object to environment */
5019 m_env->addActiveObject(playersao);
5023 scriptapi_on_newplayer(m_lua, playersao);
5025 scriptapi_on_joinplayer(m_lua, playersao);
5030 void Server::handlePeerChange(PeerChange &c)
5032 JMutexAutoLock envlock(m_env_mutex);
5033 JMutexAutoLock conlock(m_con_mutex);
5035 if(c.type == PEER_ADDED)
5042 core::map<u16, RemoteClient*>::Node *n;
5043 n = m_clients.find(c.peer_id);
5044 // The client shouldn't already exist
5048 RemoteClient *client = new RemoteClient();
5049 client->peer_id = c.peer_id;
5050 m_clients.insert(client->peer_id, client);
5053 else if(c.type == PEER_REMOVED)
5060 core::map<u16, RemoteClient*>::Node *n;
5061 n = m_clients.find(c.peer_id);
5062 // The client should exist
5066 Mark objects to be not known by the client
5068 RemoteClient *client = n->getValue();
5070 for(core::map<u16, bool>::Iterator
5071 i = client->m_known_objects.getIterator();
5072 i.atEnd()==false; i++)
5075 u16 id = i.getNode()->getKey();
5076 ServerActiveObject* obj = m_env->getActiveObject(id);
5078 if(obj && obj->m_known_by_count > 0)
5079 obj->m_known_by_count--;
5083 Clear references to playing sounds
5085 for(std::map<s32, ServerPlayingSound>::iterator
5086 i = m_playing_sounds.begin();
5087 i != m_playing_sounds.end();)
5089 ServerPlayingSound &psound = i->second;
5090 psound.clients.erase(c.peer_id);
5091 if(psound.clients.size() == 0)
5092 m_playing_sounds.erase(i++);
5097 Player *player = m_env->getPlayer(c.peer_id);
5099 // Collect information about leaving in chat
5100 std::wstring message;
5104 std::wstring name = narrow_to_wide(player->getName());
5107 message += L" left the game.";
5109 message += L" (timed out)";
5113 /* Run scripts and remove from environment */
5117 PlayerSAO *playersao = player->getPlayerSAO();
5120 scriptapi_on_leaveplayer(m_lua, playersao);
5122 playersao->disconnected();
5132 std::ostringstream os(std::ios_base::binary);
5133 for(core::map<u16, RemoteClient*>::Iterator
5134 i = m_clients.getIterator();
5135 i.atEnd() == false; i++)
5137 RemoteClient *client = i.getNode()->getValue();
5138 assert(client->peer_id == i.getNode()->getKey());
5139 if(client->serialization_version == SER_FMT_VER_INVALID)
5142 Player *player = m_env->getPlayer(client->peer_id);
5145 // Get name of player
5146 os<<player->getName()<<" ";
5149 actionstream<<player->getName()<<" "
5150 <<(c.timeout?"times out.":"leaves game.")
5151 <<" List of players: "
5152 <<os.str()<<std::endl;
5157 delete m_clients[c.peer_id];
5158 m_clients.remove(c.peer_id);
5160 // Send player info to all remaining clients
5161 //SendPlayerInfos();
5163 // Send leave chat message to all remaining clients
5164 if(message.length() != 0)
5165 BroadcastChatMessage(message);
5174 void Server::handlePeerChanges()
5176 while(m_peer_change_queue.size() > 0)
5178 PeerChange c = m_peer_change_queue.pop_front();
5180 verbosestream<<"Server: Handling peer change: "
5181 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5184 handlePeerChange(c);
5188 void dedicated_server_loop(Server &server, bool &kill)
5190 DSTACK(__FUNCTION_NAME);
5192 verbosestream<<"dedicated_server_loop()"<<std::endl;
5194 IntervalLimiter m_profiler_interval;
5198 float steplen = g_settings->getFloat("dedicated_server_step");
5199 // This is kind of a hack but can be done like this
5200 // because server.step() is very light
5202 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5203 sleep_ms((int)(steplen*1000.0));
5205 server.step(steplen);
5207 if(server.getShutdownRequested() || kill)
5209 infostream<<"Dedicated server quitting"<<std::endl;
5211 if(g_settings->getBool("server_announce") == true)
5212 ServerList::sendAnnounce("delete");
5220 float profiler_print_interval =
5221 g_settings->getFloat("profiler_print_interval");
5222 if(profiler_print_interval != 0)
5224 if(m_profiler_interval.step(steplen, profiler_print_interval))
5226 infostream<<"Profiler:"<<std::endl;
5227 g_profiler->print(infostream);
5228 g_profiler->clear();