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 // Figure out some paths
882 m_path_share = porting::path_share + DIR_DELIM + "server";
884 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
885 if(m_simple_singleplayer_mode)
886 infostream<<" in simple singleplayer mode"<<std::endl;
888 infostream<<std::endl;
889 infostream<<"- world: "<<m_path_world<<std::endl;
890 infostream<<"- config: "<<m_path_config<<std::endl;
891 infostream<<"- game: "<<m_gamespec.path<<std::endl;
892 for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
893 i != m_gamespec.addon_paths.end(); i++)
894 infostream<<"- addons: "<<(*i)<<std::endl;
896 // Path to builtin.lua
897 std::string builtinpath = m_path_share + DIR_DELIM + "builtin.lua";
899 // Add default global mod search path
900 m_modspaths.push_front(m_gamespec.path + DIR_DELIM "mods");
901 // Add world mod search path
902 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
903 // Add addon mod search path
904 for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
905 i != m_gamespec.addon_paths.end(); i++)
906 m_modspaths.push_front((*i) + DIR_DELIM + "mods");
907 // Add simple user mod search path
908 m_modspaths.push_front(porting::path_user + DIR_DELIM + "mods"
909 + DIR_DELIM + m_gamespec.id);
911 // Print out mod search paths
912 for(core::list<std::string>::Iterator i = m_modspaths.begin();
913 i != m_modspaths.end(); i++){
914 std::string modspath = *i;
915 infostream<<"- mods: "<<modspath<<std::endl;
918 // Create world if it doesn't exist
919 if(!initializeWorld(m_path_world, m_gamespec.id))
920 throw ServerError("Failed to initialize world");
923 JMutexAutoLock envlock(m_env_mutex);
924 JMutexAutoLock conlock(m_con_mutex);
926 // Initialize scripting
928 infostream<<"Server: Initializing Lua"<<std::endl;
929 m_lua = script_init();
932 scriptapi_export(m_lua, this);
933 // Load and run builtin.lua
934 infostream<<"Server: Loading builtin.lua [\""
935 <<builtinpath<<"\"]"<<std::endl;
936 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
938 errorstream<<"Server: Failed to load and run "
939 <<builtinpath<<std::endl;
940 throw ModError("Failed to load and run "+builtinpath);
942 // Find mods in mod search paths
943 m_mods = getMods(m_modspaths);
945 infostream<<"Server: Loading mods: ";
946 for(core::list<ModSpec>::Iterator i = m_mods.begin();
947 i != m_mods.end(); i++){
948 const ModSpec &mod = *i;
949 infostream<<mod.name<<" ";
951 infostream<<std::endl;
952 // Load and run "mod" scripts
953 for(core::list<ModSpec>::Iterator i = m_mods.begin();
954 i != m_mods.end(); i++){
955 const ModSpec &mod = *i;
956 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
957 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
958 <<scriptpath<<"\"]"<<std::endl;
959 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
961 errorstream<<"Server: Failed to load and run "
962 <<scriptpath<<std::endl;
963 throw ModError("Failed to load and run "+scriptpath);
967 // Read Textures and calculate sha1 sums
970 // Apply item aliases in the node definition manager
971 m_nodedef->updateAliases(m_itemdef);
973 // Initialize Environment
975 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
978 // Give environment reference to scripting api
979 scriptapi_add_environment(m_lua, m_env);
981 // Register us to receive map edit events
982 m_env->getMap().addEventReceiver(this);
984 // If file exists, load environment metadata
985 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
987 infostream<<"Server: Loading environment metadata"<<std::endl;
988 m_env->loadMeta(m_path_world);
992 infostream<<"Server: Loading players"<<std::endl;
993 m_env->deSerializePlayers(m_path_world);
996 Add some test ActiveBlockModifiers to environment
998 add_legacy_abms(m_env, m_nodedef);
1003 infostream<<"Server destructing"<<std::endl;
1006 Send shutdown message
1009 JMutexAutoLock conlock(m_con_mutex);
1011 std::wstring line = L"*** Server shutting down";
1014 Send the message to clients
1016 for(core::map<u16, RemoteClient*>::Iterator
1017 i = m_clients.getIterator();
1018 i.atEnd() == false; i++)
1020 // Get client and check that it is valid
1021 RemoteClient *client = i.getNode()->getValue();
1022 assert(client->peer_id == i.getNode()->getKey());
1023 if(client->serialization_version == SER_FMT_VER_INVALID)
1027 SendChatMessage(client->peer_id, line);
1029 catch(con::PeerNotFoundException &e)
1035 JMutexAutoLock envlock(m_env_mutex);
1040 infostream<<"Server: Saving players"<<std::endl;
1041 m_env->serializePlayers(m_path_world);
1044 Save environment metadata
1046 infostream<<"Server: Saving environment metadata"<<std::endl;
1047 m_env->saveMeta(m_path_world);
1059 JMutexAutoLock clientslock(m_con_mutex);
1061 for(core::map<u16, RemoteClient*>::Iterator
1062 i = m_clients.getIterator();
1063 i.atEnd() == false; i++)
1066 // NOTE: These are removed by env destructor
1068 u16 peer_id = i.getNode()->getKey();
1069 JMutexAutoLock envlock(m_env_mutex);
1070 m_env->removePlayer(peer_id);
1074 delete i.getNode()->getValue();
1078 // Delete Environment
1085 // Deinitialize scripting
1086 infostream<<"Server: Deinitializing scripting"<<std::endl;
1087 script_deinit(m_lua);
1090 void Server::start(unsigned short port)
1092 DSTACK(__FUNCTION_NAME);
1093 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1095 // Stop thread if already running
1098 // Initialize connection
1099 m_con.SetTimeoutMs(30);
1103 m_thread.setRun(true);
1106 // ASCII art for the win!
1108 <<" .__ __ __ "<<std::endl
1109 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1110 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1111 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1112 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1113 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1114 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1115 actionstream<<"Server for gameid=\""<<m_gamespec.id
1116 <<"\" listening on port "<<port<<"."<<std::endl;
1121 DSTACK(__FUNCTION_NAME);
1123 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1125 // Stop threads (set run=false first so both start stopping)
1126 m_thread.setRun(false);
1127 m_emergethread.setRun(false);
1129 m_emergethread.stop();
1131 infostream<<"Server: Threads stopped"<<std::endl;
1134 void Server::step(float dtime)
1136 DSTACK(__FUNCTION_NAME);
1141 JMutexAutoLock lock(m_step_dtime_mutex);
1142 m_step_dtime += dtime;
1144 // Throw if fatal error occurred in thread
1145 std::string async_err = m_async_fatal_error.get();
1146 if(async_err != ""){
1147 throw ServerError(async_err);
1151 void Server::AsyncRunStep()
1153 DSTACK(__FUNCTION_NAME);
1155 g_profiler->add("Server::AsyncRunStep (num)", 1);
1159 JMutexAutoLock lock1(m_step_dtime_mutex);
1160 dtime = m_step_dtime;
1164 // Send blocks to clients
1171 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1173 //infostream<<"Server steps "<<dtime<<std::endl;
1174 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1177 JMutexAutoLock lock1(m_step_dtime_mutex);
1178 m_step_dtime -= dtime;
1185 m_uptime.set(m_uptime.get() + dtime);
1189 // Process connection's timeouts
1190 JMutexAutoLock lock2(m_con_mutex);
1191 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1192 m_con.RunTimeouts(dtime);
1196 // This has to be called so that the client list gets synced
1197 // with the peer list of the connection
1198 handlePeerChanges();
1202 Update time of day and overall game time
1205 JMutexAutoLock envlock(m_env_mutex);
1207 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1210 Send to clients at constant intervals
1213 m_time_of_day_send_timer -= dtime;
1214 if(m_time_of_day_send_timer < 0.0)
1216 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1218 //JMutexAutoLock envlock(m_env_mutex);
1219 JMutexAutoLock conlock(m_con_mutex);
1221 for(core::map<u16, RemoteClient*>::Iterator
1222 i = m_clients.getIterator();
1223 i.atEnd() == false; i++)
1225 RemoteClient *client = i.getNode()->getValue();
1226 //Player *player = m_env->getPlayer(client->peer_id);
1228 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1229 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1231 m_con.Send(client->peer_id, 0, data, true);
1237 JMutexAutoLock lock(m_env_mutex);
1239 ScopeProfiler sp(g_profiler, "SEnv step");
1240 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1244 const float map_timer_and_unload_dtime = 2.92;
1245 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1247 JMutexAutoLock lock(m_env_mutex);
1248 // Run Map's timers and unload unused data
1249 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1250 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1251 g_settings->getFloat("server_unload_unused_data_timeout"));
1262 JMutexAutoLock lock(m_env_mutex);
1263 JMutexAutoLock lock2(m_con_mutex);
1265 ScopeProfiler sp(g_profiler, "Server: handle players");
1267 //float player_max_speed = BS * 4.0; // Normal speed
1268 float player_max_speed = BS * 20; // Fast speed
1269 float player_max_speed_up = BS * 20;
1271 player_max_speed *= 2.5; // Tolerance
1272 player_max_speed_up *= 2.5;
1274 for(core::map<u16, RemoteClient*>::Iterator
1275 i = m_clients.getIterator();
1276 i.atEnd() == false; i++)
1278 RemoteClient *client = i.getNode()->getValue();
1279 ServerRemotePlayer *player =
1280 static_cast<ServerRemotePlayer*>
1281 (m_env->getPlayer(client->peer_id));
1286 Check player movements
1288 NOTE: Actually the server should handle player physics like the
1289 client does and compare player's position to what is calculated
1290 on our side. This is required when eg. players fly due to an
1293 player->m_last_good_position_age += dtime;
1294 if(player->m_last_good_position_age >= 1.0){
1295 float age = player->m_last_good_position_age;
1296 v3f diff = (player->getPosition() - player->m_last_good_position);
1297 float d_vert = diff.Y;
1299 float d_horiz = diff.getLength();
1300 /*infostream<<player->getName()<<"'s horizontal speed is "
1301 <<(d_horiz/age)<<std::endl;*/
1302 if(d_horiz <= age * player_max_speed &&
1303 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1304 player->m_last_good_position = player->getPosition();
1306 actionstream<<"Player "<<player->getName()
1307 <<" moved too fast; resetting position"
1309 player->setPosition(player->m_last_good_position);
1310 SendMovePlayer(player);
1312 player->m_last_good_position_age = 0;
1316 Handle player HPs (die if hp=0)
1318 if(player->hp == 0 && player->m_hp_not_sent)
1322 Send player inventories and HPs if necessary
1324 if(player->m_inventory_not_sent){
1325 UpdateCrafting(player->peer_id);
1326 SendInventory(player->peer_id);
1328 if(player->m_hp_not_sent){
1329 SendPlayerHP(player);
1335 if(!player->m_is_in_environment){
1336 player->m_removed = false;
1338 m_env->addActiveObject(player);
1343 /* Transform liquids */
1344 m_liquid_transform_timer += dtime;
1345 if(m_liquid_transform_timer >= 1.00)
1347 m_liquid_transform_timer -= 1.00;
1349 JMutexAutoLock lock(m_env_mutex);
1351 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1353 core::map<v3s16, MapBlock*> modified_blocks;
1354 m_env->getMap().transformLiquids(modified_blocks);
1359 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1360 ServerMap &map = ((ServerMap&)m_env->getMap());
1361 map.updateLighting(modified_blocks, lighting_modified_blocks);
1363 // Add blocks modified by lighting to modified_blocks
1364 for(core::map<v3s16, MapBlock*>::Iterator
1365 i = lighting_modified_blocks.getIterator();
1366 i.atEnd() == false; i++)
1368 MapBlock *block = i.getNode()->getValue();
1369 modified_blocks.insert(block->getPos(), block);
1373 Set the modified blocks unsent for all the clients
1376 JMutexAutoLock lock2(m_con_mutex);
1378 for(core::map<u16, RemoteClient*>::Iterator
1379 i = m_clients.getIterator();
1380 i.atEnd() == false; i++)
1382 RemoteClient *client = i.getNode()->getValue();
1384 if(modified_blocks.size() > 0)
1386 // Remove block from sent history
1387 client->SetBlocksNotSent(modified_blocks);
1392 // Periodically print some info
1394 float &counter = m_print_info_timer;
1400 JMutexAutoLock lock2(m_con_mutex);
1402 if(m_clients.size() != 0)
1403 infostream<<"Players:"<<std::endl;
1404 for(core::map<u16, RemoteClient*>::Iterator
1405 i = m_clients.getIterator();
1406 i.atEnd() == false; i++)
1408 //u16 peer_id = i.getNode()->getKey();
1409 RemoteClient *client = i.getNode()->getValue();
1410 Player *player = m_env->getPlayer(client->peer_id);
1413 infostream<<"* "<<player->getName()<<"\t";
1414 client->PrintInfo(infostream);
1419 //if(g_settings->getBool("enable_experimental"))
1423 Check added and deleted active objects
1426 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1427 JMutexAutoLock envlock(m_env_mutex);
1428 JMutexAutoLock conlock(m_con_mutex);
1430 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1432 // Radius inside which objects are active
1433 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1434 radius *= MAP_BLOCKSIZE;
1436 for(core::map<u16, RemoteClient*>::Iterator
1437 i = m_clients.getIterator();
1438 i.atEnd() == false; i++)
1440 RemoteClient *client = i.getNode()->getValue();
1442 // If definitions and textures have not been sent, don't
1443 // send objects either
1444 if(!client->definitions_sent)
1447 Player *player = m_env->getPlayer(client->peer_id);
1450 // This can happen if the client timeouts somehow
1451 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1453 <<" has no associated player"<<std::endl;*/
1456 v3s16 pos = floatToInt(player->getPosition(), BS);
1458 core::map<u16, bool> removed_objects;
1459 core::map<u16, bool> added_objects;
1460 m_env->getRemovedActiveObjects(pos, radius,
1461 client->m_known_objects, removed_objects);
1462 m_env->getAddedActiveObjects(pos, radius,
1463 client->m_known_objects, added_objects);
1465 // Ignore if nothing happened
1466 if(removed_objects.size() == 0 && added_objects.size() == 0)
1468 //infostream<<"active objects: none changed"<<std::endl;
1472 std::string data_buffer;
1476 // Handle removed objects
1477 writeU16((u8*)buf, removed_objects.size());
1478 data_buffer.append(buf, 2);
1479 for(core::map<u16, bool>::Iterator
1480 i = removed_objects.getIterator();
1481 i.atEnd()==false; i++)
1484 u16 id = i.getNode()->getKey();
1485 ServerActiveObject* obj = m_env->getActiveObject(id);
1487 // Add to data buffer for sending
1488 writeU16((u8*)buf, i.getNode()->getKey());
1489 data_buffer.append(buf, 2);
1491 // Remove from known objects
1492 client->m_known_objects.remove(i.getNode()->getKey());
1494 if(obj && obj->m_known_by_count > 0)
1495 obj->m_known_by_count--;
1498 // Handle added objects
1499 writeU16((u8*)buf, added_objects.size());
1500 data_buffer.append(buf, 2);
1501 for(core::map<u16, bool>::Iterator
1502 i = added_objects.getIterator();
1503 i.atEnd()==false; i++)
1506 u16 id = i.getNode()->getKey();
1507 ServerActiveObject* obj = m_env->getActiveObject(id);
1510 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1512 infostream<<"WARNING: "<<__FUNCTION_NAME
1513 <<": NULL object"<<std::endl;
1515 type = obj->getType();
1517 // Add to data buffer for sending
1518 writeU16((u8*)buf, id);
1519 data_buffer.append(buf, 2);
1520 writeU8((u8*)buf, type);
1521 data_buffer.append(buf, 1);
1524 data_buffer.append(serializeLongString(
1525 obj->getClientInitializationData()));
1527 data_buffer.append(serializeLongString(""));
1529 // Add to known objects
1530 client->m_known_objects.insert(i.getNode()->getKey(), false);
1533 obj->m_known_by_count++;
1537 SharedBuffer<u8> reply(2 + data_buffer.size());
1538 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1539 memcpy((char*)&reply[2], data_buffer.c_str(),
1540 data_buffer.size());
1542 m_con.Send(client->peer_id, 0, reply, true);
1544 verbosestream<<"Server: Sent object remove/add: "
1545 <<removed_objects.size()<<" removed, "
1546 <<added_objects.size()<<" added, "
1547 <<"packet size is "<<reply.getSize()<<std::endl;
1552 Collect a list of all the objects known by the clients
1553 and report it back to the environment.
1556 core::map<u16, bool> all_known_objects;
1558 for(core::map<u16, RemoteClient*>::Iterator
1559 i = m_clients.getIterator();
1560 i.atEnd() == false; i++)
1562 RemoteClient *client = i.getNode()->getValue();
1563 // Go through all known objects of client
1564 for(core::map<u16, bool>::Iterator
1565 i = client->m_known_objects.getIterator();
1566 i.atEnd()==false; i++)
1568 u16 id = i.getNode()->getKey();
1569 all_known_objects[id] = true;
1573 m_env->setKnownActiveObjects(whatever);
1579 Send object messages
1582 JMutexAutoLock envlock(m_env_mutex);
1583 JMutexAutoLock conlock(m_con_mutex);
1585 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1588 // Value = data sent by object
1589 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1591 // Get active object messages from environment
1594 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1598 core::list<ActiveObjectMessage>* message_list = NULL;
1599 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1600 n = buffered_messages.find(aom.id);
1603 message_list = new core::list<ActiveObjectMessage>;
1604 buffered_messages.insert(aom.id, message_list);
1608 message_list = n->getValue();
1610 message_list->push_back(aom);
1613 // Route data to every client
1614 for(core::map<u16, RemoteClient*>::Iterator
1615 i = m_clients.getIterator();
1616 i.atEnd()==false; i++)
1618 RemoteClient *client = i.getNode()->getValue();
1619 std::string reliable_data;
1620 std::string unreliable_data;
1621 // Go through all objects in message buffer
1622 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1623 j = buffered_messages.getIterator();
1624 j.atEnd()==false; j++)
1626 // If object is not known by client, skip it
1627 u16 id = j.getNode()->getKey();
1628 if(client->m_known_objects.find(id) == NULL)
1630 // Get message list of object
1631 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1632 // Go through every message
1633 for(core::list<ActiveObjectMessage>::Iterator
1634 k = list->begin(); k != list->end(); k++)
1636 // Compose the full new data with header
1637 ActiveObjectMessage aom = *k;
1638 std::string new_data;
1641 writeU16((u8*)&buf[0], aom.id);
1642 new_data.append(buf, 2);
1644 new_data += serializeString(aom.datastring);
1645 // Add data to buffer
1647 reliable_data += new_data;
1649 unreliable_data += new_data;
1653 reliable_data and unreliable_data are now ready.
1656 if(reliable_data.size() > 0)
1658 SharedBuffer<u8> reply(2 + reliable_data.size());
1659 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1660 memcpy((char*)&reply[2], reliable_data.c_str(),
1661 reliable_data.size());
1663 m_con.Send(client->peer_id, 0, reply, true);
1665 if(unreliable_data.size() > 0)
1667 SharedBuffer<u8> reply(2 + unreliable_data.size());
1668 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1669 memcpy((char*)&reply[2], unreliable_data.c_str(),
1670 unreliable_data.size());
1671 // Send as unreliable
1672 m_con.Send(client->peer_id, 0, reply, false);
1675 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1677 infostream<<"Server: Size of object message data: "
1678 <<"reliable: "<<reliable_data.size()
1679 <<", unreliable: "<<unreliable_data.size()
1684 // Clear buffered_messages
1685 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1686 i = buffered_messages.getIterator();
1687 i.atEnd()==false; i++)
1689 delete i.getNode()->getValue();
1693 } // enable_experimental
1696 Send queued-for-sending map edit events.
1699 // Don't send too many at a time
1702 // Single change sending is disabled if queue size is not small
1703 bool disable_single_change_sending = false;
1704 if(m_unsent_map_edit_queue.size() >= 4)
1705 disable_single_change_sending = true;
1707 int event_count = m_unsent_map_edit_queue.size();
1709 // We'll log the amount of each
1712 while(m_unsent_map_edit_queue.size() != 0)
1714 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1716 // Players far away from the change are stored here.
1717 // Instead of sending the changes, MapBlocks are set not sent
1719 core::list<u16> far_players;
1721 if(event->type == MEET_ADDNODE)
1723 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1724 prof.add("MEET_ADDNODE", 1);
1725 if(disable_single_change_sending)
1726 sendAddNode(event->p, event->n, event->already_known_by_peer,
1729 sendAddNode(event->p, event->n, event->already_known_by_peer,
1732 else if(event->type == MEET_REMOVENODE)
1734 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1735 prof.add("MEET_REMOVENODE", 1);
1736 if(disable_single_change_sending)
1737 sendRemoveNode(event->p, event->already_known_by_peer,
1740 sendRemoveNode(event->p, event->already_known_by_peer,
1743 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1745 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1746 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1747 setBlockNotSent(event->p);
1749 else if(event->type == MEET_OTHER)
1751 infostream<<"Server: MEET_OTHER"<<std::endl;
1752 prof.add("MEET_OTHER", 1);
1753 for(core::map<v3s16, bool>::Iterator
1754 i = event->modified_blocks.getIterator();
1755 i.atEnd()==false; i++)
1757 v3s16 p = i.getNode()->getKey();
1763 prof.add("unknown", 1);
1764 infostream<<"WARNING: Server: Unknown MapEditEvent "
1765 <<((u32)event->type)<<std::endl;
1769 Set blocks not sent to far players
1771 if(far_players.size() > 0)
1773 // Convert list format to that wanted by SetBlocksNotSent
1774 core::map<v3s16, MapBlock*> modified_blocks2;
1775 for(core::map<v3s16, bool>::Iterator
1776 i = event->modified_blocks.getIterator();
1777 i.atEnd()==false; i++)
1779 v3s16 p = i.getNode()->getKey();
1780 modified_blocks2.insert(p,
1781 m_env->getMap().getBlockNoCreateNoEx(p));
1783 // Set blocks not sent
1784 for(core::list<u16>::Iterator
1785 i = far_players.begin();
1786 i != far_players.end(); i++)
1789 RemoteClient *client = getClient(peer_id);
1792 client->SetBlocksNotSent(modified_blocks2);
1798 /*// Don't send too many at a time
1800 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1804 if(event_count >= 5){
1805 infostream<<"Server: MapEditEvents:"<<std::endl;
1806 prof.print(infostream);
1807 } else if(event_count != 0){
1808 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1809 prof.print(verbosestream);
1815 Trigger emergethread (it somehow gets to a non-triggered but
1816 bysy state sometimes)
1819 float &counter = m_emergethread_trigger_timer;
1825 m_emergethread.trigger();
1829 // Save map, players and auth stuff
1831 float &counter = m_savemap_timer;
1833 if(counter >= g_settings->getFloat("server_map_save_interval"))
1836 JMutexAutoLock lock(m_env_mutex);
1838 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1841 if(m_authmanager.isModified())
1842 m_authmanager.save();
1845 if(m_banmanager.isModified())
1846 m_banmanager.save();
1848 // Save changed parts of map
1849 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1852 m_env->serializePlayers(m_path_world);
1854 // Save environment metadata
1855 m_env->saveMeta(m_path_world);
1860 void Server::Receive()
1862 DSTACK(__FUNCTION_NAME);
1863 SharedBuffer<u8> data;
1868 JMutexAutoLock conlock(m_con_mutex);
1869 datasize = m_con.Receive(peer_id, data);
1872 // This has to be called so that the client list gets synced
1873 // with the peer list of the connection
1874 handlePeerChanges();
1876 ProcessData(*data, datasize, peer_id);
1878 catch(con::InvalidIncomingDataException &e)
1880 infostream<<"Server::Receive(): "
1881 "InvalidIncomingDataException: what()="
1882 <<e.what()<<std::endl;
1884 catch(con::PeerNotFoundException &e)
1886 //NOTE: This is not needed anymore
1888 // The peer has been disconnected.
1889 // Find the associated player and remove it.
1891 /*JMutexAutoLock envlock(m_env_mutex);
1893 infostream<<"ServerThread: peer_id="<<peer_id
1894 <<" has apparently closed connection. "
1895 <<"Removing player."<<std::endl;
1897 m_env->removePlayer(peer_id);*/
1901 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1903 DSTACK(__FUNCTION_NAME);
1904 // Environment is locked first.
1905 JMutexAutoLock envlock(m_env_mutex);
1906 JMutexAutoLock conlock(m_con_mutex);
1908 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1911 Address address = m_con.GetPeerAddress(peer_id);
1913 // drop player if is ip is banned
1914 if(m_banmanager.isIpBanned(address.serializeString())){
1915 SendAccessDenied(m_con, peer_id,
1916 L"Your ip is banned. Banned name was "
1917 +narrow_to_wide(m_banmanager.getBanName(
1918 address.serializeString())));
1919 m_con.DeletePeer(peer_id);
1923 catch(con::PeerNotFoundException &e)
1925 infostream<<"Server::ProcessData(): Cancelling: peer "
1926 <<peer_id<<" not found"<<std::endl;
1930 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1932 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1940 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1942 if(command == TOSERVER_INIT)
1944 // [0] u16 TOSERVER_INIT
1945 // [2] u8 SER_FMT_VER_HIGHEST
1946 // [3] u8[20] player_name
1947 // [23] u8[28] password <--- can be sent without this, from old versions
1949 if(datasize < 2+1+PLAYERNAME_SIZE)
1952 verbosestream<<"Server: Got TOSERVER_INIT from "
1953 <<peer_id<<std::endl;
1955 // First byte after command is maximum supported
1956 // serialization version
1957 u8 client_max = data[2];
1958 u8 our_max = SER_FMT_VER_HIGHEST;
1959 // Use the highest version supported by both
1960 u8 deployed = core::min_(client_max, our_max);
1961 // If it's lower than the lowest supported, give up.
1962 if(deployed < SER_FMT_VER_LOWEST)
1963 deployed = SER_FMT_VER_INVALID;
1965 //peer->serialization_version = deployed;
1966 getClient(peer_id)->pending_serialization_version = deployed;
1968 if(deployed == SER_FMT_VER_INVALID)
1970 actionstream<<"Server: A mismatched client tried to connect from "
1971 <<addr_s<<std::endl;
1972 infostream<<"Server: Cannot negotiate "
1973 "serialization version with peer "
1974 <<peer_id<<std::endl;
1975 SendAccessDenied(m_con, peer_id, std::wstring(
1976 L"Your client's version is not supported.\n"
1977 L"Server version is ")
1978 + narrow_to_wide(VERSION_STRING) + L"."
1984 Read and check network protocol version
1987 u16 net_proto_version = 0;
1988 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1990 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1993 getClient(peer_id)->net_proto_version = net_proto_version;
1995 if(net_proto_version == 0)
1997 actionstream<<"Server: An old tried to connect from "<<addr_s
1999 SendAccessDenied(m_con, peer_id, std::wstring(
2000 L"Your client's version is not supported.\n"
2001 L"Server version is ")
2002 + narrow_to_wide(VERSION_STRING) + L"."
2007 if(g_settings->getBool("strict_protocol_version_checking"))
2009 if(net_proto_version != PROTOCOL_VERSION)
2011 actionstream<<"Server: A mismatched client tried to connect"
2012 <<" from "<<addr_s<<std::endl;
2013 SendAccessDenied(m_con, peer_id, std::wstring(
2014 L"Your client's version is not supported.\n"
2015 L"Server version is ")
2016 + narrow_to_wide(VERSION_STRING) + L",\n"
2017 + L"server's PROTOCOL_VERSION is "
2018 + narrow_to_wide(itos(PROTOCOL_VERSION))
2019 + L", client's PROTOCOL_VERSION is "
2020 + narrow_to_wide(itos(net_proto_version))
2031 char playername[PLAYERNAME_SIZE];
2032 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2034 playername[i] = data[3+i];
2036 playername[PLAYERNAME_SIZE-1] = 0;
2038 if(playername[0]=='\0')
2040 actionstream<<"Server: Player with an empty name "
2041 <<"tried to connect from "<<addr_s<<std::endl;
2042 SendAccessDenied(m_con, peer_id,
2047 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2049 actionstream<<"Server: Player with an invalid name "
2050 <<"tried to connect from "<<addr_s<<std::endl;
2051 SendAccessDenied(m_con, peer_id,
2052 L"Name contains unallowed characters");
2056 infostream<<"Server: New connection: \""<<playername<<"\" from "
2057 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2060 char password[PASSWORD_SIZE];
2061 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2063 // old version - assume blank password
2068 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2070 password[i] = data[23+i];
2072 password[PASSWORD_SIZE-1] = 0;
2075 // Add player to auth manager
2076 if(m_authmanager.exists(playername) == false)
2078 std::wstring default_password =
2079 narrow_to_wide(g_settings->get("default_password"));
2080 std::string translated_default_password =
2081 translatePassword(playername, default_password);
2083 // If default_password is empty, allow any initial password
2084 if (default_password.length() == 0)
2085 translated_default_password = password;
2087 infostream<<"Server: adding player "<<playername
2088 <<" to auth manager"<<std::endl;
2089 m_authmanager.add(playername);
2090 m_authmanager.setPassword(playername, translated_default_password);
2091 m_authmanager.setPrivs(playername,
2092 stringToPrivs(g_settings->get("default_privs")));
2093 m_authmanager.save();
2096 std::string checkpwd = m_authmanager.getPassword(playername);
2098 /*infostream<<"Server: Client gave password '"<<password
2099 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2101 if(password != checkpwd)
2103 infostream<<"Server: peer_id="<<peer_id
2104 <<": supplied invalid password for "
2105 <<playername<<std::endl;
2106 SendAccessDenied(m_con, peer_id, L"Invalid password");
2110 // Do not allow multiple players in simple singleplayer mode.
2111 // This isn't a perfect way to do it, but will suffice for now.
2112 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2113 infostream<<"Server: Not allowing another client to connect in"
2114 <<" simple singleplayer mode"<<std::endl;
2115 SendAccessDenied(m_con, peer_id,
2116 L"Running in simple singleplayer mode.");
2120 // Enforce user limit.
2121 // Don't enforce for users that have some admin right
2122 if(m_clients.size() >= g_settings->getU16("max_users") &&
2123 (m_authmanager.getPrivs(playername)
2124 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2125 playername != g_settings->get("name"))
2127 actionstream<<"Server: "<<playername<<" tried to join, but there"
2128 <<" are already max_users="
2129 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2130 SendAccessDenied(m_con, peer_id, L"Too many users.");
2135 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2137 // If failed, cancel
2140 errorstream<<"Server: peer_id="<<peer_id
2141 <<": failed to emerge player"<<std::endl;
2146 Answer with a TOCLIENT_INIT
2149 SharedBuffer<u8> reply(2+1+6+8);
2150 writeU16(&reply[0], TOCLIENT_INIT);
2151 writeU8(&reply[2], deployed);
2152 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2153 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2156 m_con.Send(peer_id, 0, reply, true);
2160 Send complete position information
2162 SendMovePlayer(player);
2167 if(command == TOSERVER_INIT2)
2169 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2170 <<peer_id<<std::endl;
2173 getClient(peer_id)->serialization_version
2174 = getClient(peer_id)->pending_serialization_version;
2177 Send some initialization data
2180 infostream<<"Server: Sending content to "
2181 <<getPlayerName(peer_id)<<std::endl;
2183 // Send item definitions
2184 SendItemDef(m_con, peer_id, m_itemdef);
2186 // Send node definitions
2187 SendNodeDef(m_con, peer_id, m_nodedef);
2189 // Send texture announcement
2190 SendTextureAnnouncement(peer_id);
2192 // Send player info to all players
2193 //SendPlayerInfos();
2195 // Send inventory to player
2196 UpdateCrafting(peer_id);
2197 SendInventory(peer_id);
2199 // Send player items to all players
2202 Player *player = m_env->getPlayer(peer_id);
2205 SendPlayerHP(player);
2207 // Show death screen if necessary
2209 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2213 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2214 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2215 m_con.Send(peer_id, 0, data, true);
2218 // Note things in chat if not in simple singleplayer mode
2219 if(!m_simple_singleplayer_mode)
2221 // Send information about server to player in chat
2222 SendChatMessage(peer_id, getStatusString());
2224 // Send information about joining in chat
2226 std::wstring name = L"unknown";
2227 Player *player = m_env->getPlayer(peer_id);
2229 name = narrow_to_wide(player->getName());
2231 std::wstring message;
2234 message += L" joined game";
2235 BroadcastChatMessage(message);
2239 // Warnings about protocol version can be issued here
2240 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2242 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2249 std::ostringstream os(std::ios_base::binary);
2250 for(core::map<u16, RemoteClient*>::Iterator
2251 i = m_clients.getIterator();
2252 i.atEnd() == false; i++)
2254 RemoteClient *client = i.getNode()->getValue();
2255 assert(client->peer_id == i.getNode()->getKey());
2256 if(client->serialization_version == SER_FMT_VER_INVALID)
2259 Player *player = m_env->getPlayer(client->peer_id);
2262 // Get name of player
2263 os<<player->getName()<<" ";
2266 actionstream<<player->getName()<<" joins game. List of players: "
2267 <<os.str()<<std::endl;
2273 if(peer_ser_ver == SER_FMT_VER_INVALID)
2275 infostream<<"Server::ProcessData(): Cancelling: Peer"
2276 " serialization format invalid or not initialized."
2277 " Skipping incoming command="<<command<<std::endl;
2281 Player *player = m_env->getPlayer(peer_id);
2282 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2285 infostream<<"Server::ProcessData(): Cancelling: "
2286 "No player for peer_id="<<peer_id
2290 if(command == TOSERVER_PLAYERPOS)
2292 if(datasize < 2+12+12+4+4)
2296 v3s32 ps = readV3S32(&data[start+2]);
2297 v3s32 ss = readV3S32(&data[start+2+12]);
2298 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2299 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2300 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2301 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2302 pitch = wrapDegrees(pitch);
2303 yaw = wrapDegrees(yaw);
2305 player->setPosition(position);
2306 player->setSpeed(speed);
2307 player->setPitch(pitch);
2308 player->setYaw(yaw);
2310 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2311 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2312 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2314 else if(command == TOSERVER_GOTBLOCKS)
2327 u16 count = data[2];
2328 for(u16 i=0; i<count; i++)
2330 if((s16)datasize < 2+1+(i+1)*6)
2331 throw con::InvalidIncomingDataException
2332 ("GOTBLOCKS length is too short");
2333 v3s16 p = readV3S16(&data[2+1+i*6]);
2334 /*infostream<<"Server: GOTBLOCKS ("
2335 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2336 RemoteClient *client = getClient(peer_id);
2337 client->GotBlock(p);
2340 else if(command == TOSERVER_DELETEDBLOCKS)
2353 u16 count = data[2];
2354 for(u16 i=0; i<count; i++)
2356 if((s16)datasize < 2+1+(i+1)*6)
2357 throw con::InvalidIncomingDataException
2358 ("DELETEDBLOCKS length is too short");
2359 v3s16 p = readV3S16(&data[2+1+i*6]);
2360 /*infostream<<"Server: DELETEDBLOCKS ("
2361 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2362 RemoteClient *client = getClient(peer_id);
2363 client->SetBlockNotSent(p);
2366 else if(command == TOSERVER_CLICK_OBJECT)
2368 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2371 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2373 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2376 else if(command == TOSERVER_GROUND_ACTION)
2378 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2382 else if(command == TOSERVER_RELEASE)
2384 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2387 else if(command == TOSERVER_SIGNTEXT)
2389 infostream<<"Server: SIGNTEXT not supported anymore"
2393 else if(command == TOSERVER_SIGNNODETEXT)
2395 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2403 std::string datastring((char*)&data[2], datasize-2);
2404 std::istringstream is(datastring, std::ios_base::binary);
2407 is.read((char*)buf, 6);
2408 v3s16 p = readV3S16(buf);
2409 is.read((char*)buf, 2);
2410 u16 textlen = readU16(buf);
2412 for(u16 i=0; i<textlen; i++)
2414 is.read((char*)buf, 1);
2415 text += (char)buf[0];
2418 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2422 meta->setText(text);
2424 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2425 <<" at "<<PP(p)<<std::endl;
2427 v3s16 blockpos = getNodeBlockPos(p);
2428 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2431 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2435 setBlockNotSent(blockpos);
2437 else if(command == TOSERVER_INVENTORY_ACTION)
2439 // Strip command and create a stream
2440 std::string datastring((char*)&data[2], datasize-2);
2441 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2442 std::istringstream is(datastring, std::ios_base::binary);
2444 InventoryAction *a = InventoryAction::deSerialize(is);
2447 infostream<<"TOSERVER_INVENTORY_ACTION: "
2448 <<"InventoryAction::deSerialize() returned NULL"
2454 Note: Always set inventory not sent, to repair cases
2455 where the client made a bad prediction.
2459 Handle restrictions and special cases of the move action
2461 if(a->getType() == IACTION_MOVE)
2463 IMoveAction *ma = (IMoveAction*)a;
2465 ma->from_inv.applyCurrentPlayer(player->getName());
2466 ma->to_inv.applyCurrentPlayer(player->getName());
2468 setInventoryModified(ma->from_inv);
2469 setInventoryModified(ma->to_inv);
2471 bool from_inv_is_current_player =
2472 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2473 (ma->from_inv.name == player->getName());
2475 bool to_inv_is_current_player =
2476 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2477 (ma->to_inv.name == player->getName());
2480 Disable moving items out of craftpreview
2482 if(ma->from_list == "craftpreview")
2484 infostream<<"Ignoring IMoveAction from "
2485 <<(ma->from_inv.dump())<<":"<<ma->from_list
2486 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2487 <<" because src is "<<ma->from_list<<std::endl;
2493 Disable moving items into craftresult and craftpreview
2495 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2497 infostream<<"Ignoring IMoveAction from "
2498 <<(ma->from_inv.dump())<<":"<<ma->from_list
2499 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2500 <<" because dst is "<<ma->to_list<<std::endl;
2505 // Disallow moving items in elsewhere than player's inventory
2506 // if not allowed to interact
2507 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2508 && (!from_inv_is_current_player
2509 || !to_inv_is_current_player))
2511 infostream<<"Cannot move outside of player's inventory: "
2512 <<"No interact privilege"<<std::endl;
2517 // If player is not an admin, check for ownership of src and dst
2518 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2520 std::string owner_from = getInventoryOwner(ma->from_inv);
2521 if(owner_from != "" && owner_from != player->getName())
2523 infostream<<"WARNING: "<<player->getName()
2524 <<" tried to access an inventory that"
2525 <<" belongs to "<<owner_from<<std::endl;
2530 std::string owner_to = getInventoryOwner(ma->to_inv);
2531 if(owner_to != "" && owner_to != player->getName())
2533 infostream<<"WARNING: "<<player->getName()
2534 <<" tried to access an inventory that"
2535 <<" belongs to "<<owner_to<<std::endl;
2542 Handle restrictions and special cases of the drop action
2544 else if(a->getType() == IACTION_DROP)
2546 IDropAction *da = (IDropAction*)a;
2548 da->from_inv.applyCurrentPlayer(player->getName());
2550 setInventoryModified(da->from_inv);
2552 // Disallow dropping items if not allowed to interact
2553 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2558 // If player is not an admin, check for ownership
2559 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2561 std::string owner_from = getInventoryOwner(da->from_inv);
2562 if(owner_from != "" && owner_from != player->getName())
2564 infostream<<"WARNING: "<<player->getName()
2565 <<" tried to access an inventory that"
2566 <<" belongs to "<<owner_from<<std::endl;
2573 Handle restrictions and special cases of the craft action
2575 else if(a->getType() == IACTION_CRAFT)
2577 ICraftAction *ca = (ICraftAction*)a;
2579 ca->craft_inv.applyCurrentPlayer(player->getName());
2581 setInventoryModified(ca->craft_inv);
2583 //bool craft_inv_is_current_player =
2584 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2585 // (ca->craft_inv.name == player->getName());
2587 // Disallow crafting if not allowed to interact
2588 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2590 infostream<<"Cannot craft: "
2591 <<"No interact privilege"<<std::endl;
2596 // If player is not an admin, check for ownership of inventory
2597 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2599 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2600 if(owner_craft != "" && owner_craft != player->getName())
2602 infostream<<"WARNING: "<<player->getName()
2603 <<" tried to access an inventory that"
2604 <<" belongs to "<<owner_craft<<std::endl;
2612 a->apply(this, srp, this);
2616 else if(command == TOSERVER_CHAT_MESSAGE)
2624 std::string datastring((char*)&data[2], datasize-2);
2625 std::istringstream is(datastring, std::ios_base::binary);
2628 is.read((char*)buf, 2);
2629 u16 len = readU16(buf);
2631 std::wstring message;
2632 for(u16 i=0; i<len; i++)
2634 is.read((char*)buf, 2);
2635 message += (wchar_t)readU16(buf);
2638 // Get player name of this client
2639 std::wstring name = narrow_to_wide(player->getName());
2642 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2643 wide_to_narrow(message));
2644 // If script ate the message, don't proceed
2648 // Line to send to players
2650 // Whether to send to the player that sent the line
2651 bool send_to_sender = false;
2652 // Whether to send to other players
2653 bool send_to_others = false;
2655 // Local player gets all privileges regardless of
2656 // what's set on their account.
2657 u64 privs = getPlayerPrivs(player);
2660 if(message[0] == L'/')
2662 size_t strip_size = 1;
2663 if (message[1] == L'#') // support old-style commans
2665 message = message.substr(strip_size);
2667 WStrfnd f1(message);
2668 f1.next(L" "); // Skip over /#whatever
2669 std::wstring paramstring = f1.next(L"");
2671 ServerCommandContext *ctx = new ServerCommandContext(
2672 str_split(message, L' '),
2679 std::wstring reply(processServerCommand(ctx));
2680 send_to_sender = ctx->flags & SEND_TO_SENDER;
2681 send_to_others = ctx->flags & SEND_TO_OTHERS;
2683 if (ctx->flags & SEND_NO_PREFIX)
2686 line += L"Server: " + reply;
2693 if(privs & PRIV_SHOUT)
2699 send_to_others = true;
2703 line += L"Server: You are not allowed to shout";
2704 send_to_sender = true;
2711 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2714 Send the message to clients
2716 for(core::map<u16, RemoteClient*>::Iterator
2717 i = m_clients.getIterator();
2718 i.atEnd() == false; i++)
2720 // Get client and check that it is valid
2721 RemoteClient *client = i.getNode()->getValue();
2722 assert(client->peer_id == i.getNode()->getKey());
2723 if(client->serialization_version == SER_FMT_VER_INVALID)
2727 bool sender_selected = (peer_id == client->peer_id);
2728 if(sender_selected == true && send_to_sender == false)
2730 if(sender_selected == false && send_to_others == false)
2733 SendChatMessage(client->peer_id, line);
2737 else if(command == TOSERVER_DAMAGE)
2739 std::string datastring((char*)&data[2], datasize-2);
2740 std::istringstream is(datastring, std::ios_base::binary);
2741 u8 damage = readU8(is);
2743 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2745 if(g_settings->getBool("enable_damage"))
2747 actionstream<<player->getName()<<" damaged by "
2748 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2751 srp->setHP(srp->getHP() - damage);
2753 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2756 if(srp->m_hp_not_sent)
2757 SendPlayerHP(player);
2761 // Force send (to correct the client's predicted HP)
2762 SendPlayerHP(player);
2765 else if(command == TOSERVER_PASSWORD)
2768 [0] u16 TOSERVER_PASSWORD
2769 [2] u8[28] old password
2770 [30] u8[28] new password
2773 if(datasize != 2+PASSWORD_SIZE*2)
2775 /*char password[PASSWORD_SIZE];
2776 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2777 password[i] = data[2+i];
2778 password[PASSWORD_SIZE-1] = 0;*/
2780 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2788 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2790 char c = data[2+PASSWORD_SIZE+i];
2796 infostream<<"Server: Client requests a password change from "
2797 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2799 std::string playername = player->getName();
2801 if(m_authmanager.exists(playername) == false)
2803 infostream<<"Server: playername not found in authmanager"<<std::endl;
2804 // Wrong old password supplied!!
2805 SendChatMessage(peer_id, L"playername not found in authmanager");
2809 std::string checkpwd = m_authmanager.getPassword(playername);
2811 if(oldpwd != checkpwd)
2813 infostream<<"Server: invalid old password"<<std::endl;
2814 // Wrong old password supplied!!
2815 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2819 actionstream<<player->getName()<<" changes password"<<std::endl;
2821 m_authmanager.setPassword(playername, newpwd);
2823 infostream<<"Server: password change successful for "<<playername
2825 SendChatMessage(peer_id, L"Password change successful");
2827 else if(command == TOSERVER_PLAYERITEM)
2832 u16 item = readU16(&data[2]);
2833 srp->setWieldIndex(item);
2834 SendWieldedItem(srp);
2836 else if(command == TOSERVER_RESPAWN)
2841 RespawnPlayer(player);
2843 actionstream<<player->getName()<<" respawns at "
2844 <<PP(player->getPosition()/BS)<<std::endl;
2846 // ActiveObject is added to environment in AsyncRunStep after
2847 // the previous addition has been succesfully removed
2849 else if(command == TOSERVER_REQUEST_TEXTURES) {
2850 std::string datastring((char*)&data[2], datasize-2);
2851 std::istringstream is(datastring, std::ios_base::binary);
2854 core::list<TextureRequest> tosend;
2855 u16 numtextures = readU16(is);
2857 infostream<<"Sending "<<numtextures<<" textures to "
2858 <<getPlayerName(peer_id)<<std::endl;
2859 verbosestream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2861 for(int i = 0; i < numtextures; i++) {
2862 std::string name = deSerializeString(is);
2863 tosend.push_back(TextureRequest(name));
2864 verbosestream<<"TOSERVER_REQUEST_TEXTURES: requested texture "
2868 SendTexturesRequested(peer_id, tosend);
2870 // Now the client should know about everything
2871 // (definitions and textures)
2872 getClient(peer_id)->definitions_sent = true;
2874 else if(command == TOSERVER_INTERACT)
2876 std::string datastring((char*)&data[2], datasize-2);
2877 std::istringstream is(datastring, std::ios_base::binary);
2883 [5] u32 length of the next item
2884 [9] serialized PointedThing
2886 0: start digging (from undersurface) or use
2887 1: stop digging (all parameters ignored)
2888 2: digging completed
2889 3: place block or item (to abovesurface)
2892 u8 action = readU8(is);
2893 u16 item_i = readU16(is);
2894 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2895 PointedThing pointed;
2896 pointed.deSerialize(tmp_is);
2898 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2899 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2903 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2904 <<" tried to interact, but is dead!"<<std::endl;
2908 v3f player_pos = srp->m_last_good_position;
2910 // Update wielded item
2911 if(srp->getWieldIndex() != item_i)
2913 srp->setWieldIndex(item_i);
2914 SendWieldedItem(srp);
2917 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2918 v3s16 p_under = pointed.node_undersurface;
2919 v3s16 p_above = pointed.node_abovesurface;
2921 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2922 ServerActiveObject *pointed_object = NULL;
2923 if(pointed.type == POINTEDTHING_OBJECT)
2925 pointed_object = m_env->getActiveObject(pointed.object_id);
2926 if(pointed_object == NULL)
2928 verbosestream<<"TOSERVER_INTERACT: "
2929 "pointed object is NULL"<<std::endl;
2935 v3f pointed_pos_under = player_pos;
2936 v3f pointed_pos_above = player_pos;
2937 if(pointed.type == POINTEDTHING_NODE)
2939 pointed_pos_under = intToFloat(p_under, BS);
2940 pointed_pos_above = intToFloat(p_above, BS);
2942 else if(pointed.type == POINTEDTHING_OBJECT)
2944 pointed_pos_under = pointed_object->getBasePosition();
2945 pointed_pos_above = pointed_pos_under;
2949 Check that target is reasonably close
2950 (only when digging or placing things)
2952 if(action == 0 || action == 2 || action == 3)
2954 float d = player_pos.getDistanceFrom(pointed_pos_under);
2955 float max_d = BS * 14; // Just some large enough value
2957 actionstream<<"Player "<<player->getName()
2958 <<" tried to access "<<pointed.dump()
2960 <<"d="<<d<<", max_d="<<max_d
2961 <<". ignoring."<<std::endl;
2962 // Re-send block to revert change on client-side
2963 RemoteClient *client = getClient(peer_id);
2964 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2965 client->SetBlockNotSent(blockpos);
2972 Make sure the player is allowed to do it
2974 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2976 infostream<<"Ignoring interaction from player "<<player->getName()
2977 <<" because privileges are "<<getPlayerPrivs(player)
2983 0: start digging or punch object
2987 if(pointed.type == POINTEDTHING_NODE)
2990 NOTE: This can be used in the future to check if
2991 somebody is cheating, by checking the timing.
2993 MapNode n(CONTENT_IGNORE);
2996 n = m_env->getMap().getNode(p_under);
2998 catch(InvalidPositionException &e)
3000 infostream<<"Server: Not punching: Node not found."
3001 <<" Adding block to emerge queue."
3003 m_emerge_queue.addBlock(peer_id,
3004 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3006 if(n.getContent() != CONTENT_IGNORE)
3007 scriptapi_node_on_punch(m_lua, p_under, n, srp);
3009 else if(pointed.type == POINTEDTHING_OBJECT)
3011 // Skip if object has been removed
3012 if(pointed_object->m_removed)
3015 actionstream<<player->getName()<<" punches object "
3016 <<pointed.object_id<<": "
3017 <<pointed_object->getDescription()<<std::endl;
3019 ItemStack punchitem = srp->getWieldedItem();
3020 ToolCapabilities toolcap =
3021 punchitem.getToolCapabilities(m_itemdef);
3022 v3f dir = (pointed_object->getBasePosition() -
3023 (srp->getPosition() + srp->getEyeOffset())
3025 pointed_object->punch(dir, &toolcap, srp,
3026 srp->m_time_from_last_punch);
3027 srp->m_time_from_last_punch = 0;
3035 else if(action == 1)
3040 2: Digging completed
3042 else if(action == 2)
3044 // Only complete digging of nodes
3045 if(pointed.type == POINTEDTHING_NODE)
3047 MapNode n(CONTENT_IGNORE);
3050 n = m_env->getMap().getNode(p_under);
3052 catch(InvalidPositionException &e)
3054 infostream<<"Server: Not finishing digging: Node not found."
3055 <<" Adding block to emerge queue."
3057 m_emerge_queue.addBlock(peer_id,
3058 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3060 if(n.getContent() != CONTENT_IGNORE)
3061 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3066 3: place block or right-click object
3068 else if(action == 3)
3070 ItemStack item = srp->getWieldedItem();
3072 // Reset build time counter
3073 if(pointed.type == POINTEDTHING_NODE &&
3074 item.getDefinition(m_itemdef).type == ITEM_NODE)
3075 getClient(peer_id)->m_time_from_building = 0.0;
3077 if(pointed.type == POINTEDTHING_OBJECT)
3079 // Right click object
3081 // Skip if object has been removed
3082 if(pointed_object->m_removed)
3085 actionstream<<player->getName()<<" right-clicks object "
3086 <<pointed.object_id<<": "
3087 <<pointed_object->getDescription()<<std::endl;
3090 pointed_object->rightClick(srp);
3092 else if(scriptapi_item_on_place(m_lua,
3093 item, srp, pointed))
3095 // Placement was handled in lua
3097 // Apply returned ItemStack
3098 if(g_settings->getBool("creative_mode") == false)
3099 srp->setWieldedItem(item);
3107 else if(action == 4)
3109 ItemStack item = srp->getWieldedItem();
3111 actionstream<<player->getName()<<" uses "<<item.name
3112 <<", pointing at "<<pointed.dump()<<std::endl;
3114 if(scriptapi_item_on_use(m_lua,
3115 item, srp, pointed))
3117 // Apply returned ItemStack
3118 if(g_settings->getBool("creative_mode") == false)
3119 srp->setWieldedItem(item);
3125 Catch invalid actions
3129 infostream<<"WARNING: Server: Invalid action "
3130 <<action<<std::endl;
3135 infostream<<"Server::ProcessData(): Ignoring "
3136 "unknown command "<<command<<std::endl;
3140 catch(SendFailedException &e)
3142 errorstream<<"Server::ProcessData(): SendFailedException: "
3148 void Server::onMapEditEvent(MapEditEvent *event)
3150 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3151 if(m_ignore_map_edit_events)
3153 MapEditEvent *e = event->clone();
3154 m_unsent_map_edit_queue.push_back(e);
3157 Inventory* Server::getInventory(const InventoryLocation &loc)
3160 case InventoryLocation::UNDEFINED:
3163 case InventoryLocation::CURRENT_PLAYER:
3166 case InventoryLocation::PLAYER:
3168 Player *player = m_env->getPlayer(loc.name.c_str());
3171 return &player->inventory;
3174 case InventoryLocation::NODEMETA:
3176 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3179 return meta->getInventory();
3187 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3190 case InventoryLocation::UNDEFINED:
3193 case InventoryLocation::CURRENT_PLAYER:
3196 case InventoryLocation::PLAYER:
3201 case InventoryLocation::NODEMETA:
3203 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3206 return meta->getOwner();
3214 void Server::setInventoryModified(const InventoryLocation &loc)
3217 case InventoryLocation::UNDEFINED:
3220 case InventoryLocation::PLAYER:
3222 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3223 (m_env->getPlayer(loc.name.c_str()));
3226 srp->m_inventory_not_sent = true;
3229 case InventoryLocation::NODEMETA:
3231 v3s16 blockpos = getNodeBlockPos(loc.p);
3233 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3235 meta->inventoryModified();
3237 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3239 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3241 setBlockNotSent(blockpos);
3249 core::list<PlayerInfo> Server::getPlayerInfo()
3251 DSTACK(__FUNCTION_NAME);
3252 JMutexAutoLock envlock(m_env_mutex);
3253 JMutexAutoLock conlock(m_con_mutex);
3255 core::list<PlayerInfo> list;
3257 core::list<Player*> players = m_env->getPlayers();
3259 core::list<Player*>::Iterator i;
3260 for(i = players.begin();
3261 i != players.end(); i++)
3265 Player *player = *i;
3268 // Copy info from connection to info struct
3269 info.id = player->peer_id;
3270 info.address = m_con.GetPeerAddress(player->peer_id);
3271 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3273 catch(con::PeerNotFoundException &e)
3275 // Set dummy peer info
3277 info.address = Address(0,0,0,0,0);
3281 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3282 info.position = player->getPosition();
3284 list.push_back(info);
3291 void Server::peerAdded(con::Peer *peer)
3293 DSTACK(__FUNCTION_NAME);
3294 verbosestream<<"Server::peerAdded(): peer->id="
3295 <<peer->id<<std::endl;
3298 c.type = PEER_ADDED;
3299 c.peer_id = peer->id;
3301 m_peer_change_queue.push_back(c);
3304 void Server::deletingPeer(con::Peer *peer, bool timeout)
3306 DSTACK(__FUNCTION_NAME);
3307 verbosestream<<"Server::deletingPeer(): peer->id="
3308 <<peer->id<<", timeout="<<timeout<<std::endl;
3311 c.type = PEER_REMOVED;
3312 c.peer_id = peer->id;
3313 c.timeout = timeout;
3314 m_peer_change_queue.push_back(c);
3321 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3323 DSTACK(__FUNCTION_NAME);
3324 std::ostringstream os(std::ios_base::binary);
3326 writeU16(os, TOCLIENT_HP);
3330 std::string s = os.str();
3331 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3333 con.Send(peer_id, 0, data, true);
3336 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3337 const std::wstring &reason)
3339 DSTACK(__FUNCTION_NAME);
3340 std::ostringstream os(std::ios_base::binary);
3342 writeU16(os, TOCLIENT_ACCESS_DENIED);
3343 os<<serializeWideString(reason);
3346 std::string s = os.str();
3347 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3349 con.Send(peer_id, 0, data, true);
3352 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3353 bool set_camera_point_target, v3f camera_point_target)
3355 DSTACK(__FUNCTION_NAME);
3356 std::ostringstream os(std::ios_base::binary);
3358 writeU16(os, TOCLIENT_DEATHSCREEN);
3359 writeU8(os, set_camera_point_target);
3360 writeV3F1000(os, camera_point_target);
3363 std::string s = os.str();
3364 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3366 con.Send(peer_id, 0, data, true);
3369 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3370 IItemDefManager *itemdef)
3372 DSTACK(__FUNCTION_NAME);
3373 std::ostringstream os(std::ios_base::binary);
3377 u32 length of the next item
3378 zlib-compressed serialized ItemDefManager
3380 writeU16(os, TOCLIENT_ITEMDEF);
3381 std::ostringstream tmp_os(std::ios::binary);
3382 itemdef->serialize(tmp_os);
3383 std::ostringstream tmp_os2(std::ios::binary);
3384 compressZlib(tmp_os.str(), tmp_os2);
3385 os<<serializeLongString(tmp_os2.str());
3388 std::string s = os.str();
3389 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3390 <<"): size="<<s.size()<<std::endl;
3391 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3393 con.Send(peer_id, 0, data, true);
3396 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3397 INodeDefManager *nodedef)
3399 DSTACK(__FUNCTION_NAME);
3400 std::ostringstream os(std::ios_base::binary);
3404 u32 length of the next item
3405 zlib-compressed serialized NodeDefManager
3407 writeU16(os, TOCLIENT_NODEDEF);
3408 std::ostringstream tmp_os(std::ios::binary);
3409 nodedef->serialize(tmp_os);
3410 std::ostringstream tmp_os2(std::ios::binary);
3411 compressZlib(tmp_os.str(), tmp_os2);
3412 os<<serializeLongString(tmp_os2.str());
3415 std::string s = os.str();
3416 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3417 <<"): size="<<s.size()<<std::endl;
3418 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3420 con.Send(peer_id, 0, data, true);
3424 Non-static send methods
3427 void Server::SendInventory(u16 peer_id)
3429 DSTACK(__FUNCTION_NAME);
3431 ServerRemotePlayer* player =
3432 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3435 player->m_inventory_not_sent = false;
3441 std::ostringstream os;
3442 //os.imbue(std::locale("C"));
3444 player->inventory.serialize(os);
3446 std::string s = os.str();
3448 SharedBuffer<u8> data(s.size()+2);
3449 writeU16(&data[0], TOCLIENT_INVENTORY);
3450 memcpy(&data[2], s.c_str(), s.size());
3453 m_con.Send(peer_id, 0, data, true);
3456 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3458 DSTACK(__FUNCTION_NAME);
3462 std::ostringstream os(std::ios_base::binary);
3464 writeU16(os, TOCLIENT_PLAYERITEM);
3466 writeU16(os, srp->peer_id);
3467 os<<serializeString(srp->getWieldedItem().getItemString());
3470 std::string s = os.str();
3471 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3473 m_con.SendToAll(0, data, true);
3476 void Server::SendPlayerItems()
3478 DSTACK(__FUNCTION_NAME);
3480 std::ostringstream os(std::ios_base::binary);
3481 core::list<Player *> players = m_env->getPlayers(true);
3483 writeU16(os, TOCLIENT_PLAYERITEM);
3484 writeU16(os, players.size());
3485 core::list<Player *>::Iterator i;
3486 for(i = players.begin(); i != players.end(); ++i)
3489 ServerRemotePlayer *srp =
3490 static_cast<ServerRemotePlayer*>(p);
3491 writeU16(os, p->peer_id);
3492 os<<serializeString(srp->getWieldedItem().getItemString());
3496 std::string s = os.str();
3497 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3499 m_con.SendToAll(0, data, true);
3502 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3504 DSTACK(__FUNCTION_NAME);
3506 std::ostringstream os(std::ios_base::binary);
3510 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3511 os.write((char*)buf, 2);
3514 writeU16(buf, message.size());
3515 os.write((char*)buf, 2);
3518 for(u32 i=0; i<message.size(); i++)
3522 os.write((char*)buf, 2);
3526 std::string s = os.str();
3527 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3529 m_con.Send(peer_id, 0, data, true);
3532 void Server::BroadcastChatMessage(const std::wstring &message)
3534 for(core::map<u16, RemoteClient*>::Iterator
3535 i = m_clients.getIterator();
3536 i.atEnd() == false; i++)
3538 // Get client and check that it is valid
3539 RemoteClient *client = i.getNode()->getValue();
3540 assert(client->peer_id == i.getNode()->getKey());
3541 if(client->serialization_version == SER_FMT_VER_INVALID)
3544 SendChatMessage(client->peer_id, message);
3548 void Server::SendPlayerHP(Player *player)
3550 SendHP(m_con, player->peer_id, player->hp);
3551 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3554 void Server::SendMovePlayer(Player *player)
3556 DSTACK(__FUNCTION_NAME);
3557 std::ostringstream os(std::ios_base::binary);
3559 writeU16(os, TOCLIENT_MOVE_PLAYER);
3560 writeV3F1000(os, player->getPosition());
3561 writeF1000(os, player->getPitch());
3562 writeF1000(os, player->getYaw());
3565 v3f pos = player->getPosition();
3566 f32 pitch = player->getPitch();
3567 f32 yaw = player->getYaw();
3568 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3569 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3576 std::string s = os.str();
3577 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3579 m_con.Send(player->peer_id, 0, data, true);
3582 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3583 core::list<u16> *far_players, float far_d_nodes)
3585 float maxd = far_d_nodes*BS;
3586 v3f p_f = intToFloat(p, BS);
3590 SharedBuffer<u8> reply(replysize);
3591 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3592 writeS16(&reply[2], p.X);
3593 writeS16(&reply[4], p.Y);
3594 writeS16(&reply[6], p.Z);
3596 for(core::map<u16, RemoteClient*>::Iterator
3597 i = m_clients.getIterator();
3598 i.atEnd() == false; i++)
3600 // Get client and check that it is valid
3601 RemoteClient *client = i.getNode()->getValue();
3602 assert(client->peer_id == i.getNode()->getKey());
3603 if(client->serialization_version == SER_FMT_VER_INVALID)
3606 // Don't send if it's the same one
3607 if(client->peer_id == ignore_id)
3613 Player *player = m_env->getPlayer(client->peer_id);
3616 // If player is far away, only set modified blocks not sent
3617 v3f player_pos = player->getPosition();
3618 if(player_pos.getDistanceFrom(p_f) > maxd)
3620 far_players->push_back(client->peer_id);
3627 m_con.Send(client->peer_id, 0, reply, true);
3631 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3632 core::list<u16> *far_players, float far_d_nodes)
3634 float maxd = far_d_nodes*BS;
3635 v3f p_f = intToFloat(p, BS);
3637 for(core::map<u16, RemoteClient*>::Iterator
3638 i = m_clients.getIterator();
3639 i.atEnd() == false; i++)
3641 // Get client and check that it is valid
3642 RemoteClient *client = i.getNode()->getValue();
3643 assert(client->peer_id == i.getNode()->getKey());
3644 if(client->serialization_version == SER_FMT_VER_INVALID)
3647 // Don't send if it's the same one
3648 if(client->peer_id == ignore_id)
3654 Player *player = m_env->getPlayer(client->peer_id);
3657 // If player is far away, only set modified blocks not sent
3658 v3f player_pos = player->getPosition();
3659 if(player_pos.getDistanceFrom(p_f) > maxd)
3661 far_players->push_back(client->peer_id);
3668 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3669 SharedBuffer<u8> reply(replysize);
3670 writeU16(&reply[0], TOCLIENT_ADDNODE);
3671 writeS16(&reply[2], p.X);
3672 writeS16(&reply[4], p.Y);
3673 writeS16(&reply[6], p.Z);
3674 n.serialize(&reply[8], client->serialization_version);
3677 m_con.Send(client->peer_id, 0, reply, true);
3681 void Server::setBlockNotSent(v3s16 p)
3683 for(core::map<u16, RemoteClient*>::Iterator
3684 i = m_clients.getIterator();
3685 i.atEnd()==false; i++)
3687 RemoteClient *client = i.getNode()->getValue();
3688 client->SetBlockNotSent(p);
3692 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3694 DSTACK(__FUNCTION_NAME);
3696 v3s16 p = block->getPos();
3700 bool completely_air = true;
3701 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3702 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3703 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3705 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3707 completely_air = false;
3708 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3713 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3715 infostream<<"[completely air] ";
3716 infostream<<std::endl;
3720 Create a packet with the block in the right format
3723 std::ostringstream os(std::ios_base::binary);
3724 block->serialize(os, ver, false);
3725 std::string s = os.str();
3726 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3728 u32 replysize = 8 + blockdata.getSize();
3729 SharedBuffer<u8> reply(replysize);
3730 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3731 writeS16(&reply[2], p.X);
3732 writeS16(&reply[4], p.Y);
3733 writeS16(&reply[6], p.Z);
3734 memcpy(&reply[8], *blockdata, blockdata.getSize());
3736 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3737 <<": \tpacket size: "<<replysize<<std::endl;*/
3742 m_con.Send(peer_id, 1, reply, true);
3745 void Server::SendBlocks(float dtime)
3747 DSTACK(__FUNCTION_NAME);
3749 JMutexAutoLock envlock(m_env_mutex);
3750 JMutexAutoLock conlock(m_con_mutex);
3752 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3754 core::array<PrioritySortedBlockTransfer> queue;
3756 s32 total_sending = 0;
3759 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3761 for(core::map<u16, RemoteClient*>::Iterator
3762 i = m_clients.getIterator();
3763 i.atEnd() == false; i++)
3765 RemoteClient *client = i.getNode()->getValue();
3766 assert(client->peer_id == i.getNode()->getKey());
3768 // If definitions and textures have not been sent, don't
3769 // send MapBlocks either
3770 if(!client->definitions_sent)
3773 total_sending += client->SendingCount();
3775 if(client->serialization_version == SER_FMT_VER_INVALID)
3778 client->GetNextBlocks(this, dtime, queue);
3783 // Lowest priority number comes first.
3784 // Lowest is most important.
3787 for(u32 i=0; i<queue.size(); i++)
3789 //TODO: Calculate limit dynamically
3790 if(total_sending >= g_settings->getS32
3791 ("max_simultaneous_block_sends_server_total"))
3794 PrioritySortedBlockTransfer q = queue[i];
3796 MapBlock *block = NULL;
3799 block = m_env->getMap().getBlockNoCreate(q.pos);
3801 catch(InvalidPositionException &e)
3806 RemoteClient *client = getClient(q.peer_id);
3808 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3810 client->SentBlock(q.pos);
3816 void Server::PrepareTextures()
3818 DSTACK(__FUNCTION_NAME);
3820 infostream<<"Server: Calculating texture checksums"<<std::endl;
3822 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3823 i != m_mods.end(); i++){
3824 const ModSpec &mod = *i;
3825 std::string texturepath = mod.path + DIR_DELIM + "textures";
3826 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3827 for(u32 j=0; j<dirlist.size(); j++){
3828 if(dirlist[j].dir) // Ignode dirs
3830 std::string tname = dirlist[j].name;
3831 // if name contains illegal characters, ignore the texture
3832 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3833 errorstream<<"Server: ignoring illegal texture name: \""
3834 <<tname<<"\""<<std::endl;
3837 std::string tpath = texturepath + DIR_DELIM + tname;
3839 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3840 if(fis.good() == false){
3841 errorstream<<"Server::PrepareTextures(): Could not open \""
3842 <<tname<<"\" for reading"<<std::endl;
3845 std::ostringstream tmp_os(std::ios_base::binary);
3849 fis.read(buf, 1024);
3850 std::streamsize len = fis.gcount();
3851 tmp_os.write(buf, len);
3860 errorstream<<"Server::PrepareTextures(): Failed to read \""
3861 <<tname<<"\""<<std::endl;
3864 if(tmp_os.str().length() == 0){
3865 errorstream<<"Server::PrepareTextures(): Empty file \""
3866 <<tpath<<"\""<<std::endl;
3871 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3873 unsigned char *digest = sha1.getDigest();
3874 std::string digest_string = base64_encode(digest, 20);
3879 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3880 verbosestream<<"Server: sha1 for "<<tname<<"\tis "<<std::endl;
3885 struct SendableTextureAnnouncement
3888 std::string sha1_digest;
3890 SendableTextureAnnouncement(const std::string name_="",
3891 const std::string sha1_digest_=""):
3893 sha1_digest(sha1_digest_)
3898 void Server::SendTextureAnnouncement(u16 peer_id){
3899 DSTACK(__FUNCTION_NAME);
3901 verbosestream<<"Server: Announcing textures to id("<<peer_id<<")"
3904 core::list<SendableTextureAnnouncement> texture_announcements;
3906 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3909 texture_announcements.push_back(
3910 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3913 //send announcements
3917 u32 number of textures
3921 u16 length of digest string
3925 std::ostringstream os(std::ios_base::binary);
3927 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3928 writeU16(os, texture_announcements.size());
3930 for(core::list<SendableTextureAnnouncement>::Iterator
3931 j = texture_announcements.begin();
3932 j != texture_announcements.end(); j++){
3933 os<<serializeString(j->name);
3934 os<<serializeString(j->sha1_digest);
3938 std::string s = os.str();
3939 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3942 m_con.Send(peer_id, 0, data, true);
3946 struct SendableTexture
3952 SendableTexture(const std::string &name_="", const std::string path_="",
3953 const std::string &data_=""):
3960 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3961 DSTACK(__FUNCTION_NAME);
3963 verbosestream<<"Server::SendTexturesRequested(): "
3964 <<"Sending textures to client"<<std::endl;
3968 // Put 5kB in one bunch (this is not accurate)
3969 u32 bytes_per_bunch = 5000;
3971 core::array< core::list<SendableTexture> > texture_bunches;
3972 texture_bunches.push_back(core::list<SendableTexture>());
3974 u32 texture_size_bunch_total = 0;
3976 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3977 if(m_Textures.find(i->name) == m_Textures.end()){
3978 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3979 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3983 //TODO get path + name
3984 std::string tpath = m_Textures[(*i).name].path;
3987 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3988 if(fis.good() == false){
3989 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3990 <<tpath<<"\" for reading"<<std::endl;
3993 std::ostringstream tmp_os(std::ios_base::binary);
3997 fis.read(buf, 1024);
3998 std::streamsize len = fis.gcount();
3999 tmp_os.write(buf, len);
4000 texture_size_bunch_total += len;
4009 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
4010 <<(*i).name<<"\""<<std::endl;
4013 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
4014 <<tname<<"\""<<std::endl;*/
4016 texture_bunches[texture_bunches.size()-1].push_back(
4017 SendableTexture((*i).name, tpath, tmp_os.str()));
4019 // Start next bunch if got enough data
4020 if(texture_size_bunch_total >= bytes_per_bunch){
4021 texture_bunches.push_back(core::list<SendableTexture>());
4022 texture_size_bunch_total = 0;
4027 /* Create and send packets */
4029 u32 num_bunches = texture_bunches.size();
4030 for(u32 i=0; i<num_bunches; i++)
4034 u16 total number of texture bunches
4035 u16 index of this bunch
4036 u32 number of textures in this bunch
4044 std::ostringstream os(std::ios_base::binary);
4046 writeU16(os, TOCLIENT_TEXTURES);
4047 writeU16(os, num_bunches);
4049 writeU32(os, texture_bunches[i].size());
4051 for(core::list<SendableTexture>::Iterator
4052 j = texture_bunches[i].begin();
4053 j != texture_bunches[i].end(); j++){
4054 os<<serializeString(j->name);
4055 os<<serializeLongString(j->data);
4059 std::string s = os.str();
4060 verbosestream<<"Server::SendTexturesRequested(): bunch "
4061 <<i<<"/"<<num_bunches
4062 <<" textures="<<texture_bunches[i].size()
4063 <<" size=" <<s.size()<<std::endl;
4064 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4066 m_con.Send(peer_id, 0, data, true);
4076 void Server::DiePlayer(Player *player)
4078 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4080 infostream<<"Server::DiePlayer(): Player "
4081 <<player->getName()<<" dies"<<std::endl;
4085 // Trigger scripted stuff
4086 scriptapi_on_dieplayer(m_lua, srp);
4088 // Handle players that are not connected
4089 if(player->peer_id == PEER_ID_INEXISTENT){
4090 RespawnPlayer(player);
4094 SendPlayerHP(player);
4095 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4098 void Server::RespawnPlayer(Player *player)
4100 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4102 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4104 v3f pos = findSpawnPos(m_env->getServerMap());
4105 player->setPosition(pos);
4106 srp->m_last_good_position = pos;
4107 srp->m_last_good_position_age = 0;
4109 SendMovePlayer(player);
4110 SendPlayerHP(player);
4113 void Server::UpdateCrafting(u16 peer_id)
4115 DSTACK(__FUNCTION_NAME);
4117 Player* player = m_env->getPlayer(peer_id);
4120 // Get a preview for crafting
4122 // No crafting in creative mode
4123 if(g_settings->getBool("creative_mode") == false)
4124 getCraftingResult(&player->inventory, preview, false, this);
4126 // Put the new preview in
4127 InventoryList *plist = player->inventory.getList("craftpreview");
4129 assert(plist->getSize() >= 1);
4130 plist->changeItem(0, preview);
4133 RemoteClient* Server::getClient(u16 peer_id)
4135 DSTACK(__FUNCTION_NAME);
4136 //JMutexAutoLock lock(m_con_mutex);
4137 core::map<u16, RemoteClient*>::Node *n;
4138 n = m_clients.find(peer_id);
4139 // A client should exist for all peers
4141 return n->getValue();
4144 std::wstring Server::getStatusString()
4146 std::wostringstream os(std::ios_base::binary);
4149 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4151 os<<L", uptime="<<m_uptime.get();
4152 // Information about clients
4154 for(core::map<u16, RemoteClient*>::Iterator
4155 i = m_clients.getIterator();
4156 i.atEnd() == false; i++)
4158 // Get client and check that it is valid
4159 RemoteClient *client = i.getNode()->getValue();
4160 assert(client->peer_id == i.getNode()->getKey());
4161 if(client->serialization_version == SER_FMT_VER_INVALID)
4164 Player *player = m_env->getPlayer(client->peer_id);
4165 // Get name of player
4166 std::wstring name = L"unknown";
4168 name = narrow_to_wide(player->getName());
4169 // Add name to information string
4173 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4174 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4175 if(g_settings->get("motd") != "")
4176 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4180 u64 Server::getPlayerAuthPrivs(const std::string &name)
4183 return m_authmanager.getPrivs(name);
4185 catch(AuthNotFoundException &e)
4187 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4192 void Server::setPlayerAuthPrivs(const std::string &name, u64 privs)
4195 return m_authmanager.setPrivs(name, privs);
4197 catch(AuthNotFoundException &e)
4199 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4203 u64 Server::getPlayerEffectivePrivs(const std::string &name)
4205 // Local player gets all privileges regardless of
4206 // what's set on their account.
4207 if(m_simple_singleplayer_mode)
4209 if(name == g_settings->get("name"))
4211 return getPlayerAuthPrivs(name);
4214 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4216 // Add player to auth manager
4217 if(m_authmanager.exists(name) == false)
4219 infostream<<"Server: adding player "<<name
4220 <<" to auth manager"<<std::endl;
4221 m_authmanager.add(name);
4222 m_authmanager.setPrivs(name,
4223 stringToPrivs(g_settings->get("default_privs")));
4225 // Change password and save
4226 m_authmanager.setPassword(name, translatePassword(name, password));
4227 m_authmanager.save();
4230 // Saves g_settings to configpath given at initialization
4231 void Server::saveConfig()
4233 if(m_path_config != "")
4234 g_settings->updateConfigFile(m_path_config.c_str());
4237 void Server::notifyPlayer(const char *name, const std::wstring msg)
4239 Player *player = m_env->getPlayer(name);
4242 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4245 void Server::notifyPlayers(const std::wstring msg)
4247 BroadcastChatMessage(msg);
4250 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4254 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4255 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4258 // IGameDef interface
4260 IItemDefManager* Server::getItemDefManager()
4264 INodeDefManager* Server::getNodeDefManager()
4268 ICraftDefManager* Server::getCraftDefManager()
4272 ITextureSource* Server::getTextureSource()
4276 u16 Server::allocateUnknownNodeId(const std::string &name)
4278 return m_nodedef->allocateDummy(name);
4281 IWritableItemDefManager* Server::getWritableItemDefManager()
4285 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4289 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4294 const ModSpec* Server::getModSpec(const std::string &modname)
4296 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4297 i != m_mods.end(); i++){
4298 const ModSpec &mod = *i;
4299 if(mod.name == modname)
4305 v3f findSpawnPos(ServerMap &map)
4307 //return v3f(50,50,50)*BS;
4312 nodepos = v2s16(0,0);
4317 // Try to find a good place a few times
4318 for(s32 i=0; i<1000; i++)
4321 // We're going to try to throw the player to this position
4322 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4323 -range + (myrand()%(range*2)));
4324 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4325 // Get ground height at point (fallbacks to heightmap function)
4326 s16 groundheight = map.findGroundLevel(nodepos2d);
4327 // Don't go underwater
4328 if(groundheight < WATER_LEVEL)
4330 //infostream<<"-> Underwater"<<std::endl;
4333 // Don't go to high places
4334 if(groundheight > WATER_LEVEL + 4)
4336 //infostream<<"-> Underwater"<<std::endl;
4340 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4341 bool is_good = false;
4343 for(s32 i=0; i<10; i++){
4344 v3s16 blockpos = getNodeBlockPos(nodepos);
4345 map.emergeBlock(blockpos, true);
4346 MapNode n = map.getNodeNoEx(nodepos);
4347 if(n.getContent() == CONTENT_AIR){
4358 // Found a good place
4359 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4365 return intToFloat(nodepos, BS);
4368 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4371 Try to get an existing player
4373 ServerRemotePlayer *player =
4374 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4377 // If player is already connected, cancel
4378 if(player->peer_id != 0)
4380 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4385 player->peer_id = peer_id;
4387 // Re-add player to environment
4388 if(player->m_removed)
4390 player->m_removed = false;
4392 m_env->addActiveObject(player);
4395 // Reset inventory to creative if in creative mode
4396 if(g_settings->getBool("creative_mode"))
4398 // Warning: double code below
4399 // Backup actual inventory
4400 player->inventory_backup = new Inventory(m_itemdef);
4401 *(player->inventory_backup) = player->inventory;
4402 // Set creative inventory
4403 player->resetInventory();
4404 scriptapi_get_creative_inventory(m_lua, player);
4411 If player with the wanted peer_id already exists, cancel.
4413 if(m_env->getPlayer(peer_id) != NULL)
4415 infostream<<"emergePlayer(): Player with wrong name but same"
4416 " peer_id already exists"<<std::endl;
4424 /* Set player position */
4426 infostream<<"Server: Finding spawn place for player \""
4427 <<name<<"\""<<std::endl;
4429 v3f pos = findSpawnPos(m_env->getServerMap());
4431 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4432 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4434 /* Add player to environment */
4435 m_env->addPlayer(player);
4436 m_env->addActiveObject(srp);
4439 scriptapi_on_newplayer(m_lua, srp);
4441 /* Add stuff to inventory */
4442 if(g_settings->getBool("creative_mode"))
4444 // Warning: double code above
4445 // Backup actual inventory
4446 player->inventory_backup = new Inventory(m_itemdef);
4447 *(player->inventory_backup) = player->inventory;
4448 // Set creative inventory
4449 player->resetInventory();
4450 scriptapi_get_creative_inventory(m_lua, player);
4455 } // create new player
4458 void Server::handlePeerChange(PeerChange &c)
4460 JMutexAutoLock envlock(m_env_mutex);
4461 JMutexAutoLock conlock(m_con_mutex);
4463 if(c.type == PEER_ADDED)
4470 core::map<u16, RemoteClient*>::Node *n;
4471 n = m_clients.find(c.peer_id);
4472 // The client shouldn't already exist
4476 RemoteClient *client = new RemoteClient();
4477 client->peer_id = c.peer_id;
4478 m_clients.insert(client->peer_id, client);
4481 else if(c.type == PEER_REMOVED)
4488 core::map<u16, RemoteClient*>::Node *n;
4489 n = m_clients.find(c.peer_id);
4490 // The client should exist
4494 Mark objects to be not known by the client
4496 RemoteClient *client = n->getValue();
4498 for(core::map<u16, bool>::Iterator
4499 i = client->m_known_objects.getIterator();
4500 i.atEnd()==false; i++)
4503 u16 id = i.getNode()->getKey();
4504 ServerActiveObject* obj = m_env->getActiveObject(id);
4506 if(obj && obj->m_known_by_count > 0)
4507 obj->m_known_by_count--;
4510 ServerRemotePlayer* player =
4511 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4513 // Collect information about leaving in chat
4514 std::wstring message;
4518 std::wstring name = narrow_to_wide(player->getName());
4521 message += L" left game";
4523 message += L" (timed out)";
4527 // Remove from environment
4529 player->m_removed = true;
4531 // Set player client disconnected
4533 player->peer_id = 0;
4541 std::ostringstream os(std::ios_base::binary);
4542 for(core::map<u16, RemoteClient*>::Iterator
4543 i = m_clients.getIterator();
4544 i.atEnd() == false; i++)
4546 RemoteClient *client = i.getNode()->getValue();
4547 assert(client->peer_id == i.getNode()->getKey());
4548 if(client->serialization_version == SER_FMT_VER_INVALID)
4551 Player *player = m_env->getPlayer(client->peer_id);
4554 // Get name of player
4555 os<<player->getName()<<" ";
4558 actionstream<<player->getName()<<" "
4559 <<(c.timeout?"times out.":"leaves game.")
4560 <<" List of players: "
4561 <<os.str()<<std::endl;
4566 delete m_clients[c.peer_id];
4567 m_clients.remove(c.peer_id);
4569 // Send player info to all remaining clients
4570 //SendPlayerInfos();
4572 // Send leave chat message to all remaining clients
4573 if(message.length() != 0)
4574 BroadcastChatMessage(message);
4583 void Server::handlePeerChanges()
4585 while(m_peer_change_queue.size() > 0)
4587 PeerChange c = m_peer_change_queue.pop_front();
4589 verbosestream<<"Server: Handling peer change: "
4590 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4593 handlePeerChange(c);
4597 u64 Server::getPlayerPrivs(Player *player)
4601 std::string playername = player->getName();
4602 return getPlayerEffectivePrivs(playername);
4605 void dedicated_server_loop(Server &server, bool &kill)
4607 DSTACK(__FUNCTION_NAME);
4609 verbosestream<<"dedicated_server_loop()"<<std::endl;
4611 IntervalLimiter m_profiler_interval;
4615 float steplen = g_settings->getFloat("dedicated_server_step");
4616 // This is kind of a hack but can be done like this
4617 // because server.step() is very light
4619 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4620 sleep_ms((int)(steplen*1000.0));
4622 server.step(steplen);
4624 if(server.getShutdownRequested() || kill)
4626 infostream<<"Dedicated server quitting"<<std::endl;
4633 float profiler_print_interval =
4634 g_settings->getFloat("profiler_print_interval");
4635 if(profiler_print_interval != 0)
4637 if(m_profiler_interval.step(steplen, profiler_print_interval))
4639 infostream<<"Profiler:"<<std::endl;
4640 g_profiler->print(infostream);
4641 g_profiler->clear();