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,
840 bool simple_singleplayer_mode
842 m_path_world(path_world),
843 m_path_config(path_config),
844 m_gamespec(gamespec),
845 m_simple_singleplayer_mode(simple_singleplayer_mode),
846 m_async_fatal_error(""),
848 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
849 m_authmanager(path_world+DIR_DELIM+"auth.txt"),
850 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
852 m_itemdef(createItemDefManager()),
853 m_nodedef(createNodeDefManager()),
854 m_craftdef(createCraftDefManager()),
856 m_emergethread(this),
858 m_time_of_day_send_timer(0),
860 m_shutdown_requested(false),
861 m_ignore_map_edit_events(false),
862 m_ignore_map_edit_events_peer_id(0)
864 m_liquid_transform_timer = 0.0;
865 m_print_info_timer = 0.0;
866 m_objectdata_timer = 0.0;
867 m_emergethread_trigger_timer = 0.0;
868 m_savemap_timer = 0.0;
872 m_step_dtime_mutex.Init();
876 throw ServerError("Supplied empty world path");
878 if(!gamespec.isValid())
879 throw ServerError("Supplied invalid gamespec");
881 // Figure out some paths
883 m_path_share = porting::path_share + DIR_DELIM + "server";
885 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
886 if(m_simple_singleplayer_mode)
887 infostream<<" in simple singleplayer mode"<<std::endl;
889 infostream<<std::endl;
890 infostream<<"- world: "<<m_path_world<<std::endl;
891 infostream<<"- config: "<<m_path_config<<std::endl;
892 infostream<<"- game: "<<m_gamespec.path<<std::endl;
893 for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
894 i != m_gamespec.addon_paths.end(); i++)
895 infostream<<"- addons: "<<(*i)<<std::endl;
897 // Path to builtin.lua
898 std::string builtinpath = m_path_share + DIR_DELIM + "builtin.lua";
900 // Add default global mod search path
901 m_modspaths.push_front(m_gamespec.path + DIR_DELIM "mods");
902 // Add world mod search path
903 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
904 // Add addon mod search path
905 for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
906 i != m_gamespec.addon_paths.end(); i++)
907 m_modspaths.push_front((*i) + DIR_DELIM + "mods");
909 // Print out mod search paths
910 for(core::list<std::string>::Iterator i = m_modspaths.begin();
911 i != m_modspaths.end(); i++){
912 std::string modspath = *i;
913 infostream<<"- mods: "<<modspath<<std::endl;
916 // Create world if it doesn't exist
917 if(!initializeWorld(m_path_world, m_gamespec.id))
918 throw ServerError("Failed to initialize world");
921 JMutexAutoLock envlock(m_env_mutex);
922 JMutexAutoLock conlock(m_con_mutex);
924 // Initialize scripting
926 infostream<<"Server: Initializing Lua"<<std::endl;
927 m_lua = script_init();
930 scriptapi_export(m_lua, this);
931 // Load and run builtin.lua
932 infostream<<"Server: Loading builtin.lua [\""
933 <<builtinpath<<"\"]"<<std::endl;
934 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
936 errorstream<<"Server: Failed to load and run "
937 <<builtinpath<<std::endl;
938 throw ModError("Failed to load and run "+builtinpath);
940 // Find mods in mod search paths
941 m_mods = getMods(m_modspaths);
943 infostream<<"Server: Loading mods: ";
944 for(core::list<ModSpec>::Iterator i = m_mods.begin();
945 i != m_mods.end(); i++){
946 const ModSpec &mod = *i;
947 infostream<<mod.name<<" ";
949 infostream<<std::endl;
950 // Load and run "mod" scripts
951 for(core::list<ModSpec>::Iterator i = m_mods.begin();
952 i != m_mods.end(); i++){
953 const ModSpec &mod = *i;
954 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
955 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
956 <<scriptpath<<"\"]"<<std::endl;
957 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
959 errorstream<<"Server: Failed to load and run "
960 <<scriptpath<<std::endl;
961 throw ModError("Failed to load and run "+scriptpath);
965 // Read Textures and calculate sha1 sums
968 // Apply item aliases in the node definition manager
969 m_nodedef->updateAliases(m_itemdef);
971 // Initialize Environment
973 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
976 // Give environment reference to scripting api
977 scriptapi_add_environment(m_lua, m_env);
979 // Register us to receive map edit events
980 m_env->getMap().addEventReceiver(this);
982 // If file exists, load environment metadata
983 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
985 infostream<<"Server: Loading environment metadata"<<std::endl;
986 m_env->loadMeta(m_path_world);
990 infostream<<"Server: Loading players"<<std::endl;
991 m_env->deSerializePlayers(m_path_world);
994 Add some test ActiveBlockModifiers to environment
996 add_legacy_abms(m_env, m_nodedef);
1001 infostream<<"Server destructing"<<std::endl;
1004 Send shutdown message
1007 JMutexAutoLock conlock(m_con_mutex);
1009 std::wstring line = L"*** Server shutting down";
1012 Send the message to clients
1014 for(core::map<u16, RemoteClient*>::Iterator
1015 i = m_clients.getIterator();
1016 i.atEnd() == false; i++)
1018 // Get client and check that it is valid
1019 RemoteClient *client = i.getNode()->getValue();
1020 assert(client->peer_id == i.getNode()->getKey());
1021 if(client->serialization_version == SER_FMT_VER_INVALID)
1025 SendChatMessage(client->peer_id, line);
1027 catch(con::PeerNotFoundException &e)
1033 JMutexAutoLock envlock(m_env_mutex);
1038 infostream<<"Server: Saving players"<<std::endl;
1039 m_env->serializePlayers(m_path_world);
1042 Save environment metadata
1044 infostream<<"Server: Saving environment metadata"<<std::endl;
1045 m_env->saveMeta(m_path_world);
1057 JMutexAutoLock clientslock(m_con_mutex);
1059 for(core::map<u16, RemoteClient*>::Iterator
1060 i = m_clients.getIterator();
1061 i.atEnd() == false; i++)
1064 // NOTE: These are removed by env destructor
1066 u16 peer_id = i.getNode()->getKey();
1067 JMutexAutoLock envlock(m_env_mutex);
1068 m_env->removePlayer(peer_id);
1072 delete i.getNode()->getValue();
1076 // Delete Environment
1083 // Deinitialize scripting
1084 infostream<<"Server: Deinitializing scripting"<<std::endl;
1085 script_deinit(m_lua);
1088 void Server::start(unsigned short port)
1090 DSTACK(__FUNCTION_NAME);
1091 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1093 // Stop thread if already running
1096 // Initialize connection
1097 m_con.SetTimeoutMs(30);
1101 m_thread.setRun(true);
1104 // ASCII art for the win!
1106 <<" .__ __ __ "<<std::endl
1107 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1108 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1109 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1110 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1111 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1112 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1113 actionstream<<"Server for gameid=\""<<m_gamespec.id
1114 <<"\" listening on port "<<port<<"."<<std::endl;
1119 DSTACK(__FUNCTION_NAME);
1121 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1123 // Stop threads (set run=false first so both start stopping)
1124 m_thread.setRun(false);
1125 m_emergethread.setRun(false);
1127 m_emergethread.stop();
1129 infostream<<"Server: Threads stopped"<<std::endl;
1132 void Server::step(float dtime)
1134 DSTACK(__FUNCTION_NAME);
1139 JMutexAutoLock lock(m_step_dtime_mutex);
1140 m_step_dtime += dtime;
1142 // Throw if fatal error occurred in thread
1143 std::string async_err = m_async_fatal_error.get();
1144 if(async_err != ""){
1145 throw ServerError(async_err);
1149 void Server::AsyncRunStep()
1151 DSTACK(__FUNCTION_NAME);
1153 g_profiler->add("Server::AsyncRunStep (num)", 1);
1157 JMutexAutoLock lock1(m_step_dtime_mutex);
1158 dtime = m_step_dtime;
1162 // Send blocks to clients
1169 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1171 //infostream<<"Server steps "<<dtime<<std::endl;
1172 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1175 JMutexAutoLock lock1(m_step_dtime_mutex);
1176 m_step_dtime -= dtime;
1183 m_uptime.set(m_uptime.get() + dtime);
1187 // Process connection's timeouts
1188 JMutexAutoLock lock2(m_con_mutex);
1189 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1190 m_con.RunTimeouts(dtime);
1194 // This has to be called so that the client list gets synced
1195 // with the peer list of the connection
1196 handlePeerChanges();
1200 Update m_time_of_day and overall game time
1203 JMutexAutoLock envlock(m_env_mutex);
1205 m_time_counter += dtime;
1206 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1207 u32 units = (u32)(m_time_counter*speed);
1208 m_time_counter -= (f32)units / speed;
1210 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1212 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1215 Send to clients at constant intervals
1218 m_time_of_day_send_timer -= dtime;
1219 if(m_time_of_day_send_timer < 0.0)
1221 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1223 //JMutexAutoLock envlock(m_env_mutex);
1224 JMutexAutoLock conlock(m_con_mutex);
1226 for(core::map<u16, RemoteClient*>::Iterator
1227 i = m_clients.getIterator();
1228 i.atEnd() == false; i++)
1230 RemoteClient *client = i.getNode()->getValue();
1231 //Player *player = m_env->getPlayer(client->peer_id);
1233 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1234 m_env->getTimeOfDay());
1236 m_con.Send(client->peer_id, 0, data, true);
1242 JMutexAutoLock lock(m_env_mutex);
1244 ScopeProfiler sp(g_profiler, "SEnv step");
1245 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1249 const float map_timer_and_unload_dtime = 2.92;
1250 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1252 JMutexAutoLock lock(m_env_mutex);
1253 // Run Map's timers and unload unused data
1254 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1255 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1256 g_settings->getFloat("server_unload_unused_data_timeout"));
1267 JMutexAutoLock lock(m_env_mutex);
1268 JMutexAutoLock lock2(m_con_mutex);
1270 ScopeProfiler sp(g_profiler, "Server: handle players");
1272 //float player_max_speed = BS * 4.0; // Normal speed
1273 float player_max_speed = BS * 20; // Fast speed
1274 float player_max_speed_up = BS * 20;
1276 player_max_speed *= 2.5; // Tolerance
1277 player_max_speed_up *= 2.5;
1279 for(core::map<u16, RemoteClient*>::Iterator
1280 i = m_clients.getIterator();
1281 i.atEnd() == false; i++)
1283 RemoteClient *client = i.getNode()->getValue();
1284 ServerRemotePlayer *player =
1285 static_cast<ServerRemotePlayer*>
1286 (m_env->getPlayer(client->peer_id));
1291 Check player movements
1293 NOTE: Actually the server should handle player physics like the
1294 client does and compare player's position to what is calculated
1295 on our side. This is required when eg. players fly due to an
1298 player->m_last_good_position_age += dtime;
1299 if(player->m_last_good_position_age >= 1.0){
1300 float age = player->m_last_good_position_age;
1301 v3f diff = (player->getPosition() - player->m_last_good_position);
1302 float d_vert = diff.Y;
1304 float d_horiz = diff.getLength();
1305 /*infostream<<player->getName()<<"'s horizontal speed is "
1306 <<(d_horiz/age)<<std::endl;*/
1307 if(d_horiz <= age * player_max_speed &&
1308 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1309 player->m_last_good_position = player->getPosition();
1311 actionstream<<"Player "<<player->getName()
1312 <<" moved too fast; resetting position"
1314 player->setPosition(player->m_last_good_position);
1315 SendMovePlayer(player);
1317 player->m_last_good_position_age = 0;
1321 Handle player HPs (die if hp=0)
1323 if(player->hp == 0 && player->m_hp_not_sent)
1327 Send player inventories and HPs if necessary
1329 if(player->m_inventory_not_sent){
1330 UpdateCrafting(player->peer_id);
1331 SendInventory(player->peer_id);
1333 if(player->m_hp_not_sent){
1334 SendPlayerHP(player);
1340 if(!player->m_is_in_environment){
1341 player->m_removed = false;
1343 m_env->addActiveObject(player);
1348 /* Transform liquids */
1349 m_liquid_transform_timer += dtime;
1350 if(m_liquid_transform_timer >= 1.00)
1352 m_liquid_transform_timer -= 1.00;
1354 JMutexAutoLock lock(m_env_mutex);
1356 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1358 core::map<v3s16, MapBlock*> modified_blocks;
1359 m_env->getMap().transformLiquids(modified_blocks);
1364 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1365 ServerMap &map = ((ServerMap&)m_env->getMap());
1366 map.updateLighting(modified_blocks, lighting_modified_blocks);
1368 // Add blocks modified by lighting to modified_blocks
1369 for(core::map<v3s16, MapBlock*>::Iterator
1370 i = lighting_modified_blocks.getIterator();
1371 i.atEnd() == false; i++)
1373 MapBlock *block = i.getNode()->getValue();
1374 modified_blocks.insert(block->getPos(), block);
1378 Set the modified blocks unsent for all the clients
1381 JMutexAutoLock lock2(m_con_mutex);
1383 for(core::map<u16, RemoteClient*>::Iterator
1384 i = m_clients.getIterator();
1385 i.atEnd() == false; i++)
1387 RemoteClient *client = i.getNode()->getValue();
1389 if(modified_blocks.size() > 0)
1391 // Remove block from sent history
1392 client->SetBlocksNotSent(modified_blocks);
1397 // Periodically print some info
1399 float &counter = m_print_info_timer;
1405 JMutexAutoLock lock2(m_con_mutex);
1407 if(m_clients.size() != 0)
1408 infostream<<"Players:"<<std::endl;
1409 for(core::map<u16, RemoteClient*>::Iterator
1410 i = m_clients.getIterator();
1411 i.atEnd() == false; i++)
1413 //u16 peer_id = i.getNode()->getKey();
1414 RemoteClient *client = i.getNode()->getValue();
1415 Player *player = m_env->getPlayer(client->peer_id);
1418 infostream<<"* "<<player->getName()<<"\t";
1419 client->PrintInfo(infostream);
1424 //if(g_settings->getBool("enable_experimental"))
1428 Check added and deleted active objects
1431 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1432 JMutexAutoLock envlock(m_env_mutex);
1433 JMutexAutoLock conlock(m_con_mutex);
1435 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1437 // Radius inside which objects are active
1438 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1439 radius *= MAP_BLOCKSIZE;
1441 for(core::map<u16, RemoteClient*>::Iterator
1442 i = m_clients.getIterator();
1443 i.atEnd() == false; i++)
1445 RemoteClient *client = i.getNode()->getValue();
1447 // If definitions and textures have not been sent, don't
1448 // send objects either
1449 if(!client->definitions_sent)
1452 Player *player = m_env->getPlayer(client->peer_id);
1455 // This can happen if the client timeouts somehow
1456 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1458 <<" has no associated player"<<std::endl;*/
1461 v3s16 pos = floatToInt(player->getPosition(), BS);
1463 core::map<u16, bool> removed_objects;
1464 core::map<u16, bool> added_objects;
1465 m_env->getRemovedActiveObjects(pos, radius,
1466 client->m_known_objects, removed_objects);
1467 m_env->getAddedActiveObjects(pos, radius,
1468 client->m_known_objects, added_objects);
1470 // Ignore if nothing happened
1471 if(removed_objects.size() == 0 && added_objects.size() == 0)
1473 //infostream<<"active objects: none changed"<<std::endl;
1477 std::string data_buffer;
1481 // Handle removed objects
1482 writeU16((u8*)buf, removed_objects.size());
1483 data_buffer.append(buf, 2);
1484 for(core::map<u16, bool>::Iterator
1485 i = removed_objects.getIterator();
1486 i.atEnd()==false; i++)
1489 u16 id = i.getNode()->getKey();
1490 ServerActiveObject* obj = m_env->getActiveObject(id);
1492 // Add to data buffer for sending
1493 writeU16((u8*)buf, i.getNode()->getKey());
1494 data_buffer.append(buf, 2);
1496 // Remove from known objects
1497 client->m_known_objects.remove(i.getNode()->getKey());
1499 if(obj && obj->m_known_by_count > 0)
1500 obj->m_known_by_count--;
1503 // Handle added objects
1504 writeU16((u8*)buf, added_objects.size());
1505 data_buffer.append(buf, 2);
1506 for(core::map<u16, bool>::Iterator
1507 i = added_objects.getIterator();
1508 i.atEnd()==false; i++)
1511 u16 id = i.getNode()->getKey();
1512 ServerActiveObject* obj = m_env->getActiveObject(id);
1515 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1517 infostream<<"WARNING: "<<__FUNCTION_NAME
1518 <<": NULL object"<<std::endl;
1520 type = obj->getType();
1522 // Add to data buffer for sending
1523 writeU16((u8*)buf, id);
1524 data_buffer.append(buf, 2);
1525 writeU8((u8*)buf, type);
1526 data_buffer.append(buf, 1);
1529 data_buffer.append(serializeLongString(
1530 obj->getClientInitializationData()));
1532 data_buffer.append(serializeLongString(""));
1534 // Add to known objects
1535 client->m_known_objects.insert(i.getNode()->getKey(), false);
1538 obj->m_known_by_count++;
1542 SharedBuffer<u8> reply(2 + data_buffer.size());
1543 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1544 memcpy((char*)&reply[2], data_buffer.c_str(),
1545 data_buffer.size());
1547 m_con.Send(client->peer_id, 0, reply, true);
1549 verbosestream<<"Server: Sent object remove/add: "
1550 <<removed_objects.size()<<" removed, "
1551 <<added_objects.size()<<" added, "
1552 <<"packet size is "<<reply.getSize()<<std::endl;
1557 Collect a list of all the objects known by the clients
1558 and report it back to the environment.
1561 core::map<u16, bool> all_known_objects;
1563 for(core::map<u16, RemoteClient*>::Iterator
1564 i = m_clients.getIterator();
1565 i.atEnd() == false; i++)
1567 RemoteClient *client = i.getNode()->getValue();
1568 // Go through all known objects of client
1569 for(core::map<u16, bool>::Iterator
1570 i = client->m_known_objects.getIterator();
1571 i.atEnd()==false; i++)
1573 u16 id = i.getNode()->getKey();
1574 all_known_objects[id] = true;
1578 m_env->setKnownActiveObjects(whatever);
1584 Send object messages
1587 JMutexAutoLock envlock(m_env_mutex);
1588 JMutexAutoLock conlock(m_con_mutex);
1590 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1593 // Value = data sent by object
1594 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1596 // Get active object messages from environment
1599 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1603 core::list<ActiveObjectMessage>* message_list = NULL;
1604 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1605 n = buffered_messages.find(aom.id);
1608 message_list = new core::list<ActiveObjectMessage>;
1609 buffered_messages.insert(aom.id, message_list);
1613 message_list = n->getValue();
1615 message_list->push_back(aom);
1618 // Route data to every client
1619 for(core::map<u16, RemoteClient*>::Iterator
1620 i = m_clients.getIterator();
1621 i.atEnd()==false; i++)
1623 RemoteClient *client = i.getNode()->getValue();
1624 std::string reliable_data;
1625 std::string unreliable_data;
1626 // Go through all objects in message buffer
1627 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1628 j = buffered_messages.getIterator();
1629 j.atEnd()==false; j++)
1631 // If object is not known by client, skip it
1632 u16 id = j.getNode()->getKey();
1633 if(client->m_known_objects.find(id) == NULL)
1635 // Get message list of object
1636 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1637 // Go through every message
1638 for(core::list<ActiveObjectMessage>::Iterator
1639 k = list->begin(); k != list->end(); k++)
1641 // Compose the full new data with header
1642 ActiveObjectMessage aom = *k;
1643 std::string new_data;
1646 writeU16((u8*)&buf[0], aom.id);
1647 new_data.append(buf, 2);
1649 new_data += serializeString(aom.datastring);
1650 // Add data to buffer
1652 reliable_data += new_data;
1654 unreliable_data += new_data;
1658 reliable_data and unreliable_data are now ready.
1661 if(reliable_data.size() > 0)
1663 SharedBuffer<u8> reply(2 + reliable_data.size());
1664 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1665 memcpy((char*)&reply[2], reliable_data.c_str(),
1666 reliable_data.size());
1668 m_con.Send(client->peer_id, 0, reply, true);
1670 if(unreliable_data.size() > 0)
1672 SharedBuffer<u8> reply(2 + unreliable_data.size());
1673 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1674 memcpy((char*)&reply[2], unreliable_data.c_str(),
1675 unreliable_data.size());
1676 // Send as unreliable
1677 m_con.Send(client->peer_id, 0, reply, false);
1680 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1682 infostream<<"Server: Size of object message data: "
1683 <<"reliable: "<<reliable_data.size()
1684 <<", unreliable: "<<unreliable_data.size()
1689 // Clear buffered_messages
1690 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1691 i = buffered_messages.getIterator();
1692 i.atEnd()==false; i++)
1694 delete i.getNode()->getValue();
1698 } // enable_experimental
1701 Send queued-for-sending map edit events.
1704 // Don't send too many at a time
1707 // Single change sending is disabled if queue size is not small
1708 bool disable_single_change_sending = false;
1709 if(m_unsent_map_edit_queue.size() >= 4)
1710 disable_single_change_sending = true;
1712 int event_count = m_unsent_map_edit_queue.size();
1714 // We'll log the amount of each
1717 while(m_unsent_map_edit_queue.size() != 0)
1719 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1721 // Players far away from the change are stored here.
1722 // Instead of sending the changes, MapBlocks are set not sent
1724 core::list<u16> far_players;
1726 if(event->type == MEET_ADDNODE)
1728 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1729 prof.add("MEET_ADDNODE", 1);
1730 if(disable_single_change_sending)
1731 sendAddNode(event->p, event->n, event->already_known_by_peer,
1734 sendAddNode(event->p, event->n, event->already_known_by_peer,
1737 else if(event->type == MEET_REMOVENODE)
1739 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1740 prof.add("MEET_REMOVENODE", 1);
1741 if(disable_single_change_sending)
1742 sendRemoveNode(event->p, event->already_known_by_peer,
1745 sendRemoveNode(event->p, event->already_known_by_peer,
1748 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1750 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1751 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1752 setBlockNotSent(event->p);
1754 else if(event->type == MEET_OTHER)
1756 infostream<<"Server: MEET_OTHER"<<std::endl;
1757 prof.add("MEET_OTHER", 1);
1758 for(core::map<v3s16, bool>::Iterator
1759 i = event->modified_blocks.getIterator();
1760 i.atEnd()==false; i++)
1762 v3s16 p = i.getNode()->getKey();
1768 prof.add("unknown", 1);
1769 infostream<<"WARNING: Server: Unknown MapEditEvent "
1770 <<((u32)event->type)<<std::endl;
1774 Set blocks not sent to far players
1776 if(far_players.size() > 0)
1778 // Convert list format to that wanted by SetBlocksNotSent
1779 core::map<v3s16, MapBlock*> modified_blocks2;
1780 for(core::map<v3s16, bool>::Iterator
1781 i = event->modified_blocks.getIterator();
1782 i.atEnd()==false; i++)
1784 v3s16 p = i.getNode()->getKey();
1785 modified_blocks2.insert(p,
1786 m_env->getMap().getBlockNoCreateNoEx(p));
1788 // Set blocks not sent
1789 for(core::list<u16>::Iterator
1790 i = far_players.begin();
1791 i != far_players.end(); i++)
1794 RemoteClient *client = getClient(peer_id);
1797 client->SetBlocksNotSent(modified_blocks2);
1803 /*// Don't send too many at a time
1805 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1809 if(event_count >= 5){
1810 infostream<<"Server: MapEditEvents:"<<std::endl;
1811 prof.print(infostream);
1812 } else if(event_count != 0){
1813 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1814 prof.print(verbosestream);
1820 Trigger emergethread (it somehow gets to a non-triggered but
1821 bysy state sometimes)
1824 float &counter = m_emergethread_trigger_timer;
1830 m_emergethread.trigger();
1834 // Save map, players and auth stuff
1836 float &counter = m_savemap_timer;
1838 if(counter >= g_settings->getFloat("server_map_save_interval"))
1841 JMutexAutoLock lock(m_env_mutex);
1843 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1846 if(m_authmanager.isModified())
1847 m_authmanager.save();
1850 if(m_banmanager.isModified())
1851 m_banmanager.save();
1853 // Save changed parts of map
1854 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1857 m_env->serializePlayers(m_path_world);
1859 // Save environment metadata
1860 m_env->saveMeta(m_path_world);
1865 void Server::Receive()
1867 DSTACK(__FUNCTION_NAME);
1868 SharedBuffer<u8> data;
1873 JMutexAutoLock conlock(m_con_mutex);
1874 datasize = m_con.Receive(peer_id, data);
1877 // This has to be called so that the client list gets synced
1878 // with the peer list of the connection
1879 handlePeerChanges();
1881 ProcessData(*data, datasize, peer_id);
1883 catch(con::InvalidIncomingDataException &e)
1885 infostream<<"Server::Receive(): "
1886 "InvalidIncomingDataException: what()="
1887 <<e.what()<<std::endl;
1889 catch(con::PeerNotFoundException &e)
1891 //NOTE: This is not needed anymore
1893 // The peer has been disconnected.
1894 // Find the associated player and remove it.
1896 /*JMutexAutoLock envlock(m_env_mutex);
1898 infostream<<"ServerThread: peer_id="<<peer_id
1899 <<" has apparently closed connection. "
1900 <<"Removing player."<<std::endl;
1902 m_env->removePlayer(peer_id);*/
1906 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1908 DSTACK(__FUNCTION_NAME);
1909 // Environment is locked first.
1910 JMutexAutoLock envlock(m_env_mutex);
1911 JMutexAutoLock conlock(m_con_mutex);
1913 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1916 Address address = m_con.GetPeerAddress(peer_id);
1918 // drop player if is ip is banned
1919 if(m_banmanager.isIpBanned(address.serializeString())){
1920 SendAccessDenied(m_con, peer_id,
1921 L"Your ip is banned. Banned name was "
1922 +narrow_to_wide(m_banmanager.getBanName(
1923 address.serializeString())));
1924 m_con.DeletePeer(peer_id);
1928 catch(con::PeerNotFoundException &e)
1930 infostream<<"Server::ProcessData(): Cancelling: peer "
1931 <<peer_id<<" not found"<<std::endl;
1935 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1937 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1945 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1947 if(command == TOSERVER_INIT)
1949 // [0] u16 TOSERVER_INIT
1950 // [2] u8 SER_FMT_VER_HIGHEST
1951 // [3] u8[20] player_name
1952 // [23] u8[28] password <--- can be sent without this, from old versions
1954 if(datasize < 2+1+PLAYERNAME_SIZE)
1957 verbosestream<<"Server: Got TOSERVER_INIT from "
1958 <<peer_id<<std::endl;
1960 // First byte after command is maximum supported
1961 // serialization version
1962 u8 client_max = data[2];
1963 u8 our_max = SER_FMT_VER_HIGHEST;
1964 // Use the highest version supported by both
1965 u8 deployed = core::min_(client_max, our_max);
1966 // If it's lower than the lowest supported, give up.
1967 if(deployed < SER_FMT_VER_LOWEST)
1968 deployed = SER_FMT_VER_INVALID;
1970 //peer->serialization_version = deployed;
1971 getClient(peer_id)->pending_serialization_version = deployed;
1973 if(deployed == SER_FMT_VER_INVALID)
1975 actionstream<<"Server: A mismatched client tried to connect from "
1976 <<addr_s<<std::endl;
1977 infostream<<"Server: Cannot negotiate "
1978 "serialization version with peer "
1979 <<peer_id<<std::endl;
1980 SendAccessDenied(m_con, peer_id, std::wstring(
1981 L"Your client's version is not supported.\n"
1982 L"Server version is ")
1983 + narrow_to_wide(VERSION_STRING) + L"."
1989 Read and check network protocol version
1992 u16 net_proto_version = 0;
1993 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1995 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1998 getClient(peer_id)->net_proto_version = net_proto_version;
2000 if(net_proto_version == 0)
2002 actionstream<<"Server: An old tried to connect from "<<addr_s
2004 SendAccessDenied(m_con, peer_id, std::wstring(
2005 L"Your client's version is not supported.\n"
2006 L"Server version is ")
2007 + narrow_to_wide(VERSION_STRING) + L"."
2012 if(g_settings->getBool("strict_protocol_version_checking"))
2014 if(net_proto_version != PROTOCOL_VERSION)
2016 actionstream<<"Server: A mismatched client tried to connect"
2017 <<" from "<<addr_s<<std::endl;
2018 SendAccessDenied(m_con, peer_id, std::wstring(
2019 L"Your client's version is not supported.\n"
2020 L"Server version is ")
2021 + narrow_to_wide(VERSION_STRING) + L",\n"
2022 + L"server's PROTOCOL_VERSION is "
2023 + narrow_to_wide(itos(PROTOCOL_VERSION))
2024 + L", client's PROTOCOL_VERSION is "
2025 + narrow_to_wide(itos(net_proto_version))
2036 char playername[PLAYERNAME_SIZE];
2037 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2039 playername[i] = data[3+i];
2041 playername[PLAYERNAME_SIZE-1] = 0;
2043 if(playername[0]=='\0')
2045 actionstream<<"Server: Player with an empty name "
2046 <<"tried to connect from "<<addr_s<<std::endl;
2047 SendAccessDenied(m_con, peer_id,
2052 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2054 actionstream<<"Server: Player with an invalid name "
2055 <<"tried to connect from "<<addr_s<<std::endl;
2056 SendAccessDenied(m_con, peer_id,
2057 L"Name contains unallowed characters");
2061 infostream<<"Server: New connection: \""<<playername<<"\" from "
2062 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2065 char password[PASSWORD_SIZE];
2066 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2068 // old version - assume blank password
2073 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2075 password[i] = data[23+i];
2077 password[PASSWORD_SIZE-1] = 0;
2080 // Add player to auth manager
2081 if(m_authmanager.exists(playername) == false)
2083 std::wstring default_password =
2084 narrow_to_wide(g_settings->get("default_password"));
2085 std::string translated_default_password =
2086 translatePassword(playername, default_password);
2088 // If default_password is empty, allow any initial password
2089 if (default_password.length() == 0)
2090 translated_default_password = password;
2092 infostream<<"Server: adding player "<<playername
2093 <<" to auth manager"<<std::endl;
2094 m_authmanager.add(playername);
2095 m_authmanager.setPassword(playername, translated_default_password);
2096 m_authmanager.setPrivs(playername,
2097 stringToPrivs(g_settings->get("default_privs")));
2098 m_authmanager.save();
2101 std::string checkpwd = m_authmanager.getPassword(playername);
2103 /*infostream<<"Server: Client gave password '"<<password
2104 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2106 if(password != checkpwd)
2108 infostream<<"Server: peer_id="<<peer_id
2109 <<": supplied invalid password for "
2110 <<playername<<std::endl;
2111 SendAccessDenied(m_con, peer_id, L"Invalid password");
2115 // Do not allow multiple players in simple singleplayer mode.
2116 // This isn't a perfect way to do it, but will suffice for now.
2117 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2118 infostream<<"Server: Not allowing another client to connect in"
2119 <<" simple singleplayer mode"<<std::endl;
2120 SendAccessDenied(m_con, peer_id,
2121 L"Running in simple singleplayer mode.");
2125 // Enforce user limit.
2126 // Don't enforce for users that have some admin right
2127 if(m_clients.size() >= g_settings->getU16("max_users") &&
2128 (m_authmanager.getPrivs(playername)
2129 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2130 playername != g_settings->get("name"))
2132 actionstream<<"Server: "<<playername<<" tried to join, but there"
2133 <<" are already max_users="
2134 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2135 SendAccessDenied(m_con, peer_id, L"Too many users.");
2140 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2142 // If failed, cancel
2145 errorstream<<"Server: peer_id="<<peer_id
2146 <<": failed to emerge player"<<std::endl;
2151 Answer with a TOCLIENT_INIT
2154 SharedBuffer<u8> reply(2+1+6+8);
2155 writeU16(&reply[0], TOCLIENT_INIT);
2156 writeU8(&reply[2], deployed);
2157 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2158 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2161 m_con.Send(peer_id, 0, reply, true);
2165 Send complete position information
2167 SendMovePlayer(player);
2172 if(command == TOSERVER_INIT2)
2174 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2175 <<peer_id<<std::endl;
2178 getClient(peer_id)->serialization_version
2179 = getClient(peer_id)->pending_serialization_version;
2182 Send some initialization data
2185 infostream<<"Server: Sending content to "
2186 <<getPlayerName(peer_id)<<std::endl;
2188 // Send item definitions
2189 SendItemDef(m_con, peer_id, m_itemdef);
2191 // Send node definitions
2192 SendNodeDef(m_con, peer_id, m_nodedef);
2194 // Send texture announcement
2195 SendTextureAnnouncement(peer_id);
2197 // Send player info to all players
2198 //SendPlayerInfos();
2200 // Send inventory to player
2201 UpdateCrafting(peer_id);
2202 SendInventory(peer_id);
2204 // Send player items to all players
2207 Player *player = m_env->getPlayer(peer_id);
2210 SendPlayerHP(player);
2212 // Show death screen if necessary
2214 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2218 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2219 m_env->getTimeOfDay());
2220 m_con.Send(peer_id, 0, data, true);
2223 // Note things in chat if not in simple singleplayer mode
2224 if(!m_simple_singleplayer_mode)
2226 // Send information about server to player in chat
2227 SendChatMessage(peer_id, getStatusString());
2229 // Send information about joining in chat
2231 std::wstring name = L"unknown";
2232 Player *player = m_env->getPlayer(peer_id);
2234 name = narrow_to_wide(player->getName());
2236 std::wstring message;
2239 message += L" joined game";
2240 BroadcastChatMessage(message);
2244 // Warnings about protocol version can be issued here
2245 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2247 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2254 std::ostringstream os(std::ios_base::binary);
2255 for(core::map<u16, RemoteClient*>::Iterator
2256 i = m_clients.getIterator();
2257 i.atEnd() == false; i++)
2259 RemoteClient *client = i.getNode()->getValue();
2260 assert(client->peer_id == i.getNode()->getKey());
2261 if(client->serialization_version == SER_FMT_VER_INVALID)
2264 Player *player = m_env->getPlayer(client->peer_id);
2267 // Get name of player
2268 os<<player->getName()<<" ";
2271 actionstream<<player->getName()<<" joins game. List of players: "
2272 <<os.str()<<std::endl;
2278 if(peer_ser_ver == SER_FMT_VER_INVALID)
2280 infostream<<"Server::ProcessData(): Cancelling: Peer"
2281 " serialization format invalid or not initialized."
2282 " Skipping incoming command="<<command<<std::endl;
2286 Player *player = m_env->getPlayer(peer_id);
2287 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2290 infostream<<"Server::ProcessData(): Cancelling: "
2291 "No player for peer_id="<<peer_id
2295 if(command == TOSERVER_PLAYERPOS)
2297 if(datasize < 2+12+12+4+4)
2301 v3s32 ps = readV3S32(&data[start+2]);
2302 v3s32 ss = readV3S32(&data[start+2+12]);
2303 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2304 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2305 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2306 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2307 pitch = wrapDegrees(pitch);
2308 yaw = wrapDegrees(yaw);
2310 player->setPosition(position);
2311 player->setSpeed(speed);
2312 player->setPitch(pitch);
2313 player->setYaw(yaw);
2315 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2316 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2317 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2319 else if(command == TOSERVER_GOTBLOCKS)
2332 u16 count = data[2];
2333 for(u16 i=0; i<count; i++)
2335 if((s16)datasize < 2+1+(i+1)*6)
2336 throw con::InvalidIncomingDataException
2337 ("GOTBLOCKS length is too short");
2338 v3s16 p = readV3S16(&data[2+1+i*6]);
2339 /*infostream<<"Server: GOTBLOCKS ("
2340 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2341 RemoteClient *client = getClient(peer_id);
2342 client->GotBlock(p);
2345 else if(command == TOSERVER_DELETEDBLOCKS)
2358 u16 count = data[2];
2359 for(u16 i=0; i<count; i++)
2361 if((s16)datasize < 2+1+(i+1)*6)
2362 throw con::InvalidIncomingDataException
2363 ("DELETEDBLOCKS length is too short");
2364 v3s16 p = readV3S16(&data[2+1+i*6]);
2365 /*infostream<<"Server: DELETEDBLOCKS ("
2366 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2367 RemoteClient *client = getClient(peer_id);
2368 client->SetBlockNotSent(p);
2371 else if(command == TOSERVER_CLICK_OBJECT)
2373 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2376 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2378 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2381 else if(command == TOSERVER_GROUND_ACTION)
2383 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2387 else if(command == TOSERVER_RELEASE)
2389 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2392 else if(command == TOSERVER_SIGNTEXT)
2394 infostream<<"Server: SIGNTEXT not supported anymore"
2398 else if(command == TOSERVER_SIGNNODETEXT)
2400 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2408 std::string datastring((char*)&data[2], datasize-2);
2409 std::istringstream is(datastring, std::ios_base::binary);
2412 is.read((char*)buf, 6);
2413 v3s16 p = readV3S16(buf);
2414 is.read((char*)buf, 2);
2415 u16 textlen = readU16(buf);
2417 for(u16 i=0; i<textlen; i++)
2419 is.read((char*)buf, 1);
2420 text += (char)buf[0];
2423 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2427 meta->setText(text);
2429 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2430 <<" at "<<PP(p)<<std::endl;
2432 v3s16 blockpos = getNodeBlockPos(p);
2433 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2436 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2440 setBlockNotSent(blockpos);
2442 else if(command == TOSERVER_INVENTORY_ACTION)
2444 // Strip command and create a stream
2445 std::string datastring((char*)&data[2], datasize-2);
2446 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2447 std::istringstream is(datastring, std::ios_base::binary);
2449 InventoryAction *a = InventoryAction::deSerialize(is);
2452 infostream<<"TOSERVER_INVENTORY_ACTION: "
2453 <<"InventoryAction::deSerialize() returned NULL"
2459 Note: Always set inventory not sent, to repair cases
2460 where the client made a bad prediction.
2464 Handle restrictions and special cases of the move action
2466 if(a->getType() == IACTION_MOVE)
2468 IMoveAction *ma = (IMoveAction*)a;
2470 ma->from_inv.applyCurrentPlayer(player->getName());
2471 ma->to_inv.applyCurrentPlayer(player->getName());
2473 setInventoryModified(ma->from_inv);
2474 setInventoryModified(ma->to_inv);
2476 bool from_inv_is_current_player =
2477 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2478 (ma->from_inv.name == player->getName());
2480 bool to_inv_is_current_player =
2481 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2482 (ma->to_inv.name == player->getName());
2485 Disable moving items out of craftpreview
2487 if(ma->from_list == "craftpreview")
2489 infostream<<"Ignoring IMoveAction from "
2490 <<(ma->from_inv.dump())<<":"<<ma->from_list
2491 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2492 <<" because src is "<<ma->from_list<<std::endl;
2498 Disable moving items into craftresult and craftpreview
2500 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2502 infostream<<"Ignoring IMoveAction from "
2503 <<(ma->from_inv.dump())<<":"<<ma->from_list
2504 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2505 <<" because dst is "<<ma->to_list<<std::endl;
2510 // Disallow moving items in elsewhere than player's inventory
2511 // if not allowed to interact
2512 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2513 && (!from_inv_is_current_player
2514 || !to_inv_is_current_player))
2516 infostream<<"Cannot move outside of player's inventory: "
2517 <<"No interact privilege"<<std::endl;
2522 // If player is not an admin, check for ownership of src and dst
2523 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2525 std::string owner_from = getInventoryOwner(ma->from_inv);
2526 if(owner_from != "" && owner_from != player->getName())
2528 infostream<<"WARNING: "<<player->getName()
2529 <<" tried to access an inventory that"
2530 <<" belongs to "<<owner_from<<std::endl;
2535 std::string owner_to = getInventoryOwner(ma->to_inv);
2536 if(owner_to != "" && owner_to != player->getName())
2538 infostream<<"WARNING: "<<player->getName()
2539 <<" tried to access an inventory that"
2540 <<" belongs to "<<owner_to<<std::endl;
2547 Handle restrictions and special cases of the drop action
2549 else if(a->getType() == IACTION_DROP)
2551 IDropAction *da = (IDropAction*)a;
2553 da->from_inv.applyCurrentPlayer(player->getName());
2555 setInventoryModified(da->from_inv);
2557 // Disallow dropping items if not allowed to interact
2558 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2563 // If player is not an admin, check for ownership
2564 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2566 std::string owner_from = getInventoryOwner(da->from_inv);
2567 if(owner_from != "" && owner_from != player->getName())
2569 infostream<<"WARNING: "<<player->getName()
2570 <<" tried to access an inventory that"
2571 <<" belongs to "<<owner_from<<std::endl;
2578 Handle restrictions and special cases of the craft action
2580 else if(a->getType() == IACTION_CRAFT)
2582 ICraftAction *ca = (ICraftAction*)a;
2584 ca->craft_inv.applyCurrentPlayer(player->getName());
2586 setInventoryModified(ca->craft_inv);
2588 //bool craft_inv_is_current_player =
2589 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2590 // (ca->craft_inv.name == player->getName());
2592 // Disallow crafting if not allowed to interact
2593 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2595 infostream<<"Cannot craft: "
2596 <<"No interact privilege"<<std::endl;
2601 // If player is not an admin, check for ownership of inventory
2602 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2604 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2605 if(owner_craft != "" && owner_craft != player->getName())
2607 infostream<<"WARNING: "<<player->getName()
2608 <<" tried to access an inventory that"
2609 <<" belongs to "<<owner_craft<<std::endl;
2617 a->apply(this, srp, this);
2621 else if(command == TOSERVER_CHAT_MESSAGE)
2629 std::string datastring((char*)&data[2], datasize-2);
2630 std::istringstream is(datastring, std::ios_base::binary);
2633 is.read((char*)buf, 2);
2634 u16 len = readU16(buf);
2636 std::wstring message;
2637 for(u16 i=0; i<len; i++)
2639 is.read((char*)buf, 2);
2640 message += (wchar_t)readU16(buf);
2643 // Get player name of this client
2644 std::wstring name = narrow_to_wide(player->getName());
2647 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2648 wide_to_narrow(message));
2649 // If script ate the message, don't proceed
2653 // Line to send to players
2655 // Whether to send to the player that sent the line
2656 bool send_to_sender = false;
2657 // Whether to send to other players
2658 bool send_to_others = false;
2660 // Local player gets all privileges regardless of
2661 // what's set on their account.
2662 u64 privs = getPlayerPrivs(player);
2665 if(message[0] == L'/')
2667 size_t strip_size = 1;
2668 if (message[1] == L'#') // support old-style commans
2670 message = message.substr(strip_size);
2672 WStrfnd f1(message);
2673 f1.next(L" "); // Skip over /#whatever
2674 std::wstring paramstring = f1.next(L"");
2676 ServerCommandContext *ctx = new ServerCommandContext(
2677 str_split(message, L' '),
2684 std::wstring reply(processServerCommand(ctx));
2685 send_to_sender = ctx->flags & SEND_TO_SENDER;
2686 send_to_others = ctx->flags & SEND_TO_OTHERS;
2688 if (ctx->flags & SEND_NO_PREFIX)
2691 line += L"Server: " + reply;
2698 if(privs & PRIV_SHOUT)
2704 send_to_others = true;
2708 line += L"Server: You are not allowed to shout";
2709 send_to_sender = true;
2716 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2719 Send the message to clients
2721 for(core::map<u16, RemoteClient*>::Iterator
2722 i = m_clients.getIterator();
2723 i.atEnd() == false; i++)
2725 // Get client and check that it is valid
2726 RemoteClient *client = i.getNode()->getValue();
2727 assert(client->peer_id == i.getNode()->getKey());
2728 if(client->serialization_version == SER_FMT_VER_INVALID)
2732 bool sender_selected = (peer_id == client->peer_id);
2733 if(sender_selected == true && send_to_sender == false)
2735 if(sender_selected == false && send_to_others == false)
2738 SendChatMessage(client->peer_id, line);
2742 else if(command == TOSERVER_DAMAGE)
2744 std::string datastring((char*)&data[2], datasize-2);
2745 std::istringstream is(datastring, std::ios_base::binary);
2746 u8 damage = readU8(is);
2748 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2750 if(g_settings->getBool("enable_damage"))
2752 actionstream<<player->getName()<<" damaged by "
2753 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2756 srp->setHP(srp->getHP() - damage);
2758 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2761 if(srp->m_hp_not_sent)
2762 SendPlayerHP(player);
2766 // Force send (to correct the client's predicted HP)
2767 SendPlayerHP(player);
2770 else if(command == TOSERVER_PASSWORD)
2773 [0] u16 TOSERVER_PASSWORD
2774 [2] u8[28] old password
2775 [30] u8[28] new password
2778 if(datasize != 2+PASSWORD_SIZE*2)
2780 /*char password[PASSWORD_SIZE];
2781 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2782 password[i] = data[2+i];
2783 password[PASSWORD_SIZE-1] = 0;*/
2785 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2793 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2795 char c = data[2+PASSWORD_SIZE+i];
2801 infostream<<"Server: Client requests a password change from "
2802 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2804 std::string playername = player->getName();
2806 if(m_authmanager.exists(playername) == false)
2808 infostream<<"Server: playername not found in authmanager"<<std::endl;
2809 // Wrong old password supplied!!
2810 SendChatMessage(peer_id, L"playername not found in authmanager");
2814 std::string checkpwd = m_authmanager.getPassword(playername);
2816 if(oldpwd != checkpwd)
2818 infostream<<"Server: invalid old password"<<std::endl;
2819 // Wrong old password supplied!!
2820 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2824 actionstream<<player->getName()<<" changes password"<<std::endl;
2826 m_authmanager.setPassword(playername, newpwd);
2828 infostream<<"Server: password change successful for "<<playername
2830 SendChatMessage(peer_id, L"Password change successful");
2832 else if(command == TOSERVER_PLAYERITEM)
2837 u16 item = readU16(&data[2]);
2838 srp->setWieldIndex(item);
2839 SendWieldedItem(srp);
2841 else if(command == TOSERVER_RESPAWN)
2846 RespawnPlayer(player);
2848 actionstream<<player->getName()<<" respawns at "
2849 <<PP(player->getPosition()/BS)<<std::endl;
2851 // ActiveObject is added to environment in AsyncRunStep after
2852 // the previous addition has been succesfully removed
2854 else if(command == TOSERVER_REQUEST_TEXTURES) {
2855 std::string datastring((char*)&data[2], datasize-2);
2856 std::istringstream is(datastring, std::ios_base::binary);
2859 core::list<TextureRequest> tosend;
2860 u16 numtextures = readU16(is);
2862 infostream<<"Sending "<<numtextures<<" textures to "
2863 <<getPlayerName(peer_id)<<std::endl;
2864 verbosestream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2866 for(int i = 0; i < numtextures; i++) {
2867 std::string name = deSerializeString(is);
2868 tosend.push_back(TextureRequest(name));
2869 verbosestream<<"TOSERVER_REQUEST_TEXTURES: requested texture "
2873 SendTexturesRequested(peer_id, tosend);
2875 // Now the client should know about everything
2876 // (definitions and textures)
2877 getClient(peer_id)->definitions_sent = true;
2879 else if(command == TOSERVER_INTERACT)
2881 std::string datastring((char*)&data[2], datasize-2);
2882 std::istringstream is(datastring, std::ios_base::binary);
2888 [5] u32 length of the next item
2889 [9] serialized PointedThing
2891 0: start digging (from undersurface) or use
2892 1: stop digging (all parameters ignored)
2893 2: digging completed
2894 3: place block or item (to abovesurface)
2897 u8 action = readU8(is);
2898 u16 item_i = readU16(is);
2899 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2900 PointedThing pointed;
2901 pointed.deSerialize(tmp_is);
2903 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2904 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2908 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2909 <<" tried to interact, but is dead!"<<std::endl;
2913 v3f player_pos = srp->m_last_good_position;
2915 // Update wielded item
2916 if(srp->getWieldIndex() != item_i)
2918 srp->setWieldIndex(item_i);
2919 SendWieldedItem(srp);
2922 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2923 v3s16 p_under = pointed.node_undersurface;
2924 v3s16 p_above = pointed.node_abovesurface;
2926 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2927 ServerActiveObject *pointed_object = NULL;
2928 if(pointed.type == POINTEDTHING_OBJECT)
2930 pointed_object = m_env->getActiveObject(pointed.object_id);
2931 if(pointed_object == NULL)
2933 verbosestream<<"TOSERVER_INTERACT: "
2934 "pointed object is NULL"<<std::endl;
2940 v3f pointed_pos_under = player_pos;
2941 v3f pointed_pos_above = player_pos;
2942 if(pointed.type == POINTEDTHING_NODE)
2944 pointed_pos_under = intToFloat(p_under, BS);
2945 pointed_pos_above = intToFloat(p_above, BS);
2947 else if(pointed.type == POINTEDTHING_OBJECT)
2949 pointed_pos_under = pointed_object->getBasePosition();
2950 pointed_pos_above = pointed_pos_under;
2954 Check that target is reasonably close
2955 (only when digging or placing things)
2957 if(action == 0 || action == 2 || action == 3)
2959 float d = player_pos.getDistanceFrom(pointed_pos_under);
2960 float max_d = BS * 14; // Just some large enough value
2962 actionstream<<"Player "<<player->getName()
2963 <<" tried to access "<<pointed.dump()
2965 <<"d="<<d<<", max_d="<<max_d
2966 <<". ignoring."<<std::endl;
2967 // Re-send block to revert change on client-side
2968 RemoteClient *client = getClient(peer_id);
2969 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2970 client->SetBlockNotSent(blockpos);
2977 Make sure the player is allowed to do it
2979 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2981 infostream<<"Ignoring interaction from player "<<player->getName()
2982 <<" because privileges are "<<getPlayerPrivs(player)
2988 0: start digging or punch object
2992 if(pointed.type == POINTEDTHING_NODE)
2995 NOTE: This can be used in the future to check if
2996 somebody is cheating, by checking the timing.
2998 MapNode n(CONTENT_IGNORE);
3001 n = m_env->getMap().getNode(p_under);
3003 catch(InvalidPositionException &e)
3005 infostream<<"Server: Not punching: Node not found."
3006 <<" Adding block to emerge queue."
3008 m_emerge_queue.addBlock(peer_id,
3009 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3011 if(n.getContent() != CONTENT_IGNORE)
3012 scriptapi_node_on_punch(m_lua, p_under, n, srp);
3014 else if(pointed.type == POINTEDTHING_OBJECT)
3016 // Skip if object has been removed
3017 if(pointed_object->m_removed)
3020 actionstream<<player->getName()<<" punches object "
3021 <<pointed.object_id<<": "
3022 <<pointed_object->getDescription()<<std::endl;
3024 ItemStack punchitem = srp->getWieldedItem();
3025 ToolCapabilities toolcap =
3026 punchitem.getToolCapabilities(m_itemdef);
3027 v3f dir = (pointed_object->getBasePosition() -
3028 (srp->getPosition() + srp->getEyeOffset())
3030 pointed_object->punch(dir, &toolcap, srp,
3031 srp->m_time_from_last_punch);
3032 srp->m_time_from_last_punch = 0;
3040 else if(action == 1)
3045 2: Digging completed
3047 else if(action == 2)
3049 // Only complete digging of nodes
3050 if(pointed.type == POINTEDTHING_NODE)
3052 MapNode n(CONTENT_IGNORE);
3055 n = m_env->getMap().getNode(p_under);
3057 catch(InvalidPositionException &e)
3059 infostream<<"Server: Not finishing digging: Node not found."
3060 <<" Adding block to emerge queue."
3062 m_emerge_queue.addBlock(peer_id,
3063 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3065 if(n.getContent() != CONTENT_IGNORE)
3066 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3071 3: place block or right-click object
3073 else if(action == 3)
3075 ItemStack item = srp->getWieldedItem();
3077 // Reset build time counter
3078 if(pointed.type == POINTEDTHING_NODE &&
3079 item.getDefinition(m_itemdef).type == ITEM_NODE)
3080 getClient(peer_id)->m_time_from_building = 0.0;
3082 if(pointed.type == POINTEDTHING_OBJECT)
3084 // Right click object
3086 // Skip if object has been removed
3087 if(pointed_object->m_removed)
3090 actionstream<<player->getName()<<" right-clicks object "
3091 <<pointed.object_id<<": "
3092 <<pointed_object->getDescription()<<std::endl;
3095 pointed_object->rightClick(srp);
3097 else if(scriptapi_item_on_place(m_lua,
3098 item, srp, pointed))
3100 // Placement was handled in lua
3102 // Apply returned ItemStack
3103 if(g_settings->getBool("creative_mode") == false)
3104 srp->setWieldedItem(item);
3112 else if(action == 4)
3114 ItemStack item = srp->getWieldedItem();
3116 actionstream<<player->getName()<<" uses "<<item.name
3117 <<", pointing at "<<pointed.dump()<<std::endl;
3119 if(scriptapi_item_on_use(m_lua,
3120 item, srp, pointed))
3122 // Apply returned ItemStack
3123 if(g_settings->getBool("creative_mode") == false)
3124 srp->setWieldedItem(item);
3130 Catch invalid actions
3134 infostream<<"WARNING: Server: Invalid action "
3135 <<action<<std::endl;
3140 infostream<<"Server::ProcessData(): Ignoring "
3141 "unknown command "<<command<<std::endl;
3145 catch(SendFailedException &e)
3147 errorstream<<"Server::ProcessData(): SendFailedException: "
3153 void Server::onMapEditEvent(MapEditEvent *event)
3155 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3156 if(m_ignore_map_edit_events)
3158 MapEditEvent *e = event->clone();
3159 m_unsent_map_edit_queue.push_back(e);
3162 Inventory* Server::getInventory(const InventoryLocation &loc)
3165 case InventoryLocation::UNDEFINED:
3168 case InventoryLocation::CURRENT_PLAYER:
3171 case InventoryLocation::PLAYER:
3173 Player *player = m_env->getPlayer(loc.name.c_str());
3176 return &player->inventory;
3179 case InventoryLocation::NODEMETA:
3181 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3184 return meta->getInventory();
3192 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3195 case InventoryLocation::UNDEFINED:
3198 case InventoryLocation::CURRENT_PLAYER:
3201 case InventoryLocation::PLAYER:
3206 case InventoryLocation::NODEMETA:
3208 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3211 return meta->getOwner();
3219 void Server::setInventoryModified(const InventoryLocation &loc)
3222 case InventoryLocation::UNDEFINED:
3225 case InventoryLocation::PLAYER:
3227 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3228 (m_env->getPlayer(loc.name.c_str()));
3231 srp->m_inventory_not_sent = true;
3234 case InventoryLocation::NODEMETA:
3236 v3s16 blockpos = getNodeBlockPos(loc.p);
3238 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3240 meta->inventoryModified();
3242 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3244 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3246 setBlockNotSent(blockpos);
3254 core::list<PlayerInfo> Server::getPlayerInfo()
3256 DSTACK(__FUNCTION_NAME);
3257 JMutexAutoLock envlock(m_env_mutex);
3258 JMutexAutoLock conlock(m_con_mutex);
3260 core::list<PlayerInfo> list;
3262 core::list<Player*> players = m_env->getPlayers();
3264 core::list<Player*>::Iterator i;
3265 for(i = players.begin();
3266 i != players.end(); i++)
3270 Player *player = *i;
3273 // Copy info from connection to info struct
3274 info.id = player->peer_id;
3275 info.address = m_con.GetPeerAddress(player->peer_id);
3276 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3278 catch(con::PeerNotFoundException &e)
3280 // Set dummy peer info
3282 info.address = Address(0,0,0,0,0);
3286 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3287 info.position = player->getPosition();
3289 list.push_back(info);
3296 void Server::peerAdded(con::Peer *peer)
3298 DSTACK(__FUNCTION_NAME);
3299 verbosestream<<"Server::peerAdded(): peer->id="
3300 <<peer->id<<std::endl;
3303 c.type = PEER_ADDED;
3304 c.peer_id = peer->id;
3306 m_peer_change_queue.push_back(c);
3309 void Server::deletingPeer(con::Peer *peer, bool timeout)
3311 DSTACK(__FUNCTION_NAME);
3312 verbosestream<<"Server::deletingPeer(): peer->id="
3313 <<peer->id<<", timeout="<<timeout<<std::endl;
3316 c.type = PEER_REMOVED;
3317 c.peer_id = peer->id;
3318 c.timeout = timeout;
3319 m_peer_change_queue.push_back(c);
3326 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3328 DSTACK(__FUNCTION_NAME);
3329 std::ostringstream os(std::ios_base::binary);
3331 writeU16(os, TOCLIENT_HP);
3335 std::string s = os.str();
3336 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3338 con.Send(peer_id, 0, data, true);
3341 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3342 const std::wstring &reason)
3344 DSTACK(__FUNCTION_NAME);
3345 std::ostringstream os(std::ios_base::binary);
3347 writeU16(os, TOCLIENT_ACCESS_DENIED);
3348 os<<serializeWideString(reason);
3351 std::string s = os.str();
3352 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3354 con.Send(peer_id, 0, data, true);
3357 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3358 bool set_camera_point_target, v3f camera_point_target)
3360 DSTACK(__FUNCTION_NAME);
3361 std::ostringstream os(std::ios_base::binary);
3363 writeU16(os, TOCLIENT_DEATHSCREEN);
3364 writeU8(os, set_camera_point_target);
3365 writeV3F1000(os, camera_point_target);
3368 std::string s = os.str();
3369 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3371 con.Send(peer_id, 0, data, true);
3374 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3375 IItemDefManager *itemdef)
3377 DSTACK(__FUNCTION_NAME);
3378 std::ostringstream os(std::ios_base::binary);
3382 u32 length of the next item
3383 zlib-compressed serialized ItemDefManager
3385 writeU16(os, TOCLIENT_ITEMDEF);
3386 std::ostringstream tmp_os(std::ios::binary);
3387 itemdef->serialize(tmp_os);
3388 std::ostringstream tmp_os2(std::ios::binary);
3389 compressZlib(tmp_os.str(), tmp_os2);
3390 os<<serializeLongString(tmp_os2.str());
3393 std::string s = os.str();
3394 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3395 <<"): size="<<s.size()<<std::endl;
3396 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3398 con.Send(peer_id, 0, data, true);
3401 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3402 INodeDefManager *nodedef)
3404 DSTACK(__FUNCTION_NAME);
3405 std::ostringstream os(std::ios_base::binary);
3409 u32 length of the next item
3410 zlib-compressed serialized NodeDefManager
3412 writeU16(os, TOCLIENT_NODEDEF);
3413 std::ostringstream tmp_os(std::ios::binary);
3414 nodedef->serialize(tmp_os);
3415 std::ostringstream tmp_os2(std::ios::binary);
3416 compressZlib(tmp_os.str(), tmp_os2);
3417 os<<serializeLongString(tmp_os2.str());
3420 std::string s = os.str();
3421 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3422 <<"): size="<<s.size()<<std::endl;
3423 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3425 con.Send(peer_id, 0, data, true);
3429 Non-static send methods
3432 void Server::SendInventory(u16 peer_id)
3434 DSTACK(__FUNCTION_NAME);
3436 ServerRemotePlayer* player =
3437 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3440 player->m_inventory_not_sent = false;
3446 std::ostringstream os;
3447 //os.imbue(std::locale("C"));
3449 player->inventory.serialize(os);
3451 std::string s = os.str();
3453 SharedBuffer<u8> data(s.size()+2);
3454 writeU16(&data[0], TOCLIENT_INVENTORY);
3455 memcpy(&data[2], s.c_str(), s.size());
3458 m_con.Send(peer_id, 0, data, true);
3461 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3463 DSTACK(__FUNCTION_NAME);
3467 std::ostringstream os(std::ios_base::binary);
3469 writeU16(os, TOCLIENT_PLAYERITEM);
3471 writeU16(os, srp->peer_id);
3472 os<<serializeString(srp->getWieldedItem().getItemString());
3475 std::string s = os.str();
3476 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3478 m_con.SendToAll(0, data, true);
3481 void Server::SendPlayerItems()
3483 DSTACK(__FUNCTION_NAME);
3485 std::ostringstream os(std::ios_base::binary);
3486 core::list<Player *> players = m_env->getPlayers(true);
3488 writeU16(os, TOCLIENT_PLAYERITEM);
3489 writeU16(os, players.size());
3490 core::list<Player *>::Iterator i;
3491 for(i = players.begin(); i != players.end(); ++i)
3494 ServerRemotePlayer *srp =
3495 static_cast<ServerRemotePlayer*>(p);
3496 writeU16(os, p->peer_id);
3497 os<<serializeString(srp->getWieldedItem().getItemString());
3501 std::string s = os.str();
3502 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3504 m_con.SendToAll(0, data, true);
3507 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3509 DSTACK(__FUNCTION_NAME);
3511 std::ostringstream os(std::ios_base::binary);
3515 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3516 os.write((char*)buf, 2);
3519 writeU16(buf, message.size());
3520 os.write((char*)buf, 2);
3523 for(u32 i=0; i<message.size(); i++)
3527 os.write((char*)buf, 2);
3531 std::string s = os.str();
3532 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3534 m_con.Send(peer_id, 0, data, true);
3537 void Server::BroadcastChatMessage(const std::wstring &message)
3539 for(core::map<u16, RemoteClient*>::Iterator
3540 i = m_clients.getIterator();
3541 i.atEnd() == false; i++)
3543 // Get client and check that it is valid
3544 RemoteClient *client = i.getNode()->getValue();
3545 assert(client->peer_id == i.getNode()->getKey());
3546 if(client->serialization_version == SER_FMT_VER_INVALID)
3549 SendChatMessage(client->peer_id, message);
3553 void Server::SendPlayerHP(Player *player)
3555 SendHP(m_con, player->peer_id, player->hp);
3556 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3559 void Server::SendMovePlayer(Player *player)
3561 DSTACK(__FUNCTION_NAME);
3562 std::ostringstream os(std::ios_base::binary);
3564 writeU16(os, TOCLIENT_MOVE_PLAYER);
3565 writeV3F1000(os, player->getPosition());
3566 writeF1000(os, player->getPitch());
3567 writeF1000(os, player->getYaw());
3570 v3f pos = player->getPosition();
3571 f32 pitch = player->getPitch();
3572 f32 yaw = player->getYaw();
3573 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3574 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3581 std::string s = os.str();
3582 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3584 m_con.Send(player->peer_id, 0, data, true);
3587 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3588 core::list<u16> *far_players, float far_d_nodes)
3590 float maxd = far_d_nodes*BS;
3591 v3f p_f = intToFloat(p, BS);
3595 SharedBuffer<u8> reply(replysize);
3596 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3597 writeS16(&reply[2], p.X);
3598 writeS16(&reply[4], p.Y);
3599 writeS16(&reply[6], p.Z);
3601 for(core::map<u16, RemoteClient*>::Iterator
3602 i = m_clients.getIterator();
3603 i.atEnd() == false; i++)
3605 // Get client and check that it is valid
3606 RemoteClient *client = i.getNode()->getValue();
3607 assert(client->peer_id == i.getNode()->getKey());
3608 if(client->serialization_version == SER_FMT_VER_INVALID)
3611 // Don't send if it's the same one
3612 if(client->peer_id == ignore_id)
3618 Player *player = m_env->getPlayer(client->peer_id);
3621 // If player is far away, only set modified blocks not sent
3622 v3f player_pos = player->getPosition();
3623 if(player_pos.getDistanceFrom(p_f) > maxd)
3625 far_players->push_back(client->peer_id);
3632 m_con.Send(client->peer_id, 0, reply, true);
3636 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3637 core::list<u16> *far_players, float far_d_nodes)
3639 float maxd = far_d_nodes*BS;
3640 v3f p_f = intToFloat(p, BS);
3642 for(core::map<u16, RemoteClient*>::Iterator
3643 i = m_clients.getIterator();
3644 i.atEnd() == false; i++)
3646 // Get client and check that it is valid
3647 RemoteClient *client = i.getNode()->getValue();
3648 assert(client->peer_id == i.getNode()->getKey());
3649 if(client->serialization_version == SER_FMT_VER_INVALID)
3652 // Don't send if it's the same one
3653 if(client->peer_id == ignore_id)
3659 Player *player = m_env->getPlayer(client->peer_id);
3662 // If player is far away, only set modified blocks not sent
3663 v3f player_pos = player->getPosition();
3664 if(player_pos.getDistanceFrom(p_f) > maxd)
3666 far_players->push_back(client->peer_id);
3673 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3674 SharedBuffer<u8> reply(replysize);
3675 writeU16(&reply[0], TOCLIENT_ADDNODE);
3676 writeS16(&reply[2], p.X);
3677 writeS16(&reply[4], p.Y);
3678 writeS16(&reply[6], p.Z);
3679 n.serialize(&reply[8], client->serialization_version);
3682 m_con.Send(client->peer_id, 0, reply, true);
3686 void Server::setBlockNotSent(v3s16 p)
3688 for(core::map<u16, RemoteClient*>::Iterator
3689 i = m_clients.getIterator();
3690 i.atEnd()==false; i++)
3692 RemoteClient *client = i.getNode()->getValue();
3693 client->SetBlockNotSent(p);
3697 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3699 DSTACK(__FUNCTION_NAME);
3701 v3s16 p = block->getPos();
3705 bool completely_air = true;
3706 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3707 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3708 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3710 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3712 completely_air = false;
3713 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3718 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3720 infostream<<"[completely air] ";
3721 infostream<<std::endl;
3725 Create a packet with the block in the right format
3728 std::ostringstream os(std::ios_base::binary);
3729 block->serialize(os, ver, false);
3730 std::string s = os.str();
3731 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3733 u32 replysize = 8 + blockdata.getSize();
3734 SharedBuffer<u8> reply(replysize);
3735 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3736 writeS16(&reply[2], p.X);
3737 writeS16(&reply[4], p.Y);
3738 writeS16(&reply[6], p.Z);
3739 memcpy(&reply[8], *blockdata, blockdata.getSize());
3741 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3742 <<": \tpacket size: "<<replysize<<std::endl;*/
3747 m_con.Send(peer_id, 1, reply, true);
3750 void Server::SendBlocks(float dtime)
3752 DSTACK(__FUNCTION_NAME);
3754 JMutexAutoLock envlock(m_env_mutex);
3755 JMutexAutoLock conlock(m_con_mutex);
3757 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3759 core::array<PrioritySortedBlockTransfer> queue;
3761 s32 total_sending = 0;
3764 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3766 for(core::map<u16, RemoteClient*>::Iterator
3767 i = m_clients.getIterator();
3768 i.atEnd() == false; i++)
3770 RemoteClient *client = i.getNode()->getValue();
3771 assert(client->peer_id == i.getNode()->getKey());
3773 // If definitions and textures have not been sent, don't
3774 // send MapBlocks either
3775 if(!client->definitions_sent)
3778 total_sending += client->SendingCount();
3780 if(client->serialization_version == SER_FMT_VER_INVALID)
3783 client->GetNextBlocks(this, dtime, queue);
3788 // Lowest priority number comes first.
3789 // Lowest is most important.
3792 for(u32 i=0; i<queue.size(); i++)
3794 //TODO: Calculate limit dynamically
3795 if(total_sending >= g_settings->getS32
3796 ("max_simultaneous_block_sends_server_total"))
3799 PrioritySortedBlockTransfer q = queue[i];
3801 MapBlock *block = NULL;
3804 block = m_env->getMap().getBlockNoCreate(q.pos);
3806 catch(InvalidPositionException &e)
3811 RemoteClient *client = getClient(q.peer_id);
3813 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3815 client->SentBlock(q.pos);
3821 void Server::PrepareTextures()
3823 DSTACK(__FUNCTION_NAME);
3825 infostream<<"Server: Calculating texture checksums"<<std::endl;
3827 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3828 i != m_mods.end(); i++){
3829 const ModSpec &mod = *i;
3830 std::string texturepath = mod.path + DIR_DELIM + "textures";
3831 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3832 for(u32 j=0; j<dirlist.size(); j++){
3833 if(dirlist[j].dir) // Ignode dirs
3835 std::string tname = dirlist[j].name;
3836 // if name contains illegal characters, ignore the texture
3837 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3838 errorstream<<"Server: ignoring illegal texture name: \""
3839 <<tname<<"\""<<std::endl;
3842 std::string tpath = texturepath + DIR_DELIM + tname;
3844 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3845 if(fis.good() == false){
3846 errorstream<<"Server::PrepareTextures(): Could not open \""
3847 <<tname<<"\" for reading"<<std::endl;
3850 std::ostringstream tmp_os(std::ios_base::binary);
3854 fis.read(buf, 1024);
3855 std::streamsize len = fis.gcount();
3856 tmp_os.write(buf, len);
3865 errorstream<<"Server::PrepareTextures(): Failed to read \""
3866 <<tname<<"\""<<std::endl;
3869 if(tmp_os.str().length() == 0){
3870 errorstream<<"Server::PrepareTextures(): Empty file \""
3871 <<tpath<<"\""<<std::endl;
3876 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3878 unsigned char *digest = sha1.getDigest();
3879 std::string digest_string = base64_encode(digest, 20);
3884 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3885 verbosestream<<"Server: sha1 for "<<tname<<"\tis "<<std::endl;
3890 struct SendableTextureAnnouncement
3893 std::string sha1_digest;
3895 SendableTextureAnnouncement(const std::string name_="",
3896 const std::string sha1_digest_=""):
3898 sha1_digest(sha1_digest_)
3903 void Server::SendTextureAnnouncement(u16 peer_id){
3904 DSTACK(__FUNCTION_NAME);
3906 verbosestream<<"Server: Announcing textures to id("<<peer_id<<")"
3909 core::list<SendableTextureAnnouncement> texture_announcements;
3911 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3914 texture_announcements.push_back(
3915 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3918 //send announcements
3922 u32 number of textures
3926 u16 length of digest string
3930 std::ostringstream os(std::ios_base::binary);
3932 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3933 writeU16(os, texture_announcements.size());
3935 for(core::list<SendableTextureAnnouncement>::Iterator
3936 j = texture_announcements.begin();
3937 j != texture_announcements.end(); j++){
3938 os<<serializeString(j->name);
3939 os<<serializeString(j->sha1_digest);
3943 std::string s = os.str();
3944 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3947 m_con.Send(peer_id, 0, data, true);
3951 struct SendableTexture
3957 SendableTexture(const std::string &name_="", const std::string path_="",
3958 const std::string &data_=""):
3965 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3966 DSTACK(__FUNCTION_NAME);
3968 verbosestream<<"Server::SendTexturesRequested(): "
3969 <<"Sending textures to client"<<std::endl;
3973 // Put 5kB in one bunch (this is not accurate)
3974 u32 bytes_per_bunch = 5000;
3976 core::array< core::list<SendableTexture> > texture_bunches;
3977 texture_bunches.push_back(core::list<SendableTexture>());
3979 u32 texture_size_bunch_total = 0;
3981 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3982 if(m_Textures.find(i->name) == m_Textures.end()){
3983 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3984 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3988 //TODO get path + name
3989 std::string tpath = m_Textures[(*i).name].path;
3992 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3993 if(fis.good() == false){
3994 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3995 <<tpath<<"\" for reading"<<std::endl;
3998 std::ostringstream tmp_os(std::ios_base::binary);
4002 fis.read(buf, 1024);
4003 std::streamsize len = fis.gcount();
4004 tmp_os.write(buf, len);
4005 texture_size_bunch_total += len;
4014 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
4015 <<(*i).name<<"\""<<std::endl;
4018 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
4019 <<tname<<"\""<<std::endl;*/
4021 texture_bunches[texture_bunches.size()-1].push_back(
4022 SendableTexture((*i).name, tpath, tmp_os.str()));
4024 // Start next bunch if got enough data
4025 if(texture_size_bunch_total >= bytes_per_bunch){
4026 texture_bunches.push_back(core::list<SendableTexture>());
4027 texture_size_bunch_total = 0;
4032 /* Create and send packets */
4034 u32 num_bunches = texture_bunches.size();
4035 for(u32 i=0; i<num_bunches; i++)
4039 u16 total number of texture bunches
4040 u16 index of this bunch
4041 u32 number of textures in this bunch
4049 std::ostringstream os(std::ios_base::binary);
4051 writeU16(os, TOCLIENT_TEXTURES);
4052 writeU16(os, num_bunches);
4054 writeU32(os, texture_bunches[i].size());
4056 for(core::list<SendableTexture>::Iterator
4057 j = texture_bunches[i].begin();
4058 j != texture_bunches[i].end(); j++){
4059 os<<serializeString(j->name);
4060 os<<serializeLongString(j->data);
4064 std::string s = os.str();
4065 verbosestream<<"Server::SendTexturesRequested(): bunch "
4066 <<i<<"/"<<num_bunches
4067 <<" textures="<<texture_bunches[i].size()
4068 <<" size=" <<s.size()<<std::endl;
4069 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4071 m_con.Send(peer_id, 0, data, true);
4081 void Server::DiePlayer(Player *player)
4083 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4085 infostream<<"Server::DiePlayer(): Player "
4086 <<player->getName()<<" dies"<<std::endl;
4090 // Trigger scripted stuff
4091 scriptapi_on_dieplayer(m_lua, srp);
4093 // Handle players that are not connected
4094 if(player->peer_id == PEER_ID_INEXISTENT){
4095 RespawnPlayer(player);
4099 SendPlayerHP(player);
4100 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4103 void Server::RespawnPlayer(Player *player)
4105 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4107 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4109 v3f pos = findSpawnPos(m_env->getServerMap());
4110 player->setPosition(pos);
4111 srp->m_last_good_position = pos;
4112 srp->m_last_good_position_age = 0;
4114 SendMovePlayer(player);
4115 SendPlayerHP(player);
4118 void Server::UpdateCrafting(u16 peer_id)
4120 DSTACK(__FUNCTION_NAME);
4122 Player* player = m_env->getPlayer(peer_id);
4125 // Get a preview for crafting
4127 // No crafting in creative mode
4128 if(g_settings->getBool("creative_mode") == false)
4129 getCraftingResult(&player->inventory, preview, false, this);
4131 // Put the new preview in
4132 InventoryList *plist = player->inventory.getList("craftpreview");
4134 assert(plist->getSize() >= 1);
4135 plist->changeItem(0, preview);
4138 RemoteClient* Server::getClient(u16 peer_id)
4140 DSTACK(__FUNCTION_NAME);
4141 //JMutexAutoLock lock(m_con_mutex);
4142 core::map<u16, RemoteClient*>::Node *n;
4143 n = m_clients.find(peer_id);
4144 // A client should exist for all peers
4146 return n->getValue();
4149 std::wstring Server::getStatusString()
4151 std::wostringstream os(std::ios_base::binary);
4154 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4156 os<<L", uptime="<<m_uptime.get();
4157 // Information about clients
4159 for(core::map<u16, RemoteClient*>::Iterator
4160 i = m_clients.getIterator();
4161 i.atEnd() == false; i++)
4163 // Get client and check that it is valid
4164 RemoteClient *client = i.getNode()->getValue();
4165 assert(client->peer_id == i.getNode()->getKey());
4166 if(client->serialization_version == SER_FMT_VER_INVALID)
4169 Player *player = m_env->getPlayer(client->peer_id);
4170 // Get name of player
4171 std::wstring name = L"unknown";
4173 name = narrow_to_wide(player->getName());
4174 // Add name to information string
4178 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4179 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4180 if(g_settings->get("motd") != "")
4181 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4185 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4187 // Add player to auth manager
4188 if(m_authmanager.exists(name) == false)
4190 infostream<<"Server: adding player "<<name
4191 <<" to auth manager"<<std::endl;
4192 m_authmanager.add(name);
4193 m_authmanager.setPrivs(name,
4194 stringToPrivs(g_settings->get("default_privs")));
4196 // Change password and save
4197 m_authmanager.setPassword(name, translatePassword(name, password));
4198 m_authmanager.save();
4201 // Saves g_settings to configpath given at initialization
4202 void Server::saveConfig()
4204 if(m_path_config != "")
4205 g_settings->updateConfigFile(m_path_config.c_str());
4208 void Server::notifyPlayer(const char *name, const std::wstring msg)
4210 Player *player = m_env->getPlayer(name);
4213 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4216 void Server::notifyPlayers(const std::wstring msg)
4218 BroadcastChatMessage(msg);
4221 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4225 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4226 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4229 // IGameDef interface
4231 IItemDefManager* Server::getItemDefManager()
4235 INodeDefManager* Server::getNodeDefManager()
4239 ICraftDefManager* Server::getCraftDefManager()
4243 ITextureSource* Server::getTextureSource()
4247 u16 Server::allocateUnknownNodeId(const std::string &name)
4249 return m_nodedef->allocateDummy(name);
4252 IWritableItemDefManager* Server::getWritableItemDefManager()
4256 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4260 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4265 const ModSpec* Server::getModSpec(const std::string &modname)
4267 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4268 i != m_mods.end(); i++){
4269 const ModSpec &mod = *i;
4270 if(mod.name == modname)
4276 v3f findSpawnPos(ServerMap &map)
4278 //return v3f(50,50,50)*BS;
4283 nodepos = v2s16(0,0);
4288 // Try to find a good place a few times
4289 for(s32 i=0; i<1000; i++)
4292 // We're going to try to throw the player to this position
4293 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4294 -range + (myrand()%(range*2)));
4295 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4296 // Get ground height at point (fallbacks to heightmap function)
4297 s16 groundheight = map.findGroundLevel(nodepos2d);
4298 // Don't go underwater
4299 if(groundheight < WATER_LEVEL)
4301 //infostream<<"-> Underwater"<<std::endl;
4304 // Don't go to high places
4305 if(groundheight > WATER_LEVEL + 4)
4307 //infostream<<"-> Underwater"<<std::endl;
4311 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4312 bool is_good = false;
4314 for(s32 i=0; i<10; i++){
4315 v3s16 blockpos = getNodeBlockPos(nodepos);
4316 map.emergeBlock(blockpos, true);
4317 MapNode n = map.getNodeNoEx(nodepos);
4318 if(n.getContent() == CONTENT_AIR){
4329 // Found a good place
4330 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4336 return intToFloat(nodepos, BS);
4339 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4342 Try to get an existing player
4344 ServerRemotePlayer *player =
4345 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4348 // If player is already connected, cancel
4349 if(player->peer_id != 0)
4351 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4356 player->peer_id = peer_id;
4358 // Re-add player to environment
4359 if(player->m_removed)
4361 player->m_removed = false;
4363 m_env->addActiveObject(player);
4366 // Reset inventory to creative if in creative mode
4367 if(g_settings->getBool("creative_mode"))
4369 // Warning: double code below
4370 // Backup actual inventory
4371 player->inventory_backup = new Inventory(m_itemdef);
4372 *(player->inventory_backup) = player->inventory;
4373 // Set creative inventory
4374 player->resetInventory();
4375 scriptapi_get_creative_inventory(m_lua, player);
4382 If player with the wanted peer_id already exists, cancel.
4384 if(m_env->getPlayer(peer_id) != NULL)
4386 infostream<<"emergePlayer(): Player with wrong name but same"
4387 " peer_id already exists"<<std::endl;
4395 /* Set player position */
4397 infostream<<"Server: Finding spawn place for player \""
4398 <<name<<"\""<<std::endl;
4400 v3f pos = findSpawnPos(m_env->getServerMap());
4402 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4403 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4405 /* Add player to environment */
4406 m_env->addPlayer(player);
4407 m_env->addActiveObject(srp);
4410 scriptapi_on_newplayer(m_lua, srp);
4412 /* Add stuff to inventory */
4413 if(g_settings->getBool("creative_mode"))
4415 // Warning: double code above
4416 // Backup actual inventory
4417 player->inventory_backup = new Inventory(m_itemdef);
4418 *(player->inventory_backup) = player->inventory;
4419 // Set creative inventory
4420 player->resetInventory();
4421 scriptapi_get_creative_inventory(m_lua, player);
4426 } // create new player
4429 void Server::handlePeerChange(PeerChange &c)
4431 JMutexAutoLock envlock(m_env_mutex);
4432 JMutexAutoLock conlock(m_con_mutex);
4434 if(c.type == PEER_ADDED)
4441 core::map<u16, RemoteClient*>::Node *n;
4442 n = m_clients.find(c.peer_id);
4443 // The client shouldn't already exist
4447 RemoteClient *client = new RemoteClient();
4448 client->peer_id = c.peer_id;
4449 m_clients.insert(client->peer_id, client);
4452 else if(c.type == PEER_REMOVED)
4459 core::map<u16, RemoteClient*>::Node *n;
4460 n = m_clients.find(c.peer_id);
4461 // The client should exist
4465 Mark objects to be not known by the client
4467 RemoteClient *client = n->getValue();
4469 for(core::map<u16, bool>::Iterator
4470 i = client->m_known_objects.getIterator();
4471 i.atEnd()==false; i++)
4474 u16 id = i.getNode()->getKey();
4475 ServerActiveObject* obj = m_env->getActiveObject(id);
4477 if(obj && obj->m_known_by_count > 0)
4478 obj->m_known_by_count--;
4481 ServerRemotePlayer* player =
4482 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4484 // Collect information about leaving in chat
4485 std::wstring message;
4489 std::wstring name = narrow_to_wide(player->getName());
4492 message += L" left game";
4494 message += L" (timed out)";
4498 // Remove from environment
4500 player->m_removed = true;
4502 // Set player client disconnected
4504 player->peer_id = 0;
4512 std::ostringstream os(std::ios_base::binary);
4513 for(core::map<u16, RemoteClient*>::Iterator
4514 i = m_clients.getIterator();
4515 i.atEnd() == false; i++)
4517 RemoteClient *client = i.getNode()->getValue();
4518 assert(client->peer_id == i.getNode()->getKey());
4519 if(client->serialization_version == SER_FMT_VER_INVALID)
4522 Player *player = m_env->getPlayer(client->peer_id);
4525 // Get name of player
4526 os<<player->getName()<<" ";
4529 actionstream<<player->getName()<<" "
4530 <<(c.timeout?"times out.":"leaves game.")
4531 <<" List of players: "
4532 <<os.str()<<std::endl;
4537 delete m_clients[c.peer_id];
4538 m_clients.remove(c.peer_id);
4540 // Send player info to all remaining clients
4541 //SendPlayerInfos();
4543 // Send leave chat message to all remaining clients
4544 if(message.length() != 0)
4545 BroadcastChatMessage(message);
4554 void Server::handlePeerChanges()
4556 while(m_peer_change_queue.size() > 0)
4558 PeerChange c = m_peer_change_queue.pop_front();
4560 verbosestream<<"Server: Handling peer change: "
4561 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4564 handlePeerChange(c);
4568 u64 Server::getPlayerPrivs(Player *player)
4572 std::string playername = player->getName();
4573 // Local player gets all privileges regardless of
4574 // what's set on their account.
4575 if(g_settings->get("name") == playername)
4581 return getPlayerAuthPrivs(playername);
4585 void dedicated_server_loop(Server &server, bool &kill)
4587 DSTACK(__FUNCTION_NAME);
4589 verbosestream<<"dedicated_server_loop()"<<std::endl;
4591 IntervalLimiter m_profiler_interval;
4595 float steplen = g_settings->getFloat("dedicated_server_step");
4596 // This is kind of a hack but can be done like this
4597 // because server.step() is very light
4599 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4600 sleep_ms((int)(steplen*1000.0));
4602 server.step(steplen);
4604 if(server.getShutdownRequested() || kill)
4606 infostream<<"Dedicated server quitting"<<std::endl;
4613 float profiler_print_interval =
4614 g_settings->getFloat("profiler_print_interval");
4615 if(profiler_print_interval != 0)
4617 if(m_profiler_interval.step(steplen, profiler_print_interval))
4619 infostream<<"Profiler:"<<std::endl;
4620 g_profiler->print(infostream);
4621 g_profiler->clear();