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");
908 // Print out mod search paths
909 for(core::list<std::string>::Iterator i = m_modspaths.begin();
910 i != m_modspaths.end(); i++){
911 std::string modspath = *i;
912 infostream<<"- mods: "<<modspath<<std::endl;
915 // Create world if it doesn't exist
916 if(!initializeWorld(m_path_world, m_gamespec.id))
917 throw ServerError("Failed to initialize world");
920 JMutexAutoLock envlock(m_env_mutex);
921 JMutexAutoLock conlock(m_con_mutex);
923 // Initialize scripting
925 infostream<<"Server: Initializing Lua"<<std::endl;
926 m_lua = script_init();
929 scriptapi_export(m_lua, this);
930 // Load and run builtin.lua
931 infostream<<"Server: Loading builtin.lua [\""
932 <<builtinpath<<"\"]"<<std::endl;
933 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
935 errorstream<<"Server: Failed to load and run "
936 <<builtinpath<<std::endl;
937 throw ModError("Failed to load and run "+builtinpath);
939 // Find mods in mod search paths
940 m_mods = getMods(m_modspaths);
942 infostream<<"Server: Loading mods: ";
943 for(core::list<ModSpec>::Iterator i = m_mods.begin();
944 i != m_mods.end(); i++){
945 const ModSpec &mod = *i;
946 infostream<<mod.name<<" ";
948 infostream<<std::endl;
949 // Load and run "mod" scripts
950 for(core::list<ModSpec>::Iterator i = m_mods.begin();
951 i != m_mods.end(); i++){
952 const ModSpec &mod = *i;
953 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
954 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
955 <<scriptpath<<"\"]"<<std::endl;
956 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
958 errorstream<<"Server: Failed to load and run "
959 <<scriptpath<<std::endl;
960 throw ModError("Failed to load and run "+scriptpath);
964 // Read Textures and calculate sha1 sums
967 // Apply item aliases in the node definition manager
968 m_nodedef->updateAliases(m_itemdef);
970 // Initialize Environment
972 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
975 // Give environment reference to scripting api
976 scriptapi_add_environment(m_lua, m_env);
978 // Register us to receive map edit events
979 m_env->getMap().addEventReceiver(this);
981 // If file exists, load environment metadata
982 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
984 infostream<<"Server: Loading environment metadata"<<std::endl;
985 m_env->loadMeta(m_path_world);
989 infostream<<"Server: Loading players"<<std::endl;
990 m_env->deSerializePlayers(m_path_world);
993 Add some test ActiveBlockModifiers to environment
995 add_legacy_abms(m_env, m_nodedef);
1000 infostream<<"Server destructing"<<std::endl;
1003 Send shutdown message
1006 JMutexAutoLock conlock(m_con_mutex);
1008 std::wstring line = L"*** Server shutting down";
1011 Send the message to clients
1013 for(core::map<u16, RemoteClient*>::Iterator
1014 i = m_clients.getIterator();
1015 i.atEnd() == false; i++)
1017 // Get client and check that it is valid
1018 RemoteClient *client = i.getNode()->getValue();
1019 assert(client->peer_id == i.getNode()->getKey());
1020 if(client->serialization_version == SER_FMT_VER_INVALID)
1024 SendChatMessage(client->peer_id, line);
1026 catch(con::PeerNotFoundException &e)
1032 JMutexAutoLock envlock(m_env_mutex);
1037 infostream<<"Server: Saving players"<<std::endl;
1038 m_env->serializePlayers(m_path_world);
1041 Save environment metadata
1043 infostream<<"Server: Saving environment metadata"<<std::endl;
1044 m_env->saveMeta(m_path_world);
1056 JMutexAutoLock clientslock(m_con_mutex);
1058 for(core::map<u16, RemoteClient*>::Iterator
1059 i = m_clients.getIterator();
1060 i.atEnd() == false; i++)
1063 // NOTE: These are removed by env destructor
1065 u16 peer_id = i.getNode()->getKey();
1066 JMutexAutoLock envlock(m_env_mutex);
1067 m_env->removePlayer(peer_id);
1071 delete i.getNode()->getValue();
1075 // Delete Environment
1082 // Deinitialize scripting
1083 infostream<<"Server: Deinitializing scripting"<<std::endl;
1084 script_deinit(m_lua);
1087 void Server::start(unsigned short port)
1089 DSTACK(__FUNCTION_NAME);
1090 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1092 // Stop thread if already running
1095 // Initialize connection
1096 m_con.SetTimeoutMs(30);
1100 m_thread.setRun(true);
1103 // ASCII art for the win!
1105 <<" .__ __ __ "<<std::endl
1106 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1107 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1108 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1109 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1110 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1111 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1112 actionstream<<"Server for gameid=\""<<m_gamespec.id
1113 <<"\" listening on port "<<port<<"."<<std::endl;
1118 DSTACK(__FUNCTION_NAME);
1120 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1122 // Stop threads (set run=false first so both start stopping)
1123 m_thread.setRun(false);
1124 m_emergethread.setRun(false);
1126 m_emergethread.stop();
1128 infostream<<"Server: Threads stopped"<<std::endl;
1131 void Server::step(float dtime)
1133 DSTACK(__FUNCTION_NAME);
1138 JMutexAutoLock lock(m_step_dtime_mutex);
1139 m_step_dtime += dtime;
1141 // Throw if fatal error occurred in thread
1142 std::string async_err = m_async_fatal_error.get();
1143 if(async_err != ""){
1144 throw ServerError(async_err);
1148 void Server::AsyncRunStep()
1150 DSTACK(__FUNCTION_NAME);
1152 g_profiler->add("Server::AsyncRunStep (num)", 1);
1156 JMutexAutoLock lock1(m_step_dtime_mutex);
1157 dtime = m_step_dtime;
1161 // Send blocks to clients
1168 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1170 //infostream<<"Server steps "<<dtime<<std::endl;
1171 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1174 JMutexAutoLock lock1(m_step_dtime_mutex);
1175 m_step_dtime -= dtime;
1182 m_uptime.set(m_uptime.get() + dtime);
1186 // Process connection's timeouts
1187 JMutexAutoLock lock2(m_con_mutex);
1188 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1189 m_con.RunTimeouts(dtime);
1193 // This has to be called so that the client list gets synced
1194 // with the peer list of the connection
1195 handlePeerChanges();
1199 Update time of day and overall game time
1202 JMutexAutoLock envlock(m_env_mutex);
1204 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1207 Send to clients at constant intervals
1210 m_time_of_day_send_timer -= dtime;
1211 if(m_time_of_day_send_timer < 0.0)
1213 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1215 //JMutexAutoLock envlock(m_env_mutex);
1216 JMutexAutoLock conlock(m_con_mutex);
1218 for(core::map<u16, RemoteClient*>::Iterator
1219 i = m_clients.getIterator();
1220 i.atEnd() == false; i++)
1222 RemoteClient *client = i.getNode()->getValue();
1223 //Player *player = m_env->getPlayer(client->peer_id);
1225 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1226 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1228 m_con.Send(client->peer_id, 0, data, true);
1234 JMutexAutoLock lock(m_env_mutex);
1236 ScopeProfiler sp(g_profiler, "SEnv step");
1237 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1241 const float map_timer_and_unload_dtime = 2.92;
1242 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1244 JMutexAutoLock lock(m_env_mutex);
1245 // Run Map's timers and unload unused data
1246 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1247 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1248 g_settings->getFloat("server_unload_unused_data_timeout"));
1259 JMutexAutoLock lock(m_env_mutex);
1260 JMutexAutoLock lock2(m_con_mutex);
1262 ScopeProfiler sp(g_profiler, "Server: handle players");
1264 //float player_max_speed = BS * 4.0; // Normal speed
1265 float player_max_speed = BS * 20; // Fast speed
1266 float player_max_speed_up = BS * 20;
1268 player_max_speed *= 2.5; // Tolerance
1269 player_max_speed_up *= 2.5;
1271 for(core::map<u16, RemoteClient*>::Iterator
1272 i = m_clients.getIterator();
1273 i.atEnd() == false; i++)
1275 RemoteClient *client = i.getNode()->getValue();
1276 ServerRemotePlayer *player =
1277 static_cast<ServerRemotePlayer*>
1278 (m_env->getPlayer(client->peer_id));
1283 Check player movements
1285 NOTE: Actually the server should handle player physics like the
1286 client does and compare player's position to what is calculated
1287 on our side. This is required when eg. players fly due to an
1290 player->m_last_good_position_age += dtime;
1291 if(player->m_last_good_position_age >= 1.0){
1292 float age = player->m_last_good_position_age;
1293 v3f diff = (player->getPosition() - player->m_last_good_position);
1294 float d_vert = diff.Y;
1296 float d_horiz = diff.getLength();
1297 /*infostream<<player->getName()<<"'s horizontal speed is "
1298 <<(d_horiz/age)<<std::endl;*/
1299 if(d_horiz <= age * player_max_speed &&
1300 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1301 player->m_last_good_position = player->getPosition();
1303 actionstream<<"Player "<<player->getName()
1304 <<" moved too fast; resetting position"
1306 player->setPosition(player->m_last_good_position);
1307 SendMovePlayer(player);
1309 player->m_last_good_position_age = 0;
1313 Handle player HPs (die if hp=0)
1315 if(player->hp == 0 && player->m_hp_not_sent)
1319 Send player inventories and HPs if necessary
1321 if(player->m_inventory_not_sent){
1322 UpdateCrafting(player->peer_id);
1323 SendInventory(player->peer_id);
1325 if(player->m_hp_not_sent){
1326 SendPlayerHP(player);
1332 if(!player->m_is_in_environment){
1333 player->m_removed = false;
1335 m_env->addActiveObject(player);
1340 /* Transform liquids */
1341 m_liquid_transform_timer += dtime;
1342 if(m_liquid_transform_timer >= 1.00)
1344 m_liquid_transform_timer -= 1.00;
1346 JMutexAutoLock lock(m_env_mutex);
1348 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1350 core::map<v3s16, MapBlock*> modified_blocks;
1351 m_env->getMap().transformLiquids(modified_blocks);
1356 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1357 ServerMap &map = ((ServerMap&)m_env->getMap());
1358 map.updateLighting(modified_blocks, lighting_modified_blocks);
1360 // Add blocks modified by lighting to modified_blocks
1361 for(core::map<v3s16, MapBlock*>::Iterator
1362 i = lighting_modified_blocks.getIterator();
1363 i.atEnd() == false; i++)
1365 MapBlock *block = i.getNode()->getValue();
1366 modified_blocks.insert(block->getPos(), block);
1370 Set the modified blocks unsent for all the clients
1373 JMutexAutoLock lock2(m_con_mutex);
1375 for(core::map<u16, RemoteClient*>::Iterator
1376 i = m_clients.getIterator();
1377 i.atEnd() == false; i++)
1379 RemoteClient *client = i.getNode()->getValue();
1381 if(modified_blocks.size() > 0)
1383 // Remove block from sent history
1384 client->SetBlocksNotSent(modified_blocks);
1389 // Periodically print some info
1391 float &counter = m_print_info_timer;
1397 JMutexAutoLock lock2(m_con_mutex);
1399 if(m_clients.size() != 0)
1400 infostream<<"Players:"<<std::endl;
1401 for(core::map<u16, RemoteClient*>::Iterator
1402 i = m_clients.getIterator();
1403 i.atEnd() == false; i++)
1405 //u16 peer_id = i.getNode()->getKey();
1406 RemoteClient *client = i.getNode()->getValue();
1407 Player *player = m_env->getPlayer(client->peer_id);
1410 infostream<<"* "<<player->getName()<<"\t";
1411 client->PrintInfo(infostream);
1416 //if(g_settings->getBool("enable_experimental"))
1420 Check added and deleted active objects
1423 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1424 JMutexAutoLock envlock(m_env_mutex);
1425 JMutexAutoLock conlock(m_con_mutex);
1427 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1429 // Radius inside which objects are active
1430 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1431 radius *= MAP_BLOCKSIZE;
1433 for(core::map<u16, RemoteClient*>::Iterator
1434 i = m_clients.getIterator();
1435 i.atEnd() == false; i++)
1437 RemoteClient *client = i.getNode()->getValue();
1439 // If definitions and textures have not been sent, don't
1440 // send objects either
1441 if(!client->definitions_sent)
1444 Player *player = m_env->getPlayer(client->peer_id);
1447 // This can happen if the client timeouts somehow
1448 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1450 <<" has no associated player"<<std::endl;*/
1453 v3s16 pos = floatToInt(player->getPosition(), BS);
1455 core::map<u16, bool> removed_objects;
1456 core::map<u16, bool> added_objects;
1457 m_env->getRemovedActiveObjects(pos, radius,
1458 client->m_known_objects, removed_objects);
1459 m_env->getAddedActiveObjects(pos, radius,
1460 client->m_known_objects, added_objects);
1462 // Ignore if nothing happened
1463 if(removed_objects.size() == 0 && added_objects.size() == 0)
1465 //infostream<<"active objects: none changed"<<std::endl;
1469 std::string data_buffer;
1473 // Handle removed objects
1474 writeU16((u8*)buf, removed_objects.size());
1475 data_buffer.append(buf, 2);
1476 for(core::map<u16, bool>::Iterator
1477 i = removed_objects.getIterator();
1478 i.atEnd()==false; i++)
1481 u16 id = i.getNode()->getKey();
1482 ServerActiveObject* obj = m_env->getActiveObject(id);
1484 // Add to data buffer for sending
1485 writeU16((u8*)buf, i.getNode()->getKey());
1486 data_buffer.append(buf, 2);
1488 // Remove from known objects
1489 client->m_known_objects.remove(i.getNode()->getKey());
1491 if(obj && obj->m_known_by_count > 0)
1492 obj->m_known_by_count--;
1495 // Handle added objects
1496 writeU16((u8*)buf, added_objects.size());
1497 data_buffer.append(buf, 2);
1498 for(core::map<u16, bool>::Iterator
1499 i = added_objects.getIterator();
1500 i.atEnd()==false; i++)
1503 u16 id = i.getNode()->getKey();
1504 ServerActiveObject* obj = m_env->getActiveObject(id);
1507 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1509 infostream<<"WARNING: "<<__FUNCTION_NAME
1510 <<": NULL object"<<std::endl;
1512 type = obj->getType();
1514 // Add to data buffer for sending
1515 writeU16((u8*)buf, id);
1516 data_buffer.append(buf, 2);
1517 writeU8((u8*)buf, type);
1518 data_buffer.append(buf, 1);
1521 data_buffer.append(serializeLongString(
1522 obj->getClientInitializationData()));
1524 data_buffer.append(serializeLongString(""));
1526 // Add to known objects
1527 client->m_known_objects.insert(i.getNode()->getKey(), false);
1530 obj->m_known_by_count++;
1534 SharedBuffer<u8> reply(2 + data_buffer.size());
1535 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1536 memcpy((char*)&reply[2], data_buffer.c_str(),
1537 data_buffer.size());
1539 m_con.Send(client->peer_id, 0, reply, true);
1541 verbosestream<<"Server: Sent object remove/add: "
1542 <<removed_objects.size()<<" removed, "
1543 <<added_objects.size()<<" added, "
1544 <<"packet size is "<<reply.getSize()<<std::endl;
1549 Collect a list of all the objects known by the clients
1550 and report it back to the environment.
1553 core::map<u16, bool> all_known_objects;
1555 for(core::map<u16, RemoteClient*>::Iterator
1556 i = m_clients.getIterator();
1557 i.atEnd() == false; i++)
1559 RemoteClient *client = i.getNode()->getValue();
1560 // Go through all known objects of client
1561 for(core::map<u16, bool>::Iterator
1562 i = client->m_known_objects.getIterator();
1563 i.atEnd()==false; i++)
1565 u16 id = i.getNode()->getKey();
1566 all_known_objects[id] = true;
1570 m_env->setKnownActiveObjects(whatever);
1576 Send object messages
1579 JMutexAutoLock envlock(m_env_mutex);
1580 JMutexAutoLock conlock(m_con_mutex);
1582 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1585 // Value = data sent by object
1586 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1588 // Get active object messages from environment
1591 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1595 core::list<ActiveObjectMessage>* message_list = NULL;
1596 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1597 n = buffered_messages.find(aom.id);
1600 message_list = new core::list<ActiveObjectMessage>;
1601 buffered_messages.insert(aom.id, message_list);
1605 message_list = n->getValue();
1607 message_list->push_back(aom);
1610 // Route data to every client
1611 for(core::map<u16, RemoteClient*>::Iterator
1612 i = m_clients.getIterator();
1613 i.atEnd()==false; i++)
1615 RemoteClient *client = i.getNode()->getValue();
1616 std::string reliable_data;
1617 std::string unreliable_data;
1618 // Go through all objects in message buffer
1619 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1620 j = buffered_messages.getIterator();
1621 j.atEnd()==false; j++)
1623 // If object is not known by client, skip it
1624 u16 id = j.getNode()->getKey();
1625 if(client->m_known_objects.find(id) == NULL)
1627 // Get message list of object
1628 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1629 // Go through every message
1630 for(core::list<ActiveObjectMessage>::Iterator
1631 k = list->begin(); k != list->end(); k++)
1633 // Compose the full new data with header
1634 ActiveObjectMessage aom = *k;
1635 std::string new_data;
1638 writeU16((u8*)&buf[0], aom.id);
1639 new_data.append(buf, 2);
1641 new_data += serializeString(aom.datastring);
1642 // Add data to buffer
1644 reliable_data += new_data;
1646 unreliable_data += new_data;
1650 reliable_data and unreliable_data are now ready.
1653 if(reliable_data.size() > 0)
1655 SharedBuffer<u8> reply(2 + reliable_data.size());
1656 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1657 memcpy((char*)&reply[2], reliable_data.c_str(),
1658 reliable_data.size());
1660 m_con.Send(client->peer_id, 0, reply, true);
1662 if(unreliable_data.size() > 0)
1664 SharedBuffer<u8> reply(2 + unreliable_data.size());
1665 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1666 memcpy((char*)&reply[2], unreliable_data.c_str(),
1667 unreliable_data.size());
1668 // Send as unreliable
1669 m_con.Send(client->peer_id, 0, reply, false);
1672 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1674 infostream<<"Server: Size of object message data: "
1675 <<"reliable: "<<reliable_data.size()
1676 <<", unreliable: "<<unreliable_data.size()
1681 // Clear buffered_messages
1682 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1683 i = buffered_messages.getIterator();
1684 i.atEnd()==false; i++)
1686 delete i.getNode()->getValue();
1690 } // enable_experimental
1693 Send queued-for-sending map edit events.
1696 // Don't send too many at a time
1699 // Single change sending is disabled if queue size is not small
1700 bool disable_single_change_sending = false;
1701 if(m_unsent_map_edit_queue.size() >= 4)
1702 disable_single_change_sending = true;
1704 int event_count = m_unsent_map_edit_queue.size();
1706 // We'll log the amount of each
1709 while(m_unsent_map_edit_queue.size() != 0)
1711 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1713 // Players far away from the change are stored here.
1714 // Instead of sending the changes, MapBlocks are set not sent
1716 core::list<u16> far_players;
1718 if(event->type == MEET_ADDNODE)
1720 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1721 prof.add("MEET_ADDNODE", 1);
1722 if(disable_single_change_sending)
1723 sendAddNode(event->p, event->n, event->already_known_by_peer,
1726 sendAddNode(event->p, event->n, event->already_known_by_peer,
1729 else if(event->type == MEET_REMOVENODE)
1731 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1732 prof.add("MEET_REMOVENODE", 1);
1733 if(disable_single_change_sending)
1734 sendRemoveNode(event->p, event->already_known_by_peer,
1737 sendRemoveNode(event->p, event->already_known_by_peer,
1740 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1742 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1743 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1744 setBlockNotSent(event->p);
1746 else if(event->type == MEET_OTHER)
1748 infostream<<"Server: MEET_OTHER"<<std::endl;
1749 prof.add("MEET_OTHER", 1);
1750 for(core::map<v3s16, bool>::Iterator
1751 i = event->modified_blocks.getIterator();
1752 i.atEnd()==false; i++)
1754 v3s16 p = i.getNode()->getKey();
1760 prof.add("unknown", 1);
1761 infostream<<"WARNING: Server: Unknown MapEditEvent "
1762 <<((u32)event->type)<<std::endl;
1766 Set blocks not sent to far players
1768 if(far_players.size() > 0)
1770 // Convert list format to that wanted by SetBlocksNotSent
1771 core::map<v3s16, MapBlock*> modified_blocks2;
1772 for(core::map<v3s16, bool>::Iterator
1773 i = event->modified_blocks.getIterator();
1774 i.atEnd()==false; i++)
1776 v3s16 p = i.getNode()->getKey();
1777 modified_blocks2.insert(p,
1778 m_env->getMap().getBlockNoCreateNoEx(p));
1780 // Set blocks not sent
1781 for(core::list<u16>::Iterator
1782 i = far_players.begin();
1783 i != far_players.end(); i++)
1786 RemoteClient *client = getClient(peer_id);
1789 client->SetBlocksNotSent(modified_blocks2);
1795 /*// Don't send too many at a time
1797 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1801 if(event_count >= 5){
1802 infostream<<"Server: MapEditEvents:"<<std::endl;
1803 prof.print(infostream);
1804 } else if(event_count != 0){
1805 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1806 prof.print(verbosestream);
1812 Trigger emergethread (it somehow gets to a non-triggered but
1813 bysy state sometimes)
1816 float &counter = m_emergethread_trigger_timer;
1822 m_emergethread.trigger();
1826 // Save map, players and auth stuff
1828 float &counter = m_savemap_timer;
1830 if(counter >= g_settings->getFloat("server_map_save_interval"))
1833 JMutexAutoLock lock(m_env_mutex);
1835 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1838 if(m_authmanager.isModified())
1839 m_authmanager.save();
1842 if(m_banmanager.isModified())
1843 m_banmanager.save();
1845 // Save changed parts of map
1846 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1849 m_env->serializePlayers(m_path_world);
1851 // Save environment metadata
1852 m_env->saveMeta(m_path_world);
1857 void Server::Receive()
1859 DSTACK(__FUNCTION_NAME);
1860 SharedBuffer<u8> data;
1865 JMutexAutoLock conlock(m_con_mutex);
1866 datasize = m_con.Receive(peer_id, data);
1869 // This has to be called so that the client list gets synced
1870 // with the peer list of the connection
1871 handlePeerChanges();
1873 ProcessData(*data, datasize, peer_id);
1875 catch(con::InvalidIncomingDataException &e)
1877 infostream<<"Server::Receive(): "
1878 "InvalidIncomingDataException: what()="
1879 <<e.what()<<std::endl;
1881 catch(con::PeerNotFoundException &e)
1883 //NOTE: This is not needed anymore
1885 // The peer has been disconnected.
1886 // Find the associated player and remove it.
1888 /*JMutexAutoLock envlock(m_env_mutex);
1890 infostream<<"ServerThread: peer_id="<<peer_id
1891 <<" has apparently closed connection. "
1892 <<"Removing player."<<std::endl;
1894 m_env->removePlayer(peer_id);*/
1898 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1900 DSTACK(__FUNCTION_NAME);
1901 // Environment is locked first.
1902 JMutexAutoLock envlock(m_env_mutex);
1903 JMutexAutoLock conlock(m_con_mutex);
1905 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1908 Address address = m_con.GetPeerAddress(peer_id);
1910 // drop player if is ip is banned
1911 if(m_banmanager.isIpBanned(address.serializeString())){
1912 SendAccessDenied(m_con, peer_id,
1913 L"Your ip is banned. Banned name was "
1914 +narrow_to_wide(m_banmanager.getBanName(
1915 address.serializeString())));
1916 m_con.DeletePeer(peer_id);
1920 catch(con::PeerNotFoundException &e)
1922 infostream<<"Server::ProcessData(): Cancelling: peer "
1923 <<peer_id<<" not found"<<std::endl;
1927 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1929 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1937 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1939 if(command == TOSERVER_INIT)
1941 // [0] u16 TOSERVER_INIT
1942 // [2] u8 SER_FMT_VER_HIGHEST
1943 // [3] u8[20] player_name
1944 // [23] u8[28] password <--- can be sent without this, from old versions
1946 if(datasize < 2+1+PLAYERNAME_SIZE)
1949 verbosestream<<"Server: Got TOSERVER_INIT from "
1950 <<peer_id<<std::endl;
1952 // First byte after command is maximum supported
1953 // serialization version
1954 u8 client_max = data[2];
1955 u8 our_max = SER_FMT_VER_HIGHEST;
1956 // Use the highest version supported by both
1957 u8 deployed = core::min_(client_max, our_max);
1958 // If it's lower than the lowest supported, give up.
1959 if(deployed < SER_FMT_VER_LOWEST)
1960 deployed = SER_FMT_VER_INVALID;
1962 //peer->serialization_version = deployed;
1963 getClient(peer_id)->pending_serialization_version = deployed;
1965 if(deployed == SER_FMT_VER_INVALID)
1967 actionstream<<"Server: A mismatched client tried to connect from "
1968 <<addr_s<<std::endl;
1969 infostream<<"Server: Cannot negotiate "
1970 "serialization version with peer "
1971 <<peer_id<<std::endl;
1972 SendAccessDenied(m_con, peer_id, std::wstring(
1973 L"Your client's version is not supported.\n"
1974 L"Server version is ")
1975 + narrow_to_wide(VERSION_STRING) + L"."
1981 Read and check network protocol version
1984 u16 net_proto_version = 0;
1985 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1987 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1990 getClient(peer_id)->net_proto_version = net_proto_version;
1992 if(net_proto_version == 0)
1994 actionstream<<"Server: An old tried to connect from "<<addr_s
1996 SendAccessDenied(m_con, peer_id, std::wstring(
1997 L"Your client's version is not supported.\n"
1998 L"Server version is ")
1999 + narrow_to_wide(VERSION_STRING) + L"."
2004 if(g_settings->getBool("strict_protocol_version_checking"))
2006 if(net_proto_version != PROTOCOL_VERSION)
2008 actionstream<<"Server: A mismatched client tried to connect"
2009 <<" from "<<addr_s<<std::endl;
2010 SendAccessDenied(m_con, peer_id, std::wstring(
2011 L"Your client's version is not supported.\n"
2012 L"Server version is ")
2013 + narrow_to_wide(VERSION_STRING) + L",\n"
2014 + L"server's PROTOCOL_VERSION is "
2015 + narrow_to_wide(itos(PROTOCOL_VERSION))
2016 + L", client's PROTOCOL_VERSION is "
2017 + narrow_to_wide(itos(net_proto_version))
2028 char playername[PLAYERNAME_SIZE];
2029 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2031 playername[i] = data[3+i];
2033 playername[PLAYERNAME_SIZE-1] = 0;
2035 if(playername[0]=='\0')
2037 actionstream<<"Server: Player with an empty name "
2038 <<"tried to connect from "<<addr_s<<std::endl;
2039 SendAccessDenied(m_con, peer_id,
2044 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2046 actionstream<<"Server: Player with an invalid name "
2047 <<"tried to connect from "<<addr_s<<std::endl;
2048 SendAccessDenied(m_con, peer_id,
2049 L"Name contains unallowed characters");
2053 infostream<<"Server: New connection: \""<<playername<<"\" from "
2054 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2057 char password[PASSWORD_SIZE];
2058 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2060 // old version - assume blank password
2065 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2067 password[i] = data[23+i];
2069 password[PASSWORD_SIZE-1] = 0;
2072 // Add player to auth manager
2073 if(m_authmanager.exists(playername) == false)
2075 std::wstring default_password =
2076 narrow_to_wide(g_settings->get("default_password"));
2077 std::string translated_default_password =
2078 translatePassword(playername, default_password);
2080 // If default_password is empty, allow any initial password
2081 if (default_password.length() == 0)
2082 translated_default_password = password;
2084 infostream<<"Server: adding player "<<playername
2085 <<" to auth manager"<<std::endl;
2086 m_authmanager.add(playername);
2087 m_authmanager.setPassword(playername, translated_default_password);
2088 m_authmanager.setPrivs(playername,
2089 stringToPrivs(g_settings->get("default_privs")));
2090 m_authmanager.save();
2093 std::string checkpwd = m_authmanager.getPassword(playername);
2095 /*infostream<<"Server: Client gave password '"<<password
2096 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2098 if(password != checkpwd)
2100 infostream<<"Server: peer_id="<<peer_id
2101 <<": supplied invalid password for "
2102 <<playername<<std::endl;
2103 SendAccessDenied(m_con, peer_id, L"Invalid password");
2107 // Do not allow multiple players in simple singleplayer mode.
2108 // This isn't a perfect way to do it, but will suffice for now.
2109 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2110 infostream<<"Server: Not allowing another client to connect in"
2111 <<" simple singleplayer mode"<<std::endl;
2112 SendAccessDenied(m_con, peer_id,
2113 L"Running in simple singleplayer mode.");
2117 // Enforce user limit.
2118 // Don't enforce for users that have some admin right
2119 if(m_clients.size() >= g_settings->getU16("max_users") &&
2120 (m_authmanager.getPrivs(playername)
2121 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2122 playername != g_settings->get("name"))
2124 actionstream<<"Server: "<<playername<<" tried to join, but there"
2125 <<" are already max_users="
2126 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2127 SendAccessDenied(m_con, peer_id, L"Too many users.");
2132 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2134 // If failed, cancel
2137 errorstream<<"Server: peer_id="<<peer_id
2138 <<": failed to emerge player"<<std::endl;
2143 Answer with a TOCLIENT_INIT
2146 SharedBuffer<u8> reply(2+1+6+8);
2147 writeU16(&reply[0], TOCLIENT_INIT);
2148 writeU8(&reply[2], deployed);
2149 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2150 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2153 m_con.Send(peer_id, 0, reply, true);
2157 Send complete position information
2159 SendMovePlayer(player);
2164 if(command == TOSERVER_INIT2)
2166 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2167 <<peer_id<<std::endl;
2170 getClient(peer_id)->serialization_version
2171 = getClient(peer_id)->pending_serialization_version;
2174 Send some initialization data
2177 infostream<<"Server: Sending content to "
2178 <<getPlayerName(peer_id)<<std::endl;
2180 // Send item definitions
2181 SendItemDef(m_con, peer_id, m_itemdef);
2183 // Send node definitions
2184 SendNodeDef(m_con, peer_id, m_nodedef);
2186 // Send texture announcement
2187 SendTextureAnnouncement(peer_id);
2189 // Send player info to all players
2190 //SendPlayerInfos();
2192 // Send inventory to player
2193 UpdateCrafting(peer_id);
2194 SendInventory(peer_id);
2196 // Send player items to all players
2199 Player *player = m_env->getPlayer(peer_id);
2202 SendPlayerHP(player);
2204 // Show death screen if necessary
2206 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2210 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2211 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2212 m_con.Send(peer_id, 0, data, true);
2215 // Note things in chat if not in simple singleplayer mode
2216 if(!m_simple_singleplayer_mode)
2218 // Send information about server to player in chat
2219 SendChatMessage(peer_id, getStatusString());
2221 // Send information about joining in chat
2223 std::wstring name = L"unknown";
2224 Player *player = m_env->getPlayer(peer_id);
2226 name = narrow_to_wide(player->getName());
2228 std::wstring message;
2231 message += L" joined game";
2232 BroadcastChatMessage(message);
2236 // Warnings about protocol version can be issued here
2237 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2239 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2246 std::ostringstream os(std::ios_base::binary);
2247 for(core::map<u16, RemoteClient*>::Iterator
2248 i = m_clients.getIterator();
2249 i.atEnd() == false; i++)
2251 RemoteClient *client = i.getNode()->getValue();
2252 assert(client->peer_id == i.getNode()->getKey());
2253 if(client->serialization_version == SER_FMT_VER_INVALID)
2256 Player *player = m_env->getPlayer(client->peer_id);
2259 // Get name of player
2260 os<<player->getName()<<" ";
2263 actionstream<<player->getName()<<" joins game. List of players: "
2264 <<os.str()<<std::endl;
2270 if(peer_ser_ver == SER_FMT_VER_INVALID)
2272 infostream<<"Server::ProcessData(): Cancelling: Peer"
2273 " serialization format invalid or not initialized."
2274 " Skipping incoming command="<<command<<std::endl;
2278 Player *player = m_env->getPlayer(peer_id);
2279 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2282 infostream<<"Server::ProcessData(): Cancelling: "
2283 "No player for peer_id="<<peer_id
2287 if(command == TOSERVER_PLAYERPOS)
2289 if(datasize < 2+12+12+4+4)
2293 v3s32 ps = readV3S32(&data[start+2]);
2294 v3s32 ss = readV3S32(&data[start+2+12]);
2295 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2296 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2297 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2298 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2299 pitch = wrapDegrees(pitch);
2300 yaw = wrapDegrees(yaw);
2302 player->setPosition(position);
2303 player->setSpeed(speed);
2304 player->setPitch(pitch);
2305 player->setYaw(yaw);
2307 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2308 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2309 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2311 else if(command == TOSERVER_GOTBLOCKS)
2324 u16 count = data[2];
2325 for(u16 i=0; i<count; i++)
2327 if((s16)datasize < 2+1+(i+1)*6)
2328 throw con::InvalidIncomingDataException
2329 ("GOTBLOCKS length is too short");
2330 v3s16 p = readV3S16(&data[2+1+i*6]);
2331 /*infostream<<"Server: GOTBLOCKS ("
2332 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2333 RemoteClient *client = getClient(peer_id);
2334 client->GotBlock(p);
2337 else if(command == TOSERVER_DELETEDBLOCKS)
2350 u16 count = data[2];
2351 for(u16 i=0; i<count; i++)
2353 if((s16)datasize < 2+1+(i+1)*6)
2354 throw con::InvalidIncomingDataException
2355 ("DELETEDBLOCKS length is too short");
2356 v3s16 p = readV3S16(&data[2+1+i*6]);
2357 /*infostream<<"Server: DELETEDBLOCKS ("
2358 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2359 RemoteClient *client = getClient(peer_id);
2360 client->SetBlockNotSent(p);
2363 else if(command == TOSERVER_CLICK_OBJECT)
2365 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2368 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2370 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2373 else if(command == TOSERVER_GROUND_ACTION)
2375 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2379 else if(command == TOSERVER_RELEASE)
2381 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2384 else if(command == TOSERVER_SIGNTEXT)
2386 infostream<<"Server: SIGNTEXT not supported anymore"
2390 else if(command == TOSERVER_SIGNNODETEXT)
2392 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2400 std::string datastring((char*)&data[2], datasize-2);
2401 std::istringstream is(datastring, std::ios_base::binary);
2404 is.read((char*)buf, 6);
2405 v3s16 p = readV3S16(buf);
2406 is.read((char*)buf, 2);
2407 u16 textlen = readU16(buf);
2409 for(u16 i=0; i<textlen; i++)
2411 is.read((char*)buf, 1);
2412 text += (char)buf[0];
2415 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2419 meta->setText(text);
2421 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2422 <<" at "<<PP(p)<<std::endl;
2424 v3s16 blockpos = getNodeBlockPos(p);
2425 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2428 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2432 setBlockNotSent(blockpos);
2434 else if(command == TOSERVER_INVENTORY_ACTION)
2436 // Strip command and create a stream
2437 std::string datastring((char*)&data[2], datasize-2);
2438 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2439 std::istringstream is(datastring, std::ios_base::binary);
2441 InventoryAction *a = InventoryAction::deSerialize(is);
2444 infostream<<"TOSERVER_INVENTORY_ACTION: "
2445 <<"InventoryAction::deSerialize() returned NULL"
2451 Note: Always set inventory not sent, to repair cases
2452 where the client made a bad prediction.
2456 Handle restrictions and special cases of the move action
2458 if(a->getType() == IACTION_MOVE)
2460 IMoveAction *ma = (IMoveAction*)a;
2462 ma->from_inv.applyCurrentPlayer(player->getName());
2463 ma->to_inv.applyCurrentPlayer(player->getName());
2465 setInventoryModified(ma->from_inv);
2466 setInventoryModified(ma->to_inv);
2468 bool from_inv_is_current_player =
2469 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2470 (ma->from_inv.name == player->getName());
2472 bool to_inv_is_current_player =
2473 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2474 (ma->to_inv.name == player->getName());
2477 Disable moving items out of craftpreview
2479 if(ma->from_list == "craftpreview")
2481 infostream<<"Ignoring IMoveAction from "
2482 <<(ma->from_inv.dump())<<":"<<ma->from_list
2483 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2484 <<" because src is "<<ma->from_list<<std::endl;
2490 Disable moving items into craftresult and craftpreview
2492 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2494 infostream<<"Ignoring IMoveAction from "
2495 <<(ma->from_inv.dump())<<":"<<ma->from_list
2496 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2497 <<" because dst is "<<ma->to_list<<std::endl;
2502 // Disallow moving items in elsewhere than player's inventory
2503 // if not allowed to interact
2504 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2505 && (!from_inv_is_current_player
2506 || !to_inv_is_current_player))
2508 infostream<<"Cannot move outside of player's inventory: "
2509 <<"No interact privilege"<<std::endl;
2514 // If player is not an admin, check for ownership of src and dst
2515 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2517 std::string owner_from = getInventoryOwner(ma->from_inv);
2518 if(owner_from != "" && owner_from != player->getName())
2520 infostream<<"WARNING: "<<player->getName()
2521 <<" tried to access an inventory that"
2522 <<" belongs to "<<owner_from<<std::endl;
2527 std::string owner_to = getInventoryOwner(ma->to_inv);
2528 if(owner_to != "" && owner_to != player->getName())
2530 infostream<<"WARNING: "<<player->getName()
2531 <<" tried to access an inventory that"
2532 <<" belongs to "<<owner_to<<std::endl;
2539 Handle restrictions and special cases of the drop action
2541 else if(a->getType() == IACTION_DROP)
2543 IDropAction *da = (IDropAction*)a;
2545 da->from_inv.applyCurrentPlayer(player->getName());
2547 setInventoryModified(da->from_inv);
2549 // Disallow dropping items if not allowed to interact
2550 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2555 // If player is not an admin, check for ownership
2556 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2558 std::string owner_from = getInventoryOwner(da->from_inv);
2559 if(owner_from != "" && owner_from != player->getName())
2561 infostream<<"WARNING: "<<player->getName()
2562 <<" tried to access an inventory that"
2563 <<" belongs to "<<owner_from<<std::endl;
2570 Handle restrictions and special cases of the craft action
2572 else if(a->getType() == IACTION_CRAFT)
2574 ICraftAction *ca = (ICraftAction*)a;
2576 ca->craft_inv.applyCurrentPlayer(player->getName());
2578 setInventoryModified(ca->craft_inv);
2580 //bool craft_inv_is_current_player =
2581 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2582 // (ca->craft_inv.name == player->getName());
2584 // Disallow crafting if not allowed to interact
2585 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2587 infostream<<"Cannot craft: "
2588 <<"No interact privilege"<<std::endl;
2593 // If player is not an admin, check for ownership of inventory
2594 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2596 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2597 if(owner_craft != "" && owner_craft != player->getName())
2599 infostream<<"WARNING: "<<player->getName()
2600 <<" tried to access an inventory that"
2601 <<" belongs to "<<owner_craft<<std::endl;
2609 a->apply(this, srp, this);
2613 else if(command == TOSERVER_CHAT_MESSAGE)
2621 std::string datastring((char*)&data[2], datasize-2);
2622 std::istringstream is(datastring, std::ios_base::binary);
2625 is.read((char*)buf, 2);
2626 u16 len = readU16(buf);
2628 std::wstring message;
2629 for(u16 i=0; i<len; i++)
2631 is.read((char*)buf, 2);
2632 message += (wchar_t)readU16(buf);
2635 // Get player name of this client
2636 std::wstring name = narrow_to_wide(player->getName());
2639 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2640 wide_to_narrow(message));
2641 // If script ate the message, don't proceed
2645 // Line to send to players
2647 // Whether to send to the player that sent the line
2648 bool send_to_sender = false;
2649 // Whether to send to other players
2650 bool send_to_others = false;
2652 // Local player gets all privileges regardless of
2653 // what's set on their account.
2654 u64 privs = getPlayerPrivs(player);
2657 if(message[0] == L'/')
2659 size_t strip_size = 1;
2660 if (message[1] == L'#') // support old-style commans
2662 message = message.substr(strip_size);
2664 WStrfnd f1(message);
2665 f1.next(L" "); // Skip over /#whatever
2666 std::wstring paramstring = f1.next(L"");
2668 ServerCommandContext *ctx = new ServerCommandContext(
2669 str_split(message, L' '),
2676 std::wstring reply(processServerCommand(ctx));
2677 send_to_sender = ctx->flags & SEND_TO_SENDER;
2678 send_to_others = ctx->flags & SEND_TO_OTHERS;
2680 if (ctx->flags & SEND_NO_PREFIX)
2683 line += L"Server: " + reply;
2690 if(privs & PRIV_SHOUT)
2696 send_to_others = true;
2700 line += L"Server: You are not allowed to shout";
2701 send_to_sender = true;
2708 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2711 Send the message to clients
2713 for(core::map<u16, RemoteClient*>::Iterator
2714 i = m_clients.getIterator();
2715 i.atEnd() == false; i++)
2717 // Get client and check that it is valid
2718 RemoteClient *client = i.getNode()->getValue();
2719 assert(client->peer_id == i.getNode()->getKey());
2720 if(client->serialization_version == SER_FMT_VER_INVALID)
2724 bool sender_selected = (peer_id == client->peer_id);
2725 if(sender_selected == true && send_to_sender == false)
2727 if(sender_selected == false && send_to_others == false)
2730 SendChatMessage(client->peer_id, line);
2734 else if(command == TOSERVER_DAMAGE)
2736 std::string datastring((char*)&data[2], datasize-2);
2737 std::istringstream is(datastring, std::ios_base::binary);
2738 u8 damage = readU8(is);
2740 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2742 if(g_settings->getBool("enable_damage"))
2744 actionstream<<player->getName()<<" damaged by "
2745 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2748 srp->setHP(srp->getHP() - damage);
2750 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2753 if(srp->m_hp_not_sent)
2754 SendPlayerHP(player);
2758 // Force send (to correct the client's predicted HP)
2759 SendPlayerHP(player);
2762 else if(command == TOSERVER_PASSWORD)
2765 [0] u16 TOSERVER_PASSWORD
2766 [2] u8[28] old password
2767 [30] u8[28] new password
2770 if(datasize != 2+PASSWORD_SIZE*2)
2772 /*char password[PASSWORD_SIZE];
2773 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2774 password[i] = data[2+i];
2775 password[PASSWORD_SIZE-1] = 0;*/
2777 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2785 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2787 char c = data[2+PASSWORD_SIZE+i];
2793 infostream<<"Server: Client requests a password change from "
2794 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2796 std::string playername = player->getName();
2798 if(m_authmanager.exists(playername) == false)
2800 infostream<<"Server: playername not found in authmanager"<<std::endl;
2801 // Wrong old password supplied!!
2802 SendChatMessage(peer_id, L"playername not found in authmanager");
2806 std::string checkpwd = m_authmanager.getPassword(playername);
2808 if(oldpwd != checkpwd)
2810 infostream<<"Server: invalid old password"<<std::endl;
2811 // Wrong old password supplied!!
2812 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2816 actionstream<<player->getName()<<" changes password"<<std::endl;
2818 m_authmanager.setPassword(playername, newpwd);
2820 infostream<<"Server: password change successful for "<<playername
2822 SendChatMessage(peer_id, L"Password change successful");
2824 else if(command == TOSERVER_PLAYERITEM)
2829 u16 item = readU16(&data[2]);
2830 srp->setWieldIndex(item);
2831 SendWieldedItem(srp);
2833 else if(command == TOSERVER_RESPAWN)
2838 RespawnPlayer(player);
2840 actionstream<<player->getName()<<" respawns at "
2841 <<PP(player->getPosition()/BS)<<std::endl;
2843 // ActiveObject is added to environment in AsyncRunStep after
2844 // the previous addition has been succesfully removed
2846 else if(command == TOSERVER_REQUEST_TEXTURES) {
2847 std::string datastring((char*)&data[2], datasize-2);
2848 std::istringstream is(datastring, std::ios_base::binary);
2851 core::list<TextureRequest> tosend;
2852 u16 numtextures = readU16(is);
2854 infostream<<"Sending "<<numtextures<<" textures to "
2855 <<getPlayerName(peer_id)<<std::endl;
2856 verbosestream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2858 for(int i = 0; i < numtextures; i++) {
2859 std::string name = deSerializeString(is);
2860 tosend.push_back(TextureRequest(name));
2861 verbosestream<<"TOSERVER_REQUEST_TEXTURES: requested texture "
2865 SendTexturesRequested(peer_id, tosend);
2867 // Now the client should know about everything
2868 // (definitions and textures)
2869 getClient(peer_id)->definitions_sent = true;
2871 else if(command == TOSERVER_INTERACT)
2873 std::string datastring((char*)&data[2], datasize-2);
2874 std::istringstream is(datastring, std::ios_base::binary);
2880 [5] u32 length of the next item
2881 [9] serialized PointedThing
2883 0: start digging (from undersurface) or use
2884 1: stop digging (all parameters ignored)
2885 2: digging completed
2886 3: place block or item (to abovesurface)
2889 u8 action = readU8(is);
2890 u16 item_i = readU16(is);
2891 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2892 PointedThing pointed;
2893 pointed.deSerialize(tmp_is);
2895 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2896 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2900 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2901 <<" tried to interact, but is dead!"<<std::endl;
2905 v3f player_pos = srp->m_last_good_position;
2907 // Update wielded item
2908 if(srp->getWieldIndex() != item_i)
2910 srp->setWieldIndex(item_i);
2911 SendWieldedItem(srp);
2914 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2915 v3s16 p_under = pointed.node_undersurface;
2916 v3s16 p_above = pointed.node_abovesurface;
2918 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2919 ServerActiveObject *pointed_object = NULL;
2920 if(pointed.type == POINTEDTHING_OBJECT)
2922 pointed_object = m_env->getActiveObject(pointed.object_id);
2923 if(pointed_object == NULL)
2925 verbosestream<<"TOSERVER_INTERACT: "
2926 "pointed object is NULL"<<std::endl;
2932 v3f pointed_pos_under = player_pos;
2933 v3f pointed_pos_above = player_pos;
2934 if(pointed.type == POINTEDTHING_NODE)
2936 pointed_pos_under = intToFloat(p_under, BS);
2937 pointed_pos_above = intToFloat(p_above, BS);
2939 else if(pointed.type == POINTEDTHING_OBJECT)
2941 pointed_pos_under = pointed_object->getBasePosition();
2942 pointed_pos_above = pointed_pos_under;
2946 Check that target is reasonably close
2947 (only when digging or placing things)
2949 if(action == 0 || action == 2 || action == 3)
2951 float d = player_pos.getDistanceFrom(pointed_pos_under);
2952 float max_d = BS * 14; // Just some large enough value
2954 actionstream<<"Player "<<player->getName()
2955 <<" tried to access "<<pointed.dump()
2957 <<"d="<<d<<", max_d="<<max_d
2958 <<". ignoring."<<std::endl;
2959 // Re-send block to revert change on client-side
2960 RemoteClient *client = getClient(peer_id);
2961 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2962 client->SetBlockNotSent(blockpos);
2969 Make sure the player is allowed to do it
2971 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2973 infostream<<"Ignoring interaction from player "<<player->getName()
2974 <<" because privileges are "<<getPlayerPrivs(player)
2980 0: start digging or punch object
2984 if(pointed.type == POINTEDTHING_NODE)
2987 NOTE: This can be used in the future to check if
2988 somebody is cheating, by checking the timing.
2990 MapNode n(CONTENT_IGNORE);
2993 n = m_env->getMap().getNode(p_under);
2995 catch(InvalidPositionException &e)
2997 infostream<<"Server: Not punching: Node not found."
2998 <<" Adding block to emerge queue."
3000 m_emerge_queue.addBlock(peer_id,
3001 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3003 if(n.getContent() != CONTENT_IGNORE)
3004 scriptapi_node_on_punch(m_lua, p_under, n, srp);
3006 else if(pointed.type == POINTEDTHING_OBJECT)
3008 // Skip if object has been removed
3009 if(pointed_object->m_removed)
3012 actionstream<<player->getName()<<" punches object "
3013 <<pointed.object_id<<": "
3014 <<pointed_object->getDescription()<<std::endl;
3016 ItemStack punchitem = srp->getWieldedItem();
3017 ToolCapabilities toolcap =
3018 punchitem.getToolCapabilities(m_itemdef);
3019 v3f dir = (pointed_object->getBasePosition() -
3020 (srp->getPosition() + srp->getEyeOffset())
3022 pointed_object->punch(dir, &toolcap, srp,
3023 srp->m_time_from_last_punch);
3024 srp->m_time_from_last_punch = 0;
3032 else if(action == 1)
3037 2: Digging completed
3039 else if(action == 2)
3041 // Only complete digging of nodes
3042 if(pointed.type == POINTEDTHING_NODE)
3044 MapNode n(CONTENT_IGNORE);
3047 n = m_env->getMap().getNode(p_under);
3049 catch(InvalidPositionException &e)
3051 infostream<<"Server: Not finishing digging: Node not found."
3052 <<" Adding block to emerge queue."
3054 m_emerge_queue.addBlock(peer_id,
3055 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3057 if(n.getContent() != CONTENT_IGNORE)
3058 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3063 3: place block or right-click object
3065 else if(action == 3)
3067 ItemStack item = srp->getWieldedItem();
3069 // Reset build time counter
3070 if(pointed.type == POINTEDTHING_NODE &&
3071 item.getDefinition(m_itemdef).type == ITEM_NODE)
3072 getClient(peer_id)->m_time_from_building = 0.0;
3074 if(pointed.type == POINTEDTHING_OBJECT)
3076 // Right click object
3078 // Skip if object has been removed
3079 if(pointed_object->m_removed)
3082 actionstream<<player->getName()<<" right-clicks object "
3083 <<pointed.object_id<<": "
3084 <<pointed_object->getDescription()<<std::endl;
3087 pointed_object->rightClick(srp);
3089 else if(scriptapi_item_on_place(m_lua,
3090 item, srp, pointed))
3092 // Placement was handled in lua
3094 // Apply returned ItemStack
3095 if(g_settings->getBool("creative_mode") == false)
3096 srp->setWieldedItem(item);
3104 else if(action == 4)
3106 ItemStack item = srp->getWieldedItem();
3108 actionstream<<player->getName()<<" uses "<<item.name
3109 <<", pointing at "<<pointed.dump()<<std::endl;
3111 if(scriptapi_item_on_use(m_lua,
3112 item, srp, pointed))
3114 // Apply returned ItemStack
3115 if(g_settings->getBool("creative_mode") == false)
3116 srp->setWieldedItem(item);
3122 Catch invalid actions
3126 infostream<<"WARNING: Server: Invalid action "
3127 <<action<<std::endl;
3132 infostream<<"Server::ProcessData(): Ignoring "
3133 "unknown command "<<command<<std::endl;
3137 catch(SendFailedException &e)
3139 errorstream<<"Server::ProcessData(): SendFailedException: "
3145 void Server::onMapEditEvent(MapEditEvent *event)
3147 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3148 if(m_ignore_map_edit_events)
3150 MapEditEvent *e = event->clone();
3151 m_unsent_map_edit_queue.push_back(e);
3154 Inventory* Server::getInventory(const InventoryLocation &loc)
3157 case InventoryLocation::UNDEFINED:
3160 case InventoryLocation::CURRENT_PLAYER:
3163 case InventoryLocation::PLAYER:
3165 Player *player = m_env->getPlayer(loc.name.c_str());
3168 return &player->inventory;
3171 case InventoryLocation::NODEMETA:
3173 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3176 return meta->getInventory();
3184 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3187 case InventoryLocation::UNDEFINED:
3190 case InventoryLocation::CURRENT_PLAYER:
3193 case InventoryLocation::PLAYER:
3198 case InventoryLocation::NODEMETA:
3200 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3203 return meta->getOwner();
3211 void Server::setInventoryModified(const InventoryLocation &loc)
3214 case InventoryLocation::UNDEFINED:
3217 case InventoryLocation::PLAYER:
3219 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3220 (m_env->getPlayer(loc.name.c_str()));
3223 srp->m_inventory_not_sent = true;
3226 case InventoryLocation::NODEMETA:
3228 v3s16 blockpos = getNodeBlockPos(loc.p);
3230 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3232 meta->inventoryModified();
3234 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3236 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3238 setBlockNotSent(blockpos);
3246 core::list<PlayerInfo> Server::getPlayerInfo()
3248 DSTACK(__FUNCTION_NAME);
3249 JMutexAutoLock envlock(m_env_mutex);
3250 JMutexAutoLock conlock(m_con_mutex);
3252 core::list<PlayerInfo> list;
3254 core::list<Player*> players = m_env->getPlayers();
3256 core::list<Player*>::Iterator i;
3257 for(i = players.begin();
3258 i != players.end(); i++)
3262 Player *player = *i;
3265 // Copy info from connection to info struct
3266 info.id = player->peer_id;
3267 info.address = m_con.GetPeerAddress(player->peer_id);
3268 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3270 catch(con::PeerNotFoundException &e)
3272 // Set dummy peer info
3274 info.address = Address(0,0,0,0,0);
3278 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3279 info.position = player->getPosition();
3281 list.push_back(info);
3288 void Server::peerAdded(con::Peer *peer)
3290 DSTACK(__FUNCTION_NAME);
3291 verbosestream<<"Server::peerAdded(): peer->id="
3292 <<peer->id<<std::endl;
3295 c.type = PEER_ADDED;
3296 c.peer_id = peer->id;
3298 m_peer_change_queue.push_back(c);
3301 void Server::deletingPeer(con::Peer *peer, bool timeout)
3303 DSTACK(__FUNCTION_NAME);
3304 verbosestream<<"Server::deletingPeer(): peer->id="
3305 <<peer->id<<", timeout="<<timeout<<std::endl;
3308 c.type = PEER_REMOVED;
3309 c.peer_id = peer->id;
3310 c.timeout = timeout;
3311 m_peer_change_queue.push_back(c);
3318 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3320 DSTACK(__FUNCTION_NAME);
3321 std::ostringstream os(std::ios_base::binary);
3323 writeU16(os, TOCLIENT_HP);
3327 std::string s = os.str();
3328 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3330 con.Send(peer_id, 0, data, true);
3333 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3334 const std::wstring &reason)
3336 DSTACK(__FUNCTION_NAME);
3337 std::ostringstream os(std::ios_base::binary);
3339 writeU16(os, TOCLIENT_ACCESS_DENIED);
3340 os<<serializeWideString(reason);
3343 std::string s = os.str();
3344 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3346 con.Send(peer_id, 0, data, true);
3349 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3350 bool set_camera_point_target, v3f camera_point_target)
3352 DSTACK(__FUNCTION_NAME);
3353 std::ostringstream os(std::ios_base::binary);
3355 writeU16(os, TOCLIENT_DEATHSCREEN);
3356 writeU8(os, set_camera_point_target);
3357 writeV3F1000(os, camera_point_target);
3360 std::string s = os.str();
3361 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3363 con.Send(peer_id, 0, data, true);
3366 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3367 IItemDefManager *itemdef)
3369 DSTACK(__FUNCTION_NAME);
3370 std::ostringstream os(std::ios_base::binary);
3374 u32 length of the next item
3375 zlib-compressed serialized ItemDefManager
3377 writeU16(os, TOCLIENT_ITEMDEF);
3378 std::ostringstream tmp_os(std::ios::binary);
3379 itemdef->serialize(tmp_os);
3380 std::ostringstream tmp_os2(std::ios::binary);
3381 compressZlib(tmp_os.str(), tmp_os2);
3382 os<<serializeLongString(tmp_os2.str());
3385 std::string s = os.str();
3386 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3387 <<"): size="<<s.size()<<std::endl;
3388 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3390 con.Send(peer_id, 0, data, true);
3393 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3394 INodeDefManager *nodedef)
3396 DSTACK(__FUNCTION_NAME);
3397 std::ostringstream os(std::ios_base::binary);
3401 u32 length of the next item
3402 zlib-compressed serialized NodeDefManager
3404 writeU16(os, TOCLIENT_NODEDEF);
3405 std::ostringstream tmp_os(std::ios::binary);
3406 nodedef->serialize(tmp_os);
3407 std::ostringstream tmp_os2(std::ios::binary);
3408 compressZlib(tmp_os.str(), tmp_os2);
3409 os<<serializeLongString(tmp_os2.str());
3412 std::string s = os.str();
3413 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3414 <<"): size="<<s.size()<<std::endl;
3415 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3417 con.Send(peer_id, 0, data, true);
3421 Non-static send methods
3424 void Server::SendInventory(u16 peer_id)
3426 DSTACK(__FUNCTION_NAME);
3428 ServerRemotePlayer* player =
3429 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3432 player->m_inventory_not_sent = false;
3438 std::ostringstream os;
3439 //os.imbue(std::locale("C"));
3441 player->inventory.serialize(os);
3443 std::string s = os.str();
3445 SharedBuffer<u8> data(s.size()+2);
3446 writeU16(&data[0], TOCLIENT_INVENTORY);
3447 memcpy(&data[2], s.c_str(), s.size());
3450 m_con.Send(peer_id, 0, data, true);
3453 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3455 DSTACK(__FUNCTION_NAME);
3459 std::ostringstream os(std::ios_base::binary);
3461 writeU16(os, TOCLIENT_PLAYERITEM);
3463 writeU16(os, srp->peer_id);
3464 os<<serializeString(srp->getWieldedItem().getItemString());
3467 std::string s = os.str();
3468 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3470 m_con.SendToAll(0, data, true);
3473 void Server::SendPlayerItems()
3475 DSTACK(__FUNCTION_NAME);
3477 std::ostringstream os(std::ios_base::binary);
3478 core::list<Player *> players = m_env->getPlayers(true);
3480 writeU16(os, TOCLIENT_PLAYERITEM);
3481 writeU16(os, players.size());
3482 core::list<Player *>::Iterator i;
3483 for(i = players.begin(); i != players.end(); ++i)
3486 ServerRemotePlayer *srp =
3487 static_cast<ServerRemotePlayer*>(p);
3488 writeU16(os, p->peer_id);
3489 os<<serializeString(srp->getWieldedItem().getItemString());
3493 std::string s = os.str();
3494 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3496 m_con.SendToAll(0, data, true);
3499 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3501 DSTACK(__FUNCTION_NAME);
3503 std::ostringstream os(std::ios_base::binary);
3507 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3508 os.write((char*)buf, 2);
3511 writeU16(buf, message.size());
3512 os.write((char*)buf, 2);
3515 for(u32 i=0; i<message.size(); i++)
3519 os.write((char*)buf, 2);
3523 std::string s = os.str();
3524 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3526 m_con.Send(peer_id, 0, data, true);
3529 void Server::BroadcastChatMessage(const std::wstring &message)
3531 for(core::map<u16, RemoteClient*>::Iterator
3532 i = m_clients.getIterator();
3533 i.atEnd() == false; i++)
3535 // Get client and check that it is valid
3536 RemoteClient *client = i.getNode()->getValue();
3537 assert(client->peer_id == i.getNode()->getKey());
3538 if(client->serialization_version == SER_FMT_VER_INVALID)
3541 SendChatMessage(client->peer_id, message);
3545 void Server::SendPlayerHP(Player *player)
3547 SendHP(m_con, player->peer_id, player->hp);
3548 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3551 void Server::SendMovePlayer(Player *player)
3553 DSTACK(__FUNCTION_NAME);
3554 std::ostringstream os(std::ios_base::binary);
3556 writeU16(os, TOCLIENT_MOVE_PLAYER);
3557 writeV3F1000(os, player->getPosition());
3558 writeF1000(os, player->getPitch());
3559 writeF1000(os, player->getYaw());
3562 v3f pos = player->getPosition();
3563 f32 pitch = player->getPitch();
3564 f32 yaw = player->getYaw();
3565 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3566 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3573 std::string s = os.str();
3574 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3576 m_con.Send(player->peer_id, 0, data, true);
3579 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3580 core::list<u16> *far_players, float far_d_nodes)
3582 float maxd = far_d_nodes*BS;
3583 v3f p_f = intToFloat(p, BS);
3587 SharedBuffer<u8> reply(replysize);
3588 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3589 writeS16(&reply[2], p.X);
3590 writeS16(&reply[4], p.Y);
3591 writeS16(&reply[6], p.Z);
3593 for(core::map<u16, RemoteClient*>::Iterator
3594 i = m_clients.getIterator();
3595 i.atEnd() == false; i++)
3597 // Get client and check that it is valid
3598 RemoteClient *client = i.getNode()->getValue();
3599 assert(client->peer_id == i.getNode()->getKey());
3600 if(client->serialization_version == SER_FMT_VER_INVALID)
3603 // Don't send if it's the same one
3604 if(client->peer_id == ignore_id)
3610 Player *player = m_env->getPlayer(client->peer_id);
3613 // If player is far away, only set modified blocks not sent
3614 v3f player_pos = player->getPosition();
3615 if(player_pos.getDistanceFrom(p_f) > maxd)
3617 far_players->push_back(client->peer_id);
3624 m_con.Send(client->peer_id, 0, reply, true);
3628 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3629 core::list<u16> *far_players, float far_d_nodes)
3631 float maxd = far_d_nodes*BS;
3632 v3f p_f = intToFloat(p, BS);
3634 for(core::map<u16, RemoteClient*>::Iterator
3635 i = m_clients.getIterator();
3636 i.atEnd() == false; i++)
3638 // Get client and check that it is valid
3639 RemoteClient *client = i.getNode()->getValue();
3640 assert(client->peer_id == i.getNode()->getKey());
3641 if(client->serialization_version == SER_FMT_VER_INVALID)
3644 // Don't send if it's the same one
3645 if(client->peer_id == ignore_id)
3651 Player *player = m_env->getPlayer(client->peer_id);
3654 // If player is far away, only set modified blocks not sent
3655 v3f player_pos = player->getPosition();
3656 if(player_pos.getDistanceFrom(p_f) > maxd)
3658 far_players->push_back(client->peer_id);
3665 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3666 SharedBuffer<u8> reply(replysize);
3667 writeU16(&reply[0], TOCLIENT_ADDNODE);
3668 writeS16(&reply[2], p.X);
3669 writeS16(&reply[4], p.Y);
3670 writeS16(&reply[6], p.Z);
3671 n.serialize(&reply[8], client->serialization_version);
3674 m_con.Send(client->peer_id, 0, reply, true);
3678 void Server::setBlockNotSent(v3s16 p)
3680 for(core::map<u16, RemoteClient*>::Iterator
3681 i = m_clients.getIterator();
3682 i.atEnd()==false; i++)
3684 RemoteClient *client = i.getNode()->getValue();
3685 client->SetBlockNotSent(p);
3689 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3691 DSTACK(__FUNCTION_NAME);
3693 v3s16 p = block->getPos();
3697 bool completely_air = true;
3698 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3699 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3700 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3702 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3704 completely_air = false;
3705 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3710 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3712 infostream<<"[completely air] ";
3713 infostream<<std::endl;
3717 Create a packet with the block in the right format
3720 std::ostringstream os(std::ios_base::binary);
3721 block->serialize(os, ver, false);
3722 std::string s = os.str();
3723 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3725 u32 replysize = 8 + blockdata.getSize();
3726 SharedBuffer<u8> reply(replysize);
3727 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3728 writeS16(&reply[2], p.X);
3729 writeS16(&reply[4], p.Y);
3730 writeS16(&reply[6], p.Z);
3731 memcpy(&reply[8], *blockdata, blockdata.getSize());
3733 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3734 <<": \tpacket size: "<<replysize<<std::endl;*/
3739 m_con.Send(peer_id, 1, reply, true);
3742 void Server::SendBlocks(float dtime)
3744 DSTACK(__FUNCTION_NAME);
3746 JMutexAutoLock envlock(m_env_mutex);
3747 JMutexAutoLock conlock(m_con_mutex);
3749 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3751 core::array<PrioritySortedBlockTransfer> queue;
3753 s32 total_sending = 0;
3756 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3758 for(core::map<u16, RemoteClient*>::Iterator
3759 i = m_clients.getIterator();
3760 i.atEnd() == false; i++)
3762 RemoteClient *client = i.getNode()->getValue();
3763 assert(client->peer_id == i.getNode()->getKey());
3765 // If definitions and textures have not been sent, don't
3766 // send MapBlocks either
3767 if(!client->definitions_sent)
3770 total_sending += client->SendingCount();
3772 if(client->serialization_version == SER_FMT_VER_INVALID)
3775 client->GetNextBlocks(this, dtime, queue);
3780 // Lowest priority number comes first.
3781 // Lowest is most important.
3784 for(u32 i=0; i<queue.size(); i++)
3786 //TODO: Calculate limit dynamically
3787 if(total_sending >= g_settings->getS32
3788 ("max_simultaneous_block_sends_server_total"))
3791 PrioritySortedBlockTransfer q = queue[i];
3793 MapBlock *block = NULL;
3796 block = m_env->getMap().getBlockNoCreate(q.pos);
3798 catch(InvalidPositionException &e)
3803 RemoteClient *client = getClient(q.peer_id);
3805 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3807 client->SentBlock(q.pos);
3813 void Server::PrepareTextures()
3815 DSTACK(__FUNCTION_NAME);
3817 infostream<<"Server: Calculating texture checksums"<<std::endl;
3819 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3820 i != m_mods.end(); i++){
3821 const ModSpec &mod = *i;
3822 std::string texturepath = mod.path + DIR_DELIM + "textures";
3823 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3824 for(u32 j=0; j<dirlist.size(); j++){
3825 if(dirlist[j].dir) // Ignode dirs
3827 std::string tname = dirlist[j].name;
3828 // if name contains illegal characters, ignore the texture
3829 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3830 errorstream<<"Server: ignoring illegal texture name: \""
3831 <<tname<<"\""<<std::endl;
3834 std::string tpath = texturepath + DIR_DELIM + tname;
3836 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3837 if(fis.good() == false){
3838 errorstream<<"Server::PrepareTextures(): Could not open \""
3839 <<tname<<"\" for reading"<<std::endl;
3842 std::ostringstream tmp_os(std::ios_base::binary);
3846 fis.read(buf, 1024);
3847 std::streamsize len = fis.gcount();
3848 tmp_os.write(buf, len);
3857 errorstream<<"Server::PrepareTextures(): Failed to read \""
3858 <<tname<<"\""<<std::endl;
3861 if(tmp_os.str().length() == 0){
3862 errorstream<<"Server::PrepareTextures(): Empty file \""
3863 <<tpath<<"\""<<std::endl;
3868 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3870 unsigned char *digest = sha1.getDigest();
3871 std::string digest_string = base64_encode(digest, 20);
3876 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3877 verbosestream<<"Server: sha1 for "<<tname<<"\tis "<<std::endl;
3882 struct SendableTextureAnnouncement
3885 std::string sha1_digest;
3887 SendableTextureAnnouncement(const std::string name_="",
3888 const std::string sha1_digest_=""):
3890 sha1_digest(sha1_digest_)
3895 void Server::SendTextureAnnouncement(u16 peer_id){
3896 DSTACK(__FUNCTION_NAME);
3898 verbosestream<<"Server: Announcing textures to id("<<peer_id<<")"
3901 core::list<SendableTextureAnnouncement> texture_announcements;
3903 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3906 texture_announcements.push_back(
3907 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3910 //send announcements
3914 u32 number of textures
3918 u16 length of digest string
3922 std::ostringstream os(std::ios_base::binary);
3924 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3925 writeU16(os, texture_announcements.size());
3927 for(core::list<SendableTextureAnnouncement>::Iterator
3928 j = texture_announcements.begin();
3929 j != texture_announcements.end(); j++){
3930 os<<serializeString(j->name);
3931 os<<serializeString(j->sha1_digest);
3935 std::string s = os.str();
3936 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3939 m_con.Send(peer_id, 0, data, true);
3943 struct SendableTexture
3949 SendableTexture(const std::string &name_="", const std::string path_="",
3950 const std::string &data_=""):
3957 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3958 DSTACK(__FUNCTION_NAME);
3960 verbosestream<<"Server::SendTexturesRequested(): "
3961 <<"Sending textures to client"<<std::endl;
3965 // Put 5kB in one bunch (this is not accurate)
3966 u32 bytes_per_bunch = 5000;
3968 core::array< core::list<SendableTexture> > texture_bunches;
3969 texture_bunches.push_back(core::list<SendableTexture>());
3971 u32 texture_size_bunch_total = 0;
3973 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3974 if(m_Textures.find(i->name) == m_Textures.end()){
3975 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3976 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3980 //TODO get path + name
3981 std::string tpath = m_Textures[(*i).name].path;
3984 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3985 if(fis.good() == false){
3986 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3987 <<tpath<<"\" for reading"<<std::endl;
3990 std::ostringstream tmp_os(std::ios_base::binary);
3994 fis.read(buf, 1024);
3995 std::streamsize len = fis.gcount();
3996 tmp_os.write(buf, len);
3997 texture_size_bunch_total += len;
4006 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
4007 <<(*i).name<<"\""<<std::endl;
4010 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
4011 <<tname<<"\""<<std::endl;*/
4013 texture_bunches[texture_bunches.size()-1].push_back(
4014 SendableTexture((*i).name, tpath, tmp_os.str()));
4016 // Start next bunch if got enough data
4017 if(texture_size_bunch_total >= bytes_per_bunch){
4018 texture_bunches.push_back(core::list<SendableTexture>());
4019 texture_size_bunch_total = 0;
4024 /* Create and send packets */
4026 u32 num_bunches = texture_bunches.size();
4027 for(u32 i=0; i<num_bunches; i++)
4031 u16 total number of texture bunches
4032 u16 index of this bunch
4033 u32 number of textures in this bunch
4041 std::ostringstream os(std::ios_base::binary);
4043 writeU16(os, TOCLIENT_TEXTURES);
4044 writeU16(os, num_bunches);
4046 writeU32(os, texture_bunches[i].size());
4048 for(core::list<SendableTexture>::Iterator
4049 j = texture_bunches[i].begin();
4050 j != texture_bunches[i].end(); j++){
4051 os<<serializeString(j->name);
4052 os<<serializeLongString(j->data);
4056 std::string s = os.str();
4057 verbosestream<<"Server::SendTexturesRequested(): bunch "
4058 <<i<<"/"<<num_bunches
4059 <<" textures="<<texture_bunches[i].size()
4060 <<" size=" <<s.size()<<std::endl;
4061 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4063 m_con.Send(peer_id, 0, data, true);
4073 void Server::DiePlayer(Player *player)
4075 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4077 infostream<<"Server::DiePlayer(): Player "
4078 <<player->getName()<<" dies"<<std::endl;
4082 // Trigger scripted stuff
4083 scriptapi_on_dieplayer(m_lua, srp);
4085 // Handle players that are not connected
4086 if(player->peer_id == PEER_ID_INEXISTENT){
4087 RespawnPlayer(player);
4091 SendPlayerHP(player);
4092 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4095 void Server::RespawnPlayer(Player *player)
4097 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4099 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4101 v3f pos = findSpawnPos(m_env->getServerMap());
4102 player->setPosition(pos);
4103 srp->m_last_good_position = pos;
4104 srp->m_last_good_position_age = 0;
4106 SendMovePlayer(player);
4107 SendPlayerHP(player);
4110 void Server::UpdateCrafting(u16 peer_id)
4112 DSTACK(__FUNCTION_NAME);
4114 Player* player = m_env->getPlayer(peer_id);
4117 // Get a preview for crafting
4119 // No crafting in creative mode
4120 if(g_settings->getBool("creative_mode") == false)
4121 getCraftingResult(&player->inventory, preview, false, this);
4123 // Put the new preview in
4124 InventoryList *plist = player->inventory.getList("craftpreview");
4126 assert(plist->getSize() >= 1);
4127 plist->changeItem(0, preview);
4130 RemoteClient* Server::getClient(u16 peer_id)
4132 DSTACK(__FUNCTION_NAME);
4133 //JMutexAutoLock lock(m_con_mutex);
4134 core::map<u16, RemoteClient*>::Node *n;
4135 n = m_clients.find(peer_id);
4136 // A client should exist for all peers
4138 return n->getValue();
4141 std::wstring Server::getStatusString()
4143 std::wostringstream os(std::ios_base::binary);
4146 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4148 os<<L", uptime="<<m_uptime.get();
4149 // Information about clients
4151 for(core::map<u16, RemoteClient*>::Iterator
4152 i = m_clients.getIterator();
4153 i.atEnd() == false; i++)
4155 // Get client and check that it is valid
4156 RemoteClient *client = i.getNode()->getValue();
4157 assert(client->peer_id == i.getNode()->getKey());
4158 if(client->serialization_version == SER_FMT_VER_INVALID)
4161 Player *player = m_env->getPlayer(client->peer_id);
4162 // Get name of player
4163 std::wstring name = L"unknown";
4165 name = narrow_to_wide(player->getName());
4166 // Add name to information string
4170 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4171 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4172 if(g_settings->get("motd") != "")
4173 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4177 u64 Server::getPlayerAuthPrivs(const std::string &name)
4180 return m_authmanager.getPrivs(name);
4182 catch(AuthNotFoundException &e)
4184 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4189 void Server::setPlayerAuthPrivs(const std::string &name, u64 privs)
4192 return m_authmanager.setPrivs(name, privs);
4194 catch(AuthNotFoundException &e)
4196 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4200 u64 Server::getPlayerEffectivePrivs(const std::string &name)
4202 // Local player gets all privileges regardless of
4203 // what's set on their account.
4204 if(m_simple_singleplayer_mode)
4206 if(name == g_settings->get("name"))
4208 return getPlayerAuthPrivs(name);
4211 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4213 // Add player to auth manager
4214 if(m_authmanager.exists(name) == false)
4216 infostream<<"Server: adding player "<<name
4217 <<" to auth manager"<<std::endl;
4218 m_authmanager.add(name);
4219 m_authmanager.setPrivs(name,
4220 stringToPrivs(g_settings->get("default_privs")));
4222 // Change password and save
4223 m_authmanager.setPassword(name, translatePassword(name, password));
4224 m_authmanager.save();
4227 // Saves g_settings to configpath given at initialization
4228 void Server::saveConfig()
4230 if(m_path_config != "")
4231 g_settings->updateConfigFile(m_path_config.c_str());
4234 void Server::notifyPlayer(const char *name, const std::wstring msg)
4236 Player *player = m_env->getPlayer(name);
4239 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4242 void Server::notifyPlayers(const std::wstring msg)
4244 BroadcastChatMessage(msg);
4247 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4251 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4252 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4255 // IGameDef interface
4257 IItemDefManager* Server::getItemDefManager()
4261 INodeDefManager* Server::getNodeDefManager()
4265 ICraftDefManager* Server::getCraftDefManager()
4269 ITextureSource* Server::getTextureSource()
4273 u16 Server::allocateUnknownNodeId(const std::string &name)
4275 return m_nodedef->allocateDummy(name);
4278 IWritableItemDefManager* Server::getWritableItemDefManager()
4282 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4286 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4291 const ModSpec* Server::getModSpec(const std::string &modname)
4293 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4294 i != m_mods.end(); i++){
4295 const ModSpec &mod = *i;
4296 if(mod.name == modname)
4302 v3f findSpawnPos(ServerMap &map)
4304 //return v3f(50,50,50)*BS;
4309 nodepos = v2s16(0,0);
4314 // Try to find a good place a few times
4315 for(s32 i=0; i<1000; i++)
4318 // We're going to try to throw the player to this position
4319 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4320 -range + (myrand()%(range*2)));
4321 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4322 // Get ground height at point (fallbacks to heightmap function)
4323 s16 groundheight = map.findGroundLevel(nodepos2d);
4324 // Don't go underwater
4325 if(groundheight < WATER_LEVEL)
4327 //infostream<<"-> Underwater"<<std::endl;
4330 // Don't go to high places
4331 if(groundheight > WATER_LEVEL + 4)
4333 //infostream<<"-> Underwater"<<std::endl;
4337 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4338 bool is_good = false;
4340 for(s32 i=0; i<10; i++){
4341 v3s16 blockpos = getNodeBlockPos(nodepos);
4342 map.emergeBlock(blockpos, true);
4343 MapNode n = map.getNodeNoEx(nodepos);
4344 if(n.getContent() == CONTENT_AIR){
4355 // Found a good place
4356 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4362 return intToFloat(nodepos, BS);
4365 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4368 Try to get an existing player
4370 ServerRemotePlayer *player =
4371 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4374 // If player is already connected, cancel
4375 if(player->peer_id != 0)
4377 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4382 player->peer_id = peer_id;
4384 // Re-add player to environment
4385 if(player->m_removed)
4387 player->m_removed = false;
4389 m_env->addActiveObject(player);
4392 // Reset inventory to creative if in creative mode
4393 if(g_settings->getBool("creative_mode"))
4395 // Warning: double code below
4396 // Backup actual inventory
4397 player->inventory_backup = new Inventory(m_itemdef);
4398 *(player->inventory_backup) = player->inventory;
4399 // Set creative inventory
4400 player->resetInventory();
4401 scriptapi_get_creative_inventory(m_lua, player);
4408 If player with the wanted peer_id already exists, cancel.
4410 if(m_env->getPlayer(peer_id) != NULL)
4412 infostream<<"emergePlayer(): Player with wrong name but same"
4413 " peer_id already exists"<<std::endl;
4421 /* Set player position */
4423 infostream<<"Server: Finding spawn place for player \""
4424 <<name<<"\""<<std::endl;
4426 v3f pos = findSpawnPos(m_env->getServerMap());
4428 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4429 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4431 /* Add player to environment */
4432 m_env->addPlayer(player);
4433 m_env->addActiveObject(srp);
4436 scriptapi_on_newplayer(m_lua, srp);
4438 /* Add stuff to inventory */
4439 if(g_settings->getBool("creative_mode"))
4441 // Warning: double code above
4442 // Backup actual inventory
4443 player->inventory_backup = new Inventory(m_itemdef);
4444 *(player->inventory_backup) = player->inventory;
4445 // Set creative inventory
4446 player->resetInventory();
4447 scriptapi_get_creative_inventory(m_lua, player);
4452 } // create new player
4455 void Server::handlePeerChange(PeerChange &c)
4457 JMutexAutoLock envlock(m_env_mutex);
4458 JMutexAutoLock conlock(m_con_mutex);
4460 if(c.type == PEER_ADDED)
4467 core::map<u16, RemoteClient*>::Node *n;
4468 n = m_clients.find(c.peer_id);
4469 // The client shouldn't already exist
4473 RemoteClient *client = new RemoteClient();
4474 client->peer_id = c.peer_id;
4475 m_clients.insert(client->peer_id, client);
4478 else if(c.type == PEER_REMOVED)
4485 core::map<u16, RemoteClient*>::Node *n;
4486 n = m_clients.find(c.peer_id);
4487 // The client should exist
4491 Mark objects to be not known by the client
4493 RemoteClient *client = n->getValue();
4495 for(core::map<u16, bool>::Iterator
4496 i = client->m_known_objects.getIterator();
4497 i.atEnd()==false; i++)
4500 u16 id = i.getNode()->getKey();
4501 ServerActiveObject* obj = m_env->getActiveObject(id);
4503 if(obj && obj->m_known_by_count > 0)
4504 obj->m_known_by_count--;
4507 ServerRemotePlayer* player =
4508 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4510 // Collect information about leaving in chat
4511 std::wstring message;
4515 std::wstring name = narrow_to_wide(player->getName());
4518 message += L" left game";
4520 message += L" (timed out)";
4524 // Remove from environment
4526 player->m_removed = true;
4528 // Set player client disconnected
4530 player->peer_id = 0;
4538 std::ostringstream os(std::ios_base::binary);
4539 for(core::map<u16, RemoteClient*>::Iterator
4540 i = m_clients.getIterator();
4541 i.atEnd() == false; i++)
4543 RemoteClient *client = i.getNode()->getValue();
4544 assert(client->peer_id == i.getNode()->getKey());
4545 if(client->serialization_version == SER_FMT_VER_INVALID)
4548 Player *player = m_env->getPlayer(client->peer_id);
4551 // Get name of player
4552 os<<player->getName()<<" ";
4555 actionstream<<player->getName()<<" "
4556 <<(c.timeout?"times out.":"leaves game.")
4557 <<" List of players: "
4558 <<os.str()<<std::endl;
4563 delete m_clients[c.peer_id];
4564 m_clients.remove(c.peer_id);
4566 // Send player info to all remaining clients
4567 //SendPlayerInfos();
4569 // Send leave chat message to all remaining clients
4570 if(message.length() != 0)
4571 BroadcastChatMessage(message);
4580 void Server::handlePeerChanges()
4582 while(m_peer_change_queue.size() > 0)
4584 PeerChange c = m_peer_change_queue.pop_front();
4586 verbosestream<<"Server: Handling peer change: "
4587 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4590 handlePeerChange(c);
4594 u64 Server::getPlayerPrivs(Player *player)
4598 std::string playername = player->getName();
4599 return getPlayerEffectivePrivs(playername);
4602 void dedicated_server_loop(Server &server, bool &kill)
4604 DSTACK(__FUNCTION_NAME);
4606 verbosestream<<"dedicated_server_loop()"<<std::endl;
4608 IntervalLimiter m_profiler_interval;
4612 float steplen = g_settings->getFloat("dedicated_server_step");
4613 // This is kind of a hack but can be done like this
4614 // because server.step() is very light
4616 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4617 sleep_ms((int)(steplen*1000.0));
4619 server.step(steplen);
4621 if(server.getShutdownRequested() || kill)
4623 infostream<<"Dedicated server quitting"<<std::endl;
4630 float profiler_print_interval =
4631 g_settings->getFloat("profiler_print_interval");
4632 if(profiler_print_interval != 0)
4634 if(m_profiler_interval.step(steplen, profiler_print_interval))
4636 infostream<<"Profiler:"<<std::endl;
4637 g_profiler->print(infostream);
4638 g_profiler->clear();