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),
857 m_time_of_day_send_timer(0),
859 m_shutdown_requested(false),
860 m_ignore_map_edit_events(false),
861 m_ignore_map_edit_events_peer_id(0)
863 m_liquid_transform_timer = 0.0;
864 m_print_info_timer = 0.0;
865 m_objectdata_timer = 0.0;
866 m_emergethread_trigger_timer = 0.0;
867 m_savemap_timer = 0.0;
871 m_step_dtime_mutex.Init();
875 throw ServerError("Supplied empty world path");
877 if(!gamespec.isValid())
878 throw ServerError("Supplied invalid gamespec");
880 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
881 if(m_simple_singleplayer_mode)
882 infostream<<" in simple singleplayer mode"<<std::endl;
884 infostream<<std::endl;
885 infostream<<"- world: "<<m_path_world<<std::endl;
886 infostream<<"- config: "<<m_path_config<<std::endl;
887 infostream<<"- game: "<<m_gamespec.path<<std::endl;
888 for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
889 i != m_gamespec.addon_paths.end(); i++)
890 infostream<<"- addons: "<<(*i)<<std::endl;
892 // Path to builtin.lua
893 std::string builtinpath = porting::path_share + DIR_DELIM + "builtin.lua";
895 // Add default global mod search path
896 m_modspaths.push_front(m_gamespec.path + DIR_DELIM "mods");
897 // Add world mod search path
898 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
899 // Add addon mod search path
900 for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
901 i != m_gamespec.addon_paths.end(); i++)
902 m_modspaths.push_front((*i) + DIR_DELIM + "mods");
903 // Add simple user mod search path
904 m_modspaths.push_front(porting::path_user + DIR_DELIM + "mods"
905 + DIR_DELIM + m_gamespec.id);
907 // Print out mod search paths
908 for(core::list<std::string>::Iterator i = m_modspaths.begin();
909 i != m_modspaths.end(); i++){
910 std::string modspath = *i;
911 infostream<<"- mods: "<<modspath<<std::endl;
914 // Create world if it doesn't exist
915 if(!initializeWorld(m_path_world, m_gamespec.id))
916 throw ServerError("Failed to initialize world");
919 JMutexAutoLock envlock(m_env_mutex);
920 JMutexAutoLock conlock(m_con_mutex);
922 // Initialize scripting
924 infostream<<"Server: Initializing Lua"<<std::endl;
925 m_lua = script_init();
928 scriptapi_export(m_lua, this);
929 // Load and run builtin.lua
930 infostream<<"Server: Loading builtin.lua [\""
931 <<builtinpath<<"\"]"<<std::endl;
932 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
934 errorstream<<"Server: Failed to load and run "
935 <<builtinpath<<std::endl;
936 throw ModError("Failed to load and run "+builtinpath);
938 // Find mods in mod search paths
939 m_mods = getMods(m_modspaths);
941 infostream<<"Server: Loading mods: ";
942 for(core::list<ModSpec>::Iterator i = m_mods.begin();
943 i != m_mods.end(); i++){
944 const ModSpec &mod = *i;
945 infostream<<mod.name<<" ";
947 infostream<<std::endl;
948 // Load and run "mod" scripts
949 for(core::list<ModSpec>::Iterator i = m_mods.begin();
950 i != m_mods.end(); i++){
951 const ModSpec &mod = *i;
952 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
953 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
954 <<scriptpath<<"\"]"<<std::endl;
955 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
957 errorstream<<"Server: Failed to load and run "
958 <<scriptpath<<std::endl;
959 throw ModError("Failed to load and run "+scriptpath);
963 // Read Textures and calculate sha1 sums
966 // Apply item aliases in the node definition manager
967 m_nodedef->updateAliases(m_itemdef);
969 // Initialize Environment
971 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
974 // Give environment reference to scripting api
975 scriptapi_add_environment(m_lua, m_env);
977 // Register us to receive map edit events
978 m_env->getMap().addEventReceiver(this);
980 // If file exists, load environment metadata
981 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
983 infostream<<"Server: Loading environment metadata"<<std::endl;
984 m_env->loadMeta(m_path_world);
988 infostream<<"Server: Loading players"<<std::endl;
989 m_env->deSerializePlayers(m_path_world);
992 Add some test ActiveBlockModifiers to environment
994 add_legacy_abms(m_env, m_nodedef);
999 infostream<<"Server destructing"<<std::endl;
1002 Send shutdown message
1005 JMutexAutoLock conlock(m_con_mutex);
1007 std::wstring line = L"*** Server shutting down";
1010 Send the message to clients
1012 for(core::map<u16, RemoteClient*>::Iterator
1013 i = m_clients.getIterator();
1014 i.atEnd() == false; i++)
1016 // Get client and check that it is valid
1017 RemoteClient *client = i.getNode()->getValue();
1018 assert(client->peer_id == i.getNode()->getKey());
1019 if(client->serialization_version == SER_FMT_VER_INVALID)
1023 SendChatMessage(client->peer_id, line);
1025 catch(con::PeerNotFoundException &e)
1031 JMutexAutoLock envlock(m_env_mutex);
1036 infostream<<"Server: Saving players"<<std::endl;
1037 m_env->serializePlayers(m_path_world);
1040 Save environment metadata
1042 infostream<<"Server: Saving environment metadata"<<std::endl;
1043 m_env->saveMeta(m_path_world);
1055 JMutexAutoLock clientslock(m_con_mutex);
1057 for(core::map<u16, RemoteClient*>::Iterator
1058 i = m_clients.getIterator();
1059 i.atEnd() == false; i++)
1062 // NOTE: These are removed by env destructor
1064 u16 peer_id = i.getNode()->getKey();
1065 JMutexAutoLock envlock(m_env_mutex);
1066 m_env->removePlayer(peer_id);
1070 delete i.getNode()->getValue();
1074 // Delete Environment
1081 // Deinitialize scripting
1082 infostream<<"Server: Deinitializing scripting"<<std::endl;
1083 script_deinit(m_lua);
1086 void Server::start(unsigned short port)
1088 DSTACK(__FUNCTION_NAME);
1089 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1091 // Stop thread if already running
1094 // Initialize connection
1095 m_con.SetTimeoutMs(30);
1099 m_thread.setRun(true);
1102 // ASCII art for the win!
1104 <<" .__ __ __ "<<std::endl
1105 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1106 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1107 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1108 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1109 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1110 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1111 actionstream<<"Server for gameid=\""<<m_gamespec.id
1112 <<"\" listening on port "<<port<<"."<<std::endl;
1117 DSTACK(__FUNCTION_NAME);
1119 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1121 // Stop threads (set run=false first so both start stopping)
1122 m_thread.setRun(false);
1123 m_emergethread.setRun(false);
1125 m_emergethread.stop();
1127 infostream<<"Server: Threads stopped"<<std::endl;
1130 void Server::step(float dtime)
1132 DSTACK(__FUNCTION_NAME);
1137 JMutexAutoLock lock(m_step_dtime_mutex);
1138 m_step_dtime += dtime;
1140 // Throw if fatal error occurred in thread
1141 std::string async_err = m_async_fatal_error.get();
1142 if(async_err != ""){
1143 throw ServerError(async_err);
1147 void Server::AsyncRunStep()
1149 DSTACK(__FUNCTION_NAME);
1151 g_profiler->add("Server::AsyncRunStep (num)", 1);
1155 JMutexAutoLock lock1(m_step_dtime_mutex);
1156 dtime = m_step_dtime;
1160 // Send blocks to clients
1167 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1169 //infostream<<"Server steps "<<dtime<<std::endl;
1170 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1173 JMutexAutoLock lock1(m_step_dtime_mutex);
1174 m_step_dtime -= dtime;
1181 m_uptime.set(m_uptime.get() + dtime);
1185 // Process connection's timeouts
1186 JMutexAutoLock lock2(m_con_mutex);
1187 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1188 m_con.RunTimeouts(dtime);
1192 // This has to be called so that the client list gets synced
1193 // with the peer list of the connection
1194 handlePeerChanges();
1198 Update time of day and overall game time
1201 JMutexAutoLock envlock(m_env_mutex);
1203 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1206 Send to clients at constant intervals
1209 m_time_of_day_send_timer -= dtime;
1210 if(m_time_of_day_send_timer < 0.0)
1212 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1214 //JMutexAutoLock envlock(m_env_mutex);
1215 JMutexAutoLock conlock(m_con_mutex);
1217 for(core::map<u16, RemoteClient*>::Iterator
1218 i = m_clients.getIterator();
1219 i.atEnd() == false; i++)
1221 RemoteClient *client = i.getNode()->getValue();
1222 //Player *player = m_env->getPlayer(client->peer_id);
1224 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1225 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1227 m_con.Send(client->peer_id, 0, data, true);
1233 JMutexAutoLock lock(m_env_mutex);
1235 ScopeProfiler sp(g_profiler, "SEnv step");
1236 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1240 const float map_timer_and_unload_dtime = 2.92;
1241 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1243 JMutexAutoLock lock(m_env_mutex);
1244 // Run Map's timers and unload unused data
1245 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1246 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1247 g_settings->getFloat("server_unload_unused_data_timeout"));
1258 JMutexAutoLock lock(m_env_mutex);
1259 JMutexAutoLock lock2(m_con_mutex);
1261 ScopeProfiler sp(g_profiler, "Server: handle players");
1263 //float player_max_speed = BS * 4.0; // Normal speed
1264 float player_max_speed = BS * 20; // Fast speed
1265 float player_max_speed_up = BS * 20;
1267 player_max_speed *= 2.5; // Tolerance
1268 player_max_speed_up *= 2.5;
1270 for(core::map<u16, RemoteClient*>::Iterator
1271 i = m_clients.getIterator();
1272 i.atEnd() == false; i++)
1274 RemoteClient *client = i.getNode()->getValue();
1275 ServerRemotePlayer *player =
1276 static_cast<ServerRemotePlayer*>
1277 (m_env->getPlayer(client->peer_id));
1282 Check player movements
1284 NOTE: Actually the server should handle player physics like the
1285 client does and compare player's position to what is calculated
1286 on our side. This is required when eg. players fly due to an
1289 player->m_last_good_position_age += dtime;
1290 if(player->m_last_good_position_age >= 1.0){
1291 float age = player->m_last_good_position_age;
1292 v3f diff = (player->getPosition() - player->m_last_good_position);
1293 float d_vert = diff.Y;
1295 float d_horiz = diff.getLength();
1296 /*infostream<<player->getName()<<"'s horizontal speed is "
1297 <<(d_horiz/age)<<std::endl;*/
1298 if(d_horiz <= age * player_max_speed &&
1299 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1300 player->m_last_good_position = player->getPosition();
1302 actionstream<<"Player "<<player->getName()
1303 <<" moved too fast; resetting position"
1305 player->setPosition(player->m_last_good_position);
1306 SendMovePlayer(player);
1308 player->m_last_good_position_age = 0;
1312 Handle player HPs (die if hp=0)
1314 if(player->hp == 0 && player->m_hp_not_sent)
1318 Send player inventories and HPs if necessary
1320 if(player->m_inventory_not_sent){
1321 UpdateCrafting(player->peer_id);
1322 SendInventory(player->peer_id);
1324 if(player->m_hp_not_sent){
1325 SendPlayerHP(player);
1331 if(!player->m_is_in_environment){
1332 player->m_removed = false;
1334 m_env->addActiveObject(player);
1339 /* Transform liquids */
1340 m_liquid_transform_timer += dtime;
1341 if(m_liquid_transform_timer >= 1.00)
1343 m_liquid_transform_timer -= 1.00;
1345 JMutexAutoLock lock(m_env_mutex);
1347 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1349 core::map<v3s16, MapBlock*> modified_blocks;
1350 m_env->getMap().transformLiquids(modified_blocks);
1355 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1356 ServerMap &map = ((ServerMap&)m_env->getMap());
1357 map.updateLighting(modified_blocks, lighting_modified_blocks);
1359 // Add blocks modified by lighting to modified_blocks
1360 for(core::map<v3s16, MapBlock*>::Iterator
1361 i = lighting_modified_blocks.getIterator();
1362 i.atEnd() == false; i++)
1364 MapBlock *block = i.getNode()->getValue();
1365 modified_blocks.insert(block->getPos(), block);
1369 Set the modified blocks unsent for all the clients
1372 JMutexAutoLock lock2(m_con_mutex);
1374 for(core::map<u16, RemoteClient*>::Iterator
1375 i = m_clients.getIterator();
1376 i.atEnd() == false; i++)
1378 RemoteClient *client = i.getNode()->getValue();
1380 if(modified_blocks.size() > 0)
1382 // Remove block from sent history
1383 client->SetBlocksNotSent(modified_blocks);
1388 // Periodically print some info
1390 float &counter = m_print_info_timer;
1396 JMutexAutoLock lock2(m_con_mutex);
1398 if(m_clients.size() != 0)
1399 infostream<<"Players:"<<std::endl;
1400 for(core::map<u16, RemoteClient*>::Iterator
1401 i = m_clients.getIterator();
1402 i.atEnd() == false; i++)
1404 //u16 peer_id = i.getNode()->getKey();
1405 RemoteClient *client = i.getNode()->getValue();
1406 Player *player = m_env->getPlayer(client->peer_id);
1409 infostream<<"* "<<player->getName()<<"\t";
1410 client->PrintInfo(infostream);
1415 //if(g_settings->getBool("enable_experimental"))
1419 Check added and deleted active objects
1422 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1423 JMutexAutoLock envlock(m_env_mutex);
1424 JMutexAutoLock conlock(m_con_mutex);
1426 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1428 // Radius inside which objects are active
1429 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1430 radius *= MAP_BLOCKSIZE;
1432 for(core::map<u16, RemoteClient*>::Iterator
1433 i = m_clients.getIterator();
1434 i.atEnd() == false; i++)
1436 RemoteClient *client = i.getNode()->getValue();
1438 // If definitions and textures have not been sent, don't
1439 // send objects either
1440 if(!client->definitions_sent)
1443 Player *player = m_env->getPlayer(client->peer_id);
1446 // This can happen if the client timeouts somehow
1447 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1449 <<" has no associated player"<<std::endl;*/
1452 v3s16 pos = floatToInt(player->getPosition(), BS);
1454 core::map<u16, bool> removed_objects;
1455 core::map<u16, bool> added_objects;
1456 m_env->getRemovedActiveObjects(pos, radius,
1457 client->m_known_objects, removed_objects);
1458 m_env->getAddedActiveObjects(pos, radius,
1459 client->m_known_objects, added_objects);
1461 // Ignore if nothing happened
1462 if(removed_objects.size() == 0 && added_objects.size() == 0)
1464 //infostream<<"active objects: none changed"<<std::endl;
1468 std::string data_buffer;
1472 // Handle removed objects
1473 writeU16((u8*)buf, removed_objects.size());
1474 data_buffer.append(buf, 2);
1475 for(core::map<u16, bool>::Iterator
1476 i = removed_objects.getIterator();
1477 i.atEnd()==false; i++)
1480 u16 id = i.getNode()->getKey();
1481 ServerActiveObject* obj = m_env->getActiveObject(id);
1483 // Add to data buffer for sending
1484 writeU16((u8*)buf, i.getNode()->getKey());
1485 data_buffer.append(buf, 2);
1487 // Remove from known objects
1488 client->m_known_objects.remove(i.getNode()->getKey());
1490 if(obj && obj->m_known_by_count > 0)
1491 obj->m_known_by_count--;
1494 // Handle added objects
1495 writeU16((u8*)buf, added_objects.size());
1496 data_buffer.append(buf, 2);
1497 for(core::map<u16, bool>::Iterator
1498 i = added_objects.getIterator();
1499 i.atEnd()==false; i++)
1502 u16 id = i.getNode()->getKey();
1503 ServerActiveObject* obj = m_env->getActiveObject(id);
1506 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1508 infostream<<"WARNING: "<<__FUNCTION_NAME
1509 <<": NULL object"<<std::endl;
1511 type = obj->getType();
1513 // Add to data buffer for sending
1514 writeU16((u8*)buf, id);
1515 data_buffer.append(buf, 2);
1516 writeU8((u8*)buf, type);
1517 data_buffer.append(buf, 1);
1520 data_buffer.append(serializeLongString(
1521 obj->getClientInitializationData()));
1523 data_buffer.append(serializeLongString(""));
1525 // Add to known objects
1526 client->m_known_objects.insert(i.getNode()->getKey(), false);
1529 obj->m_known_by_count++;
1533 SharedBuffer<u8> reply(2 + data_buffer.size());
1534 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1535 memcpy((char*)&reply[2], data_buffer.c_str(),
1536 data_buffer.size());
1538 m_con.Send(client->peer_id, 0, reply, true);
1540 verbosestream<<"Server: Sent object remove/add: "
1541 <<removed_objects.size()<<" removed, "
1542 <<added_objects.size()<<" added, "
1543 <<"packet size is "<<reply.getSize()<<std::endl;
1548 Collect a list of all the objects known by the clients
1549 and report it back to the environment.
1552 core::map<u16, bool> all_known_objects;
1554 for(core::map<u16, RemoteClient*>::Iterator
1555 i = m_clients.getIterator();
1556 i.atEnd() == false; i++)
1558 RemoteClient *client = i.getNode()->getValue();
1559 // Go through all known objects of client
1560 for(core::map<u16, bool>::Iterator
1561 i = client->m_known_objects.getIterator();
1562 i.atEnd()==false; i++)
1564 u16 id = i.getNode()->getKey();
1565 all_known_objects[id] = true;
1569 m_env->setKnownActiveObjects(whatever);
1575 Send object messages
1578 JMutexAutoLock envlock(m_env_mutex);
1579 JMutexAutoLock conlock(m_con_mutex);
1581 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1584 // Value = data sent by object
1585 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1587 // Get active object messages from environment
1590 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1594 core::list<ActiveObjectMessage>* message_list = NULL;
1595 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1596 n = buffered_messages.find(aom.id);
1599 message_list = new core::list<ActiveObjectMessage>;
1600 buffered_messages.insert(aom.id, message_list);
1604 message_list = n->getValue();
1606 message_list->push_back(aom);
1609 // Route data to every client
1610 for(core::map<u16, RemoteClient*>::Iterator
1611 i = m_clients.getIterator();
1612 i.atEnd()==false; i++)
1614 RemoteClient *client = i.getNode()->getValue();
1615 std::string reliable_data;
1616 std::string unreliable_data;
1617 // Go through all objects in message buffer
1618 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1619 j = buffered_messages.getIterator();
1620 j.atEnd()==false; j++)
1622 // If object is not known by client, skip it
1623 u16 id = j.getNode()->getKey();
1624 if(client->m_known_objects.find(id) == NULL)
1626 // Get message list of object
1627 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1628 // Go through every message
1629 for(core::list<ActiveObjectMessage>::Iterator
1630 k = list->begin(); k != list->end(); k++)
1632 // Compose the full new data with header
1633 ActiveObjectMessage aom = *k;
1634 std::string new_data;
1637 writeU16((u8*)&buf[0], aom.id);
1638 new_data.append(buf, 2);
1640 new_data += serializeString(aom.datastring);
1641 // Add data to buffer
1643 reliable_data += new_data;
1645 unreliable_data += new_data;
1649 reliable_data and unreliable_data are now ready.
1652 if(reliable_data.size() > 0)
1654 SharedBuffer<u8> reply(2 + reliable_data.size());
1655 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1656 memcpy((char*)&reply[2], reliable_data.c_str(),
1657 reliable_data.size());
1659 m_con.Send(client->peer_id, 0, reply, true);
1661 if(unreliable_data.size() > 0)
1663 SharedBuffer<u8> reply(2 + unreliable_data.size());
1664 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1665 memcpy((char*)&reply[2], unreliable_data.c_str(),
1666 unreliable_data.size());
1667 // Send as unreliable
1668 m_con.Send(client->peer_id, 0, reply, false);
1671 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1673 infostream<<"Server: Size of object message data: "
1674 <<"reliable: "<<reliable_data.size()
1675 <<", unreliable: "<<unreliable_data.size()
1680 // Clear buffered_messages
1681 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1682 i = buffered_messages.getIterator();
1683 i.atEnd()==false; i++)
1685 delete i.getNode()->getValue();
1689 } // enable_experimental
1692 Send queued-for-sending map edit events.
1695 // Don't send too many at a time
1698 // Single change sending is disabled if queue size is not small
1699 bool disable_single_change_sending = false;
1700 if(m_unsent_map_edit_queue.size() >= 4)
1701 disable_single_change_sending = true;
1703 int event_count = m_unsent_map_edit_queue.size();
1705 // We'll log the amount of each
1708 while(m_unsent_map_edit_queue.size() != 0)
1710 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1712 // Players far away from the change are stored here.
1713 // Instead of sending the changes, MapBlocks are set not sent
1715 core::list<u16> far_players;
1717 if(event->type == MEET_ADDNODE)
1719 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1720 prof.add("MEET_ADDNODE", 1);
1721 if(disable_single_change_sending)
1722 sendAddNode(event->p, event->n, event->already_known_by_peer,
1725 sendAddNode(event->p, event->n, event->already_known_by_peer,
1728 else if(event->type == MEET_REMOVENODE)
1730 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1731 prof.add("MEET_REMOVENODE", 1);
1732 if(disable_single_change_sending)
1733 sendRemoveNode(event->p, event->already_known_by_peer,
1736 sendRemoveNode(event->p, event->already_known_by_peer,
1739 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1741 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1742 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1743 setBlockNotSent(event->p);
1745 else if(event->type == MEET_OTHER)
1747 infostream<<"Server: MEET_OTHER"<<std::endl;
1748 prof.add("MEET_OTHER", 1);
1749 for(core::map<v3s16, bool>::Iterator
1750 i = event->modified_blocks.getIterator();
1751 i.atEnd()==false; i++)
1753 v3s16 p = i.getNode()->getKey();
1759 prof.add("unknown", 1);
1760 infostream<<"WARNING: Server: Unknown MapEditEvent "
1761 <<((u32)event->type)<<std::endl;
1765 Set blocks not sent to far players
1767 if(far_players.size() > 0)
1769 // Convert list format to that wanted by SetBlocksNotSent
1770 core::map<v3s16, MapBlock*> modified_blocks2;
1771 for(core::map<v3s16, bool>::Iterator
1772 i = event->modified_blocks.getIterator();
1773 i.atEnd()==false; i++)
1775 v3s16 p = i.getNode()->getKey();
1776 modified_blocks2.insert(p,
1777 m_env->getMap().getBlockNoCreateNoEx(p));
1779 // Set blocks not sent
1780 for(core::list<u16>::Iterator
1781 i = far_players.begin();
1782 i != far_players.end(); i++)
1785 RemoteClient *client = getClient(peer_id);
1788 client->SetBlocksNotSent(modified_blocks2);
1794 /*// Don't send too many at a time
1796 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1800 if(event_count >= 5){
1801 infostream<<"Server: MapEditEvents:"<<std::endl;
1802 prof.print(infostream);
1803 } else if(event_count != 0){
1804 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1805 prof.print(verbosestream);
1811 Trigger emergethread (it somehow gets to a non-triggered but
1812 bysy state sometimes)
1815 float &counter = m_emergethread_trigger_timer;
1821 m_emergethread.trigger();
1825 // Save map, players and auth stuff
1827 float &counter = m_savemap_timer;
1829 if(counter >= g_settings->getFloat("server_map_save_interval"))
1832 JMutexAutoLock lock(m_env_mutex);
1834 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1837 if(m_authmanager.isModified())
1838 m_authmanager.save();
1841 if(m_banmanager.isModified())
1842 m_banmanager.save();
1844 // Save changed parts of map
1845 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1848 m_env->serializePlayers(m_path_world);
1850 // Save environment metadata
1851 m_env->saveMeta(m_path_world);
1856 void Server::Receive()
1858 DSTACK(__FUNCTION_NAME);
1859 SharedBuffer<u8> data;
1864 JMutexAutoLock conlock(m_con_mutex);
1865 datasize = m_con.Receive(peer_id, data);
1868 // This has to be called so that the client list gets synced
1869 // with the peer list of the connection
1870 handlePeerChanges();
1872 ProcessData(*data, datasize, peer_id);
1874 catch(con::InvalidIncomingDataException &e)
1876 infostream<<"Server::Receive(): "
1877 "InvalidIncomingDataException: what()="
1878 <<e.what()<<std::endl;
1880 catch(con::PeerNotFoundException &e)
1882 //NOTE: This is not needed anymore
1884 // The peer has been disconnected.
1885 // Find the associated player and remove it.
1887 /*JMutexAutoLock envlock(m_env_mutex);
1889 infostream<<"ServerThread: peer_id="<<peer_id
1890 <<" has apparently closed connection. "
1891 <<"Removing player."<<std::endl;
1893 m_env->removePlayer(peer_id);*/
1897 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1899 DSTACK(__FUNCTION_NAME);
1900 // Environment is locked first.
1901 JMutexAutoLock envlock(m_env_mutex);
1902 JMutexAutoLock conlock(m_con_mutex);
1904 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1907 Address address = m_con.GetPeerAddress(peer_id);
1909 // drop player if is ip is banned
1910 if(m_banmanager.isIpBanned(address.serializeString())){
1911 SendAccessDenied(m_con, peer_id,
1912 L"Your ip is banned. Banned name was "
1913 +narrow_to_wide(m_banmanager.getBanName(
1914 address.serializeString())));
1915 m_con.DeletePeer(peer_id);
1919 catch(con::PeerNotFoundException &e)
1921 infostream<<"Server::ProcessData(): Cancelling: peer "
1922 <<peer_id<<" not found"<<std::endl;
1926 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1928 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1936 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1938 if(command == TOSERVER_INIT)
1940 // [0] u16 TOSERVER_INIT
1941 // [2] u8 SER_FMT_VER_HIGHEST
1942 // [3] u8[20] player_name
1943 // [23] u8[28] password <--- can be sent without this, from old versions
1945 if(datasize < 2+1+PLAYERNAME_SIZE)
1948 verbosestream<<"Server: Got TOSERVER_INIT from "
1949 <<peer_id<<std::endl;
1951 // First byte after command is maximum supported
1952 // serialization version
1953 u8 client_max = data[2];
1954 u8 our_max = SER_FMT_VER_HIGHEST;
1955 // Use the highest version supported by both
1956 u8 deployed = core::min_(client_max, our_max);
1957 // If it's lower than the lowest supported, give up.
1958 if(deployed < SER_FMT_VER_LOWEST)
1959 deployed = SER_FMT_VER_INVALID;
1961 //peer->serialization_version = deployed;
1962 getClient(peer_id)->pending_serialization_version = deployed;
1964 if(deployed == SER_FMT_VER_INVALID)
1966 actionstream<<"Server: A mismatched client tried to connect from "
1967 <<addr_s<<std::endl;
1968 infostream<<"Server: Cannot negotiate "
1969 "serialization version with peer "
1970 <<peer_id<<std::endl;
1971 SendAccessDenied(m_con, peer_id, std::wstring(
1972 L"Your client's version is not supported.\n"
1973 L"Server version is ")
1974 + narrow_to_wide(VERSION_STRING) + L"."
1980 Read and check network protocol version
1983 u16 net_proto_version = 0;
1984 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1986 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1989 getClient(peer_id)->net_proto_version = net_proto_version;
1991 if(net_proto_version == 0)
1993 actionstream<<"Server: An old tried to connect from "<<addr_s
1995 SendAccessDenied(m_con, peer_id, std::wstring(
1996 L"Your client's version is not supported.\n"
1997 L"Server version is ")
1998 + narrow_to_wide(VERSION_STRING) + L"."
2003 if(g_settings->getBool("strict_protocol_version_checking"))
2005 if(net_proto_version != PROTOCOL_VERSION)
2007 actionstream<<"Server: A mismatched client tried to connect"
2008 <<" from "<<addr_s<<std::endl;
2009 SendAccessDenied(m_con, peer_id, std::wstring(
2010 L"Your client's version is not supported.\n"
2011 L"Server version is ")
2012 + narrow_to_wide(VERSION_STRING) + L",\n"
2013 + L"server's PROTOCOL_VERSION is "
2014 + narrow_to_wide(itos(PROTOCOL_VERSION))
2015 + L", client's PROTOCOL_VERSION is "
2016 + narrow_to_wide(itos(net_proto_version))
2027 char playername[PLAYERNAME_SIZE];
2028 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2030 playername[i] = data[3+i];
2032 playername[PLAYERNAME_SIZE-1] = 0;
2034 if(playername[0]=='\0')
2036 actionstream<<"Server: Player with an empty name "
2037 <<"tried to connect from "<<addr_s<<std::endl;
2038 SendAccessDenied(m_con, peer_id,
2043 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2045 actionstream<<"Server: Player with an invalid name "
2046 <<"tried to connect from "<<addr_s<<std::endl;
2047 SendAccessDenied(m_con, peer_id,
2048 L"Name contains unallowed characters");
2052 infostream<<"Server: New connection: \""<<playername<<"\" from "
2053 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2056 char password[PASSWORD_SIZE];
2057 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2059 // old version - assume blank password
2064 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2066 password[i] = data[23+i];
2068 password[PASSWORD_SIZE-1] = 0;
2071 // Add player to auth manager
2072 if(m_authmanager.exists(playername) == false)
2074 std::wstring default_password =
2075 narrow_to_wide(g_settings->get("default_password"));
2076 std::string translated_default_password =
2077 translatePassword(playername, default_password);
2079 // If default_password is empty, allow any initial password
2080 if (default_password.length() == 0)
2081 translated_default_password = password;
2083 infostream<<"Server: adding player "<<playername
2084 <<" to auth manager"<<std::endl;
2085 m_authmanager.add(playername);
2086 m_authmanager.setPassword(playername, translated_default_password);
2087 m_authmanager.setPrivs(playername,
2088 stringToPrivs(g_settings->get("default_privs")));
2089 m_authmanager.save();
2092 std::string checkpwd = m_authmanager.getPassword(playername);
2094 /*infostream<<"Server: Client gave password '"<<password
2095 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2097 if(password != checkpwd)
2099 infostream<<"Server: peer_id="<<peer_id
2100 <<": supplied invalid password for "
2101 <<playername<<std::endl;
2102 SendAccessDenied(m_con, peer_id, L"Invalid password");
2106 // Do not allow multiple players in simple singleplayer mode.
2107 // This isn't a perfect way to do it, but will suffice for now.
2108 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2109 infostream<<"Server: Not allowing another client to connect in"
2110 <<" simple singleplayer mode"<<std::endl;
2111 SendAccessDenied(m_con, peer_id,
2112 L"Running in simple singleplayer mode.");
2116 // Enforce user limit.
2117 // Don't enforce for users that have some admin right
2118 if(m_clients.size() >= g_settings->getU16("max_users") &&
2119 (m_authmanager.getPrivs(playername)
2120 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2121 playername != g_settings->get("name"))
2123 actionstream<<"Server: "<<playername<<" tried to join, but there"
2124 <<" are already max_users="
2125 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2126 SendAccessDenied(m_con, peer_id, L"Too many users.");
2131 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2133 // If failed, cancel
2136 errorstream<<"Server: peer_id="<<peer_id
2137 <<": failed to emerge player"<<std::endl;
2142 Answer with a TOCLIENT_INIT
2145 SharedBuffer<u8> reply(2+1+6+8);
2146 writeU16(&reply[0], TOCLIENT_INIT);
2147 writeU8(&reply[2], deployed);
2148 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2149 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2152 m_con.Send(peer_id, 0, reply, true);
2156 Send complete position information
2158 SendMovePlayer(player);
2163 if(command == TOSERVER_INIT2)
2165 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2166 <<peer_id<<std::endl;
2169 getClient(peer_id)->serialization_version
2170 = getClient(peer_id)->pending_serialization_version;
2173 Send some initialization data
2176 infostream<<"Server: Sending content to "
2177 <<getPlayerName(peer_id)<<std::endl;
2179 // Send item definitions
2180 SendItemDef(m_con, peer_id, m_itemdef);
2182 // Send node definitions
2183 SendNodeDef(m_con, peer_id, m_nodedef);
2185 // Send texture announcement
2186 SendTextureAnnouncement(peer_id);
2188 // Send player info to all players
2189 //SendPlayerInfos();
2191 // Send inventory to player
2192 UpdateCrafting(peer_id);
2193 SendInventory(peer_id);
2195 // Send player items to all players
2198 Player *player = m_env->getPlayer(peer_id);
2201 SendPlayerHP(player);
2203 // Show death screen if necessary
2205 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2209 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2210 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2211 m_con.Send(peer_id, 0, data, true);
2214 // Note things in chat if not in simple singleplayer mode
2215 if(!m_simple_singleplayer_mode)
2217 // Send information about server to player in chat
2218 SendChatMessage(peer_id, getStatusString());
2220 // Send information about joining in chat
2222 std::wstring name = L"unknown";
2223 Player *player = m_env->getPlayer(peer_id);
2225 name = narrow_to_wide(player->getName());
2227 std::wstring message;
2230 message += L" joined game";
2231 BroadcastChatMessage(message);
2235 // Warnings about protocol version can be issued here
2236 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2238 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2245 std::ostringstream os(std::ios_base::binary);
2246 for(core::map<u16, RemoteClient*>::Iterator
2247 i = m_clients.getIterator();
2248 i.atEnd() == false; i++)
2250 RemoteClient *client = i.getNode()->getValue();
2251 assert(client->peer_id == i.getNode()->getKey());
2252 if(client->serialization_version == SER_FMT_VER_INVALID)
2255 Player *player = m_env->getPlayer(client->peer_id);
2258 // Get name of player
2259 os<<player->getName()<<" ";
2262 actionstream<<player->getName()<<" joins game. List of players: "
2263 <<os.str()<<std::endl;
2269 if(peer_ser_ver == SER_FMT_VER_INVALID)
2271 infostream<<"Server::ProcessData(): Cancelling: Peer"
2272 " serialization format invalid or not initialized."
2273 " Skipping incoming command="<<command<<std::endl;
2277 Player *player = m_env->getPlayer(peer_id);
2278 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2281 infostream<<"Server::ProcessData(): Cancelling: "
2282 "No player for peer_id="<<peer_id
2286 if(command == TOSERVER_PLAYERPOS)
2288 if(datasize < 2+12+12+4+4)
2292 v3s32 ps = readV3S32(&data[start+2]);
2293 v3s32 ss = readV3S32(&data[start+2+12]);
2294 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2295 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2296 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2297 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2298 pitch = wrapDegrees(pitch);
2299 yaw = wrapDegrees(yaw);
2301 player->setPosition(position);
2302 player->setSpeed(speed);
2303 player->setPitch(pitch);
2304 player->setYaw(yaw);
2306 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2307 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2308 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2310 else if(command == TOSERVER_GOTBLOCKS)
2323 u16 count = data[2];
2324 for(u16 i=0; i<count; i++)
2326 if((s16)datasize < 2+1+(i+1)*6)
2327 throw con::InvalidIncomingDataException
2328 ("GOTBLOCKS length is too short");
2329 v3s16 p = readV3S16(&data[2+1+i*6]);
2330 /*infostream<<"Server: GOTBLOCKS ("
2331 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2332 RemoteClient *client = getClient(peer_id);
2333 client->GotBlock(p);
2336 else if(command == TOSERVER_DELETEDBLOCKS)
2349 u16 count = data[2];
2350 for(u16 i=0; i<count; i++)
2352 if((s16)datasize < 2+1+(i+1)*6)
2353 throw con::InvalidIncomingDataException
2354 ("DELETEDBLOCKS length is too short");
2355 v3s16 p = readV3S16(&data[2+1+i*6]);
2356 /*infostream<<"Server: DELETEDBLOCKS ("
2357 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2358 RemoteClient *client = getClient(peer_id);
2359 client->SetBlockNotSent(p);
2362 else if(command == TOSERVER_CLICK_OBJECT)
2364 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2367 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2369 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2372 else if(command == TOSERVER_GROUND_ACTION)
2374 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2378 else if(command == TOSERVER_RELEASE)
2380 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2383 else if(command == TOSERVER_SIGNTEXT)
2385 infostream<<"Server: SIGNTEXT not supported anymore"
2389 else if(command == TOSERVER_SIGNNODETEXT)
2391 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2399 std::string datastring((char*)&data[2], datasize-2);
2400 std::istringstream is(datastring, std::ios_base::binary);
2403 is.read((char*)buf, 6);
2404 v3s16 p = readV3S16(buf);
2405 is.read((char*)buf, 2);
2406 u16 textlen = readU16(buf);
2408 for(u16 i=0; i<textlen; i++)
2410 is.read((char*)buf, 1);
2411 text += (char)buf[0];
2414 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2418 meta->setText(text);
2420 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2421 <<" at "<<PP(p)<<std::endl;
2423 v3s16 blockpos = getNodeBlockPos(p);
2424 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2427 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2431 setBlockNotSent(blockpos);
2433 else if(command == TOSERVER_INVENTORY_ACTION)
2435 // Strip command and create a stream
2436 std::string datastring((char*)&data[2], datasize-2);
2437 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2438 std::istringstream is(datastring, std::ios_base::binary);
2440 InventoryAction *a = InventoryAction::deSerialize(is);
2443 infostream<<"TOSERVER_INVENTORY_ACTION: "
2444 <<"InventoryAction::deSerialize() returned NULL"
2450 Note: Always set inventory not sent, to repair cases
2451 where the client made a bad prediction.
2455 Handle restrictions and special cases of the move action
2457 if(a->getType() == IACTION_MOVE)
2459 IMoveAction *ma = (IMoveAction*)a;
2461 ma->from_inv.applyCurrentPlayer(player->getName());
2462 ma->to_inv.applyCurrentPlayer(player->getName());
2464 setInventoryModified(ma->from_inv);
2465 setInventoryModified(ma->to_inv);
2467 bool from_inv_is_current_player =
2468 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2469 (ma->from_inv.name == player->getName());
2471 bool to_inv_is_current_player =
2472 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2473 (ma->to_inv.name == player->getName());
2476 Disable moving items out of craftpreview
2478 if(ma->from_list == "craftpreview")
2480 infostream<<"Ignoring IMoveAction from "
2481 <<(ma->from_inv.dump())<<":"<<ma->from_list
2482 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2483 <<" because src is "<<ma->from_list<<std::endl;
2489 Disable moving items into craftresult and craftpreview
2491 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2493 infostream<<"Ignoring IMoveAction from "
2494 <<(ma->from_inv.dump())<<":"<<ma->from_list
2495 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2496 <<" because dst is "<<ma->to_list<<std::endl;
2501 // Disallow moving items in elsewhere than player's inventory
2502 // if not allowed to interact
2503 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2504 && (!from_inv_is_current_player
2505 || !to_inv_is_current_player))
2507 infostream<<"Cannot move outside of player's inventory: "
2508 <<"No interact privilege"<<std::endl;
2513 // If player is not an admin, check for ownership of src and dst
2514 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2516 std::string owner_from = getInventoryOwner(ma->from_inv);
2517 if(owner_from != "" && owner_from != player->getName())
2519 infostream<<"WARNING: "<<player->getName()
2520 <<" tried to access an inventory that"
2521 <<" belongs to "<<owner_from<<std::endl;
2526 std::string owner_to = getInventoryOwner(ma->to_inv);
2527 if(owner_to != "" && owner_to != player->getName())
2529 infostream<<"WARNING: "<<player->getName()
2530 <<" tried to access an inventory that"
2531 <<" belongs to "<<owner_to<<std::endl;
2538 Handle restrictions and special cases of the drop action
2540 else if(a->getType() == IACTION_DROP)
2542 IDropAction *da = (IDropAction*)a;
2544 da->from_inv.applyCurrentPlayer(player->getName());
2546 setInventoryModified(da->from_inv);
2548 // Disallow dropping items if not allowed to interact
2549 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2554 // If player is not an admin, check for ownership
2555 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2557 std::string owner_from = getInventoryOwner(da->from_inv);
2558 if(owner_from != "" && owner_from != player->getName())
2560 infostream<<"WARNING: "<<player->getName()
2561 <<" tried to access an inventory that"
2562 <<" belongs to "<<owner_from<<std::endl;
2569 Handle restrictions and special cases of the craft action
2571 else if(a->getType() == IACTION_CRAFT)
2573 ICraftAction *ca = (ICraftAction*)a;
2575 ca->craft_inv.applyCurrentPlayer(player->getName());
2577 setInventoryModified(ca->craft_inv);
2579 //bool craft_inv_is_current_player =
2580 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2581 // (ca->craft_inv.name == player->getName());
2583 // Disallow crafting if not allowed to interact
2584 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2586 infostream<<"Cannot craft: "
2587 <<"No interact privilege"<<std::endl;
2592 // If player is not an admin, check for ownership of inventory
2593 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2595 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2596 if(owner_craft != "" && owner_craft != player->getName())
2598 infostream<<"WARNING: "<<player->getName()
2599 <<" tried to access an inventory that"
2600 <<" belongs to "<<owner_craft<<std::endl;
2608 a->apply(this, srp, this);
2612 else if(command == TOSERVER_CHAT_MESSAGE)
2620 std::string datastring((char*)&data[2], datasize-2);
2621 std::istringstream is(datastring, std::ios_base::binary);
2624 is.read((char*)buf, 2);
2625 u16 len = readU16(buf);
2627 std::wstring message;
2628 for(u16 i=0; i<len; i++)
2630 is.read((char*)buf, 2);
2631 message += (wchar_t)readU16(buf);
2634 // Get player name of this client
2635 std::wstring name = narrow_to_wide(player->getName());
2638 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2639 wide_to_narrow(message));
2640 // If script ate the message, don't proceed
2644 // Line to send to players
2646 // Whether to send to the player that sent the line
2647 bool send_to_sender = false;
2648 // Whether to send to other players
2649 bool send_to_others = false;
2651 // Local player gets all privileges regardless of
2652 // what's set on their account.
2653 u64 privs = getPlayerPrivs(player);
2656 if(message[0] == L'/')
2658 size_t strip_size = 1;
2659 if (message[1] == L'#') // support old-style commans
2661 message = message.substr(strip_size);
2663 WStrfnd f1(message);
2664 f1.next(L" "); // Skip over /#whatever
2665 std::wstring paramstring = f1.next(L"");
2667 ServerCommandContext *ctx = new ServerCommandContext(
2668 str_split(message, L' '),
2675 std::wstring reply(processServerCommand(ctx));
2676 send_to_sender = ctx->flags & SEND_TO_SENDER;
2677 send_to_others = ctx->flags & SEND_TO_OTHERS;
2679 if (ctx->flags & SEND_NO_PREFIX)
2682 line += L"Server: " + reply;
2689 if(privs & PRIV_SHOUT)
2695 send_to_others = true;
2699 line += L"Server: You are not allowed to shout";
2700 send_to_sender = true;
2707 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2710 Send the message to clients
2712 for(core::map<u16, RemoteClient*>::Iterator
2713 i = m_clients.getIterator();
2714 i.atEnd() == false; i++)
2716 // Get client and check that it is valid
2717 RemoteClient *client = i.getNode()->getValue();
2718 assert(client->peer_id == i.getNode()->getKey());
2719 if(client->serialization_version == SER_FMT_VER_INVALID)
2723 bool sender_selected = (peer_id == client->peer_id);
2724 if(sender_selected == true && send_to_sender == false)
2726 if(sender_selected == false && send_to_others == false)
2729 SendChatMessage(client->peer_id, line);
2733 else if(command == TOSERVER_DAMAGE)
2735 std::string datastring((char*)&data[2], datasize-2);
2736 std::istringstream is(datastring, std::ios_base::binary);
2737 u8 damage = readU8(is);
2739 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2741 if(g_settings->getBool("enable_damage"))
2743 actionstream<<player->getName()<<" damaged by "
2744 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2747 srp->setHP(srp->getHP() - damage);
2749 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2752 if(srp->m_hp_not_sent)
2753 SendPlayerHP(player);
2757 // Force send (to correct the client's predicted HP)
2758 SendPlayerHP(player);
2761 else if(command == TOSERVER_PASSWORD)
2764 [0] u16 TOSERVER_PASSWORD
2765 [2] u8[28] old password
2766 [30] u8[28] new password
2769 if(datasize != 2+PASSWORD_SIZE*2)
2771 /*char password[PASSWORD_SIZE];
2772 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2773 password[i] = data[2+i];
2774 password[PASSWORD_SIZE-1] = 0;*/
2776 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2784 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2786 char c = data[2+PASSWORD_SIZE+i];
2792 infostream<<"Server: Client requests a password change from "
2793 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2795 std::string playername = player->getName();
2797 if(m_authmanager.exists(playername) == false)
2799 infostream<<"Server: playername not found in authmanager"<<std::endl;
2800 // Wrong old password supplied!!
2801 SendChatMessage(peer_id, L"playername not found in authmanager");
2805 std::string checkpwd = m_authmanager.getPassword(playername);
2807 if(oldpwd != checkpwd)
2809 infostream<<"Server: invalid old password"<<std::endl;
2810 // Wrong old password supplied!!
2811 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2815 actionstream<<player->getName()<<" changes password"<<std::endl;
2817 m_authmanager.setPassword(playername, newpwd);
2819 infostream<<"Server: password change successful for "<<playername
2821 SendChatMessage(peer_id, L"Password change successful");
2823 else if(command == TOSERVER_PLAYERITEM)
2828 u16 item = readU16(&data[2]);
2829 srp->setWieldIndex(item);
2830 SendWieldedItem(srp);
2832 else if(command == TOSERVER_RESPAWN)
2837 RespawnPlayer(player);
2839 actionstream<<player->getName()<<" respawns at "
2840 <<PP(player->getPosition()/BS)<<std::endl;
2842 // ActiveObject is added to environment in AsyncRunStep after
2843 // the previous addition has been succesfully removed
2845 else if(command == TOSERVER_REQUEST_TEXTURES) {
2846 std::string datastring((char*)&data[2], datasize-2);
2847 std::istringstream is(datastring, std::ios_base::binary);
2850 core::list<TextureRequest> tosend;
2851 u16 numtextures = readU16(is);
2853 infostream<<"Sending "<<numtextures<<" textures to "
2854 <<getPlayerName(peer_id)<<std::endl;
2855 verbosestream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2857 for(int i = 0; i < numtextures; i++) {
2858 std::string name = deSerializeString(is);
2859 tosend.push_back(TextureRequest(name));
2860 verbosestream<<"TOSERVER_REQUEST_TEXTURES: requested texture "
2864 SendTexturesRequested(peer_id, tosend);
2866 // Now the client should know about everything
2867 // (definitions and textures)
2868 getClient(peer_id)->definitions_sent = true;
2870 else if(command == TOSERVER_INTERACT)
2872 std::string datastring((char*)&data[2], datasize-2);
2873 std::istringstream is(datastring, std::ios_base::binary);
2879 [5] u32 length of the next item
2880 [9] serialized PointedThing
2882 0: start digging (from undersurface) or use
2883 1: stop digging (all parameters ignored)
2884 2: digging completed
2885 3: place block or item (to abovesurface)
2888 u8 action = readU8(is);
2889 u16 item_i = readU16(is);
2890 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2891 PointedThing pointed;
2892 pointed.deSerialize(tmp_is);
2894 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2895 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2899 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2900 <<" tried to interact, but is dead!"<<std::endl;
2904 v3f player_pos = srp->m_last_good_position;
2906 // Update wielded item
2907 if(srp->getWieldIndex() != item_i)
2909 srp->setWieldIndex(item_i);
2910 SendWieldedItem(srp);
2913 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2914 v3s16 p_under = pointed.node_undersurface;
2915 v3s16 p_above = pointed.node_abovesurface;
2917 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2918 ServerActiveObject *pointed_object = NULL;
2919 if(pointed.type == POINTEDTHING_OBJECT)
2921 pointed_object = m_env->getActiveObject(pointed.object_id);
2922 if(pointed_object == NULL)
2924 verbosestream<<"TOSERVER_INTERACT: "
2925 "pointed object is NULL"<<std::endl;
2931 v3f pointed_pos_under = player_pos;
2932 v3f pointed_pos_above = player_pos;
2933 if(pointed.type == POINTEDTHING_NODE)
2935 pointed_pos_under = intToFloat(p_under, BS);
2936 pointed_pos_above = intToFloat(p_above, BS);
2938 else if(pointed.type == POINTEDTHING_OBJECT)
2940 pointed_pos_under = pointed_object->getBasePosition();
2941 pointed_pos_above = pointed_pos_under;
2945 Check that target is reasonably close
2946 (only when digging or placing things)
2948 if(action == 0 || action == 2 || action == 3)
2950 float d = player_pos.getDistanceFrom(pointed_pos_under);
2951 float max_d = BS * 14; // Just some large enough value
2953 actionstream<<"Player "<<player->getName()
2954 <<" tried to access "<<pointed.dump()
2956 <<"d="<<d<<", max_d="<<max_d
2957 <<". ignoring."<<std::endl;
2958 // Re-send block to revert change on client-side
2959 RemoteClient *client = getClient(peer_id);
2960 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2961 client->SetBlockNotSent(blockpos);
2968 Make sure the player is allowed to do it
2970 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2972 infostream<<"Ignoring interaction from player "<<player->getName()
2973 <<" because privileges are "<<getPlayerPrivs(player)
2979 0: start digging or punch object
2983 if(pointed.type == POINTEDTHING_NODE)
2986 NOTE: This can be used in the future to check if
2987 somebody is cheating, by checking the timing.
2989 MapNode n(CONTENT_IGNORE);
2992 n = m_env->getMap().getNode(p_under);
2994 catch(InvalidPositionException &e)
2996 infostream<<"Server: Not punching: Node not found."
2997 <<" Adding block to emerge queue."
2999 m_emerge_queue.addBlock(peer_id,
3000 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3002 if(n.getContent() != CONTENT_IGNORE)
3003 scriptapi_node_on_punch(m_lua, p_under, n, srp);
3005 else if(pointed.type == POINTEDTHING_OBJECT)
3007 // Skip if object has been removed
3008 if(pointed_object->m_removed)
3011 actionstream<<player->getName()<<" punches object "
3012 <<pointed.object_id<<": "
3013 <<pointed_object->getDescription()<<std::endl;
3015 ItemStack punchitem = srp->getWieldedItem();
3016 ToolCapabilities toolcap =
3017 punchitem.getToolCapabilities(m_itemdef);
3018 v3f dir = (pointed_object->getBasePosition() -
3019 (srp->getPosition() + srp->getEyeOffset())
3021 pointed_object->punch(dir, &toolcap, srp,
3022 srp->m_time_from_last_punch);
3023 srp->m_time_from_last_punch = 0;
3031 else if(action == 1)
3036 2: Digging completed
3038 else if(action == 2)
3040 // Only complete digging of nodes
3041 if(pointed.type == POINTEDTHING_NODE)
3043 MapNode n(CONTENT_IGNORE);
3046 n = m_env->getMap().getNode(p_under);
3048 catch(InvalidPositionException &e)
3050 infostream<<"Server: Not finishing digging: Node not found."
3051 <<" Adding block to emerge queue."
3053 m_emerge_queue.addBlock(peer_id,
3054 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3056 if(n.getContent() != CONTENT_IGNORE)
3057 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3062 3: place block or right-click object
3064 else if(action == 3)
3066 ItemStack item = srp->getWieldedItem();
3068 // Reset build time counter
3069 if(pointed.type == POINTEDTHING_NODE &&
3070 item.getDefinition(m_itemdef).type == ITEM_NODE)
3071 getClient(peer_id)->m_time_from_building = 0.0;
3073 if(pointed.type == POINTEDTHING_OBJECT)
3075 // Right click object
3077 // Skip if object has been removed
3078 if(pointed_object->m_removed)
3081 actionstream<<player->getName()<<" right-clicks object "
3082 <<pointed.object_id<<": "
3083 <<pointed_object->getDescription()<<std::endl;
3086 pointed_object->rightClick(srp);
3088 else if(scriptapi_item_on_place(m_lua,
3089 item, srp, pointed))
3091 // Placement was handled in lua
3093 // Apply returned ItemStack
3094 if(g_settings->getBool("creative_mode") == false)
3095 srp->setWieldedItem(item);
3103 else if(action == 4)
3105 ItemStack item = srp->getWieldedItem();
3107 actionstream<<player->getName()<<" uses "<<item.name
3108 <<", pointing at "<<pointed.dump()<<std::endl;
3110 if(scriptapi_item_on_use(m_lua,
3111 item, srp, pointed))
3113 // Apply returned ItemStack
3114 if(g_settings->getBool("creative_mode") == false)
3115 srp->setWieldedItem(item);
3121 Catch invalid actions
3125 infostream<<"WARNING: Server: Invalid action "
3126 <<action<<std::endl;
3131 infostream<<"Server::ProcessData(): Ignoring "
3132 "unknown command "<<command<<std::endl;
3136 catch(SendFailedException &e)
3138 errorstream<<"Server::ProcessData(): SendFailedException: "
3144 void Server::onMapEditEvent(MapEditEvent *event)
3146 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3147 if(m_ignore_map_edit_events)
3149 MapEditEvent *e = event->clone();
3150 m_unsent_map_edit_queue.push_back(e);
3153 Inventory* Server::getInventory(const InventoryLocation &loc)
3156 case InventoryLocation::UNDEFINED:
3159 case InventoryLocation::CURRENT_PLAYER:
3162 case InventoryLocation::PLAYER:
3164 Player *player = m_env->getPlayer(loc.name.c_str());
3167 return &player->inventory;
3170 case InventoryLocation::NODEMETA:
3172 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3175 return meta->getInventory();
3183 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3186 case InventoryLocation::UNDEFINED:
3189 case InventoryLocation::CURRENT_PLAYER:
3192 case InventoryLocation::PLAYER:
3197 case InventoryLocation::NODEMETA:
3199 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3202 return meta->getOwner();
3210 void Server::setInventoryModified(const InventoryLocation &loc)
3213 case InventoryLocation::UNDEFINED:
3216 case InventoryLocation::PLAYER:
3218 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3219 (m_env->getPlayer(loc.name.c_str()));
3222 srp->m_inventory_not_sent = true;
3225 case InventoryLocation::NODEMETA:
3227 v3s16 blockpos = getNodeBlockPos(loc.p);
3229 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3231 meta->inventoryModified();
3233 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3235 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3237 setBlockNotSent(blockpos);
3245 core::list<PlayerInfo> Server::getPlayerInfo()
3247 DSTACK(__FUNCTION_NAME);
3248 JMutexAutoLock envlock(m_env_mutex);
3249 JMutexAutoLock conlock(m_con_mutex);
3251 core::list<PlayerInfo> list;
3253 core::list<Player*> players = m_env->getPlayers();
3255 core::list<Player*>::Iterator i;
3256 for(i = players.begin();
3257 i != players.end(); i++)
3261 Player *player = *i;
3264 // Copy info from connection to info struct
3265 info.id = player->peer_id;
3266 info.address = m_con.GetPeerAddress(player->peer_id);
3267 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3269 catch(con::PeerNotFoundException &e)
3271 // Set dummy peer info
3273 info.address = Address(0,0,0,0,0);
3277 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3278 info.position = player->getPosition();
3280 list.push_back(info);
3287 void Server::peerAdded(con::Peer *peer)
3289 DSTACK(__FUNCTION_NAME);
3290 verbosestream<<"Server::peerAdded(): peer->id="
3291 <<peer->id<<std::endl;
3294 c.type = PEER_ADDED;
3295 c.peer_id = peer->id;
3297 m_peer_change_queue.push_back(c);
3300 void Server::deletingPeer(con::Peer *peer, bool timeout)
3302 DSTACK(__FUNCTION_NAME);
3303 verbosestream<<"Server::deletingPeer(): peer->id="
3304 <<peer->id<<", timeout="<<timeout<<std::endl;
3307 c.type = PEER_REMOVED;
3308 c.peer_id = peer->id;
3309 c.timeout = timeout;
3310 m_peer_change_queue.push_back(c);
3317 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3319 DSTACK(__FUNCTION_NAME);
3320 std::ostringstream os(std::ios_base::binary);
3322 writeU16(os, TOCLIENT_HP);
3326 std::string s = os.str();
3327 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3329 con.Send(peer_id, 0, data, true);
3332 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3333 const std::wstring &reason)
3335 DSTACK(__FUNCTION_NAME);
3336 std::ostringstream os(std::ios_base::binary);
3338 writeU16(os, TOCLIENT_ACCESS_DENIED);
3339 os<<serializeWideString(reason);
3342 std::string s = os.str();
3343 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3345 con.Send(peer_id, 0, data, true);
3348 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3349 bool set_camera_point_target, v3f camera_point_target)
3351 DSTACK(__FUNCTION_NAME);
3352 std::ostringstream os(std::ios_base::binary);
3354 writeU16(os, TOCLIENT_DEATHSCREEN);
3355 writeU8(os, set_camera_point_target);
3356 writeV3F1000(os, camera_point_target);
3359 std::string s = os.str();
3360 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3362 con.Send(peer_id, 0, data, true);
3365 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3366 IItemDefManager *itemdef)
3368 DSTACK(__FUNCTION_NAME);
3369 std::ostringstream os(std::ios_base::binary);
3373 u32 length of the next item
3374 zlib-compressed serialized ItemDefManager
3376 writeU16(os, TOCLIENT_ITEMDEF);
3377 std::ostringstream tmp_os(std::ios::binary);
3378 itemdef->serialize(tmp_os);
3379 std::ostringstream tmp_os2(std::ios::binary);
3380 compressZlib(tmp_os.str(), tmp_os2);
3381 os<<serializeLongString(tmp_os2.str());
3384 std::string s = os.str();
3385 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3386 <<"): size="<<s.size()<<std::endl;
3387 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3389 con.Send(peer_id, 0, data, true);
3392 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3393 INodeDefManager *nodedef)
3395 DSTACK(__FUNCTION_NAME);
3396 std::ostringstream os(std::ios_base::binary);
3400 u32 length of the next item
3401 zlib-compressed serialized NodeDefManager
3403 writeU16(os, TOCLIENT_NODEDEF);
3404 std::ostringstream tmp_os(std::ios::binary);
3405 nodedef->serialize(tmp_os);
3406 std::ostringstream tmp_os2(std::ios::binary);
3407 compressZlib(tmp_os.str(), tmp_os2);
3408 os<<serializeLongString(tmp_os2.str());
3411 std::string s = os.str();
3412 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3413 <<"): size="<<s.size()<<std::endl;
3414 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3416 con.Send(peer_id, 0, data, true);
3420 Non-static send methods
3423 void Server::SendInventory(u16 peer_id)
3425 DSTACK(__FUNCTION_NAME);
3427 ServerRemotePlayer* player =
3428 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3431 player->m_inventory_not_sent = false;
3437 std::ostringstream os;
3438 //os.imbue(std::locale("C"));
3440 player->inventory.serialize(os);
3442 std::string s = os.str();
3444 SharedBuffer<u8> data(s.size()+2);
3445 writeU16(&data[0], TOCLIENT_INVENTORY);
3446 memcpy(&data[2], s.c_str(), s.size());
3449 m_con.Send(peer_id, 0, data, true);
3452 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3454 DSTACK(__FUNCTION_NAME);
3458 std::ostringstream os(std::ios_base::binary);
3460 writeU16(os, TOCLIENT_PLAYERITEM);
3462 writeU16(os, srp->peer_id);
3463 os<<serializeString(srp->getWieldedItem().getItemString());
3466 std::string s = os.str();
3467 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3469 m_con.SendToAll(0, data, true);
3472 void Server::SendPlayerItems()
3474 DSTACK(__FUNCTION_NAME);
3476 std::ostringstream os(std::ios_base::binary);
3477 core::list<Player *> players = m_env->getPlayers(true);
3479 writeU16(os, TOCLIENT_PLAYERITEM);
3480 writeU16(os, players.size());
3481 core::list<Player *>::Iterator i;
3482 for(i = players.begin(); i != players.end(); ++i)
3485 ServerRemotePlayer *srp =
3486 static_cast<ServerRemotePlayer*>(p);
3487 writeU16(os, p->peer_id);
3488 os<<serializeString(srp->getWieldedItem().getItemString());
3492 std::string s = os.str();
3493 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3495 m_con.SendToAll(0, data, true);
3498 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3500 DSTACK(__FUNCTION_NAME);
3502 std::ostringstream os(std::ios_base::binary);
3506 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3507 os.write((char*)buf, 2);
3510 writeU16(buf, message.size());
3511 os.write((char*)buf, 2);
3514 for(u32 i=0; i<message.size(); i++)
3518 os.write((char*)buf, 2);
3522 std::string s = os.str();
3523 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3525 m_con.Send(peer_id, 0, data, true);
3528 void Server::BroadcastChatMessage(const std::wstring &message)
3530 for(core::map<u16, RemoteClient*>::Iterator
3531 i = m_clients.getIterator();
3532 i.atEnd() == false; i++)
3534 // Get client and check that it is valid
3535 RemoteClient *client = i.getNode()->getValue();
3536 assert(client->peer_id == i.getNode()->getKey());
3537 if(client->serialization_version == SER_FMT_VER_INVALID)
3540 SendChatMessage(client->peer_id, message);
3544 void Server::SendPlayerHP(Player *player)
3546 SendHP(m_con, player->peer_id, player->hp);
3547 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3550 void Server::SendMovePlayer(Player *player)
3552 DSTACK(__FUNCTION_NAME);
3553 std::ostringstream os(std::ios_base::binary);
3555 writeU16(os, TOCLIENT_MOVE_PLAYER);
3556 writeV3F1000(os, player->getPosition());
3557 writeF1000(os, player->getPitch());
3558 writeF1000(os, player->getYaw());
3561 v3f pos = player->getPosition();
3562 f32 pitch = player->getPitch();
3563 f32 yaw = player->getYaw();
3564 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3565 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3572 std::string s = os.str();
3573 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3575 m_con.Send(player->peer_id, 0, data, true);
3578 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3579 core::list<u16> *far_players, float far_d_nodes)
3581 float maxd = far_d_nodes*BS;
3582 v3f p_f = intToFloat(p, BS);
3586 SharedBuffer<u8> reply(replysize);
3587 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3588 writeS16(&reply[2], p.X);
3589 writeS16(&reply[4], p.Y);
3590 writeS16(&reply[6], p.Z);
3592 for(core::map<u16, RemoteClient*>::Iterator
3593 i = m_clients.getIterator();
3594 i.atEnd() == false; i++)
3596 // Get client and check that it is valid
3597 RemoteClient *client = i.getNode()->getValue();
3598 assert(client->peer_id == i.getNode()->getKey());
3599 if(client->serialization_version == SER_FMT_VER_INVALID)
3602 // Don't send if it's the same one
3603 if(client->peer_id == ignore_id)
3609 Player *player = m_env->getPlayer(client->peer_id);
3612 // If player is far away, only set modified blocks not sent
3613 v3f player_pos = player->getPosition();
3614 if(player_pos.getDistanceFrom(p_f) > maxd)
3616 far_players->push_back(client->peer_id);
3623 m_con.Send(client->peer_id, 0, reply, true);
3627 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3628 core::list<u16> *far_players, float far_d_nodes)
3630 float maxd = far_d_nodes*BS;
3631 v3f p_f = intToFloat(p, BS);
3633 for(core::map<u16, RemoteClient*>::Iterator
3634 i = m_clients.getIterator();
3635 i.atEnd() == false; i++)
3637 // Get client and check that it is valid
3638 RemoteClient *client = i.getNode()->getValue();
3639 assert(client->peer_id == i.getNode()->getKey());
3640 if(client->serialization_version == SER_FMT_VER_INVALID)
3643 // Don't send if it's the same one
3644 if(client->peer_id == ignore_id)
3650 Player *player = m_env->getPlayer(client->peer_id);
3653 // If player is far away, only set modified blocks not sent
3654 v3f player_pos = player->getPosition();
3655 if(player_pos.getDistanceFrom(p_f) > maxd)
3657 far_players->push_back(client->peer_id);
3664 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3665 SharedBuffer<u8> reply(replysize);
3666 writeU16(&reply[0], TOCLIENT_ADDNODE);
3667 writeS16(&reply[2], p.X);
3668 writeS16(&reply[4], p.Y);
3669 writeS16(&reply[6], p.Z);
3670 n.serialize(&reply[8], client->serialization_version);
3673 m_con.Send(client->peer_id, 0, reply, true);
3677 void Server::setBlockNotSent(v3s16 p)
3679 for(core::map<u16, RemoteClient*>::Iterator
3680 i = m_clients.getIterator();
3681 i.atEnd()==false; i++)
3683 RemoteClient *client = i.getNode()->getValue();
3684 client->SetBlockNotSent(p);
3688 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3690 DSTACK(__FUNCTION_NAME);
3692 v3s16 p = block->getPos();
3696 bool completely_air = true;
3697 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3698 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3699 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3701 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3703 completely_air = false;
3704 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3709 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3711 infostream<<"[completely air] ";
3712 infostream<<std::endl;
3716 Create a packet with the block in the right format
3719 std::ostringstream os(std::ios_base::binary);
3720 block->serialize(os, ver, false);
3721 std::string s = os.str();
3722 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3724 u32 replysize = 8 + blockdata.getSize();
3725 SharedBuffer<u8> reply(replysize);
3726 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3727 writeS16(&reply[2], p.X);
3728 writeS16(&reply[4], p.Y);
3729 writeS16(&reply[6], p.Z);
3730 memcpy(&reply[8], *blockdata, blockdata.getSize());
3732 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3733 <<": \tpacket size: "<<replysize<<std::endl;*/
3738 m_con.Send(peer_id, 1, reply, true);
3741 void Server::SendBlocks(float dtime)
3743 DSTACK(__FUNCTION_NAME);
3745 JMutexAutoLock envlock(m_env_mutex);
3746 JMutexAutoLock conlock(m_con_mutex);
3748 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3750 core::array<PrioritySortedBlockTransfer> queue;
3752 s32 total_sending = 0;
3755 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3757 for(core::map<u16, RemoteClient*>::Iterator
3758 i = m_clients.getIterator();
3759 i.atEnd() == false; i++)
3761 RemoteClient *client = i.getNode()->getValue();
3762 assert(client->peer_id == i.getNode()->getKey());
3764 // If definitions and textures have not been sent, don't
3765 // send MapBlocks either
3766 if(!client->definitions_sent)
3769 total_sending += client->SendingCount();
3771 if(client->serialization_version == SER_FMT_VER_INVALID)
3774 client->GetNextBlocks(this, dtime, queue);
3779 // Lowest priority number comes first.
3780 // Lowest is most important.
3783 for(u32 i=0; i<queue.size(); i++)
3785 //TODO: Calculate limit dynamically
3786 if(total_sending >= g_settings->getS32
3787 ("max_simultaneous_block_sends_server_total"))
3790 PrioritySortedBlockTransfer q = queue[i];
3792 MapBlock *block = NULL;
3795 block = m_env->getMap().getBlockNoCreate(q.pos);
3797 catch(InvalidPositionException &e)
3802 RemoteClient *client = getClient(q.peer_id);
3804 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3806 client->SentBlock(q.pos);
3812 void Server::PrepareTextures()
3814 DSTACK(__FUNCTION_NAME);
3816 infostream<<"Server: Calculating texture checksums"<<std::endl;
3818 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3819 i != m_mods.end(); i++){
3820 const ModSpec &mod = *i;
3821 std::string texturepath = mod.path + DIR_DELIM + "textures";
3822 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3823 for(u32 j=0; j<dirlist.size(); j++){
3824 if(dirlist[j].dir) // Ignode dirs
3826 std::string tname = dirlist[j].name;
3827 // if name contains illegal characters, ignore the texture
3828 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3829 errorstream<<"Server: ignoring illegal texture name: \""
3830 <<tname<<"\""<<std::endl;
3833 std::string tpath = texturepath + DIR_DELIM + tname;
3835 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3836 if(fis.good() == false){
3837 errorstream<<"Server::PrepareTextures(): Could not open \""
3838 <<tname<<"\" for reading"<<std::endl;
3841 std::ostringstream tmp_os(std::ios_base::binary);
3845 fis.read(buf, 1024);
3846 std::streamsize len = fis.gcount();
3847 tmp_os.write(buf, len);
3856 errorstream<<"Server::PrepareTextures(): Failed to read \""
3857 <<tname<<"\""<<std::endl;
3860 if(tmp_os.str().length() == 0){
3861 errorstream<<"Server::PrepareTextures(): Empty file \""
3862 <<tpath<<"\""<<std::endl;
3867 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3869 unsigned char *digest = sha1.getDigest();
3870 std::string digest_string = base64_encode(digest, 20);
3875 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3876 verbosestream<<"Server: sha1 for "<<tname<<"\tis "<<std::endl;
3881 struct SendableTextureAnnouncement
3884 std::string sha1_digest;
3886 SendableTextureAnnouncement(const std::string name_="",
3887 const std::string sha1_digest_=""):
3889 sha1_digest(sha1_digest_)
3894 void Server::SendTextureAnnouncement(u16 peer_id){
3895 DSTACK(__FUNCTION_NAME);
3897 verbosestream<<"Server: Announcing textures to id("<<peer_id<<")"
3900 core::list<SendableTextureAnnouncement> texture_announcements;
3902 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3905 texture_announcements.push_back(
3906 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3909 //send announcements
3913 u32 number of textures
3917 u16 length of digest string
3921 std::ostringstream os(std::ios_base::binary);
3923 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3924 writeU16(os, texture_announcements.size());
3926 for(core::list<SendableTextureAnnouncement>::Iterator
3927 j = texture_announcements.begin();
3928 j != texture_announcements.end(); j++){
3929 os<<serializeString(j->name);
3930 os<<serializeString(j->sha1_digest);
3934 std::string s = os.str();
3935 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3938 m_con.Send(peer_id, 0, data, true);
3942 struct SendableTexture
3948 SendableTexture(const std::string &name_="", const std::string path_="",
3949 const std::string &data_=""):
3956 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3957 DSTACK(__FUNCTION_NAME);
3959 verbosestream<<"Server::SendTexturesRequested(): "
3960 <<"Sending textures to client"<<std::endl;
3964 // Put 5kB in one bunch (this is not accurate)
3965 u32 bytes_per_bunch = 5000;
3967 core::array< core::list<SendableTexture> > texture_bunches;
3968 texture_bunches.push_back(core::list<SendableTexture>());
3970 u32 texture_size_bunch_total = 0;
3972 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3973 if(m_Textures.find(i->name) == m_Textures.end()){
3974 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3975 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3979 //TODO get path + name
3980 std::string tpath = m_Textures[(*i).name].path;
3983 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3984 if(fis.good() == false){
3985 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3986 <<tpath<<"\" for reading"<<std::endl;
3989 std::ostringstream tmp_os(std::ios_base::binary);
3993 fis.read(buf, 1024);
3994 std::streamsize len = fis.gcount();
3995 tmp_os.write(buf, len);
3996 texture_size_bunch_total += len;
4005 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
4006 <<(*i).name<<"\""<<std::endl;
4009 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
4010 <<tname<<"\""<<std::endl;*/
4012 texture_bunches[texture_bunches.size()-1].push_back(
4013 SendableTexture((*i).name, tpath, tmp_os.str()));
4015 // Start next bunch if got enough data
4016 if(texture_size_bunch_total >= bytes_per_bunch){
4017 texture_bunches.push_back(core::list<SendableTexture>());
4018 texture_size_bunch_total = 0;
4023 /* Create and send packets */
4025 u32 num_bunches = texture_bunches.size();
4026 for(u32 i=0; i<num_bunches; i++)
4030 u16 total number of texture bunches
4031 u16 index of this bunch
4032 u32 number of textures in this bunch
4040 std::ostringstream os(std::ios_base::binary);
4042 writeU16(os, TOCLIENT_TEXTURES);
4043 writeU16(os, num_bunches);
4045 writeU32(os, texture_bunches[i].size());
4047 for(core::list<SendableTexture>::Iterator
4048 j = texture_bunches[i].begin();
4049 j != texture_bunches[i].end(); j++){
4050 os<<serializeString(j->name);
4051 os<<serializeLongString(j->data);
4055 std::string s = os.str();
4056 verbosestream<<"Server::SendTexturesRequested(): bunch "
4057 <<i<<"/"<<num_bunches
4058 <<" textures="<<texture_bunches[i].size()
4059 <<" size=" <<s.size()<<std::endl;
4060 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4062 m_con.Send(peer_id, 0, data, true);
4072 void Server::DiePlayer(Player *player)
4074 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4076 infostream<<"Server::DiePlayer(): Player "
4077 <<player->getName()<<" dies"<<std::endl;
4081 // Trigger scripted stuff
4082 scriptapi_on_dieplayer(m_lua, srp);
4084 // Handle players that are not connected
4085 if(player->peer_id == PEER_ID_INEXISTENT){
4086 RespawnPlayer(player);
4090 SendPlayerHP(player);
4091 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4094 void Server::RespawnPlayer(Player *player)
4096 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4098 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4100 v3f pos = findSpawnPos(m_env->getServerMap());
4101 player->setPosition(pos);
4102 srp->m_last_good_position = pos;
4103 srp->m_last_good_position_age = 0;
4105 SendMovePlayer(player);
4106 SendPlayerHP(player);
4109 void Server::UpdateCrafting(u16 peer_id)
4111 DSTACK(__FUNCTION_NAME);
4113 Player* player = m_env->getPlayer(peer_id);
4116 // Get a preview for crafting
4118 // No crafting in creative mode
4119 if(g_settings->getBool("creative_mode") == false)
4120 getCraftingResult(&player->inventory, preview, false, this);
4122 // Put the new preview in
4123 InventoryList *plist = player->inventory.getList("craftpreview");
4125 assert(plist->getSize() >= 1);
4126 plist->changeItem(0, preview);
4129 RemoteClient* Server::getClient(u16 peer_id)
4131 DSTACK(__FUNCTION_NAME);
4132 //JMutexAutoLock lock(m_con_mutex);
4133 core::map<u16, RemoteClient*>::Node *n;
4134 n = m_clients.find(peer_id);
4135 // A client should exist for all peers
4137 return n->getValue();
4140 std::wstring Server::getStatusString()
4142 std::wostringstream os(std::ios_base::binary);
4145 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4147 os<<L", uptime="<<m_uptime.get();
4148 // Information about clients
4150 for(core::map<u16, RemoteClient*>::Iterator
4151 i = m_clients.getIterator();
4152 i.atEnd() == false; i++)
4154 // Get client and check that it is valid
4155 RemoteClient *client = i.getNode()->getValue();
4156 assert(client->peer_id == i.getNode()->getKey());
4157 if(client->serialization_version == SER_FMT_VER_INVALID)
4160 Player *player = m_env->getPlayer(client->peer_id);
4161 // Get name of player
4162 std::wstring name = L"unknown";
4164 name = narrow_to_wide(player->getName());
4165 // Add name to information string
4169 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4170 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4171 if(g_settings->get("motd") != "")
4172 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4176 u64 Server::getPlayerAuthPrivs(const std::string &name)
4179 return m_authmanager.getPrivs(name);
4181 catch(AuthNotFoundException &e)
4183 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4188 void Server::setPlayerAuthPrivs(const std::string &name, u64 privs)
4191 return m_authmanager.setPrivs(name, privs);
4193 catch(AuthNotFoundException &e)
4195 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4199 u64 Server::getPlayerEffectivePrivs(const std::string &name)
4201 // Local player gets all privileges regardless of
4202 // what's set on their account.
4203 if(m_simple_singleplayer_mode)
4205 if(name == g_settings->get("name"))
4207 return getPlayerAuthPrivs(name);
4210 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4212 // Add player to auth manager
4213 if(m_authmanager.exists(name) == false)
4215 infostream<<"Server: adding player "<<name
4216 <<" to auth manager"<<std::endl;
4217 m_authmanager.add(name);
4218 m_authmanager.setPrivs(name,
4219 stringToPrivs(g_settings->get("default_privs")));
4221 // Change password and save
4222 m_authmanager.setPassword(name, translatePassword(name, password));
4223 m_authmanager.save();
4226 // Saves g_settings to configpath given at initialization
4227 void Server::saveConfig()
4229 if(m_path_config != "")
4230 g_settings->updateConfigFile(m_path_config.c_str());
4233 void Server::notifyPlayer(const char *name, const std::wstring msg)
4235 Player *player = m_env->getPlayer(name);
4238 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4241 void Server::notifyPlayers(const std::wstring msg)
4243 BroadcastChatMessage(msg);
4246 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4250 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4251 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4254 // IGameDef interface
4256 IItemDefManager* Server::getItemDefManager()
4260 INodeDefManager* Server::getNodeDefManager()
4264 ICraftDefManager* Server::getCraftDefManager()
4268 ITextureSource* Server::getTextureSource()
4272 u16 Server::allocateUnknownNodeId(const std::string &name)
4274 return m_nodedef->allocateDummy(name);
4277 IWritableItemDefManager* Server::getWritableItemDefManager()
4281 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4285 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4290 const ModSpec* Server::getModSpec(const std::string &modname)
4292 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4293 i != m_mods.end(); i++){
4294 const ModSpec &mod = *i;
4295 if(mod.name == modname)
4301 v3f findSpawnPos(ServerMap &map)
4303 //return v3f(50,50,50)*BS;
4308 nodepos = v2s16(0,0);
4313 // Try to find a good place a few times
4314 for(s32 i=0; i<1000; i++)
4317 // We're going to try to throw the player to this position
4318 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4319 -range + (myrand()%(range*2)));
4320 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4321 // Get ground height at point (fallbacks to heightmap function)
4322 s16 groundheight = map.findGroundLevel(nodepos2d);
4323 // Don't go underwater
4324 if(groundheight < WATER_LEVEL)
4326 //infostream<<"-> Underwater"<<std::endl;
4329 // Don't go to high places
4330 if(groundheight > WATER_LEVEL + 4)
4332 //infostream<<"-> Underwater"<<std::endl;
4336 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4337 bool is_good = false;
4339 for(s32 i=0; i<10; i++){
4340 v3s16 blockpos = getNodeBlockPos(nodepos);
4341 map.emergeBlock(blockpos, true);
4342 MapNode n = map.getNodeNoEx(nodepos);
4343 if(n.getContent() == CONTENT_AIR){
4354 // Found a good place
4355 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4361 return intToFloat(nodepos, BS);
4364 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4367 Try to get an existing player
4369 ServerRemotePlayer *player =
4370 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4373 // If player is already connected, cancel
4374 if(player->peer_id != 0)
4376 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4381 player->peer_id = peer_id;
4383 // Re-add player to environment
4384 if(player->m_removed)
4386 player->m_removed = false;
4388 m_env->addActiveObject(player);
4391 // Reset inventory to creative if in creative mode
4392 if(g_settings->getBool("creative_mode"))
4394 // Warning: double code below
4395 // Backup actual inventory
4396 player->inventory_backup = new Inventory(m_itemdef);
4397 *(player->inventory_backup) = player->inventory;
4398 // Set creative inventory
4399 player->resetInventory();
4400 scriptapi_get_creative_inventory(m_lua, player);
4407 If player with the wanted peer_id already exists, cancel.
4409 if(m_env->getPlayer(peer_id) != NULL)
4411 infostream<<"emergePlayer(): Player with wrong name but same"
4412 " peer_id already exists"<<std::endl;
4420 /* Set player position */
4422 infostream<<"Server: Finding spawn place for player \""
4423 <<name<<"\""<<std::endl;
4425 v3f pos = findSpawnPos(m_env->getServerMap());
4427 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4428 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4430 /* Add player to environment */
4431 m_env->addPlayer(player);
4432 m_env->addActiveObject(srp);
4435 scriptapi_on_newplayer(m_lua, srp);
4437 /* Add stuff to inventory */
4438 if(g_settings->getBool("creative_mode"))
4440 // Warning: double code above
4441 // Backup actual inventory
4442 player->inventory_backup = new Inventory(m_itemdef);
4443 *(player->inventory_backup) = player->inventory;
4444 // Set creative inventory
4445 player->resetInventory();
4446 scriptapi_get_creative_inventory(m_lua, player);
4451 } // create new player
4454 void Server::handlePeerChange(PeerChange &c)
4456 JMutexAutoLock envlock(m_env_mutex);
4457 JMutexAutoLock conlock(m_con_mutex);
4459 if(c.type == PEER_ADDED)
4466 core::map<u16, RemoteClient*>::Node *n;
4467 n = m_clients.find(c.peer_id);
4468 // The client shouldn't already exist
4472 RemoteClient *client = new RemoteClient();
4473 client->peer_id = c.peer_id;
4474 m_clients.insert(client->peer_id, client);
4477 else if(c.type == PEER_REMOVED)
4484 core::map<u16, RemoteClient*>::Node *n;
4485 n = m_clients.find(c.peer_id);
4486 // The client should exist
4490 Mark objects to be not known by the client
4492 RemoteClient *client = n->getValue();
4494 for(core::map<u16, bool>::Iterator
4495 i = client->m_known_objects.getIterator();
4496 i.atEnd()==false; i++)
4499 u16 id = i.getNode()->getKey();
4500 ServerActiveObject* obj = m_env->getActiveObject(id);
4502 if(obj && obj->m_known_by_count > 0)
4503 obj->m_known_by_count--;
4506 ServerRemotePlayer* player =
4507 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4509 // Collect information about leaving in chat
4510 std::wstring message;
4514 std::wstring name = narrow_to_wide(player->getName());
4517 message += L" left game";
4519 message += L" (timed out)";
4523 // Remove from environment
4525 player->m_removed = true;
4527 // Set player client disconnected
4529 player->peer_id = 0;
4537 std::ostringstream os(std::ios_base::binary);
4538 for(core::map<u16, RemoteClient*>::Iterator
4539 i = m_clients.getIterator();
4540 i.atEnd() == false; i++)
4542 RemoteClient *client = i.getNode()->getValue();
4543 assert(client->peer_id == i.getNode()->getKey());
4544 if(client->serialization_version == SER_FMT_VER_INVALID)
4547 Player *player = m_env->getPlayer(client->peer_id);
4550 // Get name of player
4551 os<<player->getName()<<" ";
4554 actionstream<<player->getName()<<" "
4555 <<(c.timeout?"times out.":"leaves game.")
4556 <<" List of players: "
4557 <<os.str()<<std::endl;
4562 delete m_clients[c.peer_id];
4563 m_clients.remove(c.peer_id);
4565 // Send player info to all remaining clients
4566 //SendPlayerInfos();
4568 // Send leave chat message to all remaining clients
4569 if(message.length() != 0)
4570 BroadcastChatMessage(message);
4579 void Server::handlePeerChanges()
4581 while(m_peer_change_queue.size() > 0)
4583 PeerChange c = m_peer_change_queue.pop_front();
4585 verbosestream<<"Server: Handling peer change: "
4586 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4589 handlePeerChange(c);
4593 u64 Server::getPlayerPrivs(Player *player)
4597 std::string playername = player->getName();
4598 return getPlayerEffectivePrivs(playername);
4601 void dedicated_server_loop(Server &server, bool &kill)
4603 DSTACK(__FUNCTION_NAME);
4605 verbosestream<<"dedicated_server_loop()"<<std::endl;
4607 IntervalLimiter m_profiler_interval;
4611 float steplen = g_settings->getFloat("dedicated_server_step");
4612 // This is kind of a hack but can be done like this
4613 // because server.step() is very light
4615 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4616 sleep_ms((int)(steplen*1000.0));
4618 server.step(steplen);
4620 if(server.getShutdownRequested() || kill)
4622 infostream<<"Dedicated server quitting"<<std::endl;
4629 float profiler_print_interval =
4630 g_settings->getFloat("profiler_print_interval");
4631 if(profiler_print_interval != 0)
4633 if(m_profiler_interval.step(steplen, profiler_print_interval))
4635 infostream<<"Profiler:"<<std::endl;
4636 g_profiler->print(infostream);
4637 g_profiler->clear();