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"
51 #include "utility_string.h"
53 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
55 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
57 class MapEditEventIgnorer
60 MapEditEventIgnorer(bool *flag):
69 ~MapEditEventIgnorer()
82 void * ServerThread::Thread()
86 log_register_thread("ServerThread");
88 DSTACK(__FUNCTION_NAME);
90 BEGIN_DEBUG_EXCEPTION_HANDLER
95 //TimeTaker timer("AsyncRunStep() + Receive()");
98 //TimeTaker timer("AsyncRunStep()");
99 m_server->AsyncRunStep();
102 //infostream<<"Running m_server->Receive()"<<std::endl;
105 catch(con::NoIncomingDataException &e)
108 catch(con::PeerNotFoundException &e)
110 infostream<<"Server: PeerNotFoundException"<<std::endl;
112 catch(con::ConnectionBindFailed &e)
114 m_server->setAsyncFatalError(e.what());
118 END_DEBUG_EXCEPTION_HANDLER(errorstream)
123 void * EmergeThread::Thread()
127 log_register_thread("EmergeThread");
129 DSTACK(__FUNCTION_NAME);
131 BEGIN_DEBUG_EXCEPTION_HANDLER
133 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
136 Get block info from queue, emerge them and send them
139 After queue is empty, exit.
143 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
147 SharedPtr<QueuedBlockEmerge> q(qptr);
153 Do not generate over-limit
155 if(blockpos_over_limit(p))
158 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
160 //TimeTaker timer("block emerge");
163 Try to emerge it from somewhere.
165 If it is only wanted as optional, only loading from disk
170 Check if any peer wants it as non-optional. In that case it
173 Also decrement the emerge queue count in clients.
176 bool only_from_disk = true;
179 core::map<u16, u8>::Iterator i;
180 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
182 //u16 peer_id = i.getNode()->getKey();
185 u8 flags = i.getNode()->getValue();
186 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
187 only_from_disk = false;
192 if(enable_mapgen_debug_info)
193 infostream<<"EmergeThread: p="
194 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
195 <<"only_from_disk="<<only_from_disk<<std::endl;
197 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
199 MapBlock *block = NULL;
200 bool got_block = true;
201 core::map<v3s16, MapBlock*> modified_blocks;
204 Try to fetch block from memory or disk.
205 If not found and asked to generate, initialize generator.
208 bool started_generate = false;
209 mapgen::BlockMakeData data;
212 JMutexAutoLock envlock(m_server->m_env_mutex);
214 // Load sector if it isn't loaded
215 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
216 map.loadSectorMeta(p2d);
218 // Attempt to load block
219 block = map.getBlockNoCreateNoEx(p);
220 if(!block || block->isDummy() || !block->isGenerated())
222 if(enable_mapgen_debug_info)
223 infostream<<"EmergeThread: not in memory, "
224 <<"attempting to load from disk"<<std::endl;
226 block = map.loadBlock(p);
229 // If could not load and allowed to generate, start generation
230 // inside this same envlock
231 if(only_from_disk == false &&
232 (block == NULL || block->isGenerated() == false)){
233 if(enable_mapgen_debug_info)
234 infostream<<"EmergeThread: generating"<<std::endl;
235 started_generate = true;
237 map.initBlockMake(&data, p);
242 If generator was initialized, generate now when envlock is free.
247 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
249 TimeTaker t("mapgen::make_block()");
251 mapgen::make_block(&data);
253 if(enable_mapgen_debug_info == false)
254 t.stop(true); // Hide output
258 // Lock environment again to access the map
259 JMutexAutoLock envlock(m_server->m_env_mutex);
261 ScopeProfiler sp(g_profiler, "EmergeThread: after "
262 "mapgen::make_block (envlock)", SPT_AVG);
264 // Blit data back on map, update lighting, add mobs and
265 // whatever this does
266 map.finishBlockMake(&data, modified_blocks);
269 block = map.getBlockNoCreateNoEx(p);
271 // If block doesn't exist, don't try doing anything with it
272 // This happens if the block is not in generation boundaries
277 Do some post-generate stuff
280 v3s16 minp = block->getPos()*MAP_BLOCKSIZE;
281 v3s16 maxp = minp + v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
282 scriptapi_environment_on_generated(m_server->m_lua,
285 if(enable_mapgen_debug_info)
286 infostream<<"EmergeThread: ended up with: "
287 <<analyze_block(block)<<std::endl;
290 Ignore map edit events, they will not need to be
291 sent to anybody because the block hasn't been sent
294 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
296 // Activate objects and stuff
297 m_server->m_env->activateBlock(block, 0);
305 Set sent status of modified blocks on clients
308 // NOTE: Server's clients are also behind the connection mutex
309 JMutexAutoLock lock(m_server->m_con_mutex);
312 Add the originally fetched block to the modified list
316 modified_blocks.insert(p, block);
320 Set the modified blocks unsent for all the clients
323 for(core::map<u16, RemoteClient*>::Iterator
324 i = m_server->m_clients.getIterator();
325 i.atEnd() == false; i++)
327 RemoteClient *client = i.getNode()->getValue();
329 if(modified_blocks.size() > 0)
331 // Remove block from sent history
332 client->SetBlocksNotSent(modified_blocks);
338 END_DEBUG_EXCEPTION_HANDLER(errorstream)
340 log_deregister_thread();
345 void RemoteClient::GetNextBlocks(Server *server, float dtime,
346 core::array<PrioritySortedBlockTransfer> &dest)
348 DSTACK(__FUNCTION_NAME);
351 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
354 m_nothing_to_send_pause_timer -= dtime;
355 m_nearest_unsent_reset_timer += dtime;
357 if(m_nothing_to_send_pause_timer >= 0)
362 // Won't send anything if already sending
363 if(m_blocks_sending.size() >= g_settings->getU16
364 ("max_simultaneous_block_sends_per_client"))
366 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
370 //TimeTaker timer("RemoteClient::GetNextBlocks");
372 Player *player = server->m_env->getPlayer(peer_id);
374 assert(player != NULL);
376 v3f playerpos = player->getPosition();
377 v3f playerspeed = player->getSpeed();
378 v3f playerspeeddir(0,0,0);
379 if(playerspeed.getLength() > 1.0*BS)
380 playerspeeddir = playerspeed / playerspeed.getLength();
381 // Predict to next block
382 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
384 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
386 v3s16 center = getNodeBlockPos(center_nodepos);
388 // Camera position and direction
389 v3f camera_pos = player->getEyePosition();
390 v3f camera_dir = v3f(0,0,1);
391 camera_dir.rotateYZBy(player->getPitch());
392 camera_dir.rotateXZBy(player->getYaw());
394 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
395 <<camera_dir.Z<<")"<<std::endl;*/
398 Get the starting value of the block finder radius.
401 if(m_last_center != center)
403 m_nearest_unsent_d = 0;
404 m_last_center = center;
407 /*infostream<<"m_nearest_unsent_reset_timer="
408 <<m_nearest_unsent_reset_timer<<std::endl;*/
410 // Reset periodically to workaround for some bugs or stuff
411 if(m_nearest_unsent_reset_timer > 20.0)
413 m_nearest_unsent_reset_timer = 0;
414 m_nearest_unsent_d = 0;
415 //infostream<<"Resetting m_nearest_unsent_d for "
416 // <<server->getPlayerName(peer_id)<<std::endl;
419 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
420 s16 d_start = m_nearest_unsent_d;
422 //infostream<<"d_start="<<d_start<<std::endl;
424 u16 max_simul_sends_setting = g_settings->getU16
425 ("max_simultaneous_block_sends_per_client");
426 u16 max_simul_sends_usually = max_simul_sends_setting;
429 Check the time from last addNode/removeNode.
431 Decrease send rate if player is building stuff.
433 m_time_from_building += dtime;
434 if(m_time_from_building < g_settings->getFloat(
435 "full_block_send_enable_min_time_from_building"))
437 max_simul_sends_usually
438 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
442 Number of blocks sending + number of blocks selected for sending
444 u32 num_blocks_selected = m_blocks_sending.size();
447 next time d will be continued from the d from which the nearest
448 unsent block was found this time.
450 This is because not necessarily any of the blocks found this
451 time are actually sent.
453 s32 new_nearest_unsent_d = -1;
455 s16 d_max = g_settings->getS16("max_block_send_distance");
456 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
458 // Don't loop very much at a time
459 s16 max_d_increment_at_time = 2;
460 if(d_max > d_start + max_d_increment_at_time)
461 d_max = d_start + max_d_increment_at_time;
462 /*if(d_max_gen > d_start+2)
463 d_max_gen = d_start+2;*/
465 //infostream<<"Starting from "<<d_start<<std::endl;
467 s32 nearest_emerged_d = -1;
468 s32 nearest_emergefull_d = -1;
469 s32 nearest_sent_d = -1;
470 bool queue_is_full = false;
473 for(d = d_start; d <= d_max; d++)
475 /*errorstream<<"checking d="<<d<<" for "
476 <<server->getPlayerName(peer_id)<<std::endl;*/
477 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
480 If m_nearest_unsent_d was changed by the EmergeThread
481 (it can change it to 0 through SetBlockNotSent),
483 Else update m_nearest_unsent_d
485 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
487 d = m_nearest_unsent_d;
488 last_nearest_unsent_d = m_nearest_unsent_d;
492 Get the border/face dot coordinates of a "d-radiused"
495 core::list<v3s16> list;
496 getFacePositions(list, d);
498 core::list<v3s16>::Iterator li;
499 for(li=list.begin(); li!=list.end(); li++)
501 v3s16 p = *li + center;
505 - Don't allow too many simultaneous transfers
506 - EXCEPT when the blocks are very close
508 Also, don't send blocks that are already flying.
511 // Start with the usual maximum
512 u16 max_simul_dynamic = max_simul_sends_usually;
514 // If block is very close, allow full maximum
515 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
516 max_simul_dynamic = max_simul_sends_setting;
518 // Don't select too many blocks for sending
519 if(num_blocks_selected >= max_simul_dynamic)
521 queue_is_full = true;
522 goto queue_full_break;
525 // Don't send blocks that are currently being transferred
526 if(m_blocks_sending.find(p) != NULL)
532 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
533 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
534 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
535 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
536 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
537 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
540 // If this is true, inexistent block will be made from scratch
541 bool generate = d <= d_max_gen;
544 /*// Limit the generating area vertically to 2/3
545 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
548 // Limit the send area vertically to 1/2
549 if(abs(p.Y - center.Y) > d_max / 2)
555 If block is far away, don't generate it unless it is
561 // Block center y in nodes
562 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
563 // Don't generate if it's very high or very low
564 if(y < -64 || y > 64)
568 v2s16 p2d_nodes_center(
572 // Get ground height in nodes
573 s16 gh = server->m_env->getServerMap().findGroundLevel(
576 // If differs a lot, don't generate
577 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
579 // Actually, don't even send it
585 //infostream<<"d="<<d<<std::endl;
588 Don't generate or send if not in sight
589 FIXME This only works if the client uses a small enough
590 FOV setting. The default of 72 degrees is fine.
593 float camera_fov = (72.0*PI/180) * 4./3.;
594 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
600 Don't send already sent blocks
603 if(m_blocks_sent.find(p) != NULL)
610 Check if map has this block
612 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
614 bool surely_not_found_on_disk = false;
615 bool block_is_invalid = false;
618 // Reset usage timer, this block will be of use in the future.
619 block->resetUsageTimer();
621 // Block is dummy if data doesn't exist.
622 // It means it has been not found from disk and not generated
625 surely_not_found_on_disk = true;
628 // Block is valid if lighting is up-to-date and data exists
629 if(block->isValid() == false)
631 block_is_invalid = true;
634 /*if(block->isFullyGenerated() == false)
636 block_is_invalid = true;
641 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
642 v2s16 chunkpos = map->sector_to_chunk(p2d);
643 if(map->chunkNonVolatile(chunkpos) == false)
644 block_is_invalid = true;
646 if(block->isGenerated() == false)
647 block_is_invalid = true;
650 If block is not close, don't send it unless it is near
653 Block is near ground level if night-time mesh
654 differs from day-time mesh.
658 if(block->dayNightDiffed() == false)
665 If block has been marked to not exist on disk (dummy)
666 and generating new ones is not wanted, skip block.
668 if(generate == false && surely_not_found_on_disk == true)
675 Add inexistent block to emerge queue.
677 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
679 //TODO: Get value from somewhere
680 // Allow only one block in emerge queue
681 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
682 // Allow two blocks in queue per client
683 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
685 // Make it more responsive when needing to generate stuff
686 if(surely_not_found_on_disk)
688 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
690 //infostream<<"Adding block to emerge queue"<<std::endl;
692 // Add it to the emerge queue and trigger the thread
695 if(generate == false)
696 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
698 server->m_emerge_queue.addBlock(peer_id, p, flags);
699 server->m_emergethread.trigger();
701 if(nearest_emerged_d == -1)
702 nearest_emerged_d = d;
704 if(nearest_emergefull_d == -1)
705 nearest_emergefull_d = d;
712 if(nearest_sent_d == -1)
716 Add block to send queue
719 /*errorstream<<"sending from d="<<d<<" to "
720 <<server->getPlayerName(peer_id)<<std::endl;*/
722 PrioritySortedBlockTransfer q((float)d, p, peer_id);
726 num_blocks_selected += 1;
731 //infostream<<"Stopped at "<<d<<std::endl;
733 // If nothing was found for sending and nothing was queued for
734 // emerging, continue next time browsing from here
735 if(nearest_emerged_d != -1){
736 new_nearest_unsent_d = nearest_emerged_d;
737 } else if(nearest_emergefull_d != -1){
738 new_nearest_unsent_d = nearest_emergefull_d;
740 if(d > g_settings->getS16("max_block_send_distance")){
741 new_nearest_unsent_d = 0;
742 m_nothing_to_send_pause_timer = 2.0;
743 /*infostream<<"GetNextBlocks(): d wrapped around for "
744 <<server->getPlayerName(peer_id)
745 <<"; setting to 0 and pausing"<<std::endl;*/
747 if(nearest_sent_d != -1)
748 new_nearest_unsent_d = nearest_sent_d;
750 new_nearest_unsent_d = d;
754 if(new_nearest_unsent_d != -1)
755 m_nearest_unsent_d = new_nearest_unsent_d;
757 /*timer_result = timer.stop(true);
758 if(timer_result != 0)
759 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
762 void RemoteClient::GotBlock(v3s16 p)
764 if(m_blocks_sending.find(p) != NULL)
765 m_blocks_sending.remove(p);
768 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
769 " m_blocks_sending"<<std::endl;*/
770 m_excess_gotblocks++;
772 m_blocks_sent.insert(p, true);
775 void RemoteClient::SentBlock(v3s16 p)
777 if(m_blocks_sending.find(p) == NULL)
778 m_blocks_sending.insert(p, 0.0);
780 infostream<<"RemoteClient::SentBlock(): Sent block"
781 " already in m_blocks_sending"<<std::endl;
784 void RemoteClient::SetBlockNotSent(v3s16 p)
786 m_nearest_unsent_d = 0;
788 if(m_blocks_sending.find(p) != NULL)
789 m_blocks_sending.remove(p);
790 if(m_blocks_sent.find(p) != NULL)
791 m_blocks_sent.remove(p);
794 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
796 m_nearest_unsent_d = 0;
798 for(core::map<v3s16, MapBlock*>::Iterator
799 i = blocks.getIterator();
800 i.atEnd()==false; i++)
802 v3s16 p = i.getNode()->getKey();
804 if(m_blocks_sending.find(p) != NULL)
805 m_blocks_sending.remove(p);
806 if(m_blocks_sent.find(p) != NULL)
807 m_blocks_sent.remove(p);
815 PlayerInfo::PlayerInfo()
821 void PlayerInfo::PrintLine(std::ostream *s)
824 (*s)<<"\""<<name<<"\" ("
825 <<(position.X/10)<<","<<(position.Y/10)
826 <<","<<(position.Z/10)<<") ";
828 (*s)<<" avg_rtt="<<avg_rtt;
837 const std::string &path_world,
838 const std::string &path_config,
839 const SubgameSpec &gamespec
841 m_path_world(path_world),
842 m_path_config(path_config),
843 m_gamespec(gamespec),
844 m_async_fatal_error(""),
846 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
847 m_authmanager(path_world+DIR_DELIM+"auth.txt"),
848 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
850 m_itemdef(createItemDefManager()),
851 m_nodedef(createNodeDefManager()),
852 m_craftdef(createCraftDefManager()),
854 m_emergethread(this),
856 m_time_of_day_send_timer(0),
858 m_shutdown_requested(false),
859 m_ignore_map_edit_events(false),
860 m_ignore_map_edit_events_peer_id(0)
862 m_liquid_transform_timer = 0.0;
863 m_print_info_timer = 0.0;
864 m_objectdata_timer = 0.0;
865 m_emergethread_trigger_timer = 0.0;
866 m_savemap_timer = 0.0;
870 m_step_dtime_mutex.Init();
874 throw ServerError("Supplied empty world path");
876 if(!gamespec.isValid())
877 throw ServerError("Supplied invalid gamespec");
879 // Figure out some paths
881 m_path_share = porting::path_share + DIR_DELIM + "server";
883 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\""<<std::endl;
884 infostream<<"- world: "<<m_path_world<<std::endl;
885 infostream<<"- config: "<<m_path_config<<std::endl;
886 infostream<<"- game: "<<m_gamespec.path<<std::endl;
887 for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
888 i != m_gamespec.addon_paths.end(); i++)
889 infostream<<"- addons: "<<(*i)<<std::endl;
891 // Path to builtin.lua
892 std::string builtinpath = m_path_share + DIR_DELIM + "builtin.lua";
894 // Add default global mod search path
895 m_modspaths.push_front(m_gamespec.path + DIR_DELIM "mods");
896 // Add world mod search path
897 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
898 // Add addon mod search path
899 for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
900 i != m_gamespec.addon_paths.end(); i++)
901 m_modspaths.push_front((*i) + DIR_DELIM + "mods");
903 // Print out mod search paths
904 for(core::list<std::string>::Iterator i = m_modspaths.begin();
905 i != m_modspaths.end(); i++){
906 std::string modspath = *i;
907 infostream<<"- mods: "<<modspath<<std::endl;
910 // Create world if it doesn't exist
911 if(!initializeWorld(m_path_world, m_gamespec.id))
912 throw ServerError("Failed to initialize world");
915 JMutexAutoLock envlock(m_env_mutex);
916 JMutexAutoLock conlock(m_con_mutex);
918 // Initialize scripting
920 infostream<<"Server: Initializing Lua"<<std::endl;
921 m_lua = script_init();
924 scriptapi_export(m_lua, this);
925 // Load and run builtin.lua
926 infostream<<"Server: Loading builtin.lua [\""
927 <<builtinpath<<"\"]"<<std::endl;
928 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
930 errorstream<<"Server: Failed to load and run "
931 <<builtinpath<<std::endl;
932 throw ModError("Failed to load and run "+builtinpath);
934 // Find mods in mod search paths
935 m_mods = getMods(m_modspaths);
937 infostream<<"Server: Loading mods: ";
938 for(core::list<ModSpec>::Iterator i = m_mods.begin();
939 i != m_mods.end(); i++){
940 const ModSpec &mod = *i;
941 infostream<<mod.name<<" ";
943 infostream<<std::endl;
944 // Load and run "mod" scripts
945 for(core::list<ModSpec>::Iterator i = m_mods.begin();
946 i != m_mods.end(); i++){
947 const ModSpec &mod = *i;
948 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
949 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
950 <<scriptpath<<"\"]"<<std::endl;
951 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
953 errorstream<<"Server: Failed to load and run "
954 <<scriptpath<<std::endl;
955 throw ModError("Failed to load and run "+scriptpath);
959 // Read Textures and calculate sha1 sums
962 // Apply item aliases in the node definition manager
963 m_nodedef->updateAliases(m_itemdef);
965 // Initialize Environment
967 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
970 // Give environment reference to scripting api
971 scriptapi_add_environment(m_lua, m_env);
973 // Register us to receive map edit events
974 m_env->getMap().addEventReceiver(this);
976 // If file exists, load environment metadata
977 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
979 infostream<<"Server: Loading environment metadata"<<std::endl;
980 m_env->loadMeta(m_path_world);
984 infostream<<"Server: Loading players"<<std::endl;
985 m_env->deSerializePlayers(m_path_world);
988 Add some test ActiveBlockModifiers to environment
990 add_legacy_abms(m_env, m_nodedef);
995 infostream<<"Server destructing"<<std::endl;
998 Send shutdown message
1001 JMutexAutoLock conlock(m_con_mutex);
1003 std::wstring line = L"*** Server shutting down";
1006 Send the message to clients
1008 for(core::map<u16, RemoteClient*>::Iterator
1009 i = m_clients.getIterator();
1010 i.atEnd() == false; i++)
1012 // Get client and check that it is valid
1013 RemoteClient *client = i.getNode()->getValue();
1014 assert(client->peer_id == i.getNode()->getKey());
1015 if(client->serialization_version == SER_FMT_VER_INVALID)
1019 SendChatMessage(client->peer_id, line);
1021 catch(con::PeerNotFoundException &e)
1027 JMutexAutoLock envlock(m_env_mutex);
1032 infostream<<"Server: Saving players"<<std::endl;
1033 m_env->serializePlayers(m_path_world);
1036 Save environment metadata
1038 infostream<<"Server: Saving environment metadata"<<std::endl;
1039 m_env->saveMeta(m_path_world);
1051 JMutexAutoLock clientslock(m_con_mutex);
1053 for(core::map<u16, RemoteClient*>::Iterator
1054 i = m_clients.getIterator();
1055 i.atEnd() == false; i++)
1058 // NOTE: These are removed by env destructor
1060 u16 peer_id = i.getNode()->getKey();
1061 JMutexAutoLock envlock(m_env_mutex);
1062 m_env->removePlayer(peer_id);
1066 delete i.getNode()->getValue();
1070 // Delete Environment
1077 // Deinitialize scripting
1078 infostream<<"Server: Deinitializing scripting"<<std::endl;
1079 script_deinit(m_lua);
1082 void Server::start(unsigned short port)
1084 DSTACK(__FUNCTION_NAME);
1085 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1087 // Stop thread if already running
1090 // Initialize connection
1091 m_con.SetTimeoutMs(30);
1095 m_thread.setRun(true);
1098 // ASCII art for the win!
1100 <<" .__ __ __ "<<std::endl
1101 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1102 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1103 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1104 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1105 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1106 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1107 actionstream<<"Server for gameid=\""<<m_gamespec.id
1108 <<"\" listening on port "<<port<<"."<<std::endl;
1113 DSTACK(__FUNCTION_NAME);
1115 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1117 // Stop threads (set run=false first so both start stopping)
1118 m_thread.setRun(false);
1119 m_emergethread.setRun(false);
1121 m_emergethread.stop();
1123 infostream<<"Server: Threads stopped"<<std::endl;
1126 void Server::step(float dtime)
1128 DSTACK(__FUNCTION_NAME);
1133 JMutexAutoLock lock(m_step_dtime_mutex);
1134 m_step_dtime += dtime;
1136 // Throw if fatal error occurred in thread
1137 std::string async_err = m_async_fatal_error.get();
1138 if(async_err != ""){
1139 throw ServerError(async_err);
1143 void Server::AsyncRunStep()
1145 DSTACK(__FUNCTION_NAME);
1147 g_profiler->add("Server::AsyncRunStep (num)", 1);
1151 JMutexAutoLock lock1(m_step_dtime_mutex);
1152 dtime = m_step_dtime;
1156 // Send blocks to clients
1163 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1165 //infostream<<"Server steps "<<dtime<<std::endl;
1166 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1169 JMutexAutoLock lock1(m_step_dtime_mutex);
1170 m_step_dtime -= dtime;
1177 m_uptime.set(m_uptime.get() + dtime);
1181 // Process connection's timeouts
1182 JMutexAutoLock lock2(m_con_mutex);
1183 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1184 m_con.RunTimeouts(dtime);
1188 // This has to be called so that the client list gets synced
1189 // with the peer list of the connection
1190 handlePeerChanges();
1194 Update m_time_of_day and overall game time
1197 JMutexAutoLock envlock(m_env_mutex);
1199 m_time_counter += dtime;
1200 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1201 u32 units = (u32)(m_time_counter*speed);
1202 m_time_counter -= (f32)units / speed;
1204 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1206 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1209 Send to clients at constant intervals
1212 m_time_of_day_send_timer -= dtime;
1213 if(m_time_of_day_send_timer < 0.0)
1215 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1217 //JMutexAutoLock envlock(m_env_mutex);
1218 JMutexAutoLock conlock(m_con_mutex);
1220 for(core::map<u16, RemoteClient*>::Iterator
1221 i = m_clients.getIterator();
1222 i.atEnd() == false; i++)
1224 RemoteClient *client = i.getNode()->getValue();
1225 //Player *player = m_env->getPlayer(client->peer_id);
1227 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1228 m_env->getTimeOfDay());
1230 m_con.Send(client->peer_id, 0, data, true);
1236 JMutexAutoLock lock(m_env_mutex);
1238 ScopeProfiler sp(g_profiler, "SEnv step");
1239 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1243 const float map_timer_and_unload_dtime = 2.92;
1244 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1246 JMutexAutoLock lock(m_env_mutex);
1247 // Run Map's timers and unload unused data
1248 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1249 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1250 g_settings->getFloat("server_unload_unused_data_timeout"));
1261 JMutexAutoLock lock(m_env_mutex);
1262 JMutexAutoLock lock2(m_con_mutex);
1264 ScopeProfiler sp(g_profiler, "Server: handle players");
1266 //float player_max_speed = BS * 4.0; // Normal speed
1267 float player_max_speed = BS * 20; // Fast speed
1268 float player_max_speed_up = BS * 20;
1270 player_max_speed *= 2.5; // Tolerance
1271 player_max_speed_up *= 2.5;
1273 for(core::map<u16, RemoteClient*>::Iterator
1274 i = m_clients.getIterator();
1275 i.atEnd() == false; i++)
1277 RemoteClient *client = i.getNode()->getValue();
1278 ServerRemotePlayer *player =
1279 static_cast<ServerRemotePlayer*>
1280 (m_env->getPlayer(client->peer_id));
1285 Check player movements
1287 NOTE: Actually the server should handle player physics like the
1288 client does and compare player's position to what is calculated
1289 on our side. This is required when eg. players fly due to an
1292 player->m_last_good_position_age += dtime;
1293 if(player->m_last_good_position_age >= 1.0){
1294 float age = player->m_last_good_position_age;
1295 v3f diff = (player->getPosition() - player->m_last_good_position);
1296 float d_vert = diff.Y;
1298 float d_horiz = diff.getLength();
1299 /*infostream<<player->getName()<<"'s horizontal speed is "
1300 <<(d_horiz/age)<<std::endl;*/
1301 if(d_horiz <= age * player_max_speed &&
1302 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1303 player->m_last_good_position = player->getPosition();
1305 actionstream<<"Player "<<player->getName()
1306 <<" moved too fast; resetting position"
1308 player->setPosition(player->m_last_good_position);
1309 SendMovePlayer(player);
1311 player->m_last_good_position_age = 0;
1315 Handle player HPs (die if hp=0)
1317 if(player->hp == 0 && player->m_hp_not_sent)
1321 Send player inventories and HPs if necessary
1323 if(player->m_inventory_not_sent){
1324 UpdateCrafting(player->peer_id);
1325 SendInventory(player->peer_id);
1327 if(player->m_hp_not_sent){
1328 SendPlayerHP(player);
1334 if(!player->m_is_in_environment){
1335 player->m_removed = false;
1337 m_env->addActiveObject(player);
1342 /* Transform liquids */
1343 m_liquid_transform_timer += dtime;
1344 if(m_liquid_transform_timer >= 1.00)
1346 m_liquid_transform_timer -= 1.00;
1348 JMutexAutoLock lock(m_env_mutex);
1350 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1352 core::map<v3s16, MapBlock*> modified_blocks;
1353 m_env->getMap().transformLiquids(modified_blocks);
1358 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1359 ServerMap &map = ((ServerMap&)m_env->getMap());
1360 map.updateLighting(modified_blocks, lighting_modified_blocks);
1362 // Add blocks modified by lighting to modified_blocks
1363 for(core::map<v3s16, MapBlock*>::Iterator
1364 i = lighting_modified_blocks.getIterator();
1365 i.atEnd() == false; i++)
1367 MapBlock *block = i.getNode()->getValue();
1368 modified_blocks.insert(block->getPos(), block);
1372 Set the modified blocks unsent for all the clients
1375 JMutexAutoLock lock2(m_con_mutex);
1377 for(core::map<u16, RemoteClient*>::Iterator
1378 i = m_clients.getIterator();
1379 i.atEnd() == false; i++)
1381 RemoteClient *client = i.getNode()->getValue();
1383 if(modified_blocks.size() > 0)
1385 // Remove block from sent history
1386 client->SetBlocksNotSent(modified_blocks);
1391 // Periodically print some info
1393 float &counter = m_print_info_timer;
1399 JMutexAutoLock lock2(m_con_mutex);
1401 if(m_clients.size() != 0)
1402 infostream<<"Players:"<<std::endl;
1403 for(core::map<u16, RemoteClient*>::Iterator
1404 i = m_clients.getIterator();
1405 i.atEnd() == false; i++)
1407 //u16 peer_id = i.getNode()->getKey();
1408 RemoteClient *client = i.getNode()->getValue();
1409 Player *player = m_env->getPlayer(client->peer_id);
1412 infostream<<"* "<<player->getName()<<"\t";
1413 client->PrintInfo(infostream);
1418 //if(g_settings->getBool("enable_experimental"))
1422 Check added and deleted active objects
1425 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1426 JMutexAutoLock envlock(m_env_mutex);
1427 JMutexAutoLock conlock(m_con_mutex);
1429 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1431 // Radius inside which objects are active
1432 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1433 radius *= MAP_BLOCKSIZE;
1435 for(core::map<u16, RemoteClient*>::Iterator
1436 i = m_clients.getIterator();
1437 i.atEnd() == false; i++)
1439 RemoteClient *client = i.getNode()->getValue();
1441 // If definitions and textures have not been sent, don't
1442 // send objects either
1443 if(!client->definitions_sent)
1446 Player *player = m_env->getPlayer(client->peer_id);
1449 // This can happen if the client timeouts somehow
1450 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1452 <<" has no associated player"<<std::endl;*/
1455 v3s16 pos = floatToInt(player->getPosition(), BS);
1457 core::map<u16, bool> removed_objects;
1458 core::map<u16, bool> added_objects;
1459 m_env->getRemovedActiveObjects(pos, radius,
1460 client->m_known_objects, removed_objects);
1461 m_env->getAddedActiveObjects(pos, radius,
1462 client->m_known_objects, added_objects);
1464 // Ignore if nothing happened
1465 if(removed_objects.size() == 0 && added_objects.size() == 0)
1467 //infostream<<"active objects: none changed"<<std::endl;
1471 std::string data_buffer;
1475 // Handle removed objects
1476 writeU16((u8*)buf, removed_objects.size());
1477 data_buffer.append(buf, 2);
1478 for(core::map<u16, bool>::Iterator
1479 i = removed_objects.getIterator();
1480 i.atEnd()==false; i++)
1483 u16 id = i.getNode()->getKey();
1484 ServerActiveObject* obj = m_env->getActiveObject(id);
1486 // Add to data buffer for sending
1487 writeU16((u8*)buf, i.getNode()->getKey());
1488 data_buffer.append(buf, 2);
1490 // Remove from known objects
1491 client->m_known_objects.remove(i.getNode()->getKey());
1493 if(obj && obj->m_known_by_count > 0)
1494 obj->m_known_by_count--;
1497 // Handle added objects
1498 writeU16((u8*)buf, added_objects.size());
1499 data_buffer.append(buf, 2);
1500 for(core::map<u16, bool>::Iterator
1501 i = added_objects.getIterator();
1502 i.atEnd()==false; i++)
1505 u16 id = i.getNode()->getKey();
1506 ServerActiveObject* obj = m_env->getActiveObject(id);
1509 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1511 infostream<<"WARNING: "<<__FUNCTION_NAME
1512 <<": NULL object"<<std::endl;
1514 type = obj->getType();
1516 // Add to data buffer for sending
1517 writeU16((u8*)buf, id);
1518 data_buffer.append(buf, 2);
1519 writeU8((u8*)buf, type);
1520 data_buffer.append(buf, 1);
1523 data_buffer.append(serializeLongString(
1524 obj->getClientInitializationData()));
1526 data_buffer.append(serializeLongString(""));
1528 // Add to known objects
1529 client->m_known_objects.insert(i.getNode()->getKey(), false);
1532 obj->m_known_by_count++;
1536 SharedBuffer<u8> reply(2 + data_buffer.size());
1537 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1538 memcpy((char*)&reply[2], data_buffer.c_str(),
1539 data_buffer.size());
1541 m_con.Send(client->peer_id, 0, reply, true);
1543 verbosestream<<"Server: Sent object remove/add: "
1544 <<removed_objects.size()<<" removed, "
1545 <<added_objects.size()<<" added, "
1546 <<"packet size is "<<reply.getSize()<<std::endl;
1551 Collect a list of all the objects known by the clients
1552 and report it back to the environment.
1555 core::map<u16, bool> all_known_objects;
1557 for(core::map<u16, RemoteClient*>::Iterator
1558 i = m_clients.getIterator();
1559 i.atEnd() == false; i++)
1561 RemoteClient *client = i.getNode()->getValue();
1562 // Go through all known objects of client
1563 for(core::map<u16, bool>::Iterator
1564 i = client->m_known_objects.getIterator();
1565 i.atEnd()==false; i++)
1567 u16 id = i.getNode()->getKey();
1568 all_known_objects[id] = true;
1572 m_env->setKnownActiveObjects(whatever);
1578 Send object messages
1581 JMutexAutoLock envlock(m_env_mutex);
1582 JMutexAutoLock conlock(m_con_mutex);
1584 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1587 // Value = data sent by object
1588 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1590 // Get active object messages from environment
1593 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1597 core::list<ActiveObjectMessage>* message_list = NULL;
1598 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1599 n = buffered_messages.find(aom.id);
1602 message_list = new core::list<ActiveObjectMessage>;
1603 buffered_messages.insert(aom.id, message_list);
1607 message_list = n->getValue();
1609 message_list->push_back(aom);
1612 // Route data to every client
1613 for(core::map<u16, RemoteClient*>::Iterator
1614 i = m_clients.getIterator();
1615 i.atEnd()==false; i++)
1617 RemoteClient *client = i.getNode()->getValue();
1618 std::string reliable_data;
1619 std::string unreliable_data;
1620 // Go through all objects in message buffer
1621 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1622 j = buffered_messages.getIterator();
1623 j.atEnd()==false; j++)
1625 // If object is not known by client, skip it
1626 u16 id = j.getNode()->getKey();
1627 if(client->m_known_objects.find(id) == NULL)
1629 // Get message list of object
1630 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1631 // Go through every message
1632 for(core::list<ActiveObjectMessage>::Iterator
1633 k = list->begin(); k != list->end(); k++)
1635 // Compose the full new data with header
1636 ActiveObjectMessage aom = *k;
1637 std::string new_data;
1640 writeU16((u8*)&buf[0], aom.id);
1641 new_data.append(buf, 2);
1643 new_data += serializeString(aom.datastring);
1644 // Add data to buffer
1646 reliable_data += new_data;
1648 unreliable_data += new_data;
1652 reliable_data and unreliable_data are now ready.
1655 if(reliable_data.size() > 0)
1657 SharedBuffer<u8> reply(2 + reliable_data.size());
1658 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1659 memcpy((char*)&reply[2], reliable_data.c_str(),
1660 reliable_data.size());
1662 m_con.Send(client->peer_id, 0, reply, true);
1664 if(unreliable_data.size() > 0)
1666 SharedBuffer<u8> reply(2 + unreliable_data.size());
1667 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1668 memcpy((char*)&reply[2], unreliable_data.c_str(),
1669 unreliable_data.size());
1670 // Send as unreliable
1671 m_con.Send(client->peer_id, 0, reply, false);
1674 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1676 infostream<<"Server: Size of object message data: "
1677 <<"reliable: "<<reliable_data.size()
1678 <<", unreliable: "<<unreliable_data.size()
1683 // Clear buffered_messages
1684 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1685 i = buffered_messages.getIterator();
1686 i.atEnd()==false; i++)
1688 delete i.getNode()->getValue();
1692 } // enable_experimental
1695 Send queued-for-sending map edit events.
1698 // Don't send too many at a time
1701 // Single change sending is disabled if queue size is not small
1702 bool disable_single_change_sending = false;
1703 if(m_unsent_map_edit_queue.size() >= 4)
1704 disable_single_change_sending = true;
1706 int event_count = m_unsent_map_edit_queue.size();
1708 // We'll log the amount of each
1711 while(m_unsent_map_edit_queue.size() != 0)
1713 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1715 // Players far away from the change are stored here.
1716 // Instead of sending the changes, MapBlocks are set not sent
1718 core::list<u16> far_players;
1720 if(event->type == MEET_ADDNODE)
1722 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1723 prof.add("MEET_ADDNODE", 1);
1724 if(disable_single_change_sending)
1725 sendAddNode(event->p, event->n, event->already_known_by_peer,
1728 sendAddNode(event->p, event->n, event->already_known_by_peer,
1731 else if(event->type == MEET_REMOVENODE)
1733 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1734 prof.add("MEET_REMOVENODE", 1);
1735 if(disable_single_change_sending)
1736 sendRemoveNode(event->p, event->already_known_by_peer,
1739 sendRemoveNode(event->p, event->already_known_by_peer,
1742 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1744 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1745 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1746 setBlockNotSent(event->p);
1748 else if(event->type == MEET_OTHER)
1750 infostream<<"Server: MEET_OTHER"<<std::endl;
1751 prof.add("MEET_OTHER", 1);
1752 for(core::map<v3s16, bool>::Iterator
1753 i = event->modified_blocks.getIterator();
1754 i.atEnd()==false; i++)
1756 v3s16 p = i.getNode()->getKey();
1762 prof.add("unknown", 1);
1763 infostream<<"WARNING: Server: Unknown MapEditEvent "
1764 <<((u32)event->type)<<std::endl;
1768 Set blocks not sent to far players
1770 if(far_players.size() > 0)
1772 // Convert list format to that wanted by SetBlocksNotSent
1773 core::map<v3s16, MapBlock*> modified_blocks2;
1774 for(core::map<v3s16, bool>::Iterator
1775 i = event->modified_blocks.getIterator();
1776 i.atEnd()==false; i++)
1778 v3s16 p = i.getNode()->getKey();
1779 modified_blocks2.insert(p,
1780 m_env->getMap().getBlockNoCreateNoEx(p));
1782 // Set blocks not sent
1783 for(core::list<u16>::Iterator
1784 i = far_players.begin();
1785 i != far_players.end(); i++)
1788 RemoteClient *client = getClient(peer_id);
1791 client->SetBlocksNotSent(modified_blocks2);
1797 /*// Don't send too many at a time
1799 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1803 if(event_count >= 5){
1804 infostream<<"Server: MapEditEvents:"<<std::endl;
1805 prof.print(infostream);
1806 } else if(event_count != 0){
1807 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1808 prof.print(verbosestream);
1814 Trigger emergethread (it somehow gets to a non-triggered but
1815 bysy state sometimes)
1818 float &counter = m_emergethread_trigger_timer;
1824 m_emergethread.trigger();
1828 // Save map, players and auth stuff
1830 float &counter = m_savemap_timer;
1832 if(counter >= g_settings->getFloat("server_map_save_interval"))
1835 JMutexAutoLock lock(m_env_mutex);
1837 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1840 if(m_authmanager.isModified())
1841 m_authmanager.save();
1844 if(m_banmanager.isModified())
1845 m_banmanager.save();
1847 // Save changed parts of map
1848 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1851 m_env->serializePlayers(m_path_world);
1853 // Save environment metadata
1854 m_env->saveMeta(m_path_world);
1859 void Server::Receive()
1861 DSTACK(__FUNCTION_NAME);
1862 SharedBuffer<u8> data;
1867 JMutexAutoLock conlock(m_con_mutex);
1868 datasize = m_con.Receive(peer_id, data);
1871 // This has to be called so that the client list gets synced
1872 // with the peer list of the connection
1873 handlePeerChanges();
1875 ProcessData(*data, datasize, peer_id);
1877 catch(con::InvalidIncomingDataException &e)
1879 infostream<<"Server::Receive(): "
1880 "InvalidIncomingDataException: what()="
1881 <<e.what()<<std::endl;
1883 catch(con::PeerNotFoundException &e)
1885 //NOTE: This is not needed anymore
1887 // The peer has been disconnected.
1888 // Find the associated player and remove it.
1890 /*JMutexAutoLock envlock(m_env_mutex);
1892 infostream<<"ServerThread: peer_id="<<peer_id
1893 <<" has apparently closed connection. "
1894 <<"Removing player."<<std::endl;
1896 m_env->removePlayer(peer_id);*/
1900 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1902 DSTACK(__FUNCTION_NAME);
1903 // Environment is locked first.
1904 JMutexAutoLock envlock(m_env_mutex);
1905 JMutexAutoLock conlock(m_con_mutex);
1907 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1910 Address address = m_con.GetPeerAddress(peer_id);
1912 // drop player if is ip is banned
1913 if(m_banmanager.isIpBanned(address.serializeString())){
1914 SendAccessDenied(m_con, peer_id,
1915 L"Your ip is banned. Banned name was "
1916 +narrow_to_wide(m_banmanager.getBanName(
1917 address.serializeString())));
1918 m_con.DeletePeer(peer_id);
1922 catch(con::PeerNotFoundException &e)
1924 infostream<<"Server::ProcessData(): Cancelling: peer "
1925 <<peer_id<<" not found"<<std::endl;
1929 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1931 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1939 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1941 if(command == TOSERVER_INIT)
1943 // [0] u16 TOSERVER_INIT
1944 // [2] u8 SER_FMT_VER_HIGHEST
1945 // [3] u8[20] player_name
1946 // [23] u8[28] password <--- can be sent without this, from old versions
1948 if(datasize < 2+1+PLAYERNAME_SIZE)
1951 verbosestream<<"Server: Got TOSERVER_INIT from "
1952 <<peer_id<<std::endl;
1954 // First byte after command is maximum supported
1955 // serialization version
1956 u8 client_max = data[2];
1957 u8 our_max = SER_FMT_VER_HIGHEST;
1958 // Use the highest version supported by both
1959 u8 deployed = core::min_(client_max, our_max);
1960 // If it's lower than the lowest supported, give up.
1961 if(deployed < SER_FMT_VER_LOWEST)
1962 deployed = SER_FMT_VER_INVALID;
1964 //peer->serialization_version = deployed;
1965 getClient(peer_id)->pending_serialization_version = deployed;
1967 if(deployed == SER_FMT_VER_INVALID)
1969 actionstream<<"Server: A mismatched client tried to connect from "
1970 <<addr_s<<std::endl;
1971 infostream<<"Server: Cannot negotiate "
1972 "serialization version with peer "
1973 <<peer_id<<std::endl;
1974 SendAccessDenied(m_con, peer_id, std::wstring(
1975 L"Your client's version is not supported.\n"
1976 L"Server version is ")
1977 + narrow_to_wide(VERSION_STRING) + L"."
1983 Read and check network protocol version
1986 u16 net_proto_version = 0;
1987 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1989 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1992 getClient(peer_id)->net_proto_version = net_proto_version;
1994 if(net_proto_version == 0)
1996 actionstream<<"Server: An old tried to connect from "<<addr_s
1998 SendAccessDenied(m_con, peer_id, std::wstring(
1999 L"Your client's version is not supported.\n"
2000 L"Server version is ")
2001 + narrow_to_wide(VERSION_STRING) + L"."
2006 if(g_settings->getBool("strict_protocol_version_checking"))
2008 if(net_proto_version != PROTOCOL_VERSION)
2010 actionstream<<"Server: A mismatched client tried to connect"
2011 <<" from "<<addr_s<<std::endl;
2012 SendAccessDenied(m_con, peer_id, std::wstring(
2013 L"Your client's version is not supported.\n"
2014 L"Server version is ")
2015 + narrow_to_wide(VERSION_STRING) + L",\n"
2016 + L"server's PROTOCOL_VERSION is "
2017 + narrow_to_wide(itos(PROTOCOL_VERSION))
2018 + L", client's PROTOCOL_VERSION is "
2019 + narrow_to_wide(itos(net_proto_version))
2030 char playername[PLAYERNAME_SIZE];
2031 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2033 playername[i] = data[3+i];
2035 playername[PLAYERNAME_SIZE-1] = 0;
2037 if(playername[0]=='\0')
2039 actionstream<<"Server: Player with an empty name "
2040 <<"tried to connect from "<<addr_s<<std::endl;
2041 SendAccessDenied(m_con, peer_id,
2046 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2048 actionstream<<"Server: Player with an invalid name "
2049 <<"tried to connect from "<<addr_s<<std::endl;
2050 SendAccessDenied(m_con, peer_id,
2051 L"Name contains unallowed characters");
2055 infostream<<"Server: New connection: \""<<playername<<"\" from "
2056 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2059 char password[PASSWORD_SIZE];
2060 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2062 // old version - assume blank password
2067 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2069 password[i] = data[23+i];
2071 password[PASSWORD_SIZE-1] = 0;
2074 // Add player to auth manager
2075 if(m_authmanager.exists(playername) == false)
2077 std::wstring default_password =
2078 narrow_to_wide(g_settings->get("default_password"));
2079 std::string translated_default_password =
2080 translatePassword(playername, default_password);
2082 // If default_password is empty, allow any initial password
2083 if (default_password.length() == 0)
2084 translated_default_password = password;
2086 infostream<<"Server: adding player "<<playername
2087 <<" to auth manager"<<std::endl;
2088 m_authmanager.add(playername);
2089 m_authmanager.setPassword(playername, translated_default_password);
2090 m_authmanager.setPrivs(playername,
2091 stringToPrivs(g_settings->get("default_privs")));
2092 m_authmanager.save();
2095 std::string checkpwd = m_authmanager.getPassword(playername);
2097 /*infostream<<"Server: Client gave password '"<<password
2098 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2100 if(password != checkpwd)
2102 infostream<<"Server: peer_id="<<peer_id
2103 <<": supplied invalid password for "
2104 <<playername<<std::endl;
2105 SendAccessDenied(m_con, peer_id, L"Invalid password");
2109 // Enforce user limit.
2110 // Don't enforce for users that have some admin right
2111 if(m_clients.size() >= g_settings->getU16("max_users") &&
2112 (m_authmanager.getPrivs(playername)
2113 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2114 playername != g_settings->get("name"))
2116 actionstream<<"Server: "<<playername<<" tried to join, but there"
2117 <<" are already max_users="
2118 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2119 SendAccessDenied(m_con, peer_id, L"Too many users.");
2124 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2126 // If failed, cancel
2129 errorstream<<"Server: peer_id="<<peer_id
2130 <<": failed to emerge player"<<std::endl;
2135 Answer with a TOCLIENT_INIT
2138 SharedBuffer<u8> reply(2+1+6+8);
2139 writeU16(&reply[0], TOCLIENT_INIT);
2140 writeU8(&reply[2], deployed);
2141 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2142 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2145 m_con.Send(peer_id, 0, reply, true);
2149 Send complete position information
2151 SendMovePlayer(player);
2156 if(command == TOSERVER_INIT2)
2158 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2159 <<peer_id<<std::endl;
2162 getClient(peer_id)->serialization_version
2163 = getClient(peer_id)->pending_serialization_version;
2166 Send some initialization data
2169 infostream<<"Server: Sending content to "
2170 <<getPlayerName(peer_id)<<std::endl;
2172 // Send item definitions
2173 SendItemDef(m_con, peer_id, m_itemdef);
2175 // Send node definitions
2176 SendNodeDef(m_con, peer_id, m_nodedef);
2178 // Send texture announcement
2179 SendTextureAnnouncement(peer_id);
2181 // Send player info to all players
2182 //SendPlayerInfos();
2184 // Send inventory to player
2185 UpdateCrafting(peer_id);
2186 SendInventory(peer_id);
2188 // Send player items to all players
2191 Player *player = m_env->getPlayer(peer_id);
2194 SendPlayerHP(player);
2196 // Show death screen if necessary
2198 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2202 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2203 m_env->getTimeOfDay());
2204 m_con.Send(peer_id, 0, data, true);
2207 // Send information about server to player in chat
2208 SendChatMessage(peer_id, getStatusString());
2210 // Send information about joining in chat
2212 std::wstring name = L"unknown";
2213 Player *player = m_env->getPlayer(peer_id);
2215 name = narrow_to_wide(player->getName());
2217 std::wstring message;
2220 message += L" joined game";
2221 BroadcastChatMessage(message);
2224 // Warnings about protocol version can be issued here
2225 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2227 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2234 std::ostringstream os(std::ios_base::binary);
2235 for(core::map<u16, RemoteClient*>::Iterator
2236 i = m_clients.getIterator();
2237 i.atEnd() == false; i++)
2239 RemoteClient *client = i.getNode()->getValue();
2240 assert(client->peer_id == i.getNode()->getKey());
2241 if(client->serialization_version == SER_FMT_VER_INVALID)
2244 Player *player = m_env->getPlayer(client->peer_id);
2247 // Get name of player
2248 os<<player->getName()<<" ";
2251 actionstream<<player->getName()<<" joins game. List of players: "
2252 <<os.str()<<std::endl;
2258 if(peer_ser_ver == SER_FMT_VER_INVALID)
2260 infostream<<"Server::ProcessData(): Cancelling: Peer"
2261 " serialization format invalid or not initialized."
2262 " Skipping incoming command="<<command<<std::endl;
2266 Player *player = m_env->getPlayer(peer_id);
2267 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2270 infostream<<"Server::ProcessData(): Cancelling: "
2271 "No player for peer_id="<<peer_id
2275 if(command == TOSERVER_PLAYERPOS)
2277 if(datasize < 2+12+12+4+4)
2281 v3s32 ps = readV3S32(&data[start+2]);
2282 v3s32 ss = readV3S32(&data[start+2+12]);
2283 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2284 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2285 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2286 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2287 pitch = wrapDegrees(pitch);
2288 yaw = wrapDegrees(yaw);
2290 player->setPosition(position);
2291 player->setSpeed(speed);
2292 player->setPitch(pitch);
2293 player->setYaw(yaw);
2295 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2296 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2297 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2299 else if(command == TOSERVER_GOTBLOCKS)
2312 u16 count = data[2];
2313 for(u16 i=0; i<count; i++)
2315 if((s16)datasize < 2+1+(i+1)*6)
2316 throw con::InvalidIncomingDataException
2317 ("GOTBLOCKS length is too short");
2318 v3s16 p = readV3S16(&data[2+1+i*6]);
2319 /*infostream<<"Server: GOTBLOCKS ("
2320 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2321 RemoteClient *client = getClient(peer_id);
2322 client->GotBlock(p);
2325 else if(command == TOSERVER_DELETEDBLOCKS)
2338 u16 count = data[2];
2339 for(u16 i=0; i<count; i++)
2341 if((s16)datasize < 2+1+(i+1)*6)
2342 throw con::InvalidIncomingDataException
2343 ("DELETEDBLOCKS length is too short");
2344 v3s16 p = readV3S16(&data[2+1+i*6]);
2345 /*infostream<<"Server: DELETEDBLOCKS ("
2346 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2347 RemoteClient *client = getClient(peer_id);
2348 client->SetBlockNotSent(p);
2351 else if(command == TOSERVER_CLICK_OBJECT)
2353 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2356 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2358 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2361 else if(command == TOSERVER_GROUND_ACTION)
2363 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2367 else if(command == TOSERVER_RELEASE)
2369 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2372 else if(command == TOSERVER_SIGNTEXT)
2374 infostream<<"Server: SIGNTEXT not supported anymore"
2378 else if(command == TOSERVER_SIGNNODETEXT)
2380 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2388 std::string datastring((char*)&data[2], datasize-2);
2389 std::istringstream is(datastring, std::ios_base::binary);
2392 is.read((char*)buf, 6);
2393 v3s16 p = readV3S16(buf);
2394 is.read((char*)buf, 2);
2395 u16 textlen = readU16(buf);
2397 for(u16 i=0; i<textlen; i++)
2399 is.read((char*)buf, 1);
2400 text += (char)buf[0];
2403 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2407 meta->setText(text);
2409 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2410 <<" at "<<PP(p)<<std::endl;
2412 v3s16 blockpos = getNodeBlockPos(p);
2413 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2416 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2420 setBlockNotSent(blockpos);
2422 else if(command == TOSERVER_INVENTORY_ACTION)
2424 // Strip command and create a stream
2425 std::string datastring((char*)&data[2], datasize-2);
2426 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2427 std::istringstream is(datastring, std::ios_base::binary);
2429 InventoryAction *a = InventoryAction::deSerialize(is);
2432 infostream<<"TOSERVER_INVENTORY_ACTION: "
2433 <<"InventoryAction::deSerialize() returned NULL"
2439 Note: Always set inventory not sent, to repair cases
2440 where the client made a bad prediction.
2444 Handle restrictions and special cases of the move action
2446 if(a->getType() == IACTION_MOVE)
2448 IMoveAction *ma = (IMoveAction*)a;
2450 ma->from_inv.applyCurrentPlayer(player->getName());
2451 ma->to_inv.applyCurrentPlayer(player->getName());
2453 setInventoryModified(ma->from_inv);
2454 setInventoryModified(ma->to_inv);
2456 bool from_inv_is_current_player =
2457 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2458 (ma->from_inv.name == player->getName());
2460 bool to_inv_is_current_player =
2461 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2462 (ma->to_inv.name == player->getName());
2465 Disable moving items out of craftpreview
2467 if(ma->from_list == "craftpreview")
2469 infostream<<"Ignoring IMoveAction from "
2470 <<(ma->from_inv.dump())<<":"<<ma->from_list
2471 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2472 <<" because src is "<<ma->from_list<<std::endl;
2478 Disable moving items into craftresult and craftpreview
2480 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2482 infostream<<"Ignoring IMoveAction from "
2483 <<(ma->from_inv.dump())<<":"<<ma->from_list
2484 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2485 <<" because dst is "<<ma->to_list<<std::endl;
2490 // Disallow moving items in elsewhere than player's inventory
2491 // if not allowed to interact
2492 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2493 && (!from_inv_is_current_player
2494 || !to_inv_is_current_player))
2496 infostream<<"Cannot move outside of player's inventory: "
2497 <<"No interact privilege"<<std::endl;
2502 // If player is not an admin, check for ownership of src and dst
2503 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2505 std::string owner_from = getInventoryOwner(ma->from_inv);
2506 if(owner_from != "" && owner_from != player->getName())
2508 infostream<<"WARNING: "<<player->getName()
2509 <<" tried to access an inventory that"
2510 <<" belongs to "<<owner_from<<std::endl;
2515 std::string owner_to = getInventoryOwner(ma->to_inv);
2516 if(owner_to != "" && owner_to != player->getName())
2518 infostream<<"WARNING: "<<player->getName()
2519 <<" tried to access an inventory that"
2520 <<" belongs to "<<owner_to<<std::endl;
2527 Handle restrictions and special cases of the drop action
2529 else if(a->getType() == IACTION_DROP)
2531 IDropAction *da = (IDropAction*)a;
2533 da->from_inv.applyCurrentPlayer(player->getName());
2535 setInventoryModified(da->from_inv);
2537 // Disallow dropping items if not allowed to interact
2538 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2543 // If player is not an admin, check for ownership
2544 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2546 std::string owner_from = getInventoryOwner(da->from_inv);
2547 if(owner_from != "" && owner_from != player->getName())
2549 infostream<<"WARNING: "<<player->getName()
2550 <<" tried to access an inventory that"
2551 <<" belongs to "<<owner_from<<std::endl;
2558 Handle restrictions and special cases of the craft action
2560 else if(a->getType() == IACTION_CRAFT)
2562 ICraftAction *ca = (ICraftAction*)a;
2564 ca->craft_inv.applyCurrentPlayer(player->getName());
2566 setInventoryModified(ca->craft_inv);
2568 //bool craft_inv_is_current_player =
2569 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2570 // (ca->craft_inv.name == player->getName());
2572 // Disallow crafting if not allowed to interact
2573 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2575 infostream<<"Cannot craft: "
2576 <<"No interact privilege"<<std::endl;
2581 // If player is not an admin, check for ownership of inventory
2582 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2584 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2585 if(owner_craft != "" && owner_craft != player->getName())
2587 infostream<<"WARNING: "<<player->getName()
2588 <<" tried to access an inventory that"
2589 <<" belongs to "<<owner_craft<<std::endl;
2597 a->apply(this, srp, this);
2601 else if(command == TOSERVER_CHAT_MESSAGE)
2609 std::string datastring((char*)&data[2], datasize-2);
2610 std::istringstream is(datastring, std::ios_base::binary);
2613 is.read((char*)buf, 2);
2614 u16 len = readU16(buf);
2616 std::wstring message;
2617 for(u16 i=0; i<len; i++)
2619 is.read((char*)buf, 2);
2620 message += (wchar_t)readU16(buf);
2623 // Get player name of this client
2624 std::wstring name = narrow_to_wide(player->getName());
2627 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2628 wide_to_narrow(message));
2629 // If script ate the message, don't proceed
2633 // Line to send to players
2635 // Whether to send to the player that sent the line
2636 bool send_to_sender = false;
2637 // Whether to send to other players
2638 bool send_to_others = false;
2640 // Local player gets all privileges regardless of
2641 // what's set on their account.
2642 u64 privs = getPlayerPrivs(player);
2645 if(message[0] == L'/')
2647 size_t strip_size = 1;
2648 if (message[1] == L'#') // support old-style commans
2650 message = message.substr(strip_size);
2652 WStrfnd f1(message);
2653 f1.next(L" "); // Skip over /#whatever
2654 std::wstring paramstring = f1.next(L"");
2656 ServerCommandContext *ctx = new ServerCommandContext(
2657 str_split(message, L' '),
2664 std::wstring reply(processServerCommand(ctx));
2665 send_to_sender = ctx->flags & SEND_TO_SENDER;
2666 send_to_others = ctx->flags & SEND_TO_OTHERS;
2668 if (ctx->flags & SEND_NO_PREFIX)
2671 line += L"Server: " + reply;
2678 if(privs & PRIV_SHOUT)
2684 send_to_others = true;
2688 line += L"Server: You are not allowed to shout";
2689 send_to_sender = true;
2696 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2699 Send the message to clients
2701 for(core::map<u16, RemoteClient*>::Iterator
2702 i = m_clients.getIterator();
2703 i.atEnd() == false; i++)
2705 // Get client and check that it is valid
2706 RemoteClient *client = i.getNode()->getValue();
2707 assert(client->peer_id == i.getNode()->getKey());
2708 if(client->serialization_version == SER_FMT_VER_INVALID)
2712 bool sender_selected = (peer_id == client->peer_id);
2713 if(sender_selected == true && send_to_sender == false)
2715 if(sender_selected == false && send_to_others == false)
2718 SendChatMessage(client->peer_id, line);
2722 else if(command == TOSERVER_DAMAGE)
2724 std::string datastring((char*)&data[2], datasize-2);
2725 std::istringstream is(datastring, std::ios_base::binary);
2726 u8 damage = readU8(is);
2728 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2730 if(g_settings->getBool("enable_damage"))
2732 actionstream<<player->getName()<<" damaged by "
2733 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2736 srp->setHP(srp->getHP() - damage);
2738 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2741 if(srp->m_hp_not_sent)
2742 SendPlayerHP(player);
2746 // Force send (to correct the client's predicted HP)
2747 SendPlayerHP(player);
2750 else if(command == TOSERVER_PASSWORD)
2753 [0] u16 TOSERVER_PASSWORD
2754 [2] u8[28] old password
2755 [30] u8[28] new password
2758 if(datasize != 2+PASSWORD_SIZE*2)
2760 /*char password[PASSWORD_SIZE];
2761 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2762 password[i] = data[2+i];
2763 password[PASSWORD_SIZE-1] = 0;*/
2765 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2773 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2775 char c = data[2+PASSWORD_SIZE+i];
2781 infostream<<"Server: Client requests a password change from "
2782 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2784 std::string playername = player->getName();
2786 if(m_authmanager.exists(playername) == false)
2788 infostream<<"Server: playername not found in authmanager"<<std::endl;
2789 // Wrong old password supplied!!
2790 SendChatMessage(peer_id, L"playername not found in authmanager");
2794 std::string checkpwd = m_authmanager.getPassword(playername);
2796 if(oldpwd != checkpwd)
2798 infostream<<"Server: invalid old password"<<std::endl;
2799 // Wrong old password supplied!!
2800 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2804 actionstream<<player->getName()<<" changes password"<<std::endl;
2806 m_authmanager.setPassword(playername, newpwd);
2808 infostream<<"Server: password change successful for "<<playername
2810 SendChatMessage(peer_id, L"Password change successful");
2812 else if(command == TOSERVER_PLAYERITEM)
2817 u16 item = readU16(&data[2]);
2818 srp->setWieldIndex(item);
2819 SendWieldedItem(srp);
2821 else if(command == TOSERVER_RESPAWN)
2826 RespawnPlayer(player);
2828 actionstream<<player->getName()<<" respawns at "
2829 <<PP(player->getPosition()/BS)<<std::endl;
2831 // ActiveObject is added to environment in AsyncRunStep after
2832 // the previous addition has been succesfully removed
2834 else if(command == TOSERVER_REQUEST_TEXTURES) {
2835 std::string datastring((char*)&data[2], datasize-2);
2836 std::istringstream is(datastring, std::ios_base::binary);
2839 core::list<TextureRequest> tosend;
2840 u16 numtextures = readU16(is);
2842 infostream<<"Sending "<<numtextures<<" textures to "
2843 <<getPlayerName(peer_id)<<std::endl;
2844 verbosestream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2846 for(int i = 0; i < numtextures; i++) {
2847 std::string name = deSerializeString(is);
2848 tosend.push_back(TextureRequest(name));
2849 verbosestream<<"TOSERVER_REQUEST_TEXTURES: requested texture "
2853 SendTexturesRequested(peer_id, tosend);
2855 // Now the client should know about everything
2856 // (definitions and textures)
2857 getClient(peer_id)->definitions_sent = true;
2859 else if(command == TOSERVER_INTERACT)
2861 std::string datastring((char*)&data[2], datasize-2);
2862 std::istringstream is(datastring, std::ios_base::binary);
2868 [5] u32 length of the next item
2869 [9] serialized PointedThing
2871 0: start digging (from undersurface) or use
2872 1: stop digging (all parameters ignored)
2873 2: digging completed
2874 3: place block or item (to abovesurface)
2877 u8 action = readU8(is);
2878 u16 item_i = readU16(is);
2879 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2880 PointedThing pointed;
2881 pointed.deSerialize(tmp_is);
2883 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2884 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2888 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2889 <<" tried to interact, but is dead!"<<std::endl;
2893 v3f player_pos = srp->m_last_good_position;
2895 // Update wielded item
2896 if(srp->getWieldIndex() != item_i)
2898 srp->setWieldIndex(item_i);
2899 SendWieldedItem(srp);
2902 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2903 v3s16 p_under = pointed.node_undersurface;
2904 v3s16 p_above = pointed.node_abovesurface;
2906 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2907 ServerActiveObject *pointed_object = NULL;
2908 if(pointed.type == POINTEDTHING_OBJECT)
2910 pointed_object = m_env->getActiveObject(pointed.object_id);
2911 if(pointed_object == NULL)
2913 verbosestream<<"TOSERVER_INTERACT: "
2914 "pointed object is NULL"<<std::endl;
2920 v3f pointed_pos_under = player_pos;
2921 v3f pointed_pos_above = player_pos;
2922 if(pointed.type == POINTEDTHING_NODE)
2924 pointed_pos_under = intToFloat(p_under, BS);
2925 pointed_pos_above = intToFloat(p_above, BS);
2927 else if(pointed.type == POINTEDTHING_OBJECT)
2929 pointed_pos_under = pointed_object->getBasePosition();
2930 pointed_pos_above = pointed_pos_under;
2934 Check that target is reasonably close
2935 (only when digging or placing things)
2937 if(action == 0 || action == 2 || action == 3)
2939 float d = player_pos.getDistanceFrom(pointed_pos_under);
2940 float max_d = BS * 14; // Just some large enough value
2942 actionstream<<"Player "<<player->getName()
2943 <<" tried to access "<<pointed.dump()
2945 <<"d="<<d<<", max_d="<<max_d
2946 <<". ignoring."<<std::endl;
2947 // Re-send block to revert change on client-side
2948 RemoteClient *client = getClient(peer_id);
2949 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2950 client->SetBlockNotSent(blockpos);
2957 Make sure the player is allowed to do it
2959 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2961 infostream<<"Ignoring interaction from player "<<player->getName()
2962 <<" because privileges are "<<getPlayerPrivs(player)
2968 0: start digging or punch object
2972 if(pointed.type == POINTEDTHING_NODE)
2975 NOTE: This can be used in the future to check if
2976 somebody is cheating, by checking the timing.
2978 MapNode n(CONTENT_IGNORE);
2981 n = m_env->getMap().getNode(p_under);
2983 catch(InvalidPositionException &e)
2985 infostream<<"Server: Not punching: Node not found."
2986 <<" Adding block to emerge queue."
2988 m_emerge_queue.addBlock(peer_id,
2989 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2991 if(n.getContent() != CONTENT_IGNORE)
2992 scriptapi_node_on_punch(m_lua, p_under, n, srp);
2994 else if(pointed.type == POINTEDTHING_OBJECT)
2996 // Skip if object has been removed
2997 if(pointed_object->m_removed)
3000 actionstream<<player->getName()<<" punches object "
3001 <<pointed.object_id<<": "
3002 <<pointed_object->getDescription()<<std::endl;
3004 ItemStack punchitem = srp->getWieldedItem();
3005 ToolCapabilities toolcap =
3006 punchitem.getToolCapabilities(m_itemdef);
3007 v3f dir = (pointed_object->getBasePosition() -
3008 (srp->getPosition() + srp->getEyeOffset())
3010 pointed_object->punch(dir, &toolcap, srp,
3011 srp->m_time_from_last_punch);
3012 srp->m_time_from_last_punch = 0;
3020 else if(action == 1)
3025 2: Digging completed
3027 else if(action == 2)
3029 // Only complete digging of nodes
3030 if(pointed.type == POINTEDTHING_NODE)
3032 MapNode n(CONTENT_IGNORE);
3035 n = m_env->getMap().getNode(p_under);
3037 catch(InvalidPositionException &e)
3039 infostream<<"Server: Not finishing digging: Node not found."
3040 <<" Adding block to emerge queue."
3042 m_emerge_queue.addBlock(peer_id,
3043 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3045 if(n.getContent() != CONTENT_IGNORE)
3046 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3051 3: place block or right-click object
3053 else if(action == 3)
3055 ItemStack item = srp->getWieldedItem();
3057 // Reset build time counter
3058 if(pointed.type == POINTEDTHING_NODE &&
3059 item.getDefinition(m_itemdef).type == ITEM_NODE)
3060 getClient(peer_id)->m_time_from_building = 0.0;
3062 if(pointed.type == POINTEDTHING_OBJECT)
3064 // Right click object
3066 // Skip if object has been removed
3067 if(pointed_object->m_removed)
3070 actionstream<<player->getName()<<" right-clicks object "
3071 <<pointed.object_id<<": "
3072 <<pointed_object->getDescription()<<std::endl;
3075 pointed_object->rightClick(srp);
3077 else if(scriptapi_item_on_place(m_lua,
3078 item, srp, pointed))
3080 // Placement was handled in lua
3082 // Apply returned ItemStack
3083 if(g_settings->getBool("creative_mode") == false)
3084 srp->setWieldedItem(item);
3092 else if(action == 4)
3094 ItemStack item = srp->getWieldedItem();
3096 actionstream<<player->getName()<<" uses "<<item.name
3097 <<", pointing at "<<pointed.dump()<<std::endl;
3099 if(scriptapi_item_on_use(m_lua,
3100 item, srp, pointed))
3102 // Apply returned ItemStack
3103 if(g_settings->getBool("creative_mode") == false)
3104 srp->setWieldedItem(item);
3110 Catch invalid actions
3114 infostream<<"WARNING: Server: Invalid action "
3115 <<action<<std::endl;
3120 infostream<<"Server::ProcessData(): Ignoring "
3121 "unknown command "<<command<<std::endl;
3125 catch(SendFailedException &e)
3127 errorstream<<"Server::ProcessData(): SendFailedException: "
3133 void Server::onMapEditEvent(MapEditEvent *event)
3135 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3136 if(m_ignore_map_edit_events)
3138 MapEditEvent *e = event->clone();
3139 m_unsent_map_edit_queue.push_back(e);
3142 Inventory* Server::getInventory(const InventoryLocation &loc)
3145 case InventoryLocation::UNDEFINED:
3148 case InventoryLocation::CURRENT_PLAYER:
3151 case InventoryLocation::PLAYER:
3153 Player *player = m_env->getPlayer(loc.name.c_str());
3156 return &player->inventory;
3159 case InventoryLocation::NODEMETA:
3161 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3164 return meta->getInventory();
3172 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3175 case InventoryLocation::UNDEFINED:
3178 case InventoryLocation::CURRENT_PLAYER:
3181 case InventoryLocation::PLAYER:
3186 case InventoryLocation::NODEMETA:
3188 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3191 return meta->getOwner();
3199 void Server::setInventoryModified(const InventoryLocation &loc)
3202 case InventoryLocation::UNDEFINED:
3205 case InventoryLocation::PLAYER:
3207 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3208 (m_env->getPlayer(loc.name.c_str()));
3211 srp->m_inventory_not_sent = true;
3214 case InventoryLocation::NODEMETA:
3216 v3s16 blockpos = getNodeBlockPos(loc.p);
3218 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3220 meta->inventoryModified();
3222 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3224 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3226 setBlockNotSent(blockpos);
3234 core::list<PlayerInfo> Server::getPlayerInfo()
3236 DSTACK(__FUNCTION_NAME);
3237 JMutexAutoLock envlock(m_env_mutex);
3238 JMutexAutoLock conlock(m_con_mutex);
3240 core::list<PlayerInfo> list;
3242 core::list<Player*> players = m_env->getPlayers();
3244 core::list<Player*>::Iterator i;
3245 for(i = players.begin();
3246 i != players.end(); i++)
3250 Player *player = *i;
3253 // Copy info from connection to info struct
3254 info.id = player->peer_id;
3255 info.address = m_con.GetPeerAddress(player->peer_id);
3256 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3258 catch(con::PeerNotFoundException &e)
3260 // Set dummy peer info
3262 info.address = Address(0,0,0,0,0);
3266 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3267 info.position = player->getPosition();
3269 list.push_back(info);
3276 void Server::peerAdded(con::Peer *peer)
3278 DSTACK(__FUNCTION_NAME);
3279 verbosestream<<"Server::peerAdded(): peer->id="
3280 <<peer->id<<std::endl;
3283 c.type = PEER_ADDED;
3284 c.peer_id = peer->id;
3286 m_peer_change_queue.push_back(c);
3289 void Server::deletingPeer(con::Peer *peer, bool timeout)
3291 DSTACK(__FUNCTION_NAME);
3292 verbosestream<<"Server::deletingPeer(): peer->id="
3293 <<peer->id<<", timeout="<<timeout<<std::endl;
3296 c.type = PEER_REMOVED;
3297 c.peer_id = peer->id;
3298 c.timeout = timeout;
3299 m_peer_change_queue.push_back(c);
3306 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3308 DSTACK(__FUNCTION_NAME);
3309 std::ostringstream os(std::ios_base::binary);
3311 writeU16(os, TOCLIENT_HP);
3315 std::string s = os.str();
3316 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3318 con.Send(peer_id, 0, data, true);
3321 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3322 const std::wstring &reason)
3324 DSTACK(__FUNCTION_NAME);
3325 std::ostringstream os(std::ios_base::binary);
3327 writeU16(os, TOCLIENT_ACCESS_DENIED);
3328 os<<serializeWideString(reason);
3331 std::string s = os.str();
3332 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3334 con.Send(peer_id, 0, data, true);
3337 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3338 bool set_camera_point_target, v3f camera_point_target)
3340 DSTACK(__FUNCTION_NAME);
3341 std::ostringstream os(std::ios_base::binary);
3343 writeU16(os, TOCLIENT_DEATHSCREEN);
3344 writeU8(os, set_camera_point_target);
3345 writeV3F1000(os, camera_point_target);
3348 std::string s = os.str();
3349 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3351 con.Send(peer_id, 0, data, true);
3354 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3355 IItemDefManager *itemdef)
3357 DSTACK(__FUNCTION_NAME);
3358 std::ostringstream os(std::ios_base::binary);
3362 u32 length of the next item
3363 zlib-compressed serialized ItemDefManager
3365 writeU16(os, TOCLIENT_ITEMDEF);
3366 std::ostringstream tmp_os(std::ios::binary);
3367 itemdef->serialize(tmp_os);
3368 std::ostringstream tmp_os2(std::ios::binary);
3369 compressZlib(tmp_os.str(), tmp_os2);
3370 os<<serializeLongString(tmp_os2.str());
3373 std::string s = os.str();
3374 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3375 <<"): size="<<s.size()<<std::endl;
3376 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3378 con.Send(peer_id, 0, data, true);
3381 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3382 INodeDefManager *nodedef)
3384 DSTACK(__FUNCTION_NAME);
3385 std::ostringstream os(std::ios_base::binary);
3389 u32 length of the next item
3390 zlib-compressed serialized NodeDefManager
3392 writeU16(os, TOCLIENT_NODEDEF);
3393 std::ostringstream tmp_os(std::ios::binary);
3394 nodedef->serialize(tmp_os);
3395 std::ostringstream tmp_os2(std::ios::binary);
3396 compressZlib(tmp_os.str(), tmp_os2);
3397 os<<serializeLongString(tmp_os2.str());
3400 std::string s = os.str();
3401 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3402 <<"): size="<<s.size()<<std::endl;
3403 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3405 con.Send(peer_id, 0, data, true);
3409 Non-static send methods
3412 void Server::SendInventory(u16 peer_id)
3414 DSTACK(__FUNCTION_NAME);
3416 ServerRemotePlayer* player =
3417 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3420 player->m_inventory_not_sent = false;
3426 std::ostringstream os;
3427 //os.imbue(std::locale("C"));
3429 player->inventory.serialize(os);
3431 std::string s = os.str();
3433 SharedBuffer<u8> data(s.size()+2);
3434 writeU16(&data[0], TOCLIENT_INVENTORY);
3435 memcpy(&data[2], s.c_str(), s.size());
3438 m_con.Send(peer_id, 0, data, true);
3441 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3443 DSTACK(__FUNCTION_NAME);
3447 std::ostringstream os(std::ios_base::binary);
3449 writeU16(os, TOCLIENT_PLAYERITEM);
3451 writeU16(os, srp->peer_id);
3452 os<<serializeString(srp->getWieldedItem().getItemString());
3455 std::string s = os.str();
3456 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3458 m_con.SendToAll(0, data, true);
3461 void Server::SendPlayerItems()
3463 DSTACK(__FUNCTION_NAME);
3465 std::ostringstream os(std::ios_base::binary);
3466 core::list<Player *> players = m_env->getPlayers(true);
3468 writeU16(os, TOCLIENT_PLAYERITEM);
3469 writeU16(os, players.size());
3470 core::list<Player *>::Iterator i;
3471 for(i = players.begin(); i != players.end(); ++i)
3474 ServerRemotePlayer *srp =
3475 static_cast<ServerRemotePlayer*>(p);
3476 writeU16(os, p->peer_id);
3477 os<<serializeString(srp->getWieldedItem().getItemString());
3481 std::string s = os.str();
3482 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3484 m_con.SendToAll(0, data, true);
3487 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3489 DSTACK(__FUNCTION_NAME);
3491 std::ostringstream os(std::ios_base::binary);
3495 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3496 os.write((char*)buf, 2);
3499 writeU16(buf, message.size());
3500 os.write((char*)buf, 2);
3503 for(u32 i=0; i<message.size(); i++)
3507 os.write((char*)buf, 2);
3511 std::string s = os.str();
3512 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3514 m_con.Send(peer_id, 0, data, true);
3517 void Server::BroadcastChatMessage(const std::wstring &message)
3519 for(core::map<u16, RemoteClient*>::Iterator
3520 i = m_clients.getIterator();
3521 i.atEnd() == false; i++)
3523 // Get client and check that it is valid
3524 RemoteClient *client = i.getNode()->getValue();
3525 assert(client->peer_id == i.getNode()->getKey());
3526 if(client->serialization_version == SER_FMT_VER_INVALID)
3529 SendChatMessage(client->peer_id, message);
3533 void Server::SendPlayerHP(Player *player)
3535 SendHP(m_con, player->peer_id, player->hp);
3536 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3539 void Server::SendMovePlayer(Player *player)
3541 DSTACK(__FUNCTION_NAME);
3542 std::ostringstream os(std::ios_base::binary);
3544 writeU16(os, TOCLIENT_MOVE_PLAYER);
3545 writeV3F1000(os, player->getPosition());
3546 writeF1000(os, player->getPitch());
3547 writeF1000(os, player->getYaw());
3550 v3f pos = player->getPosition();
3551 f32 pitch = player->getPitch();
3552 f32 yaw = player->getYaw();
3553 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3554 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3561 std::string s = os.str();
3562 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3564 m_con.Send(player->peer_id, 0, data, true);
3567 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3568 core::list<u16> *far_players, float far_d_nodes)
3570 float maxd = far_d_nodes*BS;
3571 v3f p_f = intToFloat(p, BS);
3575 SharedBuffer<u8> reply(replysize);
3576 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3577 writeS16(&reply[2], p.X);
3578 writeS16(&reply[4], p.Y);
3579 writeS16(&reply[6], p.Z);
3581 for(core::map<u16, RemoteClient*>::Iterator
3582 i = m_clients.getIterator();
3583 i.atEnd() == false; i++)
3585 // Get client and check that it is valid
3586 RemoteClient *client = i.getNode()->getValue();
3587 assert(client->peer_id == i.getNode()->getKey());
3588 if(client->serialization_version == SER_FMT_VER_INVALID)
3591 // Don't send if it's the same one
3592 if(client->peer_id == ignore_id)
3598 Player *player = m_env->getPlayer(client->peer_id);
3601 // If player is far away, only set modified blocks not sent
3602 v3f player_pos = player->getPosition();
3603 if(player_pos.getDistanceFrom(p_f) > maxd)
3605 far_players->push_back(client->peer_id);
3612 m_con.Send(client->peer_id, 0, reply, true);
3616 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3617 core::list<u16> *far_players, float far_d_nodes)
3619 float maxd = far_d_nodes*BS;
3620 v3f p_f = intToFloat(p, BS);
3622 for(core::map<u16, RemoteClient*>::Iterator
3623 i = m_clients.getIterator();
3624 i.atEnd() == false; i++)
3626 // Get client and check that it is valid
3627 RemoteClient *client = i.getNode()->getValue();
3628 assert(client->peer_id == i.getNode()->getKey());
3629 if(client->serialization_version == SER_FMT_VER_INVALID)
3632 // Don't send if it's the same one
3633 if(client->peer_id == ignore_id)
3639 Player *player = m_env->getPlayer(client->peer_id);
3642 // If player is far away, only set modified blocks not sent
3643 v3f player_pos = player->getPosition();
3644 if(player_pos.getDistanceFrom(p_f) > maxd)
3646 far_players->push_back(client->peer_id);
3653 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3654 SharedBuffer<u8> reply(replysize);
3655 writeU16(&reply[0], TOCLIENT_ADDNODE);
3656 writeS16(&reply[2], p.X);
3657 writeS16(&reply[4], p.Y);
3658 writeS16(&reply[6], p.Z);
3659 n.serialize(&reply[8], client->serialization_version);
3662 m_con.Send(client->peer_id, 0, reply, true);
3666 void Server::setBlockNotSent(v3s16 p)
3668 for(core::map<u16, RemoteClient*>::Iterator
3669 i = m_clients.getIterator();
3670 i.atEnd()==false; i++)
3672 RemoteClient *client = i.getNode()->getValue();
3673 client->SetBlockNotSent(p);
3677 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3679 DSTACK(__FUNCTION_NAME);
3681 v3s16 p = block->getPos();
3685 bool completely_air = true;
3686 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3687 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3688 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3690 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3692 completely_air = false;
3693 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3698 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3700 infostream<<"[completely air] ";
3701 infostream<<std::endl;
3705 Create a packet with the block in the right format
3708 std::ostringstream os(std::ios_base::binary);
3709 block->serialize(os, ver, false);
3710 std::string s = os.str();
3711 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3713 u32 replysize = 8 + blockdata.getSize();
3714 SharedBuffer<u8> reply(replysize);
3715 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3716 writeS16(&reply[2], p.X);
3717 writeS16(&reply[4], p.Y);
3718 writeS16(&reply[6], p.Z);
3719 memcpy(&reply[8], *blockdata, blockdata.getSize());
3721 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3722 <<": \tpacket size: "<<replysize<<std::endl;*/
3727 m_con.Send(peer_id, 1, reply, true);
3730 void Server::SendBlocks(float dtime)
3732 DSTACK(__FUNCTION_NAME);
3734 JMutexAutoLock envlock(m_env_mutex);
3735 JMutexAutoLock conlock(m_con_mutex);
3737 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3739 core::array<PrioritySortedBlockTransfer> queue;
3741 s32 total_sending = 0;
3744 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3746 for(core::map<u16, RemoteClient*>::Iterator
3747 i = m_clients.getIterator();
3748 i.atEnd() == false; i++)
3750 RemoteClient *client = i.getNode()->getValue();
3751 assert(client->peer_id == i.getNode()->getKey());
3753 // If definitions and textures have not been sent, don't
3754 // send MapBlocks either
3755 if(!client->definitions_sent)
3758 total_sending += client->SendingCount();
3760 if(client->serialization_version == SER_FMT_VER_INVALID)
3763 client->GetNextBlocks(this, dtime, queue);
3768 // Lowest priority number comes first.
3769 // Lowest is most important.
3772 for(u32 i=0; i<queue.size(); i++)
3774 //TODO: Calculate limit dynamically
3775 if(total_sending >= g_settings->getS32
3776 ("max_simultaneous_block_sends_server_total"))
3779 PrioritySortedBlockTransfer q = queue[i];
3781 MapBlock *block = NULL;
3784 block = m_env->getMap().getBlockNoCreate(q.pos);
3786 catch(InvalidPositionException &e)
3791 RemoteClient *client = getClient(q.peer_id);
3793 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3795 client->SentBlock(q.pos);
3801 void Server::PrepareTextures()
3803 DSTACK(__FUNCTION_NAME);
3805 infostream<<"Server: Calculating texture checksums"<<std::endl;
3807 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3808 i != m_mods.end(); i++){
3809 const ModSpec &mod = *i;
3810 std::string texturepath = mod.path + DIR_DELIM + "textures";
3811 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3812 for(u32 j=0; j<dirlist.size(); j++){
3813 if(dirlist[j].dir) // Ignode dirs
3815 std::string tname = dirlist[j].name;
3816 // if name contains illegal characters, ignore the texture
3817 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3818 errorstream<<"Server: ignoring illegal texture name: \""
3819 <<tname<<"\""<<std::endl;
3822 std::string tpath = texturepath + DIR_DELIM + tname;
3824 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3825 if(fis.good() == false){
3826 errorstream<<"Server::PrepareTextures(): Could not open \""
3827 <<tname<<"\" for reading"<<std::endl;
3830 std::ostringstream tmp_os(std::ios_base::binary);
3834 fis.read(buf, 1024);
3835 std::streamsize len = fis.gcount();
3836 tmp_os.write(buf, len);
3845 errorstream<<"Server::PrepareTextures(): Failed to read \""
3846 <<tname<<"\""<<std::endl;
3849 if(tmp_os.str().length() == 0){
3850 errorstream<<"Server::PrepareTextures(): Empty file \""
3851 <<tpath<<"\""<<std::endl;
3856 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3858 unsigned char *digest = sha1.getDigest();
3859 std::string digest_string = base64_encode(digest, 20);
3864 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3865 verbosestream<<"Server: sha1 for "<<tname<<"\tis "<<std::endl;
3870 struct SendableTextureAnnouncement
3873 std::string sha1_digest;
3875 SendableTextureAnnouncement(const std::string name_="",
3876 const std::string sha1_digest_=""):
3878 sha1_digest(sha1_digest_)
3883 void Server::SendTextureAnnouncement(u16 peer_id){
3884 DSTACK(__FUNCTION_NAME);
3886 verbosestream<<"Server: Announcing textures to id("<<peer_id<<")"
3889 core::list<SendableTextureAnnouncement> texture_announcements;
3891 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3894 texture_announcements.push_back(
3895 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3898 //send announcements
3902 u32 number of textures
3906 u16 length of digest string
3910 std::ostringstream os(std::ios_base::binary);
3912 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3913 writeU16(os, texture_announcements.size());
3915 for(core::list<SendableTextureAnnouncement>::Iterator
3916 j = texture_announcements.begin();
3917 j != texture_announcements.end(); j++){
3918 os<<serializeString(j->name);
3919 os<<serializeString(j->sha1_digest);
3923 std::string s = os.str();
3924 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3927 m_con.Send(peer_id, 0, data, true);
3931 struct SendableTexture
3937 SendableTexture(const std::string &name_="", const std::string path_="",
3938 const std::string &data_=""):
3945 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3946 DSTACK(__FUNCTION_NAME);
3948 verbosestream<<"Server::SendTexturesRequested(): "
3949 <<"Sending textures to client"<<std::endl;
3953 // Put 5kB in one bunch (this is not accurate)
3954 u32 bytes_per_bunch = 5000;
3956 core::array< core::list<SendableTexture> > texture_bunches;
3957 texture_bunches.push_back(core::list<SendableTexture>());
3959 u32 texture_size_bunch_total = 0;
3961 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3962 if(m_Textures.find(i->name) == m_Textures.end()){
3963 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3964 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3968 //TODO get path + name
3969 std::string tpath = m_Textures[(*i).name].path;
3972 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3973 if(fis.good() == false){
3974 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3975 <<tpath<<"\" for reading"<<std::endl;
3978 std::ostringstream tmp_os(std::ios_base::binary);
3982 fis.read(buf, 1024);
3983 std::streamsize len = fis.gcount();
3984 tmp_os.write(buf, len);
3985 texture_size_bunch_total += len;
3994 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
3995 <<(*i).name<<"\""<<std::endl;
3998 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
3999 <<tname<<"\""<<std::endl;*/
4001 texture_bunches[texture_bunches.size()-1].push_back(
4002 SendableTexture((*i).name, tpath, tmp_os.str()));
4004 // Start next bunch if got enough data
4005 if(texture_size_bunch_total >= bytes_per_bunch){
4006 texture_bunches.push_back(core::list<SendableTexture>());
4007 texture_size_bunch_total = 0;
4012 /* Create and send packets */
4014 u32 num_bunches = texture_bunches.size();
4015 for(u32 i=0; i<num_bunches; i++)
4019 u16 total number of texture bunches
4020 u16 index of this bunch
4021 u32 number of textures in this bunch
4029 std::ostringstream os(std::ios_base::binary);
4031 writeU16(os, TOCLIENT_TEXTURES);
4032 writeU16(os, num_bunches);
4034 writeU32(os, texture_bunches[i].size());
4036 for(core::list<SendableTexture>::Iterator
4037 j = texture_bunches[i].begin();
4038 j != texture_bunches[i].end(); j++){
4039 os<<serializeString(j->name);
4040 os<<serializeLongString(j->data);
4044 std::string s = os.str();
4045 verbosestream<<"Server::SendTexturesRequested(): bunch "
4046 <<i<<"/"<<num_bunches
4047 <<" textures="<<texture_bunches[i].size()
4048 <<" size=" <<s.size()<<std::endl;
4049 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4051 m_con.Send(peer_id, 0, data, true);
4061 void Server::DiePlayer(Player *player)
4063 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4065 infostream<<"Server::DiePlayer(): Player "
4066 <<player->getName()<<" dies"<<std::endl;
4070 // Trigger scripted stuff
4071 scriptapi_on_dieplayer(m_lua, srp);
4073 // Handle players that are not connected
4074 if(player->peer_id == PEER_ID_INEXISTENT){
4075 RespawnPlayer(player);
4079 SendPlayerHP(player);
4080 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4083 void Server::RespawnPlayer(Player *player)
4085 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4087 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4089 v3f pos = findSpawnPos(m_env->getServerMap());
4090 player->setPosition(pos);
4091 srp->m_last_good_position = pos;
4092 srp->m_last_good_position_age = 0;
4094 SendMovePlayer(player);
4095 SendPlayerHP(player);
4098 void Server::UpdateCrafting(u16 peer_id)
4100 DSTACK(__FUNCTION_NAME);
4102 Player* player = m_env->getPlayer(peer_id);
4105 // Get a preview for crafting
4107 // No crafting in creative mode
4108 if(g_settings->getBool("creative_mode") == false)
4109 getCraftingResult(&player->inventory, preview, false, this);
4111 // Put the new preview in
4112 InventoryList *plist = player->inventory.getList("craftpreview");
4114 assert(plist->getSize() >= 1);
4115 plist->changeItem(0, preview);
4118 RemoteClient* Server::getClient(u16 peer_id)
4120 DSTACK(__FUNCTION_NAME);
4121 //JMutexAutoLock lock(m_con_mutex);
4122 core::map<u16, RemoteClient*>::Node *n;
4123 n = m_clients.find(peer_id);
4124 // A client should exist for all peers
4126 return n->getValue();
4129 std::wstring Server::getStatusString()
4131 std::wostringstream os(std::ios_base::binary);
4134 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4136 os<<L", uptime="<<m_uptime.get();
4137 // Information about clients
4139 for(core::map<u16, RemoteClient*>::Iterator
4140 i = m_clients.getIterator();
4141 i.atEnd() == false; i++)
4143 // Get client and check that it is valid
4144 RemoteClient *client = i.getNode()->getValue();
4145 assert(client->peer_id == i.getNode()->getKey());
4146 if(client->serialization_version == SER_FMT_VER_INVALID)
4149 Player *player = m_env->getPlayer(client->peer_id);
4150 // Get name of player
4151 std::wstring name = L"unknown";
4153 name = narrow_to_wide(player->getName());
4154 // Add name to information string
4158 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4159 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4160 if(g_settings->get("motd") != "")
4161 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4165 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4167 // Add player to auth manager
4168 if(m_authmanager.exists(name) == false)
4170 infostream<<"Server: adding player "<<name
4171 <<" to auth manager"<<std::endl;
4172 m_authmanager.add(name);
4173 m_authmanager.setPrivs(name,
4174 stringToPrivs(g_settings->get("default_privs")));
4176 // Change password and save
4177 m_authmanager.setPassword(name, translatePassword(name, password));
4178 m_authmanager.save();
4181 // Saves g_settings to configpath given at initialization
4182 void Server::saveConfig()
4184 if(m_path_config != "")
4185 g_settings->updateConfigFile(m_path_config.c_str());
4188 void Server::notifyPlayer(const char *name, const std::wstring msg)
4190 Player *player = m_env->getPlayer(name);
4193 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4196 void Server::notifyPlayers(const std::wstring msg)
4198 BroadcastChatMessage(msg);
4201 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4205 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4206 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4209 // IGameDef interface
4211 IItemDefManager* Server::getItemDefManager()
4215 INodeDefManager* Server::getNodeDefManager()
4219 ICraftDefManager* Server::getCraftDefManager()
4223 ITextureSource* Server::getTextureSource()
4227 u16 Server::allocateUnknownNodeId(const std::string &name)
4229 return m_nodedef->allocateDummy(name);
4232 IWritableItemDefManager* Server::getWritableItemDefManager()
4236 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4240 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4245 const ModSpec* Server::getModSpec(const std::string &modname)
4247 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4248 i != m_mods.end(); i++){
4249 const ModSpec &mod = *i;
4250 if(mod.name == modname)
4256 v3f findSpawnPos(ServerMap &map)
4258 //return v3f(50,50,50)*BS;
4263 nodepos = v2s16(0,0);
4268 // Try to find a good place a few times
4269 for(s32 i=0; i<1000; i++)
4272 // We're going to try to throw the player to this position
4273 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4274 -range + (myrand()%(range*2)));
4275 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4276 // Get ground height at point (fallbacks to heightmap function)
4277 s16 groundheight = map.findGroundLevel(nodepos2d);
4278 // Don't go underwater
4279 if(groundheight < WATER_LEVEL)
4281 //infostream<<"-> Underwater"<<std::endl;
4284 // Don't go to high places
4285 if(groundheight > WATER_LEVEL + 4)
4287 //infostream<<"-> Underwater"<<std::endl;
4291 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4292 bool is_good = false;
4294 for(s32 i=0; i<10; i++){
4295 v3s16 blockpos = getNodeBlockPos(nodepos);
4296 map.emergeBlock(blockpos, true);
4297 MapNode n = map.getNodeNoEx(nodepos);
4298 if(n.getContent() == CONTENT_AIR){
4309 // Found a good place
4310 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4316 return intToFloat(nodepos, BS);
4319 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4322 Try to get an existing player
4324 ServerRemotePlayer *player =
4325 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4328 // If player is already connected, cancel
4329 if(player->peer_id != 0)
4331 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4336 player->peer_id = peer_id;
4338 // Re-add player to environment
4339 if(player->m_removed)
4341 player->m_removed = false;
4343 m_env->addActiveObject(player);
4346 // Reset inventory to creative if in creative mode
4347 if(g_settings->getBool("creative_mode"))
4349 // Warning: double code below
4350 // Backup actual inventory
4351 player->inventory_backup = new Inventory(m_itemdef);
4352 *(player->inventory_backup) = player->inventory;
4353 // Set creative inventory
4354 player->resetInventory();
4355 scriptapi_get_creative_inventory(m_lua, player);
4362 If player with the wanted peer_id already exists, cancel.
4364 if(m_env->getPlayer(peer_id) != NULL)
4366 infostream<<"emergePlayer(): Player with wrong name but same"
4367 " peer_id already exists"<<std::endl;
4375 /* Set player position */
4377 infostream<<"Server: Finding spawn place for player \""
4378 <<name<<"\""<<std::endl;
4380 v3f pos = findSpawnPos(m_env->getServerMap());
4382 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4383 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4385 /* Add player to environment */
4386 m_env->addPlayer(player);
4387 m_env->addActiveObject(srp);
4390 scriptapi_on_newplayer(m_lua, srp);
4392 /* Add stuff to inventory */
4393 if(g_settings->getBool("creative_mode"))
4395 // Warning: double code above
4396 // Backup actual inventory
4397 player->inventory_backup = new Inventory(m_itemdef);
4398 *(player->inventory_backup) = player->inventory;
4399 // Set creative inventory
4400 player->resetInventory();
4401 scriptapi_get_creative_inventory(m_lua, player);
4406 } // create new player
4409 void Server::handlePeerChange(PeerChange &c)
4411 JMutexAutoLock envlock(m_env_mutex);
4412 JMutexAutoLock conlock(m_con_mutex);
4414 if(c.type == PEER_ADDED)
4421 core::map<u16, RemoteClient*>::Node *n;
4422 n = m_clients.find(c.peer_id);
4423 // The client shouldn't already exist
4427 RemoteClient *client = new RemoteClient();
4428 client->peer_id = c.peer_id;
4429 m_clients.insert(client->peer_id, client);
4432 else if(c.type == PEER_REMOVED)
4439 core::map<u16, RemoteClient*>::Node *n;
4440 n = m_clients.find(c.peer_id);
4441 // The client should exist
4445 Mark objects to be not known by the client
4447 RemoteClient *client = n->getValue();
4449 for(core::map<u16, bool>::Iterator
4450 i = client->m_known_objects.getIterator();
4451 i.atEnd()==false; i++)
4454 u16 id = i.getNode()->getKey();
4455 ServerActiveObject* obj = m_env->getActiveObject(id);
4457 if(obj && obj->m_known_by_count > 0)
4458 obj->m_known_by_count--;
4461 ServerRemotePlayer* player =
4462 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4464 // Collect information about leaving in chat
4465 std::wstring message;
4469 std::wstring name = narrow_to_wide(player->getName());
4472 message += L" left game";
4474 message += L" (timed out)";
4478 // Remove from environment
4480 player->m_removed = true;
4482 // Set player client disconnected
4484 player->peer_id = 0;
4492 std::ostringstream os(std::ios_base::binary);
4493 for(core::map<u16, RemoteClient*>::Iterator
4494 i = m_clients.getIterator();
4495 i.atEnd() == false; i++)
4497 RemoteClient *client = i.getNode()->getValue();
4498 assert(client->peer_id == i.getNode()->getKey());
4499 if(client->serialization_version == SER_FMT_VER_INVALID)
4502 Player *player = m_env->getPlayer(client->peer_id);
4505 // Get name of player
4506 os<<player->getName()<<" ";
4509 actionstream<<player->getName()<<" "
4510 <<(c.timeout?"times out.":"leaves game.")
4511 <<" List of players: "
4512 <<os.str()<<std::endl;
4517 delete m_clients[c.peer_id];
4518 m_clients.remove(c.peer_id);
4520 // Send player info to all remaining clients
4521 //SendPlayerInfos();
4523 // Send leave chat message to all remaining clients
4524 if(message.length() != 0)
4525 BroadcastChatMessage(message);
4534 void Server::handlePeerChanges()
4536 while(m_peer_change_queue.size() > 0)
4538 PeerChange c = m_peer_change_queue.pop_front();
4540 verbosestream<<"Server: Handling peer change: "
4541 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4544 handlePeerChange(c);
4548 u64 Server::getPlayerPrivs(Player *player)
4552 std::string playername = player->getName();
4553 // Local player gets all privileges regardless of
4554 // what's set on their account.
4555 if(g_settings->get("name") == playername)
4561 return getPlayerAuthPrivs(playername);
4565 void dedicated_server_loop(Server &server, bool &kill)
4567 DSTACK(__FUNCTION_NAME);
4569 verbosestream<<"dedicated_server_loop()"<<std::endl;
4571 IntervalLimiter m_profiler_interval;
4575 float steplen = g_settings->getFloat("dedicated_server_step");
4576 // This is kind of a hack but can be done like this
4577 // because server.step() is very light
4579 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4580 sleep_ms((int)(steplen*1000.0));
4582 server.step(steplen);
4584 if(server.getShutdownRequested() || kill)
4586 infostream<<"Dedicated server quitting"<<std::endl;
4593 float profiler_print_interval =
4594 g_settings->getFloat("profiler_print_interval");
4595 if(profiler_print_interval != 0)
4597 if(m_profiler_interval.step(steplen, profiler_print_interval))
4599 infostream<<"Profiler:"<<std::endl;
4600 g_profiler->print(infostream);
4601 g_profiler->clear();