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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
15 You should have received a copy of the GNU 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.
24 #include "clientserver.h"
26 #include "jmutexautolock.h"
28 #include "constants.h"
31 #include "servercommand.h"
33 #include "content_mapnode.h"
34 #include "content_nodemeta.h"
36 #include "serverobject.h"
41 #include "scriptapi.h"
46 #include "content_abm.h"
52 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
54 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
56 class MapEditEventIgnorer
59 MapEditEventIgnorer(bool *flag):
68 ~MapEditEventIgnorer()
81 void * ServerThread::Thread()
85 log_register_thread("ServerThread");
87 DSTACK(__FUNCTION_NAME);
89 BEGIN_DEBUG_EXCEPTION_HANDLER
94 //TimeTaker timer("AsyncRunStep() + Receive()");
97 //TimeTaker timer("AsyncRunStep()");
98 m_server->AsyncRunStep();
101 //infostream<<"Running m_server->Receive()"<<std::endl;
104 catch(con::NoIncomingDataException &e)
107 catch(con::PeerNotFoundException &e)
109 infostream<<"Server: PeerNotFoundException"<<std::endl;
113 END_DEBUG_EXCEPTION_HANDLER(errorstream)
118 void * EmergeThread::Thread()
122 log_register_thread("EmergeThread");
124 DSTACK(__FUNCTION_NAME);
126 BEGIN_DEBUG_EXCEPTION_HANDLER
128 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
131 Get block info from queue, emerge them and send them
134 After queue is empty, exit.
138 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
142 SharedPtr<QueuedBlockEmerge> q(qptr);
148 Do not generate over-limit
150 if(blockpos_over_limit(p))
153 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
155 //TimeTaker timer("block emerge");
158 Try to emerge it from somewhere.
160 If it is only wanted as optional, only loading from disk
165 Check if any peer wants it as non-optional. In that case it
168 Also decrement the emerge queue count in clients.
171 bool only_from_disk = true;
174 core::map<u16, u8>::Iterator i;
175 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
177 //u16 peer_id = i.getNode()->getKey();
180 u8 flags = i.getNode()->getValue();
181 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
182 only_from_disk = false;
187 if(enable_mapgen_debug_info)
188 infostream<<"EmergeThread: p="
189 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
190 <<"only_from_disk="<<only_from_disk<<std::endl;
192 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
194 MapBlock *block = NULL;
195 bool got_block = true;
196 core::map<v3s16, MapBlock*> modified_blocks;
199 Try to fetch block from memory or disk.
200 If not found and asked to generate, initialize generator.
203 bool started_generate = false;
204 mapgen::BlockMakeData data;
207 JMutexAutoLock envlock(m_server->m_env_mutex);
209 // Load sector if it isn't loaded
210 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
211 map.loadSectorMeta(p2d);
213 // Attempt to load block
214 block = map.getBlockNoCreateNoEx(p);
215 if(!block || block->isDummy() || !block->isGenerated())
217 if(enable_mapgen_debug_info)
218 infostream<<"EmergeThread: not in memory, "
219 <<"attempting to load from disk"<<std::endl;
221 block = map.loadBlock(p);
224 // If could not load and allowed to generate, start generation
225 // inside this same envlock
226 if(only_from_disk == false &&
227 (block == NULL || block->isGenerated() == false)){
228 if(enable_mapgen_debug_info)
229 infostream<<"EmergeThread: generating"<<std::endl;
230 started_generate = true;
232 map.initBlockMake(&data, p);
237 If generator was initialized, generate now when envlock is free.
242 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
244 TimeTaker t("mapgen::make_block()");
246 mapgen::make_block(&data);
248 if(enable_mapgen_debug_info == false)
249 t.stop(true); // Hide output
253 // Lock environment again to access the map
254 JMutexAutoLock envlock(m_server->m_env_mutex);
256 ScopeProfiler sp(g_profiler, "EmergeThread: after "
257 "mapgen::make_block (envlock)", SPT_AVG);
259 // Blit data back on map, update lighting, add mobs and
260 // whatever this does
261 map.finishBlockMake(&data, modified_blocks);
264 block = map.getBlockNoCreateNoEx(p);
266 // If block doesn't exist, don't try doing anything with it
267 // This happens if the block is not in generation boundaries
272 Do some post-generate stuff
275 v3s16 minp = block->getPos()*MAP_BLOCKSIZE;
276 v3s16 maxp = minp + v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
277 scriptapi_environment_on_generated(m_server->m_lua,
280 if(enable_mapgen_debug_info)
281 infostream<<"EmergeThread: ended up with: "
282 <<analyze_block(block)<<std::endl;
285 Ignore map edit events, they will not need to be
286 sent to anybody because the block hasn't been sent
289 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
291 // Activate objects and stuff
292 m_server->m_env->activateBlock(block, 0);
300 Set sent status of modified blocks on clients
303 // NOTE: Server's clients are also behind the connection mutex
304 JMutexAutoLock lock(m_server->m_con_mutex);
307 Add the originally fetched block to the modified list
311 modified_blocks.insert(p, block);
315 Set the modified blocks unsent for all the clients
318 for(core::map<u16, RemoteClient*>::Iterator
319 i = m_server->m_clients.getIterator();
320 i.atEnd() == false; i++)
322 RemoteClient *client = i.getNode()->getValue();
324 if(modified_blocks.size() > 0)
326 // Remove block from sent history
327 client->SetBlocksNotSent(modified_blocks);
333 END_DEBUG_EXCEPTION_HANDLER(errorstream)
335 log_deregister_thread();
340 void RemoteClient::GetNextBlocks(Server *server, float dtime,
341 core::array<PrioritySortedBlockTransfer> &dest)
343 DSTACK(__FUNCTION_NAME);
346 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
349 m_nothing_to_send_pause_timer -= dtime;
350 m_nearest_unsent_reset_timer += dtime;
352 if(m_nothing_to_send_pause_timer >= 0)
357 // Won't send anything if already sending
358 if(m_blocks_sending.size() >= g_settings->getU16
359 ("max_simultaneous_block_sends_per_client"))
361 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
365 //TimeTaker timer("RemoteClient::GetNextBlocks");
367 Player *player = server->m_env->getPlayer(peer_id);
369 assert(player != NULL);
371 v3f playerpos = player->getPosition();
372 v3f playerspeed = player->getSpeed();
373 v3f playerspeeddir(0,0,0);
374 if(playerspeed.getLength() > 1.0*BS)
375 playerspeeddir = playerspeed / playerspeed.getLength();
376 // Predict to next block
377 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
379 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
381 v3s16 center = getNodeBlockPos(center_nodepos);
383 // Camera position and direction
384 v3f camera_pos = player->getEyePosition();
385 v3f camera_dir = v3f(0,0,1);
386 camera_dir.rotateYZBy(player->getPitch());
387 camera_dir.rotateXZBy(player->getYaw());
389 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
390 <<camera_dir.Z<<")"<<std::endl;*/
393 Get the starting value of the block finder radius.
396 if(m_last_center != center)
398 m_nearest_unsent_d = 0;
399 m_last_center = center;
402 /*infostream<<"m_nearest_unsent_reset_timer="
403 <<m_nearest_unsent_reset_timer<<std::endl;*/
405 // Reset periodically to workaround for some bugs or stuff
406 if(m_nearest_unsent_reset_timer > 20.0)
408 m_nearest_unsent_reset_timer = 0;
409 m_nearest_unsent_d = 0;
410 //infostream<<"Resetting m_nearest_unsent_d for "
411 // <<server->getPlayerName(peer_id)<<std::endl;
414 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
415 s16 d_start = m_nearest_unsent_d;
417 //infostream<<"d_start="<<d_start<<std::endl;
419 u16 max_simul_sends_setting = g_settings->getU16
420 ("max_simultaneous_block_sends_per_client");
421 u16 max_simul_sends_usually = max_simul_sends_setting;
424 Check the time from last addNode/removeNode.
426 Decrease send rate if player is building stuff.
428 m_time_from_building += dtime;
429 if(m_time_from_building < g_settings->getFloat(
430 "full_block_send_enable_min_time_from_building"))
432 max_simul_sends_usually
433 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
437 Number of blocks sending + number of blocks selected for sending
439 u32 num_blocks_selected = m_blocks_sending.size();
442 next time d will be continued from the d from which the nearest
443 unsent block was found this time.
445 This is because not necessarily any of the blocks found this
446 time are actually sent.
448 s32 new_nearest_unsent_d = -1;
450 s16 d_max = g_settings->getS16("max_block_send_distance");
451 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
453 // Don't loop very much at a time
454 s16 max_d_increment_at_time = 2;
455 if(d_max > d_start + max_d_increment_at_time)
456 d_max = d_start + max_d_increment_at_time;
457 /*if(d_max_gen > d_start+2)
458 d_max_gen = d_start+2;*/
460 //infostream<<"Starting from "<<d_start<<std::endl;
462 s32 nearest_emerged_d = -1;
463 s32 nearest_emergefull_d = -1;
464 s32 nearest_sent_d = -1;
465 bool queue_is_full = false;
468 for(d = d_start; d <= d_max; d++)
470 /*errorstream<<"checking d="<<d<<" for "
471 <<server->getPlayerName(peer_id)<<std::endl;*/
472 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
475 If m_nearest_unsent_d was changed by the EmergeThread
476 (it can change it to 0 through SetBlockNotSent),
478 Else update m_nearest_unsent_d
480 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
482 d = m_nearest_unsent_d;
483 last_nearest_unsent_d = m_nearest_unsent_d;
487 Get the border/face dot coordinates of a "d-radiused"
490 core::list<v3s16> list;
491 getFacePositions(list, d);
493 core::list<v3s16>::Iterator li;
494 for(li=list.begin(); li!=list.end(); li++)
496 v3s16 p = *li + center;
500 - Don't allow too many simultaneous transfers
501 - EXCEPT when the blocks are very close
503 Also, don't send blocks that are already flying.
506 // Start with the usual maximum
507 u16 max_simul_dynamic = max_simul_sends_usually;
509 // If block is very close, allow full maximum
510 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
511 max_simul_dynamic = max_simul_sends_setting;
513 // Don't select too many blocks for sending
514 if(num_blocks_selected >= max_simul_dynamic)
516 queue_is_full = true;
517 goto queue_full_break;
520 // Don't send blocks that are currently being transferred
521 if(m_blocks_sending.find(p) != NULL)
527 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
528 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
529 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
530 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
531 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
532 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
535 // If this is true, inexistent block will be made from scratch
536 bool generate = d <= d_max_gen;
539 /*// Limit the generating area vertically to 2/3
540 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
543 // Limit the send area vertically to 1/2
544 if(abs(p.Y - center.Y) > d_max / 2)
550 If block is far away, don't generate it unless it is
556 // Block center y in nodes
557 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
558 // Don't generate if it's very high or very low
559 if(y < -64 || y > 64)
563 v2s16 p2d_nodes_center(
567 // Get ground height in nodes
568 s16 gh = server->m_env->getServerMap().findGroundLevel(
571 // If differs a lot, don't generate
572 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
574 // Actually, don't even send it
580 //infostream<<"d="<<d<<std::endl;
583 Don't generate or send if not in sight
584 FIXME This only works if the client uses a small enough
585 FOV setting. The default of 72 degrees is fine.
588 float camera_fov = (72.0*PI/180) * 4./3.;
589 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
595 Don't send already sent blocks
598 if(m_blocks_sent.find(p) != NULL)
605 Check if map has this block
607 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
609 bool surely_not_found_on_disk = false;
610 bool block_is_invalid = false;
613 // Reset usage timer, this block will be of use in the future.
614 block->resetUsageTimer();
616 // Block is dummy if data doesn't exist.
617 // It means it has been not found from disk and not generated
620 surely_not_found_on_disk = true;
623 // Block is valid if lighting is up-to-date and data exists
624 if(block->isValid() == false)
626 block_is_invalid = true;
629 /*if(block->isFullyGenerated() == false)
631 block_is_invalid = true;
636 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
637 v2s16 chunkpos = map->sector_to_chunk(p2d);
638 if(map->chunkNonVolatile(chunkpos) == false)
639 block_is_invalid = true;
641 if(block->isGenerated() == false)
642 block_is_invalid = true;
645 If block is not close, don't send it unless it is near
648 Block is near ground level if night-time mesh
649 differs from day-time mesh.
653 if(block->dayNightDiffed() == false)
660 If block has been marked to not exist on disk (dummy)
661 and generating new ones is not wanted, skip block.
663 if(generate == false && surely_not_found_on_disk == true)
670 Add inexistent block to emerge queue.
672 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
674 //TODO: Get value from somewhere
675 // Allow only one block in emerge queue
676 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
677 // Allow two blocks in queue per client
678 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
680 // Make it more responsive when needing to generate stuff
681 if(surely_not_found_on_disk)
683 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
685 //infostream<<"Adding block to emerge queue"<<std::endl;
687 // Add it to the emerge queue and trigger the thread
690 if(generate == false)
691 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
693 server->m_emerge_queue.addBlock(peer_id, p, flags);
694 server->m_emergethread.trigger();
696 if(nearest_emerged_d == -1)
697 nearest_emerged_d = d;
699 if(nearest_emergefull_d == -1)
700 nearest_emergefull_d = d;
707 if(nearest_sent_d == -1)
711 Add block to send queue
714 /*errorstream<<"sending from d="<<d<<" to "
715 <<server->getPlayerName(peer_id)<<std::endl;*/
717 PrioritySortedBlockTransfer q((float)d, p, peer_id);
721 num_blocks_selected += 1;
726 //infostream<<"Stopped at "<<d<<std::endl;
728 // If nothing was found for sending and nothing was queued for
729 // emerging, continue next time browsing from here
730 if(nearest_emerged_d != -1){
731 new_nearest_unsent_d = nearest_emerged_d;
732 } else if(nearest_emergefull_d != -1){
733 new_nearest_unsent_d = nearest_emergefull_d;
735 if(d > g_settings->getS16("max_block_send_distance")){
736 new_nearest_unsent_d = 0;
737 m_nothing_to_send_pause_timer = 2.0;
738 /*infostream<<"GetNextBlocks(): d wrapped around for "
739 <<server->getPlayerName(peer_id)
740 <<"; setting to 0 and pausing"<<std::endl;*/
742 if(nearest_sent_d != -1)
743 new_nearest_unsent_d = nearest_sent_d;
745 new_nearest_unsent_d = d;
749 if(new_nearest_unsent_d != -1)
750 m_nearest_unsent_d = new_nearest_unsent_d;
752 /*timer_result = timer.stop(true);
753 if(timer_result != 0)
754 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
757 void RemoteClient::GotBlock(v3s16 p)
759 if(m_blocks_sending.find(p) != NULL)
760 m_blocks_sending.remove(p);
763 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
764 " m_blocks_sending"<<std::endl;*/
765 m_excess_gotblocks++;
767 m_blocks_sent.insert(p, true);
770 void RemoteClient::SentBlock(v3s16 p)
772 if(m_blocks_sending.find(p) == NULL)
773 m_blocks_sending.insert(p, 0.0);
775 infostream<<"RemoteClient::SentBlock(): Sent block"
776 " already in m_blocks_sending"<<std::endl;
779 void RemoteClient::SetBlockNotSent(v3s16 p)
781 m_nearest_unsent_d = 0;
783 if(m_blocks_sending.find(p) != NULL)
784 m_blocks_sending.remove(p);
785 if(m_blocks_sent.find(p) != NULL)
786 m_blocks_sent.remove(p);
789 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
791 m_nearest_unsent_d = 0;
793 for(core::map<v3s16, MapBlock*>::Iterator
794 i = blocks.getIterator();
795 i.atEnd()==false; i++)
797 v3s16 p = i.getNode()->getKey();
799 if(m_blocks_sending.find(p) != NULL)
800 m_blocks_sending.remove(p);
801 if(m_blocks_sent.find(p) != NULL)
802 m_blocks_sent.remove(p);
810 PlayerInfo::PlayerInfo()
816 void PlayerInfo::PrintLine(std::ostream *s)
819 (*s)<<"\""<<name<<"\" ("
820 <<(position.X/10)<<","<<(position.Y/10)
821 <<","<<(position.Z/10)<<") ";
823 (*s)<<" avg_rtt="<<avg_rtt;
827 static std::string padStringRight(std::string s, size_t len)
830 s.insert(s.end(), len - s.size(), ' ');
839 std::string path_world,
840 std::string path_config,
843 m_gamename(gamename),
844 m_path_world(path_world),
845 m_path_config(path_config),
847 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
848 m_authmanager(path_world+DIR_DELIM+"auth.txt"),
849 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
851 m_itemdef(createItemDefManager()),
852 m_nodedef(createNodeDefManager()),
853 m_craftdef(createCraftDefManager()),
855 m_emergethread(this),
857 m_time_of_day_send_timer(0),
859 m_shutdown_requested(false),
860 m_ignore_map_edit_events(false),
861 m_ignore_map_edit_events_peer_id(0)
863 m_liquid_transform_timer = 0.0;
864 m_print_info_timer = 0.0;
865 m_objectdata_timer = 0.0;
866 m_emergethread_trigger_timer = 0.0;
867 m_savemap_timer = 0.0;
871 m_step_dtime_mutex.Init();
874 // Figure out some paths
876 m_path_share = porting::path_share + DIR_DELIM + "server";
878 m_path_game = porting::path_user + DIR_DELIM + "server" + DIR_DELIM
879 + "games" + DIR_DELIM + m_gamename;
880 bool user_game = true; // Game is in user's directory
881 if(!fs::PathExists(m_path_game)){
882 m_path_game = m_path_share + DIR_DELIM + "games" + DIR_DELIM
886 if(!fs::PathExists(m_path_game)){
887 throw ServerError("Could not find game files for game \""
892 m_path_addons.insert(m_path_share + DIR_DELIM + "addons"
893 + DIR_DELIM + m_gamename);
894 m_path_addons.insert(porting::path_user + DIR_DELIM + "server"
895 + DIR_DELIM + "addons" + DIR_DELIM + m_gamename);
897 infostream<<"Server created for gamename=\""<<gamename<<"\""<<std::endl;
898 infostream<<"- path_world = "<<m_path_world<<std::endl;
899 infostream<<"- path_config = "<<m_path_config<<std::endl;
900 infostream<<"- path_game = "<<m_path_game<<std::endl;
901 for(std::set<std::string>::const_iterator i = m_path_addons.begin();
902 i != m_path_addons.end(); i++)
903 infostream<<"- path_addons+= "<<(*i)<<std::endl;
905 // Path to builtin.lua
906 std::string builtinpath = m_path_share + DIR_DELIM + "builtin.lua";
908 // Add default global mod search path
909 m_modspaths.push_front(m_path_game + DIR_DELIM "mods");
910 // Add world mod search path
911 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
912 // Add addon mod search path
913 for(std::set<std::string>::const_iterator i = m_path_addons.begin();
914 i != m_path_addons.end(); i++){
915 m_modspaths.push_front((*i) + DIR_DELIM + "mods");
918 // Print out mod search paths
919 for(core::list<std::string>::Iterator i = m_modspaths.begin();
920 i != m_modspaths.end(); i++){
921 std::string modspath = *i;
922 infostream<<"- modspath += "<<modspath<<std::endl;
926 JMutexAutoLock envlock(m_env_mutex);
927 JMutexAutoLock conlock(m_con_mutex);
929 // Initialize scripting
931 infostream<<"Server: Initializing Lua"<<std::endl;
932 m_lua = script_init();
935 scriptapi_export(m_lua, this);
936 // Load and run builtin.lua
937 infostream<<"Server: Loading builtin.lua [\""
938 <<builtinpath<<"\"]"<<std::endl;
939 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
941 errorstream<<"Server: Failed to load and run "
942 <<builtinpath<<std::endl;
943 throw ModError("Failed to load and run "+builtinpath);
945 // Find mods in mod search paths
946 m_mods = getMods(m_modspaths);
948 infostream<<"Server: Loading mods: ";
949 for(core::list<ModSpec>::Iterator i = m_mods.begin();
950 i != m_mods.end(); i++){
951 const ModSpec &mod = *i;
952 infostream<<mod.name<<" ";
954 infostream<<std::endl;
955 // Load and run "mod" scripts
956 for(core::list<ModSpec>::Iterator i = m_mods.begin();
957 i != m_mods.end(); i++){
958 const ModSpec &mod = *i;
959 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
960 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
961 <<scriptpath<<"\"]"<<std::endl;
962 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
964 errorstream<<"Server: Failed to load and run "
965 <<scriptpath<<std::endl;
966 throw ModError("Failed to load and run "+scriptpath);
970 // Read Textures and calculate sha1 sums
973 // Apply item aliases in the node definition manager
974 m_nodedef->updateAliases(m_itemdef);
976 // Initialize Environment
978 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
981 // Give environment reference to scripting api
982 scriptapi_add_environment(m_lua, m_env);
984 // Register us to receive map edit events
985 m_env->getMap().addEventReceiver(this);
987 // If file exists, load environment metadata
988 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
990 infostream<<"Server: Loading environment metadata"<<std::endl;
991 m_env->loadMeta(m_path_world);
995 infostream<<"Server: Loading players"<<std::endl;
996 m_env->deSerializePlayers(m_path_world);
999 Add some test ActiveBlockModifiers to environment
1001 add_legacy_abms(m_env, m_nodedef);
1006 infostream<<"Server destructing"<<std::endl;
1009 Send shutdown message
1012 JMutexAutoLock conlock(m_con_mutex);
1014 std::wstring line = L"*** Server shutting down";
1017 Send the message to clients
1019 for(core::map<u16, RemoteClient*>::Iterator
1020 i = m_clients.getIterator();
1021 i.atEnd() == false; i++)
1023 // Get client and check that it is valid
1024 RemoteClient *client = i.getNode()->getValue();
1025 assert(client->peer_id == i.getNode()->getKey());
1026 if(client->serialization_version == SER_FMT_VER_INVALID)
1030 SendChatMessage(client->peer_id, line);
1032 catch(con::PeerNotFoundException &e)
1038 JMutexAutoLock envlock(m_env_mutex);
1043 infostream<<"Server: Saving players"<<std::endl;
1044 m_env->serializePlayers(m_path_world);
1047 Save environment metadata
1049 infostream<<"Server: Saving environment metadata"<<std::endl;
1050 m_env->saveMeta(m_path_world);
1062 JMutexAutoLock clientslock(m_con_mutex);
1064 for(core::map<u16, RemoteClient*>::Iterator
1065 i = m_clients.getIterator();
1066 i.atEnd() == false; i++)
1069 // NOTE: These are removed by env destructor
1071 u16 peer_id = i.getNode()->getKey();
1072 JMutexAutoLock envlock(m_env_mutex);
1073 m_env->removePlayer(peer_id);
1077 delete i.getNode()->getValue();
1081 // Delete Environment
1088 // Deinitialize scripting
1089 infostream<<"Server: Deinitializing scripting"<<std::endl;
1090 script_deinit(m_lua);
1093 void Server::start(unsigned short port)
1095 DSTACK(__FUNCTION_NAME);
1096 // Stop thread if already running
1099 // Initialize connection
1100 m_con.SetTimeoutMs(30);
1104 m_thread.setRun(true);
1107 // ASCII art for the win!
1109 <<" .__ __ __ "<<std::endl
1110 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1111 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1112 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1113 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1114 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1115 actionstream<<"Server listening on port "<<port<<"."<<std::endl;
1120 DSTACK(__FUNCTION_NAME);
1122 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1124 // Stop threads (set run=false first so both start stopping)
1125 m_thread.setRun(false);
1126 m_emergethread.setRun(false);
1128 m_emergethread.stop();
1130 infostream<<"Server: Threads stopped"<<std::endl;
1133 void Server::step(float dtime)
1135 DSTACK(__FUNCTION_NAME);
1140 JMutexAutoLock lock(m_step_dtime_mutex);
1141 m_step_dtime += dtime;
1145 void Server::AsyncRunStep()
1147 DSTACK(__FUNCTION_NAME);
1149 g_profiler->add("Server::AsyncRunStep (num)", 1);
1153 JMutexAutoLock lock1(m_step_dtime_mutex);
1154 dtime = m_step_dtime;
1158 // Send blocks to clients
1165 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1167 //infostream<<"Server steps "<<dtime<<std::endl;
1168 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1171 JMutexAutoLock lock1(m_step_dtime_mutex);
1172 m_step_dtime -= dtime;
1179 m_uptime.set(m_uptime.get() + dtime);
1183 // Process connection's timeouts
1184 JMutexAutoLock lock2(m_con_mutex);
1185 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1186 m_con.RunTimeouts(dtime);
1190 // This has to be called so that the client list gets synced
1191 // with the peer list of the connection
1192 handlePeerChanges();
1196 Update m_time_of_day and overall game time
1199 JMutexAutoLock envlock(m_env_mutex);
1201 m_time_counter += dtime;
1202 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1203 u32 units = (u32)(m_time_counter*speed);
1204 m_time_counter -= (f32)units / speed;
1206 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1208 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1211 Send to clients at constant intervals
1214 m_time_of_day_send_timer -= dtime;
1215 if(m_time_of_day_send_timer < 0.0)
1217 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1219 //JMutexAutoLock envlock(m_env_mutex);
1220 JMutexAutoLock conlock(m_con_mutex);
1222 for(core::map<u16, RemoteClient*>::Iterator
1223 i = m_clients.getIterator();
1224 i.atEnd() == false; i++)
1226 RemoteClient *client = i.getNode()->getValue();
1227 //Player *player = m_env->getPlayer(client->peer_id);
1229 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1230 m_env->getTimeOfDay());
1232 m_con.Send(client->peer_id, 0, data, true);
1238 JMutexAutoLock lock(m_env_mutex);
1240 ScopeProfiler sp(g_profiler, "SEnv step");
1241 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1245 const float map_timer_and_unload_dtime = 2.92;
1246 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1248 JMutexAutoLock lock(m_env_mutex);
1249 // Run Map's timers and unload unused data
1250 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1251 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1252 g_settings->getFloat("server_unload_unused_data_timeout"));
1263 JMutexAutoLock lock(m_env_mutex);
1264 JMutexAutoLock lock2(m_con_mutex);
1266 ScopeProfiler sp(g_profiler, "Server: handle players");
1268 //float player_max_speed = BS * 4.0; // Normal speed
1269 float player_max_speed = BS * 20; // Fast speed
1270 float player_max_speed_up = BS * 20;
1272 player_max_speed *= 2.5; // Tolerance
1273 player_max_speed_up *= 2.5;
1275 for(core::map<u16, RemoteClient*>::Iterator
1276 i = m_clients.getIterator();
1277 i.atEnd() == false; i++)
1279 RemoteClient *client = i.getNode()->getValue();
1280 ServerRemotePlayer *player =
1281 static_cast<ServerRemotePlayer*>
1282 (m_env->getPlayer(client->peer_id));
1287 Check player movements
1289 NOTE: Actually the server should handle player physics like the
1290 client does and compare player's position to what is calculated
1291 on our side. This is required when eg. players fly due to an
1294 player->m_last_good_position_age += dtime;
1295 if(player->m_last_good_position_age >= 1.0){
1296 float age = player->m_last_good_position_age;
1297 v3f diff = (player->getPosition() - player->m_last_good_position);
1298 float d_vert = diff.Y;
1300 float d_horiz = diff.getLength();
1301 /*infostream<<player->getName()<<"'s horizontal speed is "
1302 <<(d_horiz/age)<<std::endl;*/
1303 if(d_horiz <= age * player_max_speed &&
1304 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1305 player->m_last_good_position = player->getPosition();
1307 actionstream<<"Player "<<player->getName()
1308 <<" moved too fast; resetting position"
1310 player->setPosition(player->m_last_good_position);
1311 SendMovePlayer(player);
1313 player->m_last_good_position_age = 0;
1317 Handle player HPs (die if hp=0)
1319 if(player->hp == 0 && player->m_hp_not_sent)
1323 Send player inventories and HPs if necessary
1325 if(player->m_inventory_not_sent){
1326 UpdateCrafting(player->peer_id);
1327 SendInventory(player->peer_id);
1329 if(player->m_hp_not_sent){
1330 SendPlayerHP(player);
1336 if(!player->m_is_in_environment){
1337 player->m_removed = false;
1339 m_env->addActiveObject(player);
1344 /* Transform liquids */
1345 m_liquid_transform_timer += dtime;
1346 if(m_liquid_transform_timer >= 1.00)
1348 m_liquid_transform_timer -= 1.00;
1350 JMutexAutoLock lock(m_env_mutex);
1352 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1354 core::map<v3s16, MapBlock*> modified_blocks;
1355 m_env->getMap().transformLiquids(modified_blocks);
1360 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1361 ServerMap &map = ((ServerMap&)m_env->getMap());
1362 map.updateLighting(modified_blocks, lighting_modified_blocks);
1364 // Add blocks modified by lighting to modified_blocks
1365 for(core::map<v3s16, MapBlock*>::Iterator
1366 i = lighting_modified_blocks.getIterator();
1367 i.atEnd() == false; i++)
1369 MapBlock *block = i.getNode()->getValue();
1370 modified_blocks.insert(block->getPos(), block);
1374 Set the modified blocks unsent for all the clients
1377 JMutexAutoLock lock2(m_con_mutex);
1379 for(core::map<u16, RemoteClient*>::Iterator
1380 i = m_clients.getIterator();
1381 i.atEnd() == false; i++)
1383 RemoteClient *client = i.getNode()->getValue();
1385 if(modified_blocks.size() > 0)
1387 // Remove block from sent history
1388 client->SetBlocksNotSent(modified_blocks);
1393 // Periodically print some info
1395 float &counter = m_print_info_timer;
1401 JMutexAutoLock lock2(m_con_mutex);
1403 if(m_clients.size() != 0)
1404 infostream<<"Players:"<<std::endl;
1405 for(core::map<u16, RemoteClient*>::Iterator
1406 i = m_clients.getIterator();
1407 i.atEnd() == false; i++)
1409 //u16 peer_id = i.getNode()->getKey();
1410 RemoteClient *client = i.getNode()->getValue();
1411 Player *player = m_env->getPlayer(client->peer_id);
1414 infostream<<"* "<<player->getName()<<"\t";
1415 client->PrintInfo(infostream);
1420 //if(g_settings->getBool("enable_experimental"))
1424 Check added and deleted active objects
1427 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1428 JMutexAutoLock envlock(m_env_mutex);
1429 JMutexAutoLock conlock(m_con_mutex);
1431 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1433 // Radius inside which objects are active
1434 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1435 radius *= MAP_BLOCKSIZE;
1437 for(core::map<u16, RemoteClient*>::Iterator
1438 i = m_clients.getIterator();
1439 i.atEnd() == false; i++)
1441 RemoteClient *client = i.getNode()->getValue();
1443 // If definitions and textures have not been sent, don't
1444 // send objects either
1445 if(!client->definitions_sent)
1448 Player *player = m_env->getPlayer(client->peer_id);
1451 // This can happen if the client timeouts somehow
1452 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1454 <<" has no associated player"<<std::endl;*/
1457 v3s16 pos = floatToInt(player->getPosition(), BS);
1459 core::map<u16, bool> removed_objects;
1460 core::map<u16, bool> added_objects;
1461 m_env->getRemovedActiveObjects(pos, radius,
1462 client->m_known_objects, removed_objects);
1463 m_env->getAddedActiveObjects(pos, radius,
1464 client->m_known_objects, added_objects);
1466 // Ignore if nothing happened
1467 if(removed_objects.size() == 0 && added_objects.size() == 0)
1469 //infostream<<"active objects: none changed"<<std::endl;
1473 std::string data_buffer;
1477 // Handle removed objects
1478 writeU16((u8*)buf, removed_objects.size());
1479 data_buffer.append(buf, 2);
1480 for(core::map<u16, bool>::Iterator
1481 i = removed_objects.getIterator();
1482 i.atEnd()==false; i++)
1485 u16 id = i.getNode()->getKey();
1486 ServerActiveObject* obj = m_env->getActiveObject(id);
1488 // Add to data buffer for sending
1489 writeU16((u8*)buf, i.getNode()->getKey());
1490 data_buffer.append(buf, 2);
1492 // Remove from known objects
1493 client->m_known_objects.remove(i.getNode()->getKey());
1495 if(obj && obj->m_known_by_count > 0)
1496 obj->m_known_by_count--;
1499 // Handle added objects
1500 writeU16((u8*)buf, added_objects.size());
1501 data_buffer.append(buf, 2);
1502 for(core::map<u16, bool>::Iterator
1503 i = added_objects.getIterator();
1504 i.atEnd()==false; i++)
1507 u16 id = i.getNode()->getKey();
1508 ServerActiveObject* obj = m_env->getActiveObject(id);
1511 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1513 infostream<<"WARNING: "<<__FUNCTION_NAME
1514 <<": NULL object"<<std::endl;
1516 type = obj->getType();
1518 // Add to data buffer for sending
1519 writeU16((u8*)buf, id);
1520 data_buffer.append(buf, 2);
1521 writeU8((u8*)buf, type);
1522 data_buffer.append(buf, 1);
1525 data_buffer.append(serializeLongString(
1526 obj->getClientInitializationData()));
1528 data_buffer.append(serializeLongString(""));
1530 // Add to known objects
1531 client->m_known_objects.insert(i.getNode()->getKey(), false);
1534 obj->m_known_by_count++;
1538 SharedBuffer<u8> reply(2 + data_buffer.size());
1539 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1540 memcpy((char*)&reply[2], data_buffer.c_str(),
1541 data_buffer.size());
1543 m_con.Send(client->peer_id, 0, reply, true);
1545 verbosestream<<"Server: Sent object remove/add: "
1546 <<removed_objects.size()<<" removed, "
1547 <<added_objects.size()<<" added, "
1548 <<"packet size is "<<reply.getSize()<<std::endl;
1553 Collect a list of all the objects known by the clients
1554 and report it back to the environment.
1557 core::map<u16, bool> all_known_objects;
1559 for(core::map<u16, RemoteClient*>::Iterator
1560 i = m_clients.getIterator();
1561 i.atEnd() == false; i++)
1563 RemoteClient *client = i.getNode()->getValue();
1564 // Go through all known objects of client
1565 for(core::map<u16, bool>::Iterator
1566 i = client->m_known_objects.getIterator();
1567 i.atEnd()==false; i++)
1569 u16 id = i.getNode()->getKey();
1570 all_known_objects[id] = true;
1574 m_env->setKnownActiveObjects(whatever);
1580 Send object messages
1583 JMutexAutoLock envlock(m_env_mutex);
1584 JMutexAutoLock conlock(m_con_mutex);
1586 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1589 // Value = data sent by object
1590 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1592 // Get active object messages from environment
1595 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1599 core::list<ActiveObjectMessage>* message_list = NULL;
1600 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1601 n = buffered_messages.find(aom.id);
1604 message_list = new core::list<ActiveObjectMessage>;
1605 buffered_messages.insert(aom.id, message_list);
1609 message_list = n->getValue();
1611 message_list->push_back(aom);
1614 // Route data to every client
1615 for(core::map<u16, RemoteClient*>::Iterator
1616 i = m_clients.getIterator();
1617 i.atEnd()==false; i++)
1619 RemoteClient *client = i.getNode()->getValue();
1620 std::string reliable_data;
1621 std::string unreliable_data;
1622 // Go through all objects in message buffer
1623 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1624 j = buffered_messages.getIterator();
1625 j.atEnd()==false; j++)
1627 // If object is not known by client, skip it
1628 u16 id = j.getNode()->getKey();
1629 if(client->m_known_objects.find(id) == NULL)
1631 // Get message list of object
1632 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1633 // Go through every message
1634 for(core::list<ActiveObjectMessage>::Iterator
1635 k = list->begin(); k != list->end(); k++)
1637 // Compose the full new data with header
1638 ActiveObjectMessage aom = *k;
1639 std::string new_data;
1642 writeU16((u8*)&buf[0], aom.id);
1643 new_data.append(buf, 2);
1645 new_data += serializeString(aom.datastring);
1646 // Add data to buffer
1648 reliable_data += new_data;
1650 unreliable_data += new_data;
1654 reliable_data and unreliable_data are now ready.
1657 if(reliable_data.size() > 0)
1659 SharedBuffer<u8> reply(2 + reliable_data.size());
1660 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1661 memcpy((char*)&reply[2], reliable_data.c_str(),
1662 reliable_data.size());
1664 m_con.Send(client->peer_id, 0, reply, true);
1666 if(unreliable_data.size() > 0)
1668 SharedBuffer<u8> reply(2 + unreliable_data.size());
1669 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1670 memcpy((char*)&reply[2], unreliable_data.c_str(),
1671 unreliable_data.size());
1672 // Send as unreliable
1673 m_con.Send(client->peer_id, 0, reply, false);
1676 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1678 infostream<<"Server: Size of object message data: "
1679 <<"reliable: "<<reliable_data.size()
1680 <<", unreliable: "<<unreliable_data.size()
1685 // Clear buffered_messages
1686 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1687 i = buffered_messages.getIterator();
1688 i.atEnd()==false; i++)
1690 delete i.getNode()->getValue();
1694 } // enable_experimental
1697 Send queued-for-sending map edit events.
1700 // Don't send too many at a time
1703 // Single change sending is disabled if queue size is not small
1704 bool disable_single_change_sending = false;
1705 if(m_unsent_map_edit_queue.size() >= 4)
1706 disable_single_change_sending = true;
1708 int event_count = m_unsent_map_edit_queue.size();
1710 // We'll log the amount of each
1713 while(m_unsent_map_edit_queue.size() != 0)
1715 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1717 // Players far away from the change are stored here.
1718 // Instead of sending the changes, MapBlocks are set not sent
1720 core::list<u16> far_players;
1722 if(event->type == MEET_ADDNODE)
1724 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1725 prof.add("MEET_ADDNODE", 1);
1726 if(disable_single_change_sending)
1727 sendAddNode(event->p, event->n, event->already_known_by_peer,
1730 sendAddNode(event->p, event->n, event->already_known_by_peer,
1733 else if(event->type == MEET_REMOVENODE)
1735 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1736 prof.add("MEET_REMOVENODE", 1);
1737 if(disable_single_change_sending)
1738 sendRemoveNode(event->p, event->already_known_by_peer,
1741 sendRemoveNode(event->p, event->already_known_by_peer,
1744 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1746 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1747 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1748 setBlockNotSent(event->p);
1750 else if(event->type == MEET_OTHER)
1752 infostream<<"Server: MEET_OTHER"<<std::endl;
1753 prof.add("MEET_OTHER", 1);
1754 for(core::map<v3s16, bool>::Iterator
1755 i = event->modified_blocks.getIterator();
1756 i.atEnd()==false; i++)
1758 v3s16 p = i.getNode()->getKey();
1764 prof.add("unknown", 1);
1765 infostream<<"WARNING: Server: Unknown MapEditEvent "
1766 <<((u32)event->type)<<std::endl;
1770 Set blocks not sent to far players
1772 if(far_players.size() > 0)
1774 // Convert list format to that wanted by SetBlocksNotSent
1775 core::map<v3s16, MapBlock*> modified_blocks2;
1776 for(core::map<v3s16, bool>::Iterator
1777 i = event->modified_blocks.getIterator();
1778 i.atEnd()==false; i++)
1780 v3s16 p = i.getNode()->getKey();
1781 modified_blocks2.insert(p,
1782 m_env->getMap().getBlockNoCreateNoEx(p));
1784 // Set blocks not sent
1785 for(core::list<u16>::Iterator
1786 i = far_players.begin();
1787 i != far_players.end(); i++)
1790 RemoteClient *client = getClient(peer_id);
1793 client->SetBlocksNotSent(modified_blocks2);
1799 /*// Don't send too many at a time
1801 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1805 if(event_count >= 5){
1806 infostream<<"Server: MapEditEvents:"<<std::endl;
1807 prof.print(infostream);
1808 } else if(event_count != 0){
1809 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1810 prof.print(verbosestream);
1816 Trigger emergethread (it somehow gets to a non-triggered but
1817 bysy state sometimes)
1820 float &counter = m_emergethread_trigger_timer;
1826 m_emergethread.trigger();
1830 // Save map, players and auth stuff
1832 float &counter = m_savemap_timer;
1834 if(counter >= g_settings->getFloat("server_map_save_interval"))
1837 JMutexAutoLock lock(m_env_mutex);
1839 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1842 if(m_authmanager.isModified())
1843 m_authmanager.save();
1846 if(m_banmanager.isModified())
1847 m_banmanager.save();
1849 // Save changed parts of map
1850 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1853 m_env->serializePlayers(m_path_world);
1855 // Save environment metadata
1856 m_env->saveMeta(m_path_world);
1861 void Server::Receive()
1863 DSTACK(__FUNCTION_NAME);
1864 SharedBuffer<u8> data;
1869 JMutexAutoLock conlock(m_con_mutex);
1870 datasize = m_con.Receive(peer_id, data);
1873 // This has to be called so that the client list gets synced
1874 // with the peer list of the connection
1875 handlePeerChanges();
1877 ProcessData(*data, datasize, peer_id);
1879 catch(con::InvalidIncomingDataException &e)
1881 infostream<<"Server::Receive(): "
1882 "InvalidIncomingDataException: what()="
1883 <<e.what()<<std::endl;
1885 catch(con::PeerNotFoundException &e)
1887 //NOTE: This is not needed anymore
1889 // The peer has been disconnected.
1890 // Find the associated player and remove it.
1892 /*JMutexAutoLock envlock(m_env_mutex);
1894 infostream<<"ServerThread: peer_id="<<peer_id
1895 <<" has apparently closed connection. "
1896 <<"Removing player."<<std::endl;
1898 m_env->removePlayer(peer_id);*/
1902 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1904 DSTACK(__FUNCTION_NAME);
1905 // Environment is locked first.
1906 JMutexAutoLock envlock(m_env_mutex);
1907 JMutexAutoLock conlock(m_con_mutex);
1909 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1912 Address address = m_con.GetPeerAddress(peer_id);
1914 // drop player if is ip is banned
1915 if(m_banmanager.isIpBanned(address.serializeString())){
1916 SendAccessDenied(m_con, peer_id,
1917 L"Your ip is banned. Banned name was "
1918 +narrow_to_wide(m_banmanager.getBanName(
1919 address.serializeString())));
1920 m_con.DeletePeer(peer_id);
1924 catch(con::PeerNotFoundException &e)
1926 infostream<<"Server::ProcessData(): Cancelling: peer "
1927 <<peer_id<<" not found"<<std::endl;
1931 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1933 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1941 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1943 if(command == TOSERVER_INIT)
1945 // [0] u16 TOSERVER_INIT
1946 // [2] u8 SER_FMT_VER_HIGHEST
1947 // [3] u8[20] player_name
1948 // [23] u8[28] password <--- can be sent without this, from old versions
1950 if(datasize < 2+1+PLAYERNAME_SIZE)
1953 verbosestream<<"Server: Got TOSERVER_INIT from "
1954 <<peer_id<<std::endl;
1956 // First byte after command is maximum supported
1957 // serialization version
1958 u8 client_max = data[2];
1959 u8 our_max = SER_FMT_VER_HIGHEST;
1960 // Use the highest version supported by both
1961 u8 deployed = core::min_(client_max, our_max);
1962 // If it's lower than the lowest supported, give up.
1963 if(deployed < SER_FMT_VER_LOWEST)
1964 deployed = SER_FMT_VER_INVALID;
1966 //peer->serialization_version = deployed;
1967 getClient(peer_id)->pending_serialization_version = deployed;
1969 if(deployed == SER_FMT_VER_INVALID)
1971 actionstream<<"Server: A mismatched client tried to connect from "
1972 <<addr_s<<std::endl;
1973 infostream<<"Server: Cannot negotiate "
1974 "serialization version with peer "
1975 <<peer_id<<std::endl;
1976 SendAccessDenied(m_con, peer_id, std::wstring(
1977 L"Your client's version is not supported.\n"
1978 L"Server version is ")
1979 + narrow_to_wide(VERSION_STRING) + L"."
1985 Read and check network protocol version
1988 u16 net_proto_version = 0;
1989 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1991 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1994 getClient(peer_id)->net_proto_version = net_proto_version;
1996 if(net_proto_version == 0)
1998 actionstream<<"Server: An old tried to connect from "<<addr_s
2000 SendAccessDenied(m_con, peer_id, std::wstring(
2001 L"Your client's version is not supported.\n"
2002 L"Server version is ")
2003 + narrow_to_wide(VERSION_STRING) + L"."
2008 if(g_settings->getBool("strict_protocol_version_checking"))
2010 if(net_proto_version != PROTOCOL_VERSION)
2012 actionstream<<"Server: A mismatched client tried to connect"
2013 <<" from "<<addr_s<<std::endl;
2014 SendAccessDenied(m_con, peer_id, std::wstring(
2015 L"Your client's version is not supported.\n"
2016 L"Server version is ")
2017 + narrow_to_wide(VERSION_STRING) + L",\n"
2018 + L"server's PROTOCOL_VERSION is "
2019 + narrow_to_wide(itos(PROTOCOL_VERSION))
2020 + L", client's PROTOCOL_VERSION is "
2021 + narrow_to_wide(itos(net_proto_version))
2032 char playername[PLAYERNAME_SIZE];
2033 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2035 playername[i] = data[3+i];
2037 playername[PLAYERNAME_SIZE-1] = 0;
2039 if(playername[0]=='\0')
2041 actionstream<<"Server: Player with an empty name "
2042 <<"tried to connect from "<<addr_s<<std::endl;
2043 SendAccessDenied(m_con, peer_id,
2048 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2050 actionstream<<"Server: Player with an invalid name "
2051 <<"tried to connect from "<<addr_s<<std::endl;
2052 SendAccessDenied(m_con, peer_id,
2053 L"Name contains unallowed characters");
2057 infostream<<"Server: New connection: \""<<playername<<"\" from "
2058 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2061 char password[PASSWORD_SIZE];
2062 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2064 // old version - assume blank password
2069 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2071 password[i] = data[23+i];
2073 password[PASSWORD_SIZE-1] = 0;
2076 // Add player to auth manager
2077 if(m_authmanager.exists(playername) == false)
2079 std::wstring default_password =
2080 narrow_to_wide(g_settings->get("default_password"));
2081 std::string translated_default_password =
2082 translatePassword(playername, default_password);
2084 // If default_password is empty, allow any initial password
2085 if (default_password.length() == 0)
2086 translated_default_password = password;
2088 infostream<<"Server: adding player "<<playername
2089 <<" to auth manager"<<std::endl;
2090 m_authmanager.add(playername);
2091 m_authmanager.setPassword(playername, translated_default_password);
2092 m_authmanager.setPrivs(playername,
2093 stringToPrivs(g_settings->get("default_privs")));
2094 m_authmanager.save();
2097 std::string checkpwd = m_authmanager.getPassword(playername);
2099 /*infostream<<"Server: Client gave password '"<<password
2100 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2102 if(password != checkpwd)
2104 infostream<<"Server: peer_id="<<peer_id
2105 <<": supplied invalid password for "
2106 <<playername<<std::endl;
2107 SendAccessDenied(m_con, peer_id, L"Invalid password");
2111 // Enforce user limit.
2112 // Don't enforce for users that have some admin right
2113 if(m_clients.size() >= g_settings->getU16("max_users") &&
2114 (m_authmanager.getPrivs(playername)
2115 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2116 playername != g_settings->get("name"))
2118 actionstream<<"Server: "<<playername<<" tried to join, but there"
2119 <<" are already max_users="
2120 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2121 SendAccessDenied(m_con, peer_id, L"Too many users.");
2126 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2128 // If failed, cancel
2131 errorstream<<"Server: peer_id="<<peer_id
2132 <<": failed to emerge player"<<std::endl;
2137 Answer with a TOCLIENT_INIT
2140 SharedBuffer<u8> reply(2+1+6+8);
2141 writeU16(&reply[0], TOCLIENT_INIT);
2142 writeU8(&reply[2], deployed);
2143 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2144 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2147 m_con.Send(peer_id, 0, reply, true);
2151 Send complete position information
2153 SendMovePlayer(player);
2158 if(command == TOSERVER_INIT2)
2160 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2161 <<peer_id<<std::endl;
2164 getClient(peer_id)->serialization_version
2165 = getClient(peer_id)->pending_serialization_version;
2168 Send some initialization data
2171 infostream<<"Server: Sending content to "
2172 <<getPlayerName(peer_id)<<std::endl;
2174 // Send item definitions
2175 SendItemDef(m_con, peer_id, m_itemdef);
2177 // Send node definitions
2178 SendNodeDef(m_con, peer_id, m_nodedef);
2180 // Send texture announcement
2181 SendTextureAnnouncement(peer_id);
2183 // Send player info to all players
2184 //SendPlayerInfos();
2186 // Send inventory to player
2187 UpdateCrafting(peer_id);
2188 SendInventory(peer_id);
2190 // Send player items to all players
2193 Player *player = m_env->getPlayer(peer_id);
2196 SendPlayerHP(player);
2198 // Show death screen if necessary
2200 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2204 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2205 m_env->getTimeOfDay());
2206 m_con.Send(peer_id, 0, data, true);
2209 // Send information about server to player in chat
2210 SendChatMessage(peer_id, getStatusString());
2212 // Send information about joining in chat
2214 std::wstring name = L"unknown";
2215 Player *player = m_env->getPlayer(peer_id);
2217 name = narrow_to_wide(player->getName());
2219 std::wstring message;
2222 message += L" joined game";
2223 BroadcastChatMessage(message);
2226 // Warnings about protocol version can be issued here
2227 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2229 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2236 std::ostringstream os(std::ios_base::binary);
2237 for(core::map<u16, RemoteClient*>::Iterator
2238 i = m_clients.getIterator();
2239 i.atEnd() == false; i++)
2241 RemoteClient *client = i.getNode()->getValue();
2242 assert(client->peer_id == i.getNode()->getKey());
2243 if(client->serialization_version == SER_FMT_VER_INVALID)
2246 Player *player = m_env->getPlayer(client->peer_id);
2249 // Get name of player
2250 os<<player->getName()<<" ";
2253 actionstream<<player->getName()<<" joins game. List of players: "
2254 <<os.str()<<std::endl;
2260 if(peer_ser_ver == SER_FMT_VER_INVALID)
2262 infostream<<"Server::ProcessData(): Cancelling: Peer"
2263 " serialization format invalid or not initialized."
2264 " Skipping incoming command="<<command<<std::endl;
2268 Player *player = m_env->getPlayer(peer_id);
2269 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2272 infostream<<"Server::ProcessData(): Cancelling: "
2273 "No player for peer_id="<<peer_id
2277 if(command == TOSERVER_PLAYERPOS)
2279 if(datasize < 2+12+12+4+4)
2283 v3s32 ps = readV3S32(&data[start+2]);
2284 v3s32 ss = readV3S32(&data[start+2+12]);
2285 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2286 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2287 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2288 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2289 pitch = wrapDegrees(pitch);
2290 yaw = wrapDegrees(yaw);
2292 player->setPosition(position);
2293 player->setSpeed(speed);
2294 player->setPitch(pitch);
2295 player->setYaw(yaw);
2297 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2298 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2299 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2301 else if(command == TOSERVER_GOTBLOCKS)
2314 u16 count = data[2];
2315 for(u16 i=0; i<count; i++)
2317 if((s16)datasize < 2+1+(i+1)*6)
2318 throw con::InvalidIncomingDataException
2319 ("GOTBLOCKS length is too short");
2320 v3s16 p = readV3S16(&data[2+1+i*6]);
2321 /*infostream<<"Server: GOTBLOCKS ("
2322 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2323 RemoteClient *client = getClient(peer_id);
2324 client->GotBlock(p);
2327 else if(command == TOSERVER_DELETEDBLOCKS)
2340 u16 count = data[2];
2341 for(u16 i=0; i<count; i++)
2343 if((s16)datasize < 2+1+(i+1)*6)
2344 throw con::InvalidIncomingDataException
2345 ("DELETEDBLOCKS length is too short");
2346 v3s16 p = readV3S16(&data[2+1+i*6]);
2347 /*infostream<<"Server: DELETEDBLOCKS ("
2348 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2349 RemoteClient *client = getClient(peer_id);
2350 client->SetBlockNotSent(p);
2353 else if(command == TOSERVER_CLICK_OBJECT)
2355 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2358 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2360 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2363 else if(command == TOSERVER_GROUND_ACTION)
2365 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2369 else if(command == TOSERVER_RELEASE)
2371 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2374 else if(command == TOSERVER_SIGNTEXT)
2376 infostream<<"Server: SIGNTEXT not supported anymore"
2380 else if(command == TOSERVER_SIGNNODETEXT)
2382 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2390 std::string datastring((char*)&data[2], datasize-2);
2391 std::istringstream is(datastring, std::ios_base::binary);
2394 is.read((char*)buf, 6);
2395 v3s16 p = readV3S16(buf);
2396 is.read((char*)buf, 2);
2397 u16 textlen = readU16(buf);
2399 for(u16 i=0; i<textlen; i++)
2401 is.read((char*)buf, 1);
2402 text += (char)buf[0];
2405 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2409 meta->setText(text);
2411 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2412 <<" at "<<PP(p)<<std::endl;
2414 v3s16 blockpos = getNodeBlockPos(p);
2415 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2418 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2422 setBlockNotSent(blockpos);
2424 else if(command == TOSERVER_INVENTORY_ACTION)
2426 // Strip command and create a stream
2427 std::string datastring((char*)&data[2], datasize-2);
2428 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2429 std::istringstream is(datastring, std::ios_base::binary);
2431 InventoryAction *a = InventoryAction::deSerialize(is);
2434 infostream<<"TOSERVER_INVENTORY_ACTION: "
2435 <<"InventoryAction::deSerialize() returned NULL"
2441 Note: Always set inventory not sent, to repair cases
2442 where the client made a bad prediction.
2446 Handle restrictions and special cases of the move action
2448 if(a->getType() == IACTION_MOVE)
2450 IMoveAction *ma = (IMoveAction*)a;
2452 ma->from_inv.applyCurrentPlayer(player->getName());
2453 ma->to_inv.applyCurrentPlayer(player->getName());
2455 setInventoryModified(ma->from_inv);
2456 setInventoryModified(ma->to_inv);
2458 bool from_inv_is_current_player =
2459 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2460 (ma->from_inv.name == player->getName());
2462 bool to_inv_is_current_player =
2463 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2464 (ma->to_inv.name == player->getName());
2467 Disable moving items out of craftpreview
2469 if(ma->from_list == "craftpreview")
2471 infostream<<"Ignoring IMoveAction from "
2472 <<(ma->from_inv.dump())<<":"<<ma->from_list
2473 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2474 <<" because src is "<<ma->from_list<<std::endl;
2480 Disable moving items into craftresult and craftpreview
2482 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2484 infostream<<"Ignoring IMoveAction from "
2485 <<(ma->from_inv.dump())<<":"<<ma->from_list
2486 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2487 <<" because dst is "<<ma->to_list<<std::endl;
2492 // Disallow moving items in elsewhere than player's inventory
2493 // if not allowed to interact
2494 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2495 && (!from_inv_is_current_player
2496 || !to_inv_is_current_player))
2498 infostream<<"Cannot move outside of player's inventory: "
2499 <<"No interact privilege"<<std::endl;
2504 // If player is not an admin, check for ownership of src and dst
2505 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2507 std::string owner_from = getInventoryOwner(ma->from_inv);
2508 if(owner_from != "" && owner_from != player->getName())
2510 infostream<<"WARNING: "<<player->getName()
2511 <<" tried to access an inventory that"
2512 <<" belongs to "<<owner_from<<std::endl;
2517 std::string owner_to = getInventoryOwner(ma->to_inv);
2518 if(owner_to != "" && owner_to != player->getName())
2520 infostream<<"WARNING: "<<player->getName()
2521 <<" tried to access an inventory that"
2522 <<" belongs to "<<owner_to<<std::endl;
2529 Handle restrictions and special cases of the drop action
2531 else if(a->getType() == IACTION_DROP)
2533 IDropAction *da = (IDropAction*)a;
2535 da->from_inv.applyCurrentPlayer(player->getName());
2537 setInventoryModified(da->from_inv);
2539 // Disallow dropping items if not allowed to interact
2540 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2545 // If player is not an admin, check for ownership
2546 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2548 std::string owner_from = getInventoryOwner(da->from_inv);
2549 if(owner_from != "" && owner_from != player->getName())
2551 infostream<<"WARNING: "<<player->getName()
2552 <<" tried to access an inventory that"
2553 <<" belongs to "<<owner_from<<std::endl;
2560 Handle restrictions and special cases of the craft action
2562 else if(a->getType() == IACTION_CRAFT)
2564 ICraftAction *ca = (ICraftAction*)a;
2566 ca->craft_inv.applyCurrentPlayer(player->getName());
2568 setInventoryModified(ca->craft_inv);
2570 //bool craft_inv_is_current_player =
2571 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2572 // (ca->craft_inv.name == player->getName());
2574 // Disallow crafting if not allowed to interact
2575 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2577 infostream<<"Cannot craft: "
2578 <<"No interact privilege"<<std::endl;
2583 // If player is not an admin, check for ownership of inventory
2584 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2586 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2587 if(owner_craft != "" && owner_craft != player->getName())
2589 infostream<<"WARNING: "<<player->getName()
2590 <<" tried to access an inventory that"
2591 <<" belongs to "<<owner_craft<<std::endl;
2599 a->apply(this, srp, this);
2603 else if(command == TOSERVER_CHAT_MESSAGE)
2611 std::string datastring((char*)&data[2], datasize-2);
2612 std::istringstream is(datastring, std::ios_base::binary);
2615 is.read((char*)buf, 2);
2616 u16 len = readU16(buf);
2618 std::wstring message;
2619 for(u16 i=0; i<len; i++)
2621 is.read((char*)buf, 2);
2622 message += (wchar_t)readU16(buf);
2625 // Get player name of this client
2626 std::wstring name = narrow_to_wide(player->getName());
2629 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2630 wide_to_narrow(message));
2631 // If script ate the message, don't proceed
2635 // Line to send to players
2637 // Whether to send to the player that sent the line
2638 bool send_to_sender = false;
2639 // Whether to send to other players
2640 bool send_to_others = false;
2642 // Local player gets all privileges regardless of
2643 // what's set on their account.
2644 u64 privs = getPlayerPrivs(player);
2647 if(message[0] == L'/')
2649 size_t strip_size = 1;
2650 if (message[1] == L'#') // support old-style commans
2652 message = message.substr(strip_size);
2654 WStrfnd f1(message);
2655 f1.next(L" "); // Skip over /#whatever
2656 std::wstring paramstring = f1.next(L"");
2658 ServerCommandContext *ctx = new ServerCommandContext(
2659 str_split(message, L' '),
2666 std::wstring reply(processServerCommand(ctx));
2667 send_to_sender = ctx->flags & SEND_TO_SENDER;
2668 send_to_others = ctx->flags & SEND_TO_OTHERS;
2670 if (ctx->flags & SEND_NO_PREFIX)
2673 line += L"Server: " + reply;
2680 if(privs & PRIV_SHOUT)
2686 send_to_others = true;
2690 line += L"Server: You are not allowed to shout";
2691 send_to_sender = true;
2698 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2701 Send the message to clients
2703 for(core::map<u16, RemoteClient*>::Iterator
2704 i = m_clients.getIterator();
2705 i.atEnd() == false; i++)
2707 // Get client and check that it is valid
2708 RemoteClient *client = i.getNode()->getValue();
2709 assert(client->peer_id == i.getNode()->getKey());
2710 if(client->serialization_version == SER_FMT_VER_INVALID)
2714 bool sender_selected = (peer_id == client->peer_id);
2715 if(sender_selected == true && send_to_sender == false)
2717 if(sender_selected == false && send_to_others == false)
2720 SendChatMessage(client->peer_id, line);
2724 else if(command == TOSERVER_DAMAGE)
2726 std::string datastring((char*)&data[2], datasize-2);
2727 std::istringstream is(datastring, std::ios_base::binary);
2728 u8 damage = readU8(is);
2730 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2732 if(g_settings->getBool("enable_damage"))
2734 actionstream<<player->getName()<<" damaged by "
2735 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2738 srp->setHP(srp->getHP() - damage);
2740 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2743 if(srp->m_hp_not_sent)
2744 SendPlayerHP(player);
2748 // Force send (to correct the client's predicted HP)
2749 SendPlayerHP(player);
2752 else if(command == TOSERVER_PASSWORD)
2755 [0] u16 TOSERVER_PASSWORD
2756 [2] u8[28] old password
2757 [30] u8[28] new password
2760 if(datasize != 2+PASSWORD_SIZE*2)
2762 /*char password[PASSWORD_SIZE];
2763 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2764 password[i] = data[2+i];
2765 password[PASSWORD_SIZE-1] = 0;*/
2767 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2775 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2777 char c = data[2+PASSWORD_SIZE+i];
2783 infostream<<"Server: Client requests a password change from "
2784 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2786 std::string playername = player->getName();
2788 if(m_authmanager.exists(playername) == false)
2790 infostream<<"Server: playername not found in authmanager"<<std::endl;
2791 // Wrong old password supplied!!
2792 SendChatMessage(peer_id, L"playername not found in authmanager");
2796 std::string checkpwd = m_authmanager.getPassword(playername);
2798 if(oldpwd != checkpwd)
2800 infostream<<"Server: invalid old password"<<std::endl;
2801 // Wrong old password supplied!!
2802 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2806 actionstream<<player->getName()<<" changes password"<<std::endl;
2808 m_authmanager.setPassword(playername, newpwd);
2810 infostream<<"Server: password change successful for "<<playername
2812 SendChatMessage(peer_id, L"Password change successful");
2814 else if(command == TOSERVER_PLAYERITEM)
2819 u16 item = readU16(&data[2]);
2820 srp->setWieldIndex(item);
2821 SendWieldedItem(srp);
2823 else if(command == TOSERVER_RESPAWN)
2828 RespawnPlayer(player);
2830 actionstream<<player->getName()<<" respawns at "
2831 <<PP(player->getPosition()/BS)<<std::endl;
2833 // ActiveObject is added to environment in AsyncRunStep after
2834 // the previous addition has been succesfully removed
2836 else if(command == TOSERVER_REQUEST_TEXTURES) {
2837 std::string datastring((char*)&data[2], datasize-2);
2838 std::istringstream is(datastring, std::ios_base::binary);
2841 core::list<TextureRequest> tosend;
2842 u16 numtextures = readU16(is);
2844 infostream<<"Sending "<<numtextures<<" textures to "
2845 <<getPlayerName(peer_id)<<std::endl;
2846 verbosestream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2848 for(int i = 0; i < numtextures; i++) {
2849 std::string name = deSerializeString(is);
2850 tosend.push_back(TextureRequest(name));
2851 verbosestream<<"TOSERVER_REQUEST_TEXTURES: requested texture "
2855 SendTexturesRequested(peer_id, tosend);
2857 // Now the client should know about everything
2858 // (definitions and textures)
2859 getClient(peer_id)->definitions_sent = true;
2861 else if(command == TOSERVER_INTERACT)
2863 std::string datastring((char*)&data[2], datasize-2);
2864 std::istringstream is(datastring, std::ios_base::binary);
2870 [5] u32 length of the next item
2871 [9] serialized PointedThing
2873 0: start digging (from undersurface) or use
2874 1: stop digging (all parameters ignored)
2875 2: digging completed
2876 3: place block or item (to abovesurface)
2879 u8 action = readU8(is);
2880 u16 item_i = readU16(is);
2881 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2882 PointedThing pointed;
2883 pointed.deSerialize(tmp_is);
2885 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2886 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2890 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2891 <<" tried to interact, but is dead!"<<std::endl;
2895 v3f player_pos = srp->m_last_good_position;
2897 // Update wielded item
2898 if(srp->getWieldIndex() != item_i)
2900 srp->setWieldIndex(item_i);
2901 SendWieldedItem(srp);
2904 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2905 v3s16 p_under = pointed.node_undersurface;
2906 v3s16 p_above = pointed.node_abovesurface;
2908 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2909 ServerActiveObject *pointed_object = NULL;
2910 if(pointed.type == POINTEDTHING_OBJECT)
2912 pointed_object = m_env->getActiveObject(pointed.object_id);
2913 if(pointed_object == NULL)
2915 verbosestream<<"TOSERVER_INTERACT: "
2916 "pointed object is NULL"<<std::endl;
2922 v3f pointed_pos_under = player_pos;
2923 v3f pointed_pos_above = player_pos;
2924 if(pointed.type == POINTEDTHING_NODE)
2926 pointed_pos_under = intToFloat(p_under, BS);
2927 pointed_pos_above = intToFloat(p_above, BS);
2929 else if(pointed.type == POINTEDTHING_OBJECT)
2931 pointed_pos_under = pointed_object->getBasePosition();
2932 pointed_pos_above = pointed_pos_under;
2936 Check that target is reasonably close
2937 (only when digging or placing things)
2939 if(action == 0 || action == 2 || action == 3)
2941 float d = player_pos.getDistanceFrom(pointed_pos_under);
2942 float max_d = BS * 14; // Just some large enough value
2944 actionstream<<"Player "<<player->getName()
2945 <<" tried to access "<<pointed.dump()
2947 <<"d="<<d<<", max_d="<<max_d
2948 <<". ignoring."<<std::endl;
2949 // Re-send block to revert change on client-side
2950 RemoteClient *client = getClient(peer_id);
2951 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2952 client->SetBlockNotSent(blockpos);
2959 Make sure the player is allowed to do it
2961 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2963 infostream<<"Ignoring interaction from player "<<player->getName()
2964 <<" because privileges are "<<getPlayerPrivs(player)
2970 0: start digging or punch object
2974 if(pointed.type == POINTEDTHING_NODE)
2977 NOTE: This can be used in the future to check if
2978 somebody is cheating, by checking the timing.
2980 MapNode n(CONTENT_IGNORE);
2983 n = m_env->getMap().getNode(p_under);
2985 catch(InvalidPositionException &e)
2987 infostream<<"Server: Not punching: Node not found."
2988 <<" Adding block to emerge queue."
2990 m_emerge_queue.addBlock(peer_id,
2991 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2993 if(n.getContent() != CONTENT_IGNORE)
2994 scriptapi_node_on_punch(m_lua, p_under, n, srp);
2996 else if(pointed.type == POINTEDTHING_OBJECT)
2998 // Skip if object has been removed
2999 if(pointed_object->m_removed)
3002 actionstream<<player->getName()<<" punches object "
3003 <<pointed.object_id<<": "
3004 <<pointed_object->getDescription()<<std::endl;
3006 ItemStack punchitem = srp->getWieldedItem();
3007 ToolCapabilities toolcap =
3008 punchitem.getToolCapabilities(m_itemdef);
3009 v3f dir = (pointed_object->getBasePosition() -
3010 (srp->getPosition() + srp->getEyeOffset())
3012 pointed_object->punch(dir, &toolcap, srp,
3013 srp->m_time_from_last_punch);
3014 srp->m_time_from_last_punch = 0;
3022 else if(action == 1)
3027 2: Digging completed
3029 else if(action == 2)
3031 // Only complete digging of nodes
3032 if(pointed.type == POINTEDTHING_NODE)
3034 MapNode n(CONTENT_IGNORE);
3037 n = m_env->getMap().getNode(p_under);
3039 catch(InvalidPositionException &e)
3041 infostream<<"Server: Not finishing digging: Node not found."
3042 <<" Adding block to emerge queue."
3044 m_emerge_queue.addBlock(peer_id,
3045 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3047 if(n.getContent() != CONTENT_IGNORE)
3048 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3053 3: place block or right-click object
3055 else if(action == 3)
3057 ItemStack item = srp->getWieldedItem();
3059 // Reset build time counter
3060 if(pointed.type == POINTEDTHING_NODE &&
3061 item.getDefinition(m_itemdef).type == ITEM_NODE)
3062 getClient(peer_id)->m_time_from_building = 0.0;
3064 if(pointed.type == POINTEDTHING_OBJECT)
3066 // Right click object
3068 // Skip if object has been removed
3069 if(pointed_object->m_removed)
3072 actionstream<<player->getName()<<" right-clicks object "
3073 <<pointed.object_id<<": "
3074 <<pointed_object->getDescription()<<std::endl;
3077 pointed_object->rightClick(srp);
3079 else if(scriptapi_item_on_place(m_lua,
3080 item, srp, pointed))
3082 // Placement was handled in lua
3084 // Apply returned ItemStack
3085 if(g_settings->getBool("creative_mode") == false)
3086 srp->setWieldedItem(item);
3094 else if(action == 4)
3096 ItemStack item = srp->getWieldedItem();
3098 actionstream<<player->getName()<<" uses "<<item.name
3099 <<", pointing at "<<pointed.dump()<<std::endl;
3101 if(scriptapi_item_on_use(m_lua,
3102 item, srp, pointed))
3104 // Apply returned ItemStack
3105 if(g_settings->getBool("creative_mode") == false)
3106 srp->setWieldedItem(item);
3112 Catch invalid actions
3116 infostream<<"WARNING: Server: Invalid action "
3117 <<action<<std::endl;
3122 infostream<<"Server::ProcessData(): Ignoring "
3123 "unknown command "<<command<<std::endl;
3127 catch(SendFailedException &e)
3129 errorstream<<"Server::ProcessData(): SendFailedException: "
3135 void Server::onMapEditEvent(MapEditEvent *event)
3137 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3138 if(m_ignore_map_edit_events)
3140 MapEditEvent *e = event->clone();
3141 m_unsent_map_edit_queue.push_back(e);
3144 Inventory* Server::getInventory(const InventoryLocation &loc)
3147 case InventoryLocation::UNDEFINED:
3150 case InventoryLocation::CURRENT_PLAYER:
3153 case InventoryLocation::PLAYER:
3155 Player *player = m_env->getPlayer(loc.name.c_str());
3158 return &player->inventory;
3161 case InventoryLocation::NODEMETA:
3163 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3166 return meta->getInventory();
3174 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3177 case InventoryLocation::UNDEFINED:
3180 case InventoryLocation::CURRENT_PLAYER:
3183 case InventoryLocation::PLAYER:
3188 case InventoryLocation::NODEMETA:
3190 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3193 return meta->getOwner();
3201 void Server::setInventoryModified(const InventoryLocation &loc)
3204 case InventoryLocation::UNDEFINED:
3207 case InventoryLocation::PLAYER:
3209 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3210 (m_env->getPlayer(loc.name.c_str()));
3213 srp->m_inventory_not_sent = true;
3216 case InventoryLocation::NODEMETA:
3218 v3s16 blockpos = getNodeBlockPos(loc.p);
3220 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3222 meta->inventoryModified();
3224 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3226 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3228 setBlockNotSent(blockpos);
3236 core::list<PlayerInfo> Server::getPlayerInfo()
3238 DSTACK(__FUNCTION_NAME);
3239 JMutexAutoLock envlock(m_env_mutex);
3240 JMutexAutoLock conlock(m_con_mutex);
3242 core::list<PlayerInfo> list;
3244 core::list<Player*> players = m_env->getPlayers();
3246 core::list<Player*>::Iterator i;
3247 for(i = players.begin();
3248 i != players.end(); i++)
3252 Player *player = *i;
3255 // Copy info from connection to info struct
3256 info.id = player->peer_id;
3257 info.address = m_con.GetPeerAddress(player->peer_id);
3258 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3260 catch(con::PeerNotFoundException &e)
3262 // Set dummy peer info
3264 info.address = Address(0,0,0,0,0);
3268 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3269 info.position = player->getPosition();
3271 list.push_back(info);
3278 void Server::peerAdded(con::Peer *peer)
3280 DSTACK(__FUNCTION_NAME);
3281 verbosestream<<"Server::peerAdded(): peer->id="
3282 <<peer->id<<std::endl;
3285 c.type = PEER_ADDED;
3286 c.peer_id = peer->id;
3288 m_peer_change_queue.push_back(c);
3291 void Server::deletingPeer(con::Peer *peer, bool timeout)
3293 DSTACK(__FUNCTION_NAME);
3294 verbosestream<<"Server::deletingPeer(): peer->id="
3295 <<peer->id<<", timeout="<<timeout<<std::endl;
3298 c.type = PEER_REMOVED;
3299 c.peer_id = peer->id;
3300 c.timeout = timeout;
3301 m_peer_change_queue.push_back(c);
3308 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3310 DSTACK(__FUNCTION_NAME);
3311 std::ostringstream os(std::ios_base::binary);
3313 writeU16(os, TOCLIENT_HP);
3317 std::string s = os.str();
3318 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3320 con.Send(peer_id, 0, data, true);
3323 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3324 const std::wstring &reason)
3326 DSTACK(__FUNCTION_NAME);
3327 std::ostringstream os(std::ios_base::binary);
3329 writeU16(os, TOCLIENT_ACCESS_DENIED);
3330 os<<serializeWideString(reason);
3333 std::string s = os.str();
3334 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3336 con.Send(peer_id, 0, data, true);
3339 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3340 bool set_camera_point_target, v3f camera_point_target)
3342 DSTACK(__FUNCTION_NAME);
3343 std::ostringstream os(std::ios_base::binary);
3345 writeU16(os, TOCLIENT_DEATHSCREEN);
3346 writeU8(os, set_camera_point_target);
3347 writeV3F1000(os, camera_point_target);
3350 std::string s = os.str();
3351 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3353 con.Send(peer_id, 0, data, true);
3356 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3357 IItemDefManager *itemdef)
3359 DSTACK(__FUNCTION_NAME);
3360 std::ostringstream os(std::ios_base::binary);
3364 u32 length of the next item
3365 zlib-compressed serialized ItemDefManager
3367 writeU16(os, TOCLIENT_ITEMDEF);
3368 std::ostringstream tmp_os(std::ios::binary);
3369 itemdef->serialize(tmp_os);
3370 std::ostringstream tmp_os2(std::ios::binary);
3371 compressZlib(tmp_os.str(), tmp_os2);
3372 os<<serializeLongString(tmp_os2.str());
3375 std::string s = os.str();
3376 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3377 <<"): size="<<s.size()<<std::endl;
3378 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3380 con.Send(peer_id, 0, data, true);
3383 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3384 INodeDefManager *nodedef)
3386 DSTACK(__FUNCTION_NAME);
3387 std::ostringstream os(std::ios_base::binary);
3391 u32 length of the next item
3392 zlib-compressed serialized NodeDefManager
3394 writeU16(os, TOCLIENT_NODEDEF);
3395 std::ostringstream tmp_os(std::ios::binary);
3396 nodedef->serialize(tmp_os);
3397 std::ostringstream tmp_os2(std::ios::binary);
3398 compressZlib(tmp_os.str(), tmp_os2);
3399 os<<serializeLongString(tmp_os2.str());
3402 std::string s = os.str();
3403 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3404 <<"): size="<<s.size()<<std::endl;
3405 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3407 con.Send(peer_id, 0, data, true);
3411 Non-static send methods
3414 void Server::SendInventory(u16 peer_id)
3416 DSTACK(__FUNCTION_NAME);
3418 ServerRemotePlayer* player =
3419 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3422 player->m_inventory_not_sent = false;
3428 std::ostringstream os;
3429 //os.imbue(std::locale("C"));
3431 player->inventory.serialize(os);
3433 std::string s = os.str();
3435 SharedBuffer<u8> data(s.size()+2);
3436 writeU16(&data[0], TOCLIENT_INVENTORY);
3437 memcpy(&data[2], s.c_str(), s.size());
3440 m_con.Send(peer_id, 0, data, true);
3443 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3445 DSTACK(__FUNCTION_NAME);
3449 std::ostringstream os(std::ios_base::binary);
3451 writeU16(os, TOCLIENT_PLAYERITEM);
3453 writeU16(os, srp->peer_id);
3454 os<<serializeString(srp->getWieldedItem().getItemString());
3457 std::string s = os.str();
3458 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3460 m_con.SendToAll(0, data, true);
3463 void Server::SendPlayerItems()
3465 DSTACK(__FUNCTION_NAME);
3467 std::ostringstream os(std::ios_base::binary);
3468 core::list<Player *> players = m_env->getPlayers(true);
3470 writeU16(os, TOCLIENT_PLAYERITEM);
3471 writeU16(os, players.size());
3472 core::list<Player *>::Iterator i;
3473 for(i = players.begin(); i != players.end(); ++i)
3476 ServerRemotePlayer *srp =
3477 static_cast<ServerRemotePlayer*>(p);
3478 writeU16(os, p->peer_id);
3479 os<<serializeString(srp->getWieldedItem().getItemString());
3483 std::string s = os.str();
3484 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3486 m_con.SendToAll(0, data, true);
3489 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3491 DSTACK(__FUNCTION_NAME);
3493 std::ostringstream os(std::ios_base::binary);
3497 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3498 os.write((char*)buf, 2);
3501 writeU16(buf, message.size());
3502 os.write((char*)buf, 2);
3505 for(u32 i=0; i<message.size(); i++)
3509 os.write((char*)buf, 2);
3513 std::string s = os.str();
3514 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3516 m_con.Send(peer_id, 0, data, true);
3519 void Server::BroadcastChatMessage(const std::wstring &message)
3521 for(core::map<u16, RemoteClient*>::Iterator
3522 i = m_clients.getIterator();
3523 i.atEnd() == false; i++)
3525 // Get client and check that it is valid
3526 RemoteClient *client = i.getNode()->getValue();
3527 assert(client->peer_id == i.getNode()->getKey());
3528 if(client->serialization_version == SER_FMT_VER_INVALID)
3531 SendChatMessage(client->peer_id, message);
3535 void Server::SendPlayerHP(Player *player)
3537 SendHP(m_con, player->peer_id, player->hp);
3538 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3541 void Server::SendMovePlayer(Player *player)
3543 DSTACK(__FUNCTION_NAME);
3544 std::ostringstream os(std::ios_base::binary);
3546 writeU16(os, TOCLIENT_MOVE_PLAYER);
3547 writeV3F1000(os, player->getPosition());
3548 writeF1000(os, player->getPitch());
3549 writeF1000(os, player->getYaw());
3552 v3f pos = player->getPosition();
3553 f32 pitch = player->getPitch();
3554 f32 yaw = player->getYaw();
3555 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3556 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3563 std::string s = os.str();
3564 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3566 m_con.Send(player->peer_id, 0, data, true);
3569 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3570 core::list<u16> *far_players, float far_d_nodes)
3572 float maxd = far_d_nodes*BS;
3573 v3f p_f = intToFloat(p, BS);
3577 SharedBuffer<u8> reply(replysize);
3578 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3579 writeS16(&reply[2], p.X);
3580 writeS16(&reply[4], p.Y);
3581 writeS16(&reply[6], p.Z);
3583 for(core::map<u16, RemoteClient*>::Iterator
3584 i = m_clients.getIterator();
3585 i.atEnd() == false; i++)
3587 // Get client and check that it is valid
3588 RemoteClient *client = i.getNode()->getValue();
3589 assert(client->peer_id == i.getNode()->getKey());
3590 if(client->serialization_version == SER_FMT_VER_INVALID)
3593 // Don't send if it's the same one
3594 if(client->peer_id == ignore_id)
3600 Player *player = m_env->getPlayer(client->peer_id);
3603 // If player is far away, only set modified blocks not sent
3604 v3f player_pos = player->getPosition();
3605 if(player_pos.getDistanceFrom(p_f) > maxd)
3607 far_players->push_back(client->peer_id);
3614 m_con.Send(client->peer_id, 0, reply, true);
3618 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3619 core::list<u16> *far_players, float far_d_nodes)
3621 float maxd = far_d_nodes*BS;
3622 v3f p_f = intToFloat(p, BS);
3624 for(core::map<u16, RemoteClient*>::Iterator
3625 i = m_clients.getIterator();
3626 i.atEnd() == false; i++)
3628 // Get client and check that it is valid
3629 RemoteClient *client = i.getNode()->getValue();
3630 assert(client->peer_id == i.getNode()->getKey());
3631 if(client->serialization_version == SER_FMT_VER_INVALID)
3634 // Don't send if it's the same one
3635 if(client->peer_id == ignore_id)
3641 Player *player = m_env->getPlayer(client->peer_id);
3644 // If player is far away, only set modified blocks not sent
3645 v3f player_pos = player->getPosition();
3646 if(player_pos.getDistanceFrom(p_f) > maxd)
3648 far_players->push_back(client->peer_id);
3655 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3656 SharedBuffer<u8> reply(replysize);
3657 writeU16(&reply[0], TOCLIENT_ADDNODE);
3658 writeS16(&reply[2], p.X);
3659 writeS16(&reply[4], p.Y);
3660 writeS16(&reply[6], p.Z);
3661 n.serialize(&reply[8], client->serialization_version);
3664 m_con.Send(client->peer_id, 0, reply, true);
3668 void Server::setBlockNotSent(v3s16 p)
3670 for(core::map<u16, RemoteClient*>::Iterator
3671 i = m_clients.getIterator();
3672 i.atEnd()==false; i++)
3674 RemoteClient *client = i.getNode()->getValue();
3675 client->SetBlockNotSent(p);
3679 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3681 DSTACK(__FUNCTION_NAME);
3683 v3s16 p = block->getPos();
3687 bool completely_air = true;
3688 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3689 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3690 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3692 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3694 completely_air = false;
3695 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3700 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3702 infostream<<"[completely air] ";
3703 infostream<<std::endl;
3707 Create a packet with the block in the right format
3710 std::ostringstream os(std::ios_base::binary);
3711 block->serialize(os, ver, false);
3712 std::string s = os.str();
3713 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3715 u32 replysize = 8 + blockdata.getSize();
3716 SharedBuffer<u8> reply(replysize);
3717 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3718 writeS16(&reply[2], p.X);
3719 writeS16(&reply[4], p.Y);
3720 writeS16(&reply[6], p.Z);
3721 memcpy(&reply[8], *blockdata, blockdata.getSize());
3723 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3724 <<": \tpacket size: "<<replysize<<std::endl;*/
3729 m_con.Send(peer_id, 1, reply, true);
3732 void Server::SendBlocks(float dtime)
3734 DSTACK(__FUNCTION_NAME);
3736 JMutexAutoLock envlock(m_env_mutex);
3737 JMutexAutoLock conlock(m_con_mutex);
3739 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3741 core::array<PrioritySortedBlockTransfer> queue;
3743 s32 total_sending = 0;
3746 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3748 for(core::map<u16, RemoteClient*>::Iterator
3749 i = m_clients.getIterator();
3750 i.atEnd() == false; i++)
3752 RemoteClient *client = i.getNode()->getValue();
3753 assert(client->peer_id == i.getNode()->getKey());
3755 // If definitions and textures have not been sent, don't
3756 // send MapBlocks either
3757 if(!client->definitions_sent)
3760 total_sending += client->SendingCount();
3762 if(client->serialization_version == SER_FMT_VER_INVALID)
3765 client->GetNextBlocks(this, dtime, queue);
3770 // Lowest priority number comes first.
3771 // Lowest is most important.
3774 for(u32 i=0; i<queue.size(); i++)
3776 //TODO: Calculate limit dynamically
3777 if(total_sending >= g_settings->getS32
3778 ("max_simultaneous_block_sends_server_total"))
3781 PrioritySortedBlockTransfer q = queue[i];
3783 MapBlock *block = NULL;
3786 block = m_env->getMap().getBlockNoCreate(q.pos);
3788 catch(InvalidPositionException &e)
3793 RemoteClient *client = getClient(q.peer_id);
3795 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3797 client->SentBlock(q.pos);
3803 void Server::PrepareTextures()
3805 DSTACK(__FUNCTION_NAME);
3807 infostream<<"Server: Calculating texture checksums"<<std::endl;
3809 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3810 i != m_mods.end(); i++){
3811 const ModSpec &mod = *i;
3812 std::string texturepath = mod.path + DIR_DELIM + "textures";
3813 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3814 for(u32 j=0; j<dirlist.size(); j++){
3815 if(dirlist[j].dir) // Ignode dirs
3817 std::string tname = dirlist[j].name;
3818 // if name contains illegal characters, ignore the texture
3819 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3820 errorstream<<"Server: ignoring illegal texture name: \""
3821 <<tname<<"\""<<std::endl;
3824 std::string tpath = texturepath + DIR_DELIM + tname;
3826 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3827 if(fis.good() == false){
3828 errorstream<<"Server::PrepareTextures(): Could not open \""
3829 <<tname<<"\" for reading"<<std::endl;
3832 std::ostringstream tmp_os(std::ios_base::binary);
3836 fis.read(buf, 1024);
3837 std::streamsize len = fis.gcount();
3838 tmp_os.write(buf, len);
3847 errorstream<<"Server::PrepareTextures(): Failed to read \""
3848 <<tname<<"\""<<std::endl;
3851 if(tmp_os.str().length() == 0){
3852 errorstream<<"Server::PrepareTextures(): Empty file \""
3853 <<tpath<<"\""<<std::endl;
3858 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3860 unsigned char *digest = sha1.getDigest();
3861 std::string digest_string = base64_encode(digest, 20);
3866 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3867 verbosestream<<"Server: sha1 for "<<tname<<"\tis "<<std::endl;
3872 struct SendableTextureAnnouncement
3875 std::string sha1_digest;
3877 SendableTextureAnnouncement(const std::string name_="",
3878 const std::string sha1_digest_=""):
3880 sha1_digest(sha1_digest_)
3885 void Server::SendTextureAnnouncement(u16 peer_id){
3886 DSTACK(__FUNCTION_NAME);
3888 verbosestream<<"Server: Announcing textures to id("<<peer_id<<")"
3891 core::list<SendableTextureAnnouncement> texture_announcements;
3893 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3896 texture_announcements.push_back(
3897 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3900 //send announcements
3904 u32 number of textures
3908 u16 length of digest string
3912 std::ostringstream os(std::ios_base::binary);
3914 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3915 writeU16(os, texture_announcements.size());
3917 for(core::list<SendableTextureAnnouncement>::Iterator
3918 j = texture_announcements.begin();
3919 j != texture_announcements.end(); j++){
3920 os<<serializeString(j->name);
3921 os<<serializeString(j->sha1_digest);
3925 std::string s = os.str();
3926 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3929 m_con.Send(peer_id, 0, data, true);
3933 struct SendableTexture
3939 SendableTexture(const std::string &name_="", const std::string path_="",
3940 const std::string &data_=""):
3947 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3948 DSTACK(__FUNCTION_NAME);
3950 verbosestream<<"Server::SendTexturesRequested(): "
3951 <<"Sending textures to client"<<std::endl;
3955 // Put 5kB in one bunch (this is not accurate)
3956 u32 bytes_per_bunch = 5000;
3958 core::array< core::list<SendableTexture> > texture_bunches;
3959 texture_bunches.push_back(core::list<SendableTexture>());
3961 u32 texture_size_bunch_total = 0;
3963 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3964 if(m_Textures.find(i->name) == m_Textures.end()){
3965 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3966 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3970 //TODO get path + name
3971 std::string tpath = m_Textures[(*i).name].path;
3974 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3975 if(fis.good() == false){
3976 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3977 <<tpath<<"\" for reading"<<std::endl;
3980 std::ostringstream tmp_os(std::ios_base::binary);
3984 fis.read(buf, 1024);
3985 std::streamsize len = fis.gcount();
3986 tmp_os.write(buf, len);
3987 texture_size_bunch_total += len;
3996 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
3997 <<(*i).name<<"\""<<std::endl;
4000 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
4001 <<tname<<"\""<<std::endl;*/
4003 texture_bunches[texture_bunches.size()-1].push_back(
4004 SendableTexture((*i).name, tpath, tmp_os.str()));
4006 // Start next bunch if got enough data
4007 if(texture_size_bunch_total >= bytes_per_bunch){
4008 texture_bunches.push_back(core::list<SendableTexture>());
4009 texture_size_bunch_total = 0;
4014 /* Create and send packets */
4016 u32 num_bunches = texture_bunches.size();
4017 for(u32 i=0; i<num_bunches; i++)
4021 u16 total number of texture bunches
4022 u16 index of this bunch
4023 u32 number of textures in this bunch
4031 std::ostringstream os(std::ios_base::binary);
4033 writeU16(os, TOCLIENT_TEXTURES);
4034 writeU16(os, num_bunches);
4036 writeU32(os, texture_bunches[i].size());
4038 for(core::list<SendableTexture>::Iterator
4039 j = texture_bunches[i].begin();
4040 j != texture_bunches[i].end(); j++){
4041 os<<serializeString(j->name);
4042 os<<serializeLongString(j->data);
4046 std::string s = os.str();
4047 verbosestream<<"Server::SendTexturesRequested(): bunch "
4048 <<i<<"/"<<num_bunches
4049 <<" textures="<<texture_bunches[i].size()
4050 <<" size=" <<s.size()<<std::endl;
4051 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4053 m_con.Send(peer_id, 0, data, true);
4063 void Server::DiePlayer(Player *player)
4065 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4067 infostream<<"Server::DiePlayer(): Player "
4068 <<player->getName()<<" dies"<<std::endl;
4072 // Trigger scripted stuff
4073 scriptapi_on_dieplayer(m_lua, srp);
4075 // Handle players that are not connected
4076 if(player->peer_id == PEER_ID_INEXISTENT){
4077 RespawnPlayer(player);
4081 SendPlayerHP(player);
4082 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4085 void Server::RespawnPlayer(Player *player)
4087 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4089 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4091 v3f pos = findSpawnPos(m_env->getServerMap());
4092 player->setPosition(pos);
4093 srp->m_last_good_position = pos;
4094 srp->m_last_good_position_age = 0;
4096 SendMovePlayer(player);
4097 SendPlayerHP(player);
4100 void Server::UpdateCrafting(u16 peer_id)
4102 DSTACK(__FUNCTION_NAME);
4104 Player* player = m_env->getPlayer(peer_id);
4107 // Get a preview for crafting
4109 // No crafting in creative mode
4110 if(g_settings->getBool("creative_mode") == false)
4111 getCraftingResult(&player->inventory, preview, false, this);
4113 // Put the new preview in
4114 InventoryList *plist = player->inventory.getList("craftpreview");
4116 assert(plist->getSize() >= 1);
4117 plist->changeItem(0, preview);
4120 RemoteClient* Server::getClient(u16 peer_id)
4122 DSTACK(__FUNCTION_NAME);
4123 //JMutexAutoLock lock(m_con_mutex);
4124 core::map<u16, RemoteClient*>::Node *n;
4125 n = m_clients.find(peer_id);
4126 // A client should exist for all peers
4128 return n->getValue();
4131 std::wstring Server::getStatusString()
4133 std::wostringstream os(std::ios_base::binary);
4136 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4138 os<<L", uptime="<<m_uptime.get();
4139 // Information about clients
4141 for(core::map<u16, RemoteClient*>::Iterator
4142 i = m_clients.getIterator();
4143 i.atEnd() == false; i++)
4145 // Get client and check that it is valid
4146 RemoteClient *client = i.getNode()->getValue();
4147 assert(client->peer_id == i.getNode()->getKey());
4148 if(client->serialization_version == SER_FMT_VER_INVALID)
4151 Player *player = m_env->getPlayer(client->peer_id);
4152 // Get name of player
4153 std::wstring name = L"unknown";
4155 name = narrow_to_wide(player->getName());
4156 // Add name to information string
4160 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4161 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4162 if(g_settings->get("motd") != "")
4163 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4167 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4169 // Add player to auth manager
4170 if(m_authmanager.exists(name) == false)
4172 infostream<<"Server: adding player "<<name
4173 <<" to auth manager"<<std::endl;
4174 m_authmanager.add(name);
4175 m_authmanager.setPrivs(name,
4176 stringToPrivs(g_settings->get("default_privs")));
4178 // Change password and save
4179 m_authmanager.setPassword(name, translatePassword(name, password));
4180 m_authmanager.save();
4183 // Saves g_settings to configpath given at initialization
4184 void Server::saveConfig()
4186 if(m_path_config != "")
4187 g_settings->updateConfigFile(m_path_config.c_str());
4190 void Server::notifyPlayer(const char *name, const std::wstring msg)
4192 Player *player = m_env->getPlayer(name);
4195 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4198 void Server::notifyPlayers(const std::wstring msg)
4200 BroadcastChatMessage(msg);
4203 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4207 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4208 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4211 // IGameDef interface
4213 IItemDefManager* Server::getItemDefManager()
4217 INodeDefManager* Server::getNodeDefManager()
4221 ICraftDefManager* Server::getCraftDefManager()
4225 ITextureSource* Server::getTextureSource()
4229 u16 Server::allocateUnknownNodeId(const std::string &name)
4231 return m_nodedef->allocateDummy(name);
4234 IWritableItemDefManager* Server::getWritableItemDefManager()
4238 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4242 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4247 const ModSpec* Server::getModSpec(const std::string &modname)
4249 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4250 i != m_mods.end(); i++){
4251 const ModSpec &mod = *i;
4252 if(mod.name == modname)
4258 v3f findSpawnPos(ServerMap &map)
4260 //return v3f(50,50,50)*BS;
4265 nodepos = v2s16(0,0);
4270 // Try to find a good place a few times
4271 for(s32 i=0; i<1000; i++)
4274 // We're going to try to throw the player to this position
4275 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4276 -range + (myrand()%(range*2)));
4277 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4278 // Get ground height at point (fallbacks to heightmap function)
4279 s16 groundheight = map.findGroundLevel(nodepos2d);
4280 // Don't go underwater
4281 if(groundheight < WATER_LEVEL)
4283 //infostream<<"-> Underwater"<<std::endl;
4286 // Don't go to high places
4287 if(groundheight > WATER_LEVEL + 4)
4289 //infostream<<"-> Underwater"<<std::endl;
4293 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4294 bool is_good = false;
4296 for(s32 i=0; i<10; i++){
4297 v3s16 blockpos = getNodeBlockPos(nodepos);
4298 map.emergeBlock(blockpos, true);
4299 MapNode n = map.getNodeNoEx(nodepos);
4300 if(n.getContent() == CONTENT_AIR){
4311 // Found a good place
4312 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4318 return intToFloat(nodepos, BS);
4321 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4324 Try to get an existing player
4326 ServerRemotePlayer *player =
4327 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4330 // If player is already connected, cancel
4331 if(player->peer_id != 0)
4333 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4338 player->peer_id = peer_id;
4340 // Re-add player to environment
4341 if(player->m_removed)
4343 player->m_removed = false;
4345 m_env->addActiveObject(player);
4348 // Reset inventory to creative if in creative mode
4349 if(g_settings->getBool("creative_mode"))
4351 // Warning: double code below
4352 // Backup actual inventory
4353 player->inventory_backup = new Inventory(m_itemdef);
4354 *(player->inventory_backup) = player->inventory;
4355 // Set creative inventory
4356 player->resetInventory();
4357 scriptapi_get_creative_inventory(m_lua, player);
4364 If player with the wanted peer_id already exists, cancel.
4366 if(m_env->getPlayer(peer_id) != NULL)
4368 infostream<<"emergePlayer(): Player with wrong name but same"
4369 " peer_id already exists"<<std::endl;
4377 /* Set player position */
4379 infostream<<"Server: Finding spawn place for player \""
4380 <<name<<"\""<<std::endl;
4382 v3f pos = findSpawnPos(m_env->getServerMap());
4384 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4385 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4387 /* Add player to environment */
4388 m_env->addPlayer(player);
4389 m_env->addActiveObject(srp);
4392 scriptapi_on_newplayer(m_lua, srp);
4394 /* Add stuff to inventory */
4395 if(g_settings->getBool("creative_mode"))
4397 // Warning: double code above
4398 // Backup actual inventory
4399 player->inventory_backup = new Inventory(m_itemdef);
4400 *(player->inventory_backup) = player->inventory;
4401 // Set creative inventory
4402 player->resetInventory();
4403 scriptapi_get_creative_inventory(m_lua, player);
4408 } // create new player
4411 void Server::handlePeerChange(PeerChange &c)
4413 JMutexAutoLock envlock(m_env_mutex);
4414 JMutexAutoLock conlock(m_con_mutex);
4416 if(c.type == PEER_ADDED)
4423 core::map<u16, RemoteClient*>::Node *n;
4424 n = m_clients.find(c.peer_id);
4425 // The client shouldn't already exist
4429 RemoteClient *client = new RemoteClient();
4430 client->peer_id = c.peer_id;
4431 m_clients.insert(client->peer_id, client);
4434 else if(c.type == PEER_REMOVED)
4441 core::map<u16, RemoteClient*>::Node *n;
4442 n = m_clients.find(c.peer_id);
4443 // The client should exist
4447 Mark objects to be not known by the client
4449 RemoteClient *client = n->getValue();
4451 for(core::map<u16, bool>::Iterator
4452 i = client->m_known_objects.getIterator();
4453 i.atEnd()==false; i++)
4456 u16 id = i.getNode()->getKey();
4457 ServerActiveObject* obj = m_env->getActiveObject(id);
4459 if(obj && obj->m_known_by_count > 0)
4460 obj->m_known_by_count--;
4463 ServerRemotePlayer* player =
4464 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4466 // Collect information about leaving in chat
4467 std::wstring message;
4471 std::wstring name = narrow_to_wide(player->getName());
4474 message += L" left game";
4476 message += L" (timed out)";
4480 // Remove from environment
4482 player->m_removed = true;
4484 // Set player client disconnected
4486 player->peer_id = 0;
4494 std::ostringstream os(std::ios_base::binary);
4495 for(core::map<u16, RemoteClient*>::Iterator
4496 i = m_clients.getIterator();
4497 i.atEnd() == false; i++)
4499 RemoteClient *client = i.getNode()->getValue();
4500 assert(client->peer_id == i.getNode()->getKey());
4501 if(client->serialization_version == SER_FMT_VER_INVALID)
4504 Player *player = m_env->getPlayer(client->peer_id);
4507 // Get name of player
4508 os<<player->getName()<<" ";
4511 actionstream<<player->getName()<<" "
4512 <<(c.timeout?"times out.":"leaves game.")
4513 <<" List of players: "
4514 <<os.str()<<std::endl;
4519 delete m_clients[c.peer_id];
4520 m_clients.remove(c.peer_id);
4522 // Send player info to all remaining clients
4523 //SendPlayerInfos();
4525 // Send leave chat message to all remaining clients
4526 if(message.length() != 0)
4527 BroadcastChatMessage(message);
4536 void Server::handlePeerChanges()
4538 while(m_peer_change_queue.size() > 0)
4540 PeerChange c = m_peer_change_queue.pop_front();
4542 verbosestream<<"Server: Handling peer change: "
4543 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4546 handlePeerChange(c);
4550 u64 Server::getPlayerPrivs(Player *player)
4554 std::string playername = player->getName();
4555 // Local player gets all privileges regardless of
4556 // what's set on their account.
4557 if(g_settings->get("name") == playername)
4563 return getPlayerAuthPrivs(playername);
4567 void dedicated_server_loop(Server &server, bool &kill)
4569 DSTACK(__FUNCTION_NAME);
4571 verbosestream<<"dedicated_server_loop()"<<std::endl;
4573 IntervalLimiter m_profiler_interval;
4577 float steplen = g_settings->getFloat("dedicated_server_step");
4578 // This is kind of a hack but can be done like this
4579 // because server.step() is very light
4581 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4582 sleep_ms((int)(steplen*1000.0));
4584 server.step(steplen);
4586 if(server.getShutdownRequested() || kill)
4588 infostream<<"Dedicated server quitting"<<std::endl;
4595 float profiler_print_interval =
4596 g_settings->getFloat("profiler_print_interval");
4597 if(profiler_print_interval != 0)
4599 if(m_profiler_interval.step(steplen, profiler_print_interval))
4601 infostream<<"Profiler:"<<std::endl;
4602 g_profiler->print(infostream);
4603 g_profiler->clear();