3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "jmutexautolock.h"
28 #include "constants.h"
31 #include "servercommand.h"
33 #include "content_mapnode.h"
34 #include "content_nodemeta.h"
36 #include "serverobject.h"
41 #include "scriptapi.h"
46 #include "content_abm.h"
51 #include "utility_string.h"
53 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
55 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
57 class MapEditEventIgnorer
60 MapEditEventIgnorer(bool *flag):
69 ~MapEditEventIgnorer()
82 void * ServerThread::Thread()
86 log_register_thread("ServerThread");
88 DSTACK(__FUNCTION_NAME);
90 BEGIN_DEBUG_EXCEPTION_HANDLER
95 //TimeTaker timer("AsyncRunStep() + Receive()");
98 //TimeTaker timer("AsyncRunStep()");
99 m_server->AsyncRunStep();
102 //infostream<<"Running m_server->Receive()"<<std::endl;
105 catch(con::NoIncomingDataException &e)
108 catch(con::PeerNotFoundException &e)
110 infostream<<"Server: PeerNotFoundException"<<std::endl;
112 catch(con::ConnectionBindFailed &e)
114 m_server->setAsyncFatalError(e.what());
118 END_DEBUG_EXCEPTION_HANDLER(errorstream)
123 void * EmergeThread::Thread()
127 log_register_thread("EmergeThread");
129 DSTACK(__FUNCTION_NAME);
131 BEGIN_DEBUG_EXCEPTION_HANDLER
133 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
136 Get block info from queue, emerge them and send them
139 After queue is empty, exit.
143 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
147 SharedPtr<QueuedBlockEmerge> q(qptr);
153 Do not generate over-limit
155 if(blockpos_over_limit(p))
158 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
160 //TimeTaker timer("block emerge");
163 Try to emerge it from somewhere.
165 If it is only wanted as optional, only loading from disk
170 Check if any peer wants it as non-optional. In that case it
173 Also decrement the emerge queue count in clients.
176 bool only_from_disk = true;
179 core::map<u16, u8>::Iterator i;
180 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
182 //u16 peer_id = i.getNode()->getKey();
185 u8 flags = i.getNode()->getValue();
186 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
187 only_from_disk = false;
192 if(enable_mapgen_debug_info)
193 infostream<<"EmergeThread: p="
194 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
195 <<"only_from_disk="<<only_from_disk<<std::endl;
197 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
199 MapBlock *block = NULL;
200 bool got_block = true;
201 core::map<v3s16, MapBlock*> modified_blocks;
204 Try to fetch block from memory or disk.
205 If not found and asked to generate, initialize generator.
208 bool started_generate = false;
209 mapgen::BlockMakeData data;
212 JMutexAutoLock envlock(m_server->m_env_mutex);
214 // Load sector if it isn't loaded
215 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
216 map.loadSectorMeta(p2d);
218 // Attempt to load block
219 block = map.getBlockNoCreateNoEx(p);
220 if(!block || block->isDummy() || !block->isGenerated())
222 if(enable_mapgen_debug_info)
223 infostream<<"EmergeThread: not in memory, "
224 <<"attempting to load from disk"<<std::endl;
226 block = map.loadBlock(p);
229 // If could not load and allowed to generate, start generation
230 // inside this same envlock
231 if(only_from_disk == false &&
232 (block == NULL || block->isGenerated() == false)){
233 if(enable_mapgen_debug_info)
234 infostream<<"EmergeThread: generating"<<std::endl;
235 started_generate = true;
237 map.initBlockMake(&data, p);
242 If generator was initialized, generate now when envlock is free.
247 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
249 TimeTaker t("mapgen::make_block()");
251 mapgen::make_block(&data);
253 if(enable_mapgen_debug_info == false)
254 t.stop(true); // Hide output
258 // Lock environment again to access the map
259 JMutexAutoLock envlock(m_server->m_env_mutex);
261 ScopeProfiler sp(g_profiler, "EmergeThread: after "
262 "mapgen::make_block (envlock)", SPT_AVG);
264 // Blit data back on map, update lighting, add mobs and
265 // whatever this does
266 map.finishBlockMake(&data, modified_blocks);
269 block = map.getBlockNoCreateNoEx(p);
271 // If block doesn't exist, don't try doing anything with it
272 // This happens if the block is not in generation boundaries
277 Do some post-generate stuff
280 v3s16 minp = block->getPos()*MAP_BLOCKSIZE;
281 v3s16 maxp = minp + v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
282 scriptapi_environment_on_generated(m_server->m_lua,
285 if(enable_mapgen_debug_info)
286 infostream<<"EmergeThread: ended up with: "
287 <<analyze_block(block)<<std::endl;
290 Ignore map edit events, they will not need to be
291 sent to anybody because the block hasn't been sent
294 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
296 // Activate objects and stuff
297 m_server->m_env->activateBlock(block, 0);
305 Set sent status of modified blocks on clients
308 // NOTE: Server's clients are also behind the connection mutex
309 JMutexAutoLock lock(m_server->m_con_mutex);
312 Add the originally fetched block to the modified list
316 modified_blocks.insert(p, block);
320 Set the modified blocks unsent for all the clients
323 for(core::map<u16, RemoteClient*>::Iterator
324 i = m_server->m_clients.getIterator();
325 i.atEnd() == false; i++)
327 RemoteClient *client = i.getNode()->getValue();
329 if(modified_blocks.size() > 0)
331 // Remove block from sent history
332 client->SetBlocksNotSent(modified_blocks);
338 END_DEBUG_EXCEPTION_HANDLER(errorstream)
340 log_deregister_thread();
345 void RemoteClient::GetNextBlocks(Server *server, float dtime,
346 core::array<PrioritySortedBlockTransfer> &dest)
348 DSTACK(__FUNCTION_NAME);
351 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
354 m_nothing_to_send_pause_timer -= dtime;
355 m_nearest_unsent_reset_timer += dtime;
357 if(m_nothing_to_send_pause_timer >= 0)
362 // Won't send anything if already sending
363 if(m_blocks_sending.size() >= g_settings->getU16
364 ("max_simultaneous_block_sends_per_client"))
366 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
370 //TimeTaker timer("RemoteClient::GetNextBlocks");
372 Player *player = server->m_env->getPlayer(peer_id);
374 assert(player != NULL);
376 v3f playerpos = player->getPosition();
377 v3f playerspeed = player->getSpeed();
378 v3f playerspeeddir(0,0,0);
379 if(playerspeed.getLength() > 1.0*BS)
380 playerspeeddir = playerspeed / playerspeed.getLength();
381 // Predict to next block
382 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
384 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
386 v3s16 center = getNodeBlockPos(center_nodepos);
388 // Camera position and direction
389 v3f camera_pos = player->getEyePosition();
390 v3f camera_dir = v3f(0,0,1);
391 camera_dir.rotateYZBy(player->getPitch());
392 camera_dir.rotateXZBy(player->getYaw());
394 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
395 <<camera_dir.Z<<")"<<std::endl;*/
398 Get the starting value of the block finder radius.
401 if(m_last_center != center)
403 m_nearest_unsent_d = 0;
404 m_last_center = center;
407 /*infostream<<"m_nearest_unsent_reset_timer="
408 <<m_nearest_unsent_reset_timer<<std::endl;*/
410 // Reset periodically to workaround for some bugs or stuff
411 if(m_nearest_unsent_reset_timer > 20.0)
413 m_nearest_unsent_reset_timer = 0;
414 m_nearest_unsent_d = 0;
415 //infostream<<"Resetting m_nearest_unsent_d for "
416 // <<server->getPlayerName(peer_id)<<std::endl;
419 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
420 s16 d_start = m_nearest_unsent_d;
422 //infostream<<"d_start="<<d_start<<std::endl;
424 u16 max_simul_sends_setting = g_settings->getU16
425 ("max_simultaneous_block_sends_per_client");
426 u16 max_simul_sends_usually = max_simul_sends_setting;
429 Check the time from last addNode/removeNode.
431 Decrease send rate if player is building stuff.
433 m_time_from_building += dtime;
434 if(m_time_from_building < g_settings->getFloat(
435 "full_block_send_enable_min_time_from_building"))
437 max_simul_sends_usually
438 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
442 Number of blocks sending + number of blocks selected for sending
444 u32 num_blocks_selected = m_blocks_sending.size();
447 next time d will be continued from the d from which the nearest
448 unsent block was found this time.
450 This is because not necessarily any of the blocks found this
451 time are actually sent.
453 s32 new_nearest_unsent_d = -1;
455 s16 d_max = g_settings->getS16("max_block_send_distance");
456 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
458 // Don't loop very much at a time
459 s16 max_d_increment_at_time = 2;
460 if(d_max > d_start + max_d_increment_at_time)
461 d_max = d_start + max_d_increment_at_time;
462 /*if(d_max_gen > d_start+2)
463 d_max_gen = d_start+2;*/
465 //infostream<<"Starting from "<<d_start<<std::endl;
467 s32 nearest_emerged_d = -1;
468 s32 nearest_emergefull_d = -1;
469 s32 nearest_sent_d = -1;
470 bool queue_is_full = false;
473 for(d = d_start; d <= d_max; d++)
475 /*errorstream<<"checking d="<<d<<" for "
476 <<server->getPlayerName(peer_id)<<std::endl;*/
477 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
480 If m_nearest_unsent_d was changed by the EmergeThread
481 (it can change it to 0 through SetBlockNotSent),
483 Else update m_nearest_unsent_d
485 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
487 d = m_nearest_unsent_d;
488 last_nearest_unsent_d = m_nearest_unsent_d;
492 Get the border/face dot coordinates of a "d-radiused"
495 core::list<v3s16> list;
496 getFacePositions(list, d);
498 core::list<v3s16>::Iterator li;
499 for(li=list.begin(); li!=list.end(); li++)
501 v3s16 p = *li + center;
505 - Don't allow too many simultaneous transfers
506 - EXCEPT when the blocks are very close
508 Also, don't send blocks that are already flying.
511 // Start with the usual maximum
512 u16 max_simul_dynamic = max_simul_sends_usually;
514 // If block is very close, allow full maximum
515 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
516 max_simul_dynamic = max_simul_sends_setting;
518 // Don't select too many blocks for sending
519 if(num_blocks_selected >= max_simul_dynamic)
521 queue_is_full = true;
522 goto queue_full_break;
525 // Don't send blocks that are currently being transferred
526 if(m_blocks_sending.find(p) != NULL)
532 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
533 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
534 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
535 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
536 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
537 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
540 // If this is true, inexistent block will be made from scratch
541 bool generate = d <= d_max_gen;
544 /*// Limit the generating area vertically to 2/3
545 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
548 // Limit the send area vertically to 1/2
549 if(abs(p.Y - center.Y) > d_max / 2)
555 If block is far away, don't generate it unless it is
561 // Block center y in nodes
562 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
563 // Don't generate if it's very high or very low
564 if(y < -64 || y > 64)
568 v2s16 p2d_nodes_center(
572 // Get ground height in nodes
573 s16 gh = server->m_env->getServerMap().findGroundLevel(
576 // If differs a lot, don't generate
577 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
579 // Actually, don't even send it
585 //infostream<<"d="<<d<<std::endl;
588 Don't generate or send if not in sight
589 FIXME This only works if the client uses a small enough
590 FOV setting. The default of 72 degrees is fine.
593 float camera_fov = (72.0*PI/180) * 4./3.;
594 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
600 Don't send already sent blocks
603 if(m_blocks_sent.find(p) != NULL)
610 Check if map has this block
612 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
614 bool surely_not_found_on_disk = false;
615 bool block_is_invalid = false;
618 // Reset usage timer, this block will be of use in the future.
619 block->resetUsageTimer();
621 // Block is dummy if data doesn't exist.
622 // It means it has been not found from disk and not generated
625 surely_not_found_on_disk = true;
628 // Block is valid if lighting is up-to-date and data exists
629 if(block->isValid() == false)
631 block_is_invalid = true;
634 /*if(block->isFullyGenerated() == false)
636 block_is_invalid = true;
641 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
642 v2s16 chunkpos = map->sector_to_chunk(p2d);
643 if(map->chunkNonVolatile(chunkpos) == false)
644 block_is_invalid = true;
646 if(block->isGenerated() == false)
647 block_is_invalid = true;
650 If block is not close, don't send it unless it is near
653 Block is near ground level if night-time mesh
654 differs from day-time mesh.
658 if(block->dayNightDiffed() == false)
665 If block has been marked to not exist on disk (dummy)
666 and generating new ones is not wanted, skip block.
668 if(generate == false && surely_not_found_on_disk == true)
675 Add inexistent block to emerge queue.
677 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
679 //TODO: Get value from somewhere
680 // Allow only one block in emerge queue
681 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
682 // Allow two blocks in queue per client
683 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
685 // Make it more responsive when needing to generate stuff
686 if(surely_not_found_on_disk)
688 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
690 //infostream<<"Adding block to emerge queue"<<std::endl;
692 // Add it to the emerge queue and trigger the thread
695 if(generate == false)
696 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
698 server->m_emerge_queue.addBlock(peer_id, p, flags);
699 server->m_emergethread.trigger();
701 if(nearest_emerged_d == -1)
702 nearest_emerged_d = d;
704 if(nearest_emergefull_d == -1)
705 nearest_emergefull_d = d;
712 if(nearest_sent_d == -1)
716 Add block to send queue
719 /*errorstream<<"sending from d="<<d<<" to "
720 <<server->getPlayerName(peer_id)<<std::endl;*/
722 PrioritySortedBlockTransfer q((float)d, p, peer_id);
726 num_blocks_selected += 1;
731 //infostream<<"Stopped at "<<d<<std::endl;
733 // If nothing was found for sending and nothing was queued for
734 // emerging, continue next time browsing from here
735 if(nearest_emerged_d != -1){
736 new_nearest_unsent_d = nearest_emerged_d;
737 } else if(nearest_emergefull_d != -1){
738 new_nearest_unsent_d = nearest_emergefull_d;
740 if(d > g_settings->getS16("max_block_send_distance")){
741 new_nearest_unsent_d = 0;
742 m_nothing_to_send_pause_timer = 2.0;
743 /*infostream<<"GetNextBlocks(): d wrapped around for "
744 <<server->getPlayerName(peer_id)
745 <<"; setting to 0 and pausing"<<std::endl;*/
747 if(nearest_sent_d != -1)
748 new_nearest_unsent_d = nearest_sent_d;
750 new_nearest_unsent_d = d;
754 if(new_nearest_unsent_d != -1)
755 m_nearest_unsent_d = new_nearest_unsent_d;
757 /*timer_result = timer.stop(true);
758 if(timer_result != 0)
759 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
762 void RemoteClient::GotBlock(v3s16 p)
764 if(m_blocks_sending.find(p) != NULL)
765 m_blocks_sending.remove(p);
768 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
769 " m_blocks_sending"<<std::endl;*/
770 m_excess_gotblocks++;
772 m_blocks_sent.insert(p, true);
775 void RemoteClient::SentBlock(v3s16 p)
777 if(m_blocks_sending.find(p) == NULL)
778 m_blocks_sending.insert(p, 0.0);
780 infostream<<"RemoteClient::SentBlock(): Sent block"
781 " already in m_blocks_sending"<<std::endl;
784 void RemoteClient::SetBlockNotSent(v3s16 p)
786 m_nearest_unsent_d = 0;
788 if(m_blocks_sending.find(p) != NULL)
789 m_blocks_sending.remove(p);
790 if(m_blocks_sent.find(p) != NULL)
791 m_blocks_sent.remove(p);
794 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
796 m_nearest_unsent_d = 0;
798 for(core::map<v3s16, MapBlock*>::Iterator
799 i = blocks.getIterator();
800 i.atEnd()==false; i++)
802 v3s16 p = i.getNode()->getKey();
804 if(m_blocks_sending.find(p) != NULL)
805 m_blocks_sending.remove(p);
806 if(m_blocks_sent.find(p) != NULL)
807 m_blocks_sent.remove(p);
815 PlayerInfo::PlayerInfo()
821 void PlayerInfo::PrintLine(std::ostream *s)
824 (*s)<<"\""<<name<<"\" ("
825 <<(position.X/10)<<","<<(position.Y/10)
826 <<","<<(position.Z/10)<<") ";
828 (*s)<<" avg_rtt="<<avg_rtt;
837 const std::string &path_world,
838 const std::string &path_config,
839 const SubgameSpec &gamespec,
840 bool simple_singleplayer_mode
842 m_path_world(path_world),
843 m_path_config(path_config),
844 m_gamespec(gamespec),
845 m_simple_singleplayer_mode(simple_singleplayer_mode),
846 m_async_fatal_error(""),
848 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
849 m_authmanager(path_world+DIR_DELIM+"auth.txt"),
850 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
852 m_itemdef(createItemDefManager()),
853 m_nodedef(createNodeDefManager()),
854 m_craftdef(createCraftDefManager()),
856 m_emergethread(this),
857 m_time_of_day_send_timer(0),
859 m_shutdown_requested(false),
860 m_ignore_map_edit_events(false),
861 m_ignore_map_edit_events_peer_id(0)
863 m_liquid_transform_timer = 0.0;
864 m_print_info_timer = 0.0;
865 m_objectdata_timer = 0.0;
866 m_emergethread_trigger_timer = 0.0;
867 m_savemap_timer = 0.0;
871 m_step_dtime_mutex.Init();
875 throw ServerError("Supplied empty world path");
877 if(!gamespec.isValid())
878 throw ServerError("Supplied invalid gamespec");
880 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
881 if(m_simple_singleplayer_mode)
882 infostream<<" in simple singleplayer mode"<<std::endl;
884 infostream<<std::endl;
885 infostream<<"- world: "<<m_path_world<<std::endl;
886 infostream<<"- config: "<<m_path_config<<std::endl;
887 infostream<<"- game: "<<m_gamespec.path<<std::endl;
889 // Add world mod search path
890 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
891 // Add addon mod search path
892 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
893 i != m_gamespec.mods_paths.end(); i++)
894 m_modspaths.push_front((*i));
896 // Print out mod search paths
897 for(core::list<std::string>::Iterator i = m_modspaths.begin();
898 i != m_modspaths.end(); i++){
899 std::string modspath = *i;
900 infostream<<"- mods: "<<modspath<<std::endl;
903 // Path to builtin.lua
904 std::string builtinpath = porting::path_share + DIR_DELIM + "builtin"
905 + DIR_DELIM + "builtin.lua";
907 // Create world if it doesn't exist
908 if(!initializeWorld(m_path_world, m_gamespec.id))
909 throw ServerError("Failed to initialize world");
912 JMutexAutoLock envlock(m_env_mutex);
913 JMutexAutoLock conlock(m_con_mutex);
915 // Initialize scripting
917 infostream<<"Server: Initializing Lua"<<std::endl;
918 m_lua = script_init();
921 scriptapi_export(m_lua, this);
922 // Load and run builtin.lua
923 infostream<<"Server: Loading builtin.lua [\""
924 <<builtinpath<<"\"]"<<std::endl;
925 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
927 errorstream<<"Server: Failed to load and run "
928 <<builtinpath<<std::endl;
929 throw ModError("Failed to load and run "+builtinpath);
931 // Find mods in mod search paths
932 m_mods = getMods(m_modspaths);
934 infostream<<"Server: Loading mods: ";
935 for(core::list<ModSpec>::Iterator i = m_mods.begin();
936 i != m_mods.end(); i++){
937 const ModSpec &mod = *i;
938 infostream<<mod.name<<" ";
940 infostream<<std::endl;
941 // Load and run "mod" scripts
942 for(core::list<ModSpec>::Iterator i = m_mods.begin();
943 i != m_mods.end(); i++){
944 const ModSpec &mod = *i;
945 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
946 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
947 <<scriptpath<<"\"]"<<std::endl;
948 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
950 errorstream<<"Server: Failed to load and run "
951 <<scriptpath<<std::endl;
952 throw ModError("Failed to load and run "+scriptpath);
956 // Read Textures and calculate sha1 sums
959 // Apply item aliases in the node definition manager
960 m_nodedef->updateAliases(m_itemdef);
962 // Initialize Environment
964 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
967 // Give environment reference to scripting api
968 scriptapi_add_environment(m_lua, m_env);
970 // Register us to receive map edit events
971 m_env->getMap().addEventReceiver(this);
973 // If file exists, load environment metadata
974 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
976 infostream<<"Server: Loading environment metadata"<<std::endl;
977 m_env->loadMeta(m_path_world);
981 infostream<<"Server: Loading players"<<std::endl;
982 m_env->deSerializePlayers(m_path_world);
985 Add some test ActiveBlockModifiers to environment
987 add_legacy_abms(m_env, m_nodedef);
992 infostream<<"Server destructing"<<std::endl;
995 Send shutdown message
998 JMutexAutoLock conlock(m_con_mutex);
1000 std::wstring line = L"*** Server shutting down";
1003 Send the message to clients
1005 for(core::map<u16, RemoteClient*>::Iterator
1006 i = m_clients.getIterator();
1007 i.atEnd() == false; i++)
1009 // Get client and check that it is valid
1010 RemoteClient *client = i.getNode()->getValue();
1011 assert(client->peer_id == i.getNode()->getKey());
1012 if(client->serialization_version == SER_FMT_VER_INVALID)
1016 SendChatMessage(client->peer_id, line);
1018 catch(con::PeerNotFoundException &e)
1024 JMutexAutoLock envlock(m_env_mutex);
1029 infostream<<"Server: Saving players"<<std::endl;
1030 m_env->serializePlayers(m_path_world);
1033 Save environment metadata
1035 infostream<<"Server: Saving environment metadata"<<std::endl;
1036 m_env->saveMeta(m_path_world);
1048 JMutexAutoLock clientslock(m_con_mutex);
1050 for(core::map<u16, RemoteClient*>::Iterator
1051 i = m_clients.getIterator();
1052 i.atEnd() == false; i++)
1055 // NOTE: These are removed by env destructor
1057 u16 peer_id = i.getNode()->getKey();
1058 JMutexAutoLock envlock(m_env_mutex);
1059 m_env->removePlayer(peer_id);
1063 delete i.getNode()->getValue();
1067 // Delete Environment
1074 // Deinitialize scripting
1075 infostream<<"Server: Deinitializing scripting"<<std::endl;
1076 script_deinit(m_lua);
1079 void Server::start(unsigned short port)
1081 DSTACK(__FUNCTION_NAME);
1082 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1084 // Stop thread if already running
1087 // Initialize connection
1088 m_con.SetTimeoutMs(30);
1092 m_thread.setRun(true);
1095 // ASCII art for the win!
1097 <<" .__ __ __ "<<std::endl
1098 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1099 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1100 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1101 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1102 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1103 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1104 actionstream<<"Server for gameid=\""<<m_gamespec.id
1105 <<"\" listening on port "<<port<<"."<<std::endl;
1110 DSTACK(__FUNCTION_NAME);
1112 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1114 // Stop threads (set run=false first so both start stopping)
1115 m_thread.setRun(false);
1116 m_emergethread.setRun(false);
1118 m_emergethread.stop();
1120 infostream<<"Server: Threads stopped"<<std::endl;
1123 void Server::step(float dtime)
1125 DSTACK(__FUNCTION_NAME);
1130 JMutexAutoLock lock(m_step_dtime_mutex);
1131 m_step_dtime += dtime;
1133 // Throw if fatal error occurred in thread
1134 std::string async_err = m_async_fatal_error.get();
1135 if(async_err != ""){
1136 throw ServerError(async_err);
1140 void Server::AsyncRunStep()
1142 DSTACK(__FUNCTION_NAME);
1144 g_profiler->add("Server::AsyncRunStep (num)", 1);
1148 JMutexAutoLock lock1(m_step_dtime_mutex);
1149 dtime = m_step_dtime;
1153 // Send blocks to clients
1160 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1162 //infostream<<"Server steps "<<dtime<<std::endl;
1163 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1166 JMutexAutoLock lock1(m_step_dtime_mutex);
1167 m_step_dtime -= dtime;
1174 m_uptime.set(m_uptime.get() + dtime);
1178 // Process connection's timeouts
1179 JMutexAutoLock lock2(m_con_mutex);
1180 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1181 m_con.RunTimeouts(dtime);
1185 // This has to be called so that the client list gets synced
1186 // with the peer list of the connection
1187 handlePeerChanges();
1191 Update time of day and overall game time
1194 JMutexAutoLock envlock(m_env_mutex);
1196 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1199 Send to clients at constant intervals
1202 m_time_of_day_send_timer -= dtime;
1203 if(m_time_of_day_send_timer < 0.0)
1205 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1207 //JMutexAutoLock envlock(m_env_mutex);
1208 JMutexAutoLock conlock(m_con_mutex);
1210 for(core::map<u16, RemoteClient*>::Iterator
1211 i = m_clients.getIterator();
1212 i.atEnd() == false; i++)
1214 RemoteClient *client = i.getNode()->getValue();
1215 //Player *player = m_env->getPlayer(client->peer_id);
1217 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1218 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1220 m_con.Send(client->peer_id, 0, data, true);
1226 JMutexAutoLock lock(m_env_mutex);
1228 ScopeProfiler sp(g_profiler, "SEnv step");
1229 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1233 const float map_timer_and_unload_dtime = 2.92;
1234 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1236 JMutexAutoLock lock(m_env_mutex);
1237 // Run Map's timers and unload unused data
1238 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1239 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1240 g_settings->getFloat("server_unload_unused_data_timeout"));
1251 JMutexAutoLock lock(m_env_mutex);
1252 JMutexAutoLock lock2(m_con_mutex);
1254 ScopeProfiler sp(g_profiler, "Server: handle players");
1256 //float player_max_speed = BS * 4.0; // Normal speed
1257 float player_max_speed = BS * 20; // Fast speed
1258 float player_max_speed_up = BS * 20;
1260 player_max_speed *= 2.5; // Tolerance
1261 player_max_speed_up *= 2.5;
1263 for(core::map<u16, RemoteClient*>::Iterator
1264 i = m_clients.getIterator();
1265 i.atEnd() == false; i++)
1267 RemoteClient *client = i.getNode()->getValue();
1268 ServerRemotePlayer *player =
1269 static_cast<ServerRemotePlayer*>
1270 (m_env->getPlayer(client->peer_id));
1275 Check player movements
1277 NOTE: Actually the server should handle player physics like the
1278 client does and compare player's position to what is calculated
1279 on our side. This is required when eg. players fly due to an
1282 player->m_last_good_position_age += dtime;
1283 if(player->m_last_good_position_age >= 1.0){
1284 float age = player->m_last_good_position_age;
1285 v3f diff = (player->getPosition() - player->m_last_good_position);
1286 float d_vert = diff.Y;
1288 float d_horiz = diff.getLength();
1289 /*infostream<<player->getName()<<"'s horizontal speed is "
1290 <<(d_horiz/age)<<std::endl;*/
1291 if(d_horiz <= age * player_max_speed &&
1292 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1293 player->m_last_good_position = player->getPosition();
1295 actionstream<<"Player "<<player->getName()
1296 <<" moved too fast; resetting position"
1298 player->setPosition(player->m_last_good_position);
1299 SendMovePlayer(player);
1301 player->m_last_good_position_age = 0;
1305 Handle player HPs (die if hp=0)
1307 if(player->hp == 0 && player->m_hp_not_sent)
1311 Send player inventories and HPs if necessary
1313 if(player->m_inventory_not_sent){
1314 UpdateCrafting(player->peer_id);
1315 SendInventory(player->peer_id);
1317 if(player->m_hp_not_sent){
1318 SendPlayerHP(player);
1324 if(!player->m_is_in_environment){
1325 player->m_removed = false;
1327 m_env->addActiveObject(player);
1332 /* Transform liquids */
1333 m_liquid_transform_timer += dtime;
1334 if(m_liquid_transform_timer >= 1.00)
1336 m_liquid_transform_timer -= 1.00;
1338 JMutexAutoLock lock(m_env_mutex);
1340 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1342 core::map<v3s16, MapBlock*> modified_blocks;
1343 m_env->getMap().transformLiquids(modified_blocks);
1348 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1349 ServerMap &map = ((ServerMap&)m_env->getMap());
1350 map.updateLighting(modified_blocks, lighting_modified_blocks);
1352 // Add blocks modified by lighting to modified_blocks
1353 for(core::map<v3s16, MapBlock*>::Iterator
1354 i = lighting_modified_blocks.getIterator();
1355 i.atEnd() == false; i++)
1357 MapBlock *block = i.getNode()->getValue();
1358 modified_blocks.insert(block->getPos(), block);
1362 Set the modified blocks unsent for all the clients
1365 JMutexAutoLock lock2(m_con_mutex);
1367 for(core::map<u16, RemoteClient*>::Iterator
1368 i = m_clients.getIterator();
1369 i.atEnd() == false; i++)
1371 RemoteClient *client = i.getNode()->getValue();
1373 if(modified_blocks.size() > 0)
1375 // Remove block from sent history
1376 client->SetBlocksNotSent(modified_blocks);
1381 // Periodically print some info
1383 float &counter = m_print_info_timer;
1389 JMutexAutoLock lock2(m_con_mutex);
1391 if(m_clients.size() != 0)
1392 infostream<<"Players:"<<std::endl;
1393 for(core::map<u16, RemoteClient*>::Iterator
1394 i = m_clients.getIterator();
1395 i.atEnd() == false; i++)
1397 //u16 peer_id = i.getNode()->getKey();
1398 RemoteClient *client = i.getNode()->getValue();
1399 Player *player = m_env->getPlayer(client->peer_id);
1402 infostream<<"* "<<player->getName()<<"\t";
1403 client->PrintInfo(infostream);
1408 //if(g_settings->getBool("enable_experimental"))
1412 Check added and deleted active objects
1415 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1416 JMutexAutoLock envlock(m_env_mutex);
1417 JMutexAutoLock conlock(m_con_mutex);
1419 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1421 // Radius inside which objects are active
1422 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1423 radius *= MAP_BLOCKSIZE;
1425 for(core::map<u16, RemoteClient*>::Iterator
1426 i = m_clients.getIterator();
1427 i.atEnd() == false; i++)
1429 RemoteClient *client = i.getNode()->getValue();
1431 // If definitions and textures have not been sent, don't
1432 // send objects either
1433 if(!client->definitions_sent)
1436 Player *player = m_env->getPlayer(client->peer_id);
1439 // This can happen if the client timeouts somehow
1440 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1442 <<" has no associated player"<<std::endl;*/
1445 v3s16 pos = floatToInt(player->getPosition(), BS);
1447 core::map<u16, bool> removed_objects;
1448 core::map<u16, bool> added_objects;
1449 m_env->getRemovedActiveObjects(pos, radius,
1450 client->m_known_objects, removed_objects);
1451 m_env->getAddedActiveObjects(pos, radius,
1452 client->m_known_objects, added_objects);
1454 // Ignore if nothing happened
1455 if(removed_objects.size() == 0 && added_objects.size() == 0)
1457 //infostream<<"active objects: none changed"<<std::endl;
1461 std::string data_buffer;
1465 // Handle removed objects
1466 writeU16((u8*)buf, removed_objects.size());
1467 data_buffer.append(buf, 2);
1468 for(core::map<u16, bool>::Iterator
1469 i = removed_objects.getIterator();
1470 i.atEnd()==false; i++)
1473 u16 id = i.getNode()->getKey();
1474 ServerActiveObject* obj = m_env->getActiveObject(id);
1476 // Add to data buffer for sending
1477 writeU16((u8*)buf, i.getNode()->getKey());
1478 data_buffer.append(buf, 2);
1480 // Remove from known objects
1481 client->m_known_objects.remove(i.getNode()->getKey());
1483 if(obj && obj->m_known_by_count > 0)
1484 obj->m_known_by_count--;
1487 // Handle added objects
1488 writeU16((u8*)buf, added_objects.size());
1489 data_buffer.append(buf, 2);
1490 for(core::map<u16, bool>::Iterator
1491 i = added_objects.getIterator();
1492 i.atEnd()==false; i++)
1495 u16 id = i.getNode()->getKey();
1496 ServerActiveObject* obj = m_env->getActiveObject(id);
1499 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1501 infostream<<"WARNING: "<<__FUNCTION_NAME
1502 <<": NULL object"<<std::endl;
1504 type = obj->getType();
1506 // Add to data buffer for sending
1507 writeU16((u8*)buf, id);
1508 data_buffer.append(buf, 2);
1509 writeU8((u8*)buf, type);
1510 data_buffer.append(buf, 1);
1513 data_buffer.append(serializeLongString(
1514 obj->getClientInitializationData()));
1516 data_buffer.append(serializeLongString(""));
1518 // Add to known objects
1519 client->m_known_objects.insert(i.getNode()->getKey(), false);
1522 obj->m_known_by_count++;
1526 SharedBuffer<u8> reply(2 + data_buffer.size());
1527 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1528 memcpy((char*)&reply[2], data_buffer.c_str(),
1529 data_buffer.size());
1531 m_con.Send(client->peer_id, 0, reply, true);
1533 verbosestream<<"Server: Sent object remove/add: "
1534 <<removed_objects.size()<<" removed, "
1535 <<added_objects.size()<<" added, "
1536 <<"packet size is "<<reply.getSize()<<std::endl;
1541 Collect a list of all the objects known by the clients
1542 and report it back to the environment.
1545 core::map<u16, bool> all_known_objects;
1547 for(core::map<u16, RemoteClient*>::Iterator
1548 i = m_clients.getIterator();
1549 i.atEnd() == false; i++)
1551 RemoteClient *client = i.getNode()->getValue();
1552 // Go through all known objects of client
1553 for(core::map<u16, bool>::Iterator
1554 i = client->m_known_objects.getIterator();
1555 i.atEnd()==false; i++)
1557 u16 id = i.getNode()->getKey();
1558 all_known_objects[id] = true;
1562 m_env->setKnownActiveObjects(whatever);
1568 Send object messages
1571 JMutexAutoLock envlock(m_env_mutex);
1572 JMutexAutoLock conlock(m_con_mutex);
1574 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1577 // Value = data sent by object
1578 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1580 // Get active object messages from environment
1583 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1587 core::list<ActiveObjectMessage>* message_list = NULL;
1588 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1589 n = buffered_messages.find(aom.id);
1592 message_list = new core::list<ActiveObjectMessage>;
1593 buffered_messages.insert(aom.id, message_list);
1597 message_list = n->getValue();
1599 message_list->push_back(aom);
1602 // Route data to every client
1603 for(core::map<u16, RemoteClient*>::Iterator
1604 i = m_clients.getIterator();
1605 i.atEnd()==false; i++)
1607 RemoteClient *client = i.getNode()->getValue();
1608 std::string reliable_data;
1609 std::string unreliable_data;
1610 // Go through all objects in message buffer
1611 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1612 j = buffered_messages.getIterator();
1613 j.atEnd()==false; j++)
1615 // If object is not known by client, skip it
1616 u16 id = j.getNode()->getKey();
1617 if(client->m_known_objects.find(id) == NULL)
1619 // Get message list of object
1620 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1621 // Go through every message
1622 for(core::list<ActiveObjectMessage>::Iterator
1623 k = list->begin(); k != list->end(); k++)
1625 // Compose the full new data with header
1626 ActiveObjectMessage aom = *k;
1627 std::string new_data;
1630 writeU16((u8*)&buf[0], aom.id);
1631 new_data.append(buf, 2);
1633 new_data += serializeString(aom.datastring);
1634 // Add data to buffer
1636 reliable_data += new_data;
1638 unreliable_data += new_data;
1642 reliable_data and unreliable_data are now ready.
1645 if(reliable_data.size() > 0)
1647 SharedBuffer<u8> reply(2 + reliable_data.size());
1648 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1649 memcpy((char*)&reply[2], reliable_data.c_str(),
1650 reliable_data.size());
1652 m_con.Send(client->peer_id, 0, reply, true);
1654 if(unreliable_data.size() > 0)
1656 SharedBuffer<u8> reply(2 + unreliable_data.size());
1657 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1658 memcpy((char*)&reply[2], unreliable_data.c_str(),
1659 unreliable_data.size());
1660 // Send as unreliable
1661 m_con.Send(client->peer_id, 0, reply, false);
1664 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1666 infostream<<"Server: Size of object message data: "
1667 <<"reliable: "<<reliable_data.size()
1668 <<", unreliable: "<<unreliable_data.size()
1673 // Clear buffered_messages
1674 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1675 i = buffered_messages.getIterator();
1676 i.atEnd()==false; i++)
1678 delete i.getNode()->getValue();
1682 } // enable_experimental
1685 Send queued-for-sending map edit events.
1688 // Don't send too many at a time
1691 // Single change sending is disabled if queue size is not small
1692 bool disable_single_change_sending = false;
1693 if(m_unsent_map_edit_queue.size() >= 4)
1694 disable_single_change_sending = true;
1696 int event_count = m_unsent_map_edit_queue.size();
1698 // We'll log the amount of each
1701 while(m_unsent_map_edit_queue.size() != 0)
1703 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1705 // Players far away from the change are stored here.
1706 // Instead of sending the changes, MapBlocks are set not sent
1708 core::list<u16> far_players;
1710 if(event->type == MEET_ADDNODE)
1712 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1713 prof.add("MEET_ADDNODE", 1);
1714 if(disable_single_change_sending)
1715 sendAddNode(event->p, event->n, event->already_known_by_peer,
1718 sendAddNode(event->p, event->n, event->already_known_by_peer,
1721 else if(event->type == MEET_REMOVENODE)
1723 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1724 prof.add("MEET_REMOVENODE", 1);
1725 if(disable_single_change_sending)
1726 sendRemoveNode(event->p, event->already_known_by_peer,
1729 sendRemoveNode(event->p, event->already_known_by_peer,
1732 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1734 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1735 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1736 setBlockNotSent(event->p);
1738 else if(event->type == MEET_OTHER)
1740 infostream<<"Server: MEET_OTHER"<<std::endl;
1741 prof.add("MEET_OTHER", 1);
1742 for(core::map<v3s16, bool>::Iterator
1743 i = event->modified_blocks.getIterator();
1744 i.atEnd()==false; i++)
1746 v3s16 p = i.getNode()->getKey();
1752 prof.add("unknown", 1);
1753 infostream<<"WARNING: Server: Unknown MapEditEvent "
1754 <<((u32)event->type)<<std::endl;
1758 Set blocks not sent to far players
1760 if(far_players.size() > 0)
1762 // Convert list format to that wanted by SetBlocksNotSent
1763 core::map<v3s16, MapBlock*> modified_blocks2;
1764 for(core::map<v3s16, bool>::Iterator
1765 i = event->modified_blocks.getIterator();
1766 i.atEnd()==false; i++)
1768 v3s16 p = i.getNode()->getKey();
1769 modified_blocks2.insert(p,
1770 m_env->getMap().getBlockNoCreateNoEx(p));
1772 // Set blocks not sent
1773 for(core::list<u16>::Iterator
1774 i = far_players.begin();
1775 i != far_players.end(); i++)
1778 RemoteClient *client = getClient(peer_id);
1781 client->SetBlocksNotSent(modified_blocks2);
1787 /*// Don't send too many at a time
1789 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1793 if(event_count >= 5){
1794 infostream<<"Server: MapEditEvents:"<<std::endl;
1795 prof.print(infostream);
1796 } else if(event_count != 0){
1797 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1798 prof.print(verbosestream);
1804 Trigger emergethread (it somehow gets to a non-triggered but
1805 bysy state sometimes)
1808 float &counter = m_emergethread_trigger_timer;
1814 m_emergethread.trigger();
1818 // Save map, players and auth stuff
1820 float &counter = m_savemap_timer;
1822 if(counter >= g_settings->getFloat("server_map_save_interval"))
1825 JMutexAutoLock lock(m_env_mutex);
1827 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1830 if(m_authmanager.isModified())
1831 m_authmanager.save();
1834 if(m_banmanager.isModified())
1835 m_banmanager.save();
1837 // Save changed parts of map
1838 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1841 m_env->serializePlayers(m_path_world);
1843 // Save environment metadata
1844 m_env->saveMeta(m_path_world);
1849 void Server::Receive()
1851 DSTACK(__FUNCTION_NAME);
1852 SharedBuffer<u8> data;
1857 JMutexAutoLock conlock(m_con_mutex);
1858 datasize = m_con.Receive(peer_id, data);
1861 // This has to be called so that the client list gets synced
1862 // with the peer list of the connection
1863 handlePeerChanges();
1865 ProcessData(*data, datasize, peer_id);
1867 catch(con::InvalidIncomingDataException &e)
1869 infostream<<"Server::Receive(): "
1870 "InvalidIncomingDataException: what()="
1871 <<e.what()<<std::endl;
1873 catch(con::PeerNotFoundException &e)
1875 //NOTE: This is not needed anymore
1877 // The peer has been disconnected.
1878 // Find the associated player and remove it.
1880 /*JMutexAutoLock envlock(m_env_mutex);
1882 infostream<<"ServerThread: peer_id="<<peer_id
1883 <<" has apparently closed connection. "
1884 <<"Removing player."<<std::endl;
1886 m_env->removePlayer(peer_id);*/
1890 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1892 DSTACK(__FUNCTION_NAME);
1893 // Environment is locked first.
1894 JMutexAutoLock envlock(m_env_mutex);
1895 JMutexAutoLock conlock(m_con_mutex);
1897 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1900 Address address = m_con.GetPeerAddress(peer_id);
1901 std::string addr_s = address.serializeString();
1903 // drop player if is ip is banned
1904 if(m_banmanager.isIpBanned(addr_s)){
1905 infostream<<"Server: A banned client tried to connect from "
1906 <<addr_s<<"; banned name was "
1907 <<m_banmanager.getBanName(addr_s)<<std::endl;
1908 // This actually doesn't seem to transfer to the client
1909 SendAccessDenied(m_con, peer_id,
1910 L"Your ip is banned. Banned name was "
1911 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1912 m_con.DeletePeer(peer_id);
1916 catch(con::PeerNotFoundException &e)
1918 infostream<<"Server::ProcessData(): Cancelling: peer "
1919 <<peer_id<<" not found"<<std::endl;
1923 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1925 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1933 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1935 if(command == TOSERVER_INIT)
1937 // [0] u16 TOSERVER_INIT
1938 // [2] u8 SER_FMT_VER_HIGHEST
1939 // [3] u8[20] player_name
1940 // [23] u8[28] password <--- can be sent without this, from old versions
1942 if(datasize < 2+1+PLAYERNAME_SIZE)
1945 verbosestream<<"Server: Got TOSERVER_INIT from "
1946 <<peer_id<<std::endl;
1948 // First byte after command is maximum supported
1949 // serialization version
1950 u8 client_max = data[2];
1951 u8 our_max = SER_FMT_VER_HIGHEST;
1952 // Use the highest version supported by both
1953 u8 deployed = core::min_(client_max, our_max);
1954 // If it's lower than the lowest supported, give up.
1955 if(deployed < SER_FMT_VER_LOWEST)
1956 deployed = SER_FMT_VER_INVALID;
1958 //peer->serialization_version = deployed;
1959 getClient(peer_id)->pending_serialization_version = deployed;
1961 if(deployed == SER_FMT_VER_INVALID)
1963 actionstream<<"Server: A mismatched client tried to connect from "
1964 <<addr_s<<std::endl;
1965 infostream<<"Server: Cannot negotiate "
1966 "serialization version with peer "
1967 <<peer_id<<std::endl;
1968 SendAccessDenied(m_con, peer_id, std::wstring(
1969 L"Your client's version is not supported.\n"
1970 L"Server version is ")
1971 + narrow_to_wide(VERSION_STRING) + L"."
1977 Read and check network protocol version
1980 u16 net_proto_version = 0;
1981 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1983 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1986 getClient(peer_id)->net_proto_version = net_proto_version;
1988 if(net_proto_version == 0)
1990 actionstream<<"Server: An old tried to connect from "<<addr_s
1992 SendAccessDenied(m_con, peer_id, std::wstring(
1993 L"Your client's version is not supported.\n"
1994 L"Server version is ")
1995 + narrow_to_wide(VERSION_STRING) + L"."
2000 if(g_settings->getBool("strict_protocol_version_checking"))
2002 if(net_proto_version != PROTOCOL_VERSION)
2004 actionstream<<"Server: A mismatched client tried to connect"
2005 <<" from "<<addr_s<<std::endl;
2006 SendAccessDenied(m_con, peer_id, std::wstring(
2007 L"Your client's version is not supported.\n"
2008 L"Server version is ")
2009 + narrow_to_wide(VERSION_STRING) + L",\n"
2010 + L"server's PROTOCOL_VERSION is "
2011 + narrow_to_wide(itos(PROTOCOL_VERSION))
2012 + L", client's PROTOCOL_VERSION is "
2013 + narrow_to_wide(itos(net_proto_version))
2024 char playername[PLAYERNAME_SIZE];
2025 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2027 playername[i] = data[3+i];
2029 playername[PLAYERNAME_SIZE-1] = 0;
2031 if(playername[0]=='\0')
2033 actionstream<<"Server: Player with an empty name "
2034 <<"tried to connect from "<<addr_s<<std::endl;
2035 SendAccessDenied(m_con, peer_id,
2040 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2042 actionstream<<"Server: Player with an invalid name "
2043 <<"tried to connect from "<<addr_s<<std::endl;
2044 SendAccessDenied(m_con, peer_id,
2045 L"Name contains unallowed characters");
2049 infostream<<"Server: New connection: \""<<playername<<"\" from "
2050 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2053 char password[PASSWORD_SIZE];
2054 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2056 // old version - assume blank password
2061 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2063 password[i] = data[23+i];
2065 password[PASSWORD_SIZE-1] = 0;
2068 // Add player to auth manager
2069 if(m_authmanager.exists(playername) == false)
2071 std::wstring default_password =
2072 narrow_to_wide(g_settings->get("default_password"));
2073 std::string translated_default_password =
2074 translatePassword(playername, default_password);
2076 // If default_password is empty, allow any initial password
2077 if (default_password.length() == 0)
2078 translated_default_password = password;
2080 infostream<<"Server: adding player "<<playername
2081 <<" to auth manager"<<std::endl;
2082 m_authmanager.add(playername);
2083 m_authmanager.setPassword(playername, translated_default_password);
2084 m_authmanager.setPrivs(playername,
2085 stringToPrivs(g_settings->get("default_privs")));
2086 m_authmanager.save();
2089 std::string checkpwd = m_authmanager.getPassword(playername);
2091 /*infostream<<"Server: Client gave password '"<<password
2092 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2094 if(password != checkpwd)
2096 infostream<<"Server: peer_id="<<peer_id
2097 <<": supplied invalid password for "
2098 <<playername<<std::endl;
2099 SendAccessDenied(m_con, peer_id, L"Invalid password");
2103 // Do not allow multiple players in simple singleplayer mode.
2104 // This isn't a perfect way to do it, but will suffice for now.
2105 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2106 infostream<<"Server: Not allowing another client to connect in"
2107 <<" simple singleplayer mode"<<std::endl;
2108 SendAccessDenied(m_con, peer_id,
2109 L"Running in simple singleplayer mode.");
2113 // Enforce user limit.
2114 // Don't enforce for users that have some admin right
2115 if(m_clients.size() >= g_settings->getU16("max_users") &&
2116 (m_authmanager.getPrivs(playername)
2117 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2118 playername != g_settings->get("name"))
2120 actionstream<<"Server: "<<playername<<" tried to join, but there"
2121 <<" are already max_users="
2122 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2123 SendAccessDenied(m_con, peer_id, L"Too many users.");
2128 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2130 // If failed, cancel
2133 errorstream<<"Server: peer_id="<<peer_id
2134 <<": failed to emerge player"<<std::endl;
2139 Answer with a TOCLIENT_INIT
2142 SharedBuffer<u8> reply(2+1+6+8);
2143 writeU16(&reply[0], TOCLIENT_INIT);
2144 writeU8(&reply[2], deployed);
2145 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2146 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2149 m_con.Send(peer_id, 0, reply, true);
2153 Send complete position information
2155 SendMovePlayer(player);
2160 if(command == TOSERVER_INIT2)
2162 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2163 <<peer_id<<std::endl;
2166 getClient(peer_id)->serialization_version
2167 = getClient(peer_id)->pending_serialization_version;
2170 Send some initialization data
2173 infostream<<"Server: Sending content to "
2174 <<getPlayerName(peer_id)<<std::endl;
2176 // Send item definitions
2177 SendItemDef(m_con, peer_id, m_itemdef);
2179 // Send node definitions
2180 SendNodeDef(m_con, peer_id, m_nodedef);
2182 // Send texture announcement
2183 SendTextureAnnouncement(peer_id);
2185 // Send player info to all players
2186 //SendPlayerInfos();
2188 // Send inventory to player
2189 UpdateCrafting(peer_id);
2190 SendInventory(peer_id);
2192 // Send player items to all players
2195 Player *player = m_env->getPlayer(peer_id);
2198 SendPlayerHP(player);
2200 // Show death screen if necessary
2202 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2206 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2207 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2208 m_con.Send(peer_id, 0, data, true);
2211 // Note things in chat if not in simple singleplayer mode
2212 if(!m_simple_singleplayer_mode)
2214 // Send information about server to player in chat
2215 SendChatMessage(peer_id, getStatusString());
2217 // Send information about joining in chat
2219 std::wstring name = L"unknown";
2220 Player *player = m_env->getPlayer(peer_id);
2222 name = narrow_to_wide(player->getName());
2224 std::wstring message;
2227 message += L" joined game";
2228 BroadcastChatMessage(message);
2232 // Warnings about protocol version can be issued here
2233 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2235 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2242 std::ostringstream os(std::ios_base::binary);
2243 for(core::map<u16, RemoteClient*>::Iterator
2244 i = m_clients.getIterator();
2245 i.atEnd() == false; i++)
2247 RemoteClient *client = i.getNode()->getValue();
2248 assert(client->peer_id == i.getNode()->getKey());
2249 if(client->serialization_version == SER_FMT_VER_INVALID)
2252 Player *player = m_env->getPlayer(client->peer_id);
2255 // Get name of player
2256 os<<player->getName()<<" ";
2259 actionstream<<player->getName()<<" joins game. List of players: "
2260 <<os.str()<<std::endl;
2266 if(peer_ser_ver == SER_FMT_VER_INVALID)
2268 infostream<<"Server::ProcessData(): Cancelling: Peer"
2269 " serialization format invalid or not initialized."
2270 " Skipping incoming command="<<command<<std::endl;
2274 Player *player = m_env->getPlayer(peer_id);
2275 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2278 infostream<<"Server::ProcessData(): Cancelling: "
2279 "No player for peer_id="<<peer_id
2283 if(command == TOSERVER_PLAYERPOS)
2285 if(datasize < 2+12+12+4+4)
2289 v3s32 ps = readV3S32(&data[start+2]);
2290 v3s32 ss = readV3S32(&data[start+2+12]);
2291 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2292 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2293 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2294 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2295 pitch = wrapDegrees(pitch);
2296 yaw = wrapDegrees(yaw);
2298 player->setPosition(position);
2299 player->setSpeed(speed);
2300 player->setPitch(pitch);
2301 player->setYaw(yaw);
2303 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2304 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2305 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2307 else if(command == TOSERVER_GOTBLOCKS)
2320 u16 count = data[2];
2321 for(u16 i=0; i<count; i++)
2323 if((s16)datasize < 2+1+(i+1)*6)
2324 throw con::InvalidIncomingDataException
2325 ("GOTBLOCKS length is too short");
2326 v3s16 p = readV3S16(&data[2+1+i*6]);
2327 /*infostream<<"Server: GOTBLOCKS ("
2328 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2329 RemoteClient *client = getClient(peer_id);
2330 client->GotBlock(p);
2333 else if(command == TOSERVER_DELETEDBLOCKS)
2346 u16 count = data[2];
2347 for(u16 i=0; i<count; i++)
2349 if((s16)datasize < 2+1+(i+1)*6)
2350 throw con::InvalidIncomingDataException
2351 ("DELETEDBLOCKS length is too short");
2352 v3s16 p = readV3S16(&data[2+1+i*6]);
2353 /*infostream<<"Server: DELETEDBLOCKS ("
2354 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2355 RemoteClient *client = getClient(peer_id);
2356 client->SetBlockNotSent(p);
2359 else if(command == TOSERVER_CLICK_OBJECT)
2361 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2364 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2366 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2369 else if(command == TOSERVER_GROUND_ACTION)
2371 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2375 else if(command == TOSERVER_RELEASE)
2377 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2380 else if(command == TOSERVER_SIGNTEXT)
2382 infostream<<"Server: SIGNTEXT not supported anymore"
2386 else if(command == TOSERVER_SIGNNODETEXT)
2388 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2396 std::string datastring((char*)&data[2], datasize-2);
2397 std::istringstream is(datastring, std::ios_base::binary);
2400 is.read((char*)buf, 6);
2401 v3s16 p = readV3S16(buf);
2402 is.read((char*)buf, 2);
2403 u16 textlen = readU16(buf);
2405 for(u16 i=0; i<textlen; i++)
2407 is.read((char*)buf, 1);
2408 text += (char)buf[0];
2411 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2415 meta->setText(text);
2417 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2418 <<" at "<<PP(p)<<std::endl;
2420 v3s16 blockpos = getNodeBlockPos(p);
2421 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2424 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2428 setBlockNotSent(blockpos);
2430 else if(command == TOSERVER_INVENTORY_ACTION)
2432 // Strip command and create a stream
2433 std::string datastring((char*)&data[2], datasize-2);
2434 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2435 std::istringstream is(datastring, std::ios_base::binary);
2437 InventoryAction *a = InventoryAction::deSerialize(is);
2440 infostream<<"TOSERVER_INVENTORY_ACTION: "
2441 <<"InventoryAction::deSerialize() returned NULL"
2447 Note: Always set inventory not sent, to repair cases
2448 where the client made a bad prediction.
2452 Handle restrictions and special cases of the move action
2454 if(a->getType() == IACTION_MOVE)
2456 IMoveAction *ma = (IMoveAction*)a;
2458 ma->from_inv.applyCurrentPlayer(player->getName());
2459 ma->to_inv.applyCurrentPlayer(player->getName());
2461 setInventoryModified(ma->from_inv);
2462 setInventoryModified(ma->to_inv);
2464 bool from_inv_is_current_player =
2465 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2466 (ma->from_inv.name == player->getName());
2468 bool to_inv_is_current_player =
2469 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2470 (ma->to_inv.name == player->getName());
2473 Disable moving items out of craftpreview
2475 if(ma->from_list == "craftpreview")
2477 infostream<<"Ignoring IMoveAction from "
2478 <<(ma->from_inv.dump())<<":"<<ma->from_list
2479 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2480 <<" because src is "<<ma->from_list<<std::endl;
2486 Disable moving items into craftresult and craftpreview
2488 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2490 infostream<<"Ignoring IMoveAction from "
2491 <<(ma->from_inv.dump())<<":"<<ma->from_list
2492 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2493 <<" because dst is "<<ma->to_list<<std::endl;
2498 // Disallow moving items in elsewhere than player's inventory
2499 // if not allowed to interact
2500 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2501 && (!from_inv_is_current_player
2502 || !to_inv_is_current_player))
2504 infostream<<"Cannot move outside of player's inventory: "
2505 <<"No interact privilege"<<std::endl;
2510 // If player is not an admin, check for ownership of src and dst
2511 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2513 std::string owner_from = getInventoryOwner(ma->from_inv);
2514 if(owner_from != "" && owner_from != player->getName())
2516 infostream<<"WARNING: "<<player->getName()
2517 <<" tried to access an inventory that"
2518 <<" belongs to "<<owner_from<<std::endl;
2523 std::string owner_to = getInventoryOwner(ma->to_inv);
2524 if(owner_to != "" && owner_to != player->getName())
2526 infostream<<"WARNING: "<<player->getName()
2527 <<" tried to access an inventory that"
2528 <<" belongs to "<<owner_to<<std::endl;
2535 Handle restrictions and special cases of the drop action
2537 else if(a->getType() == IACTION_DROP)
2539 IDropAction *da = (IDropAction*)a;
2541 da->from_inv.applyCurrentPlayer(player->getName());
2543 setInventoryModified(da->from_inv);
2545 // Disallow dropping items if not allowed to interact
2546 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2551 // If player is not an admin, check for ownership
2552 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2554 std::string owner_from = getInventoryOwner(da->from_inv);
2555 if(owner_from != "" && owner_from != player->getName())
2557 infostream<<"WARNING: "<<player->getName()
2558 <<" tried to access an inventory that"
2559 <<" belongs to "<<owner_from<<std::endl;
2566 Handle restrictions and special cases of the craft action
2568 else if(a->getType() == IACTION_CRAFT)
2570 ICraftAction *ca = (ICraftAction*)a;
2572 ca->craft_inv.applyCurrentPlayer(player->getName());
2574 setInventoryModified(ca->craft_inv);
2576 //bool craft_inv_is_current_player =
2577 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2578 // (ca->craft_inv.name == player->getName());
2580 // Disallow crafting if not allowed to interact
2581 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2583 infostream<<"Cannot craft: "
2584 <<"No interact privilege"<<std::endl;
2589 // If player is not an admin, check for ownership of inventory
2590 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2592 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2593 if(owner_craft != "" && owner_craft != player->getName())
2595 infostream<<"WARNING: "<<player->getName()
2596 <<" tried to access an inventory that"
2597 <<" belongs to "<<owner_craft<<std::endl;
2605 a->apply(this, srp, this);
2609 else if(command == TOSERVER_CHAT_MESSAGE)
2617 std::string datastring((char*)&data[2], datasize-2);
2618 std::istringstream is(datastring, std::ios_base::binary);
2621 is.read((char*)buf, 2);
2622 u16 len = readU16(buf);
2624 std::wstring message;
2625 for(u16 i=0; i<len; i++)
2627 is.read((char*)buf, 2);
2628 message += (wchar_t)readU16(buf);
2631 // Get player name of this client
2632 std::wstring name = narrow_to_wide(player->getName());
2635 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2636 wide_to_narrow(message));
2637 // If script ate the message, don't proceed
2641 // Line to send to players
2643 // Whether to send to the player that sent the line
2644 bool send_to_sender = false;
2645 // Whether to send to other players
2646 bool send_to_others = false;
2648 // Local player gets all privileges regardless of
2649 // what's set on their account.
2650 u64 privs = getPlayerPrivs(player);
2653 if(message[0] == L'/')
2655 size_t strip_size = 1;
2656 if (message[1] == L'#') // support old-style commans
2658 message = message.substr(strip_size);
2660 WStrfnd f1(message);
2661 f1.next(L" "); // Skip over /#whatever
2662 std::wstring paramstring = f1.next(L"");
2664 ServerCommandContext *ctx = new ServerCommandContext(
2665 str_split(message, L' '),
2672 std::wstring reply(processServerCommand(ctx));
2673 send_to_sender = ctx->flags & SEND_TO_SENDER;
2674 send_to_others = ctx->flags & SEND_TO_OTHERS;
2676 if (ctx->flags & SEND_NO_PREFIX)
2679 line += L"Server: " + reply;
2686 if(privs & PRIV_SHOUT)
2692 send_to_others = true;
2696 line += L"Server: You are not allowed to shout";
2697 send_to_sender = true;
2704 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2707 Send the message to clients
2709 for(core::map<u16, RemoteClient*>::Iterator
2710 i = m_clients.getIterator();
2711 i.atEnd() == false; i++)
2713 // Get client and check that it is valid
2714 RemoteClient *client = i.getNode()->getValue();
2715 assert(client->peer_id == i.getNode()->getKey());
2716 if(client->serialization_version == SER_FMT_VER_INVALID)
2720 bool sender_selected = (peer_id == client->peer_id);
2721 if(sender_selected == true && send_to_sender == false)
2723 if(sender_selected == false && send_to_others == false)
2726 SendChatMessage(client->peer_id, line);
2730 else if(command == TOSERVER_DAMAGE)
2732 std::string datastring((char*)&data[2], datasize-2);
2733 std::istringstream is(datastring, std::ios_base::binary);
2734 u8 damage = readU8(is);
2736 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2738 if(g_settings->getBool("enable_damage"))
2740 actionstream<<player->getName()<<" damaged by "
2741 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2744 srp->setHP(srp->getHP() - damage);
2746 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2749 if(srp->m_hp_not_sent)
2750 SendPlayerHP(player);
2754 // Force send (to correct the client's predicted HP)
2755 SendPlayerHP(player);
2758 else if(command == TOSERVER_PASSWORD)
2761 [0] u16 TOSERVER_PASSWORD
2762 [2] u8[28] old password
2763 [30] u8[28] new password
2766 if(datasize != 2+PASSWORD_SIZE*2)
2768 /*char password[PASSWORD_SIZE];
2769 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2770 password[i] = data[2+i];
2771 password[PASSWORD_SIZE-1] = 0;*/
2773 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2781 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2783 char c = data[2+PASSWORD_SIZE+i];
2789 infostream<<"Server: Client requests a password change from "
2790 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2792 std::string playername = player->getName();
2794 if(m_authmanager.exists(playername) == false)
2796 infostream<<"Server: playername not found in authmanager"<<std::endl;
2797 // Wrong old password supplied!!
2798 SendChatMessage(peer_id, L"playername not found in authmanager");
2802 std::string checkpwd = m_authmanager.getPassword(playername);
2804 if(oldpwd != checkpwd)
2806 infostream<<"Server: invalid old password"<<std::endl;
2807 // Wrong old password supplied!!
2808 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2812 actionstream<<player->getName()<<" changes password"<<std::endl;
2814 m_authmanager.setPassword(playername, newpwd);
2816 infostream<<"Server: password change successful for "<<playername
2818 SendChatMessage(peer_id, L"Password change successful");
2820 else if(command == TOSERVER_PLAYERITEM)
2825 u16 item = readU16(&data[2]);
2826 srp->setWieldIndex(item);
2827 SendWieldedItem(srp);
2829 else if(command == TOSERVER_RESPAWN)
2834 RespawnPlayer(player);
2836 actionstream<<player->getName()<<" respawns at "
2837 <<PP(player->getPosition()/BS)<<std::endl;
2839 // ActiveObject is added to environment in AsyncRunStep after
2840 // the previous addition has been succesfully removed
2842 else if(command == TOSERVER_REQUEST_TEXTURES) {
2843 std::string datastring((char*)&data[2], datasize-2);
2844 std::istringstream is(datastring, std::ios_base::binary);
2847 core::list<TextureRequest> tosend;
2848 u16 numtextures = readU16(is);
2850 infostream<<"Sending "<<numtextures<<" textures to "
2851 <<getPlayerName(peer_id)<<std::endl;
2852 verbosestream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2854 for(int i = 0; i < numtextures; i++) {
2855 std::string name = deSerializeString(is);
2856 tosend.push_back(TextureRequest(name));
2857 verbosestream<<"TOSERVER_REQUEST_TEXTURES: requested texture "
2861 SendTexturesRequested(peer_id, tosend);
2863 // Now the client should know about everything
2864 // (definitions and textures)
2865 getClient(peer_id)->definitions_sent = true;
2867 else if(command == TOSERVER_INTERACT)
2869 std::string datastring((char*)&data[2], datasize-2);
2870 std::istringstream is(datastring, std::ios_base::binary);
2876 [5] u32 length of the next item
2877 [9] serialized PointedThing
2879 0: start digging (from undersurface) or use
2880 1: stop digging (all parameters ignored)
2881 2: digging completed
2882 3: place block or item (to abovesurface)
2885 u8 action = readU8(is);
2886 u16 item_i = readU16(is);
2887 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2888 PointedThing pointed;
2889 pointed.deSerialize(tmp_is);
2891 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2892 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2896 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2897 <<" tried to interact, but is dead!"<<std::endl;
2901 v3f player_pos = srp->m_last_good_position;
2903 // Update wielded item
2904 if(srp->getWieldIndex() != item_i)
2906 srp->setWieldIndex(item_i);
2907 SendWieldedItem(srp);
2910 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2911 v3s16 p_under = pointed.node_undersurface;
2912 v3s16 p_above = pointed.node_abovesurface;
2914 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2915 ServerActiveObject *pointed_object = NULL;
2916 if(pointed.type == POINTEDTHING_OBJECT)
2918 pointed_object = m_env->getActiveObject(pointed.object_id);
2919 if(pointed_object == NULL)
2921 verbosestream<<"TOSERVER_INTERACT: "
2922 "pointed object is NULL"<<std::endl;
2928 v3f pointed_pos_under = player_pos;
2929 v3f pointed_pos_above = player_pos;
2930 if(pointed.type == POINTEDTHING_NODE)
2932 pointed_pos_under = intToFloat(p_under, BS);
2933 pointed_pos_above = intToFloat(p_above, BS);
2935 else if(pointed.type == POINTEDTHING_OBJECT)
2937 pointed_pos_under = pointed_object->getBasePosition();
2938 pointed_pos_above = pointed_pos_under;
2942 Check that target is reasonably close
2943 (only when digging or placing things)
2945 if(action == 0 || action == 2 || action == 3)
2947 float d = player_pos.getDistanceFrom(pointed_pos_under);
2948 float max_d = BS * 14; // Just some large enough value
2950 actionstream<<"Player "<<player->getName()
2951 <<" tried to access "<<pointed.dump()
2953 <<"d="<<d<<", max_d="<<max_d
2954 <<". ignoring."<<std::endl;
2955 // Re-send block to revert change on client-side
2956 RemoteClient *client = getClient(peer_id);
2957 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2958 client->SetBlockNotSent(blockpos);
2965 Make sure the player is allowed to do it
2967 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2969 infostream<<"Ignoring interaction from player "<<player->getName()
2970 <<" because privileges are "<<getPlayerPrivs(player)
2976 0: start digging or punch object
2980 if(pointed.type == POINTEDTHING_NODE)
2983 NOTE: This can be used in the future to check if
2984 somebody is cheating, by checking the timing.
2986 MapNode n(CONTENT_IGNORE);
2989 n = m_env->getMap().getNode(p_under);
2991 catch(InvalidPositionException &e)
2993 infostream<<"Server: Not punching: Node not found."
2994 <<" Adding block to emerge queue."
2996 m_emerge_queue.addBlock(peer_id,
2997 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2999 if(n.getContent() != CONTENT_IGNORE)
3000 scriptapi_node_on_punch(m_lua, p_under, n, srp);
3002 else if(pointed.type == POINTEDTHING_OBJECT)
3004 // Skip if object has been removed
3005 if(pointed_object->m_removed)
3008 actionstream<<player->getName()<<" punches object "
3009 <<pointed.object_id<<": "
3010 <<pointed_object->getDescription()<<std::endl;
3012 ItemStack punchitem = srp->getWieldedItem();
3013 ToolCapabilities toolcap =
3014 punchitem.getToolCapabilities(m_itemdef);
3015 v3f dir = (pointed_object->getBasePosition() -
3016 (srp->getPosition() + srp->getEyeOffset())
3018 pointed_object->punch(dir, &toolcap, srp,
3019 srp->m_time_from_last_punch);
3020 srp->m_time_from_last_punch = 0;
3028 else if(action == 1)
3033 2: Digging completed
3035 else if(action == 2)
3037 // Only complete digging of nodes
3038 if(pointed.type == POINTEDTHING_NODE)
3040 MapNode n(CONTENT_IGNORE);
3043 n = m_env->getMap().getNode(p_under);
3045 catch(InvalidPositionException &e)
3047 infostream<<"Server: Not finishing digging: Node not found."
3048 <<" Adding block to emerge queue."
3050 m_emerge_queue.addBlock(peer_id,
3051 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3053 if(n.getContent() != CONTENT_IGNORE)
3054 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3059 3: place block or right-click object
3061 else if(action == 3)
3063 ItemStack item = srp->getWieldedItem();
3065 // Reset build time counter
3066 if(pointed.type == POINTEDTHING_NODE &&
3067 item.getDefinition(m_itemdef).type == ITEM_NODE)
3068 getClient(peer_id)->m_time_from_building = 0.0;
3070 if(pointed.type == POINTEDTHING_OBJECT)
3072 // Right click object
3074 // Skip if object has been removed
3075 if(pointed_object->m_removed)
3078 actionstream<<player->getName()<<" right-clicks object "
3079 <<pointed.object_id<<": "
3080 <<pointed_object->getDescription()<<std::endl;
3083 pointed_object->rightClick(srp);
3085 else if(scriptapi_item_on_place(m_lua,
3086 item, srp, pointed))
3088 // Placement was handled in lua
3090 // Apply returned ItemStack
3091 if(g_settings->getBool("creative_mode") == false)
3092 srp->setWieldedItem(item);
3100 else if(action == 4)
3102 ItemStack item = srp->getWieldedItem();
3104 actionstream<<player->getName()<<" uses "<<item.name
3105 <<", pointing at "<<pointed.dump()<<std::endl;
3107 if(scriptapi_item_on_use(m_lua,
3108 item, srp, pointed))
3110 // Apply returned ItemStack
3111 if(g_settings->getBool("creative_mode") == false)
3112 srp->setWieldedItem(item);
3118 Catch invalid actions
3122 infostream<<"WARNING: Server: Invalid action "
3123 <<action<<std::endl;
3128 infostream<<"Server::ProcessData(): Ignoring "
3129 "unknown command "<<command<<std::endl;
3133 catch(SendFailedException &e)
3135 errorstream<<"Server::ProcessData(): SendFailedException: "
3141 void Server::onMapEditEvent(MapEditEvent *event)
3143 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3144 if(m_ignore_map_edit_events)
3146 MapEditEvent *e = event->clone();
3147 m_unsent_map_edit_queue.push_back(e);
3150 Inventory* Server::getInventory(const InventoryLocation &loc)
3153 case InventoryLocation::UNDEFINED:
3156 case InventoryLocation::CURRENT_PLAYER:
3159 case InventoryLocation::PLAYER:
3161 Player *player = m_env->getPlayer(loc.name.c_str());
3164 return &player->inventory;
3167 case InventoryLocation::NODEMETA:
3169 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3172 return meta->getInventory();
3180 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3183 case InventoryLocation::UNDEFINED:
3186 case InventoryLocation::CURRENT_PLAYER:
3189 case InventoryLocation::PLAYER:
3194 case InventoryLocation::NODEMETA:
3196 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3199 return meta->getOwner();
3207 void Server::setInventoryModified(const InventoryLocation &loc)
3210 case InventoryLocation::UNDEFINED:
3213 case InventoryLocation::PLAYER:
3215 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3216 (m_env->getPlayer(loc.name.c_str()));
3219 srp->m_inventory_not_sent = true;
3222 case InventoryLocation::NODEMETA:
3224 v3s16 blockpos = getNodeBlockPos(loc.p);
3226 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3228 meta->inventoryModified();
3230 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3232 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3234 setBlockNotSent(blockpos);
3242 core::list<PlayerInfo> Server::getPlayerInfo()
3244 DSTACK(__FUNCTION_NAME);
3245 JMutexAutoLock envlock(m_env_mutex);
3246 JMutexAutoLock conlock(m_con_mutex);
3248 core::list<PlayerInfo> list;
3250 core::list<Player*> players = m_env->getPlayers();
3252 core::list<Player*>::Iterator i;
3253 for(i = players.begin();
3254 i != players.end(); i++)
3258 Player *player = *i;
3261 // Copy info from connection to info struct
3262 info.id = player->peer_id;
3263 info.address = m_con.GetPeerAddress(player->peer_id);
3264 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3266 catch(con::PeerNotFoundException &e)
3268 // Set dummy peer info
3270 info.address = Address(0,0,0,0,0);
3274 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3275 info.position = player->getPosition();
3277 list.push_back(info);
3284 void Server::peerAdded(con::Peer *peer)
3286 DSTACK(__FUNCTION_NAME);
3287 verbosestream<<"Server::peerAdded(): peer->id="
3288 <<peer->id<<std::endl;
3291 c.type = PEER_ADDED;
3292 c.peer_id = peer->id;
3294 m_peer_change_queue.push_back(c);
3297 void Server::deletingPeer(con::Peer *peer, bool timeout)
3299 DSTACK(__FUNCTION_NAME);
3300 verbosestream<<"Server::deletingPeer(): peer->id="
3301 <<peer->id<<", timeout="<<timeout<<std::endl;
3304 c.type = PEER_REMOVED;
3305 c.peer_id = peer->id;
3306 c.timeout = timeout;
3307 m_peer_change_queue.push_back(c);
3314 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3316 DSTACK(__FUNCTION_NAME);
3317 std::ostringstream os(std::ios_base::binary);
3319 writeU16(os, TOCLIENT_HP);
3323 std::string s = os.str();
3324 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3326 con.Send(peer_id, 0, data, true);
3329 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3330 const std::wstring &reason)
3332 DSTACK(__FUNCTION_NAME);
3333 std::ostringstream os(std::ios_base::binary);
3335 writeU16(os, TOCLIENT_ACCESS_DENIED);
3336 os<<serializeWideString(reason);
3339 std::string s = os.str();
3340 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3342 con.Send(peer_id, 0, data, true);
3345 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3346 bool set_camera_point_target, v3f camera_point_target)
3348 DSTACK(__FUNCTION_NAME);
3349 std::ostringstream os(std::ios_base::binary);
3351 writeU16(os, TOCLIENT_DEATHSCREEN);
3352 writeU8(os, set_camera_point_target);
3353 writeV3F1000(os, camera_point_target);
3356 std::string s = os.str();
3357 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3359 con.Send(peer_id, 0, data, true);
3362 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3363 IItemDefManager *itemdef)
3365 DSTACK(__FUNCTION_NAME);
3366 std::ostringstream os(std::ios_base::binary);
3370 u32 length of the next item
3371 zlib-compressed serialized ItemDefManager
3373 writeU16(os, TOCLIENT_ITEMDEF);
3374 std::ostringstream tmp_os(std::ios::binary);
3375 itemdef->serialize(tmp_os);
3376 std::ostringstream tmp_os2(std::ios::binary);
3377 compressZlib(tmp_os.str(), tmp_os2);
3378 os<<serializeLongString(tmp_os2.str());
3381 std::string s = os.str();
3382 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3383 <<"): size="<<s.size()<<std::endl;
3384 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3386 con.Send(peer_id, 0, data, true);
3389 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3390 INodeDefManager *nodedef)
3392 DSTACK(__FUNCTION_NAME);
3393 std::ostringstream os(std::ios_base::binary);
3397 u32 length of the next item
3398 zlib-compressed serialized NodeDefManager
3400 writeU16(os, TOCLIENT_NODEDEF);
3401 std::ostringstream tmp_os(std::ios::binary);
3402 nodedef->serialize(tmp_os);
3403 std::ostringstream tmp_os2(std::ios::binary);
3404 compressZlib(tmp_os.str(), tmp_os2);
3405 os<<serializeLongString(tmp_os2.str());
3408 std::string s = os.str();
3409 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3410 <<"): size="<<s.size()<<std::endl;
3411 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3413 con.Send(peer_id, 0, data, true);
3417 Non-static send methods
3420 void Server::SendInventory(u16 peer_id)
3422 DSTACK(__FUNCTION_NAME);
3424 ServerRemotePlayer* player =
3425 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3428 player->m_inventory_not_sent = false;
3434 std::ostringstream os;
3435 //os.imbue(std::locale("C"));
3437 player->inventory.serialize(os);
3439 std::string s = os.str();
3441 SharedBuffer<u8> data(s.size()+2);
3442 writeU16(&data[0], TOCLIENT_INVENTORY);
3443 memcpy(&data[2], s.c_str(), s.size());
3446 m_con.Send(peer_id, 0, data, true);
3449 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3451 DSTACK(__FUNCTION_NAME);
3455 std::ostringstream os(std::ios_base::binary);
3457 writeU16(os, TOCLIENT_PLAYERITEM);
3459 writeU16(os, srp->peer_id);
3460 os<<serializeString(srp->getWieldedItem().getItemString());
3463 std::string s = os.str();
3464 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3466 m_con.SendToAll(0, data, true);
3469 void Server::SendPlayerItems()
3471 DSTACK(__FUNCTION_NAME);
3473 std::ostringstream os(std::ios_base::binary);
3474 core::list<Player *> players = m_env->getPlayers(true);
3476 writeU16(os, TOCLIENT_PLAYERITEM);
3477 writeU16(os, players.size());
3478 core::list<Player *>::Iterator i;
3479 for(i = players.begin(); i != players.end(); ++i)
3482 ServerRemotePlayer *srp =
3483 static_cast<ServerRemotePlayer*>(p);
3484 writeU16(os, p->peer_id);
3485 os<<serializeString(srp->getWieldedItem().getItemString());
3489 std::string s = os.str();
3490 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3492 m_con.SendToAll(0, data, true);
3495 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3497 DSTACK(__FUNCTION_NAME);
3499 std::ostringstream os(std::ios_base::binary);
3503 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3504 os.write((char*)buf, 2);
3507 writeU16(buf, message.size());
3508 os.write((char*)buf, 2);
3511 for(u32 i=0; i<message.size(); i++)
3515 os.write((char*)buf, 2);
3519 std::string s = os.str();
3520 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3522 m_con.Send(peer_id, 0, data, true);
3525 void Server::BroadcastChatMessage(const std::wstring &message)
3527 for(core::map<u16, RemoteClient*>::Iterator
3528 i = m_clients.getIterator();
3529 i.atEnd() == false; i++)
3531 // Get client and check that it is valid
3532 RemoteClient *client = i.getNode()->getValue();
3533 assert(client->peer_id == i.getNode()->getKey());
3534 if(client->serialization_version == SER_FMT_VER_INVALID)
3537 SendChatMessage(client->peer_id, message);
3541 void Server::SendPlayerHP(Player *player)
3543 SendHP(m_con, player->peer_id, player->hp);
3544 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3547 void Server::SendMovePlayer(Player *player)
3549 DSTACK(__FUNCTION_NAME);
3550 std::ostringstream os(std::ios_base::binary);
3552 writeU16(os, TOCLIENT_MOVE_PLAYER);
3553 writeV3F1000(os, player->getPosition());
3554 writeF1000(os, player->getPitch());
3555 writeF1000(os, player->getYaw());
3558 v3f pos = player->getPosition();
3559 f32 pitch = player->getPitch();
3560 f32 yaw = player->getYaw();
3561 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3562 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3569 std::string s = os.str();
3570 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3572 m_con.Send(player->peer_id, 0, data, true);
3575 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3576 core::list<u16> *far_players, float far_d_nodes)
3578 float maxd = far_d_nodes*BS;
3579 v3f p_f = intToFloat(p, BS);
3583 SharedBuffer<u8> reply(replysize);
3584 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3585 writeS16(&reply[2], p.X);
3586 writeS16(&reply[4], p.Y);
3587 writeS16(&reply[6], p.Z);
3589 for(core::map<u16, RemoteClient*>::Iterator
3590 i = m_clients.getIterator();
3591 i.atEnd() == false; i++)
3593 // Get client and check that it is valid
3594 RemoteClient *client = i.getNode()->getValue();
3595 assert(client->peer_id == i.getNode()->getKey());
3596 if(client->serialization_version == SER_FMT_VER_INVALID)
3599 // Don't send if it's the same one
3600 if(client->peer_id == ignore_id)
3606 Player *player = m_env->getPlayer(client->peer_id);
3609 // If player is far away, only set modified blocks not sent
3610 v3f player_pos = player->getPosition();
3611 if(player_pos.getDistanceFrom(p_f) > maxd)
3613 far_players->push_back(client->peer_id);
3620 m_con.Send(client->peer_id, 0, reply, true);
3624 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3625 core::list<u16> *far_players, float far_d_nodes)
3627 float maxd = far_d_nodes*BS;
3628 v3f p_f = intToFloat(p, BS);
3630 for(core::map<u16, RemoteClient*>::Iterator
3631 i = m_clients.getIterator();
3632 i.atEnd() == false; i++)
3634 // Get client and check that it is valid
3635 RemoteClient *client = i.getNode()->getValue();
3636 assert(client->peer_id == i.getNode()->getKey());
3637 if(client->serialization_version == SER_FMT_VER_INVALID)
3640 // Don't send if it's the same one
3641 if(client->peer_id == ignore_id)
3647 Player *player = m_env->getPlayer(client->peer_id);
3650 // If player is far away, only set modified blocks not sent
3651 v3f player_pos = player->getPosition();
3652 if(player_pos.getDistanceFrom(p_f) > maxd)
3654 far_players->push_back(client->peer_id);
3661 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3662 SharedBuffer<u8> reply(replysize);
3663 writeU16(&reply[0], TOCLIENT_ADDNODE);
3664 writeS16(&reply[2], p.X);
3665 writeS16(&reply[4], p.Y);
3666 writeS16(&reply[6], p.Z);
3667 n.serialize(&reply[8], client->serialization_version);
3670 m_con.Send(client->peer_id, 0, reply, true);
3674 void Server::setBlockNotSent(v3s16 p)
3676 for(core::map<u16, RemoteClient*>::Iterator
3677 i = m_clients.getIterator();
3678 i.atEnd()==false; i++)
3680 RemoteClient *client = i.getNode()->getValue();
3681 client->SetBlockNotSent(p);
3685 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3687 DSTACK(__FUNCTION_NAME);
3689 v3s16 p = block->getPos();
3693 bool completely_air = true;
3694 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3695 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3696 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3698 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3700 completely_air = false;
3701 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3706 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3708 infostream<<"[completely air] ";
3709 infostream<<std::endl;
3713 Create a packet with the block in the right format
3716 std::ostringstream os(std::ios_base::binary);
3717 block->serialize(os, ver, false);
3718 std::string s = os.str();
3719 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3721 u32 replysize = 8 + blockdata.getSize();
3722 SharedBuffer<u8> reply(replysize);
3723 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3724 writeS16(&reply[2], p.X);
3725 writeS16(&reply[4], p.Y);
3726 writeS16(&reply[6], p.Z);
3727 memcpy(&reply[8], *blockdata, blockdata.getSize());
3729 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3730 <<": \tpacket size: "<<replysize<<std::endl;*/
3735 m_con.Send(peer_id, 1, reply, true);
3738 void Server::SendBlocks(float dtime)
3740 DSTACK(__FUNCTION_NAME);
3742 JMutexAutoLock envlock(m_env_mutex);
3743 JMutexAutoLock conlock(m_con_mutex);
3745 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3747 core::array<PrioritySortedBlockTransfer> queue;
3749 s32 total_sending = 0;
3752 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3754 for(core::map<u16, RemoteClient*>::Iterator
3755 i = m_clients.getIterator();
3756 i.atEnd() == false; i++)
3758 RemoteClient *client = i.getNode()->getValue();
3759 assert(client->peer_id == i.getNode()->getKey());
3761 // If definitions and textures have not been sent, don't
3762 // send MapBlocks either
3763 if(!client->definitions_sent)
3766 total_sending += client->SendingCount();
3768 if(client->serialization_version == SER_FMT_VER_INVALID)
3771 client->GetNextBlocks(this, dtime, queue);
3776 // Lowest priority number comes first.
3777 // Lowest is most important.
3780 for(u32 i=0; i<queue.size(); i++)
3782 //TODO: Calculate limit dynamically
3783 if(total_sending >= g_settings->getS32
3784 ("max_simultaneous_block_sends_server_total"))
3787 PrioritySortedBlockTransfer q = queue[i];
3789 MapBlock *block = NULL;
3792 block = m_env->getMap().getBlockNoCreate(q.pos);
3794 catch(InvalidPositionException &e)
3799 RemoteClient *client = getClient(q.peer_id);
3801 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3803 client->SentBlock(q.pos);
3809 void Server::PrepareTextures()
3811 DSTACK(__FUNCTION_NAME);
3813 infostream<<"Server: Calculating texture checksums"<<std::endl;
3815 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3816 i != m_mods.end(); i++){
3817 const ModSpec &mod = *i;
3818 std::string texturepath = mod.path + DIR_DELIM + "textures";
3819 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3820 for(u32 j=0; j<dirlist.size(); j++){
3821 if(dirlist[j].dir) // Ignode dirs
3823 std::string tname = dirlist[j].name;
3824 // if name contains illegal characters, ignore the texture
3825 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3826 errorstream<<"Server: ignoring illegal texture name: \""
3827 <<tname<<"\""<<std::endl;
3830 std::string tpath = texturepath + DIR_DELIM + tname;
3832 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3833 if(fis.good() == false){
3834 errorstream<<"Server::PrepareTextures(): Could not open \""
3835 <<tname<<"\" for reading"<<std::endl;
3838 std::ostringstream tmp_os(std::ios_base::binary);
3842 fis.read(buf, 1024);
3843 std::streamsize len = fis.gcount();
3844 tmp_os.write(buf, len);
3853 errorstream<<"Server::PrepareTextures(): Failed to read \""
3854 <<tname<<"\""<<std::endl;
3857 if(tmp_os.str().length() == 0){
3858 errorstream<<"Server::PrepareTextures(): Empty file \""
3859 <<tpath<<"\""<<std::endl;
3864 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3866 unsigned char *digest = sha1.getDigest();
3867 std::string digest_string = base64_encode(digest, 20);
3872 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3873 verbosestream<<"Server: sha1 for "<<tname<<"\tis "<<std::endl;
3878 struct SendableTextureAnnouncement
3881 std::string sha1_digest;
3883 SendableTextureAnnouncement(const std::string name_="",
3884 const std::string sha1_digest_=""):
3886 sha1_digest(sha1_digest_)
3891 void Server::SendTextureAnnouncement(u16 peer_id){
3892 DSTACK(__FUNCTION_NAME);
3894 verbosestream<<"Server: Announcing textures to id("<<peer_id<<")"
3897 core::list<SendableTextureAnnouncement> texture_announcements;
3899 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3902 texture_announcements.push_back(
3903 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3906 //send announcements
3910 u32 number of textures
3914 u16 length of digest string
3918 std::ostringstream os(std::ios_base::binary);
3920 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3921 writeU16(os, texture_announcements.size());
3923 for(core::list<SendableTextureAnnouncement>::Iterator
3924 j = texture_announcements.begin();
3925 j != texture_announcements.end(); j++){
3926 os<<serializeString(j->name);
3927 os<<serializeString(j->sha1_digest);
3931 std::string s = os.str();
3932 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3935 m_con.Send(peer_id, 0, data, true);
3939 struct SendableTexture
3945 SendableTexture(const std::string &name_="", const std::string path_="",
3946 const std::string &data_=""):
3953 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3954 DSTACK(__FUNCTION_NAME);
3956 verbosestream<<"Server::SendTexturesRequested(): "
3957 <<"Sending textures to client"<<std::endl;
3961 // Put 5kB in one bunch (this is not accurate)
3962 u32 bytes_per_bunch = 5000;
3964 core::array< core::list<SendableTexture> > texture_bunches;
3965 texture_bunches.push_back(core::list<SendableTexture>());
3967 u32 texture_size_bunch_total = 0;
3969 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3970 if(m_Textures.find(i->name) == m_Textures.end()){
3971 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3972 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3976 //TODO get path + name
3977 std::string tpath = m_Textures[(*i).name].path;
3980 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3981 if(fis.good() == false){
3982 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3983 <<tpath<<"\" for reading"<<std::endl;
3986 std::ostringstream tmp_os(std::ios_base::binary);
3990 fis.read(buf, 1024);
3991 std::streamsize len = fis.gcount();
3992 tmp_os.write(buf, len);
3993 texture_size_bunch_total += len;
4002 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
4003 <<(*i).name<<"\""<<std::endl;
4006 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
4007 <<tname<<"\""<<std::endl;*/
4009 texture_bunches[texture_bunches.size()-1].push_back(
4010 SendableTexture((*i).name, tpath, tmp_os.str()));
4012 // Start next bunch if got enough data
4013 if(texture_size_bunch_total >= bytes_per_bunch){
4014 texture_bunches.push_back(core::list<SendableTexture>());
4015 texture_size_bunch_total = 0;
4020 /* Create and send packets */
4022 u32 num_bunches = texture_bunches.size();
4023 for(u32 i=0; i<num_bunches; i++)
4027 u16 total number of texture bunches
4028 u16 index of this bunch
4029 u32 number of textures in this bunch
4037 std::ostringstream os(std::ios_base::binary);
4039 writeU16(os, TOCLIENT_TEXTURES);
4040 writeU16(os, num_bunches);
4042 writeU32(os, texture_bunches[i].size());
4044 for(core::list<SendableTexture>::Iterator
4045 j = texture_bunches[i].begin();
4046 j != texture_bunches[i].end(); j++){
4047 os<<serializeString(j->name);
4048 os<<serializeLongString(j->data);
4052 std::string s = os.str();
4053 verbosestream<<"Server::SendTexturesRequested(): bunch "
4054 <<i<<"/"<<num_bunches
4055 <<" textures="<<texture_bunches[i].size()
4056 <<" size=" <<s.size()<<std::endl;
4057 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4059 m_con.Send(peer_id, 0, data, true);
4069 void Server::DiePlayer(Player *player)
4071 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4073 infostream<<"Server::DiePlayer(): Player "
4074 <<player->getName()<<" dies"<<std::endl;
4078 // Trigger scripted stuff
4079 scriptapi_on_dieplayer(m_lua, srp);
4081 // Handle players that are not connected
4082 if(player->peer_id == PEER_ID_INEXISTENT){
4083 RespawnPlayer(player);
4087 SendPlayerHP(player);
4088 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4091 void Server::RespawnPlayer(Player *player)
4093 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4095 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4097 v3f pos = findSpawnPos(m_env->getServerMap());
4098 player->setPosition(pos);
4099 srp->m_last_good_position = pos;
4100 srp->m_last_good_position_age = 0;
4102 SendMovePlayer(player);
4103 SendPlayerHP(player);
4106 void Server::UpdateCrafting(u16 peer_id)
4108 DSTACK(__FUNCTION_NAME);
4110 Player* player = m_env->getPlayer(peer_id);
4113 // Get a preview for crafting
4115 // No crafting in creative mode
4116 if(g_settings->getBool("creative_mode") == false)
4117 getCraftingResult(&player->inventory, preview, false, this);
4119 // Put the new preview in
4120 InventoryList *plist = player->inventory.getList("craftpreview");
4122 assert(plist->getSize() >= 1);
4123 plist->changeItem(0, preview);
4126 RemoteClient* Server::getClient(u16 peer_id)
4128 DSTACK(__FUNCTION_NAME);
4129 //JMutexAutoLock lock(m_con_mutex);
4130 core::map<u16, RemoteClient*>::Node *n;
4131 n = m_clients.find(peer_id);
4132 // A client should exist for all peers
4134 return n->getValue();
4137 std::wstring Server::getStatusString()
4139 std::wostringstream os(std::ios_base::binary);
4142 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4144 os<<L", uptime="<<m_uptime.get();
4145 // Information about clients
4147 for(core::map<u16, RemoteClient*>::Iterator
4148 i = m_clients.getIterator();
4149 i.atEnd() == false; i++)
4151 // Get client and check that it is valid
4152 RemoteClient *client = i.getNode()->getValue();
4153 assert(client->peer_id == i.getNode()->getKey());
4154 if(client->serialization_version == SER_FMT_VER_INVALID)
4157 Player *player = m_env->getPlayer(client->peer_id);
4158 // Get name of player
4159 std::wstring name = L"unknown";
4161 name = narrow_to_wide(player->getName());
4162 // Add name to information string
4166 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4167 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4168 if(g_settings->get("motd") != "")
4169 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4173 u64 Server::getPlayerAuthPrivs(const std::string &name)
4176 return m_authmanager.getPrivs(name);
4178 catch(AuthNotFoundException &e)
4180 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4185 void Server::setPlayerAuthPrivs(const std::string &name, u64 privs)
4188 return m_authmanager.setPrivs(name, privs);
4190 catch(AuthNotFoundException &e)
4192 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4196 u64 Server::getPlayerEffectivePrivs(const std::string &name)
4198 // Local player gets all privileges regardless of
4199 // what's set on their account.
4200 if(m_simple_singleplayer_mode)
4202 if(name == g_settings->get("name"))
4204 return getPlayerAuthPrivs(name);
4207 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4209 // Add player to auth manager
4210 if(m_authmanager.exists(name) == false)
4212 infostream<<"Server: adding player "<<name
4213 <<" to auth manager"<<std::endl;
4214 m_authmanager.add(name);
4215 m_authmanager.setPrivs(name,
4216 stringToPrivs(g_settings->get("default_privs")));
4218 // Change password and save
4219 m_authmanager.setPassword(name, translatePassword(name, password));
4220 m_authmanager.save();
4223 // Saves g_settings to configpath given at initialization
4224 void Server::saveConfig()
4226 if(m_path_config != "")
4227 g_settings->updateConfigFile(m_path_config.c_str());
4230 void Server::notifyPlayer(const char *name, const std::wstring msg)
4232 Player *player = m_env->getPlayer(name);
4235 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4238 void Server::notifyPlayers(const std::wstring msg)
4240 BroadcastChatMessage(msg);
4243 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4247 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4248 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4251 // IGameDef interface
4253 IItemDefManager* Server::getItemDefManager()
4257 INodeDefManager* Server::getNodeDefManager()
4261 ICraftDefManager* Server::getCraftDefManager()
4265 ITextureSource* Server::getTextureSource()
4269 u16 Server::allocateUnknownNodeId(const std::string &name)
4271 return m_nodedef->allocateDummy(name);
4274 IWritableItemDefManager* Server::getWritableItemDefManager()
4278 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4282 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4287 const ModSpec* Server::getModSpec(const std::string &modname)
4289 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4290 i != m_mods.end(); i++){
4291 const ModSpec &mod = *i;
4292 if(mod.name == modname)
4298 v3f findSpawnPos(ServerMap &map)
4300 //return v3f(50,50,50)*BS;
4305 nodepos = v2s16(0,0);
4310 // Try to find a good place a few times
4311 for(s32 i=0; i<1000; i++)
4314 // We're going to try to throw the player to this position
4315 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4316 -range + (myrand()%(range*2)));
4317 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4318 // Get ground height at point (fallbacks to heightmap function)
4319 s16 groundheight = map.findGroundLevel(nodepos2d);
4320 // Don't go underwater
4321 if(groundheight < WATER_LEVEL)
4323 //infostream<<"-> Underwater"<<std::endl;
4326 // Don't go to high places
4327 if(groundheight > WATER_LEVEL + 4)
4329 //infostream<<"-> Underwater"<<std::endl;
4333 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4334 bool is_good = false;
4336 for(s32 i=0; i<10; i++){
4337 v3s16 blockpos = getNodeBlockPos(nodepos);
4338 map.emergeBlock(blockpos, true);
4339 MapNode n = map.getNodeNoEx(nodepos);
4340 if(n.getContent() == CONTENT_AIR){
4351 // Found a good place
4352 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4358 return intToFloat(nodepos, BS);
4361 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4364 Try to get an existing player
4366 ServerRemotePlayer *player =
4367 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4370 // If player is already connected, cancel
4371 if(player->peer_id != 0)
4373 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4378 player->peer_id = peer_id;
4380 // Re-add player to environment
4381 if(player->m_removed)
4383 player->m_removed = false;
4385 m_env->addActiveObject(player);
4388 // Reset inventory to creative if in creative mode
4389 if(g_settings->getBool("creative_mode"))
4391 // Warning: double code below
4392 // Backup actual inventory
4393 player->inventory_backup = new Inventory(m_itemdef);
4394 *(player->inventory_backup) = player->inventory;
4395 // Set creative inventory
4396 player->resetInventory();
4397 scriptapi_get_creative_inventory(m_lua, player);
4404 If player with the wanted peer_id already exists, cancel.
4406 if(m_env->getPlayer(peer_id) != NULL)
4408 infostream<<"emergePlayer(): Player with wrong name but same"
4409 " peer_id already exists"<<std::endl;
4417 /* Set player position */
4419 infostream<<"Server: Finding spawn place for player \""
4420 <<name<<"\""<<std::endl;
4422 v3f pos = findSpawnPos(m_env->getServerMap());
4424 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4425 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4427 /* Add player to environment */
4428 m_env->addPlayer(player);
4429 m_env->addActiveObject(srp);
4432 scriptapi_on_newplayer(m_lua, srp);
4434 /* Add stuff to inventory */
4435 if(g_settings->getBool("creative_mode"))
4437 // Warning: double code above
4438 // Backup actual inventory
4439 player->inventory_backup = new Inventory(m_itemdef);
4440 *(player->inventory_backup) = player->inventory;
4441 // Set creative inventory
4442 player->resetInventory();
4443 scriptapi_get_creative_inventory(m_lua, player);
4448 } // create new player
4451 void Server::handlePeerChange(PeerChange &c)
4453 JMutexAutoLock envlock(m_env_mutex);
4454 JMutexAutoLock conlock(m_con_mutex);
4456 if(c.type == PEER_ADDED)
4463 core::map<u16, RemoteClient*>::Node *n;
4464 n = m_clients.find(c.peer_id);
4465 // The client shouldn't already exist
4469 RemoteClient *client = new RemoteClient();
4470 client->peer_id = c.peer_id;
4471 m_clients.insert(client->peer_id, client);
4474 else if(c.type == PEER_REMOVED)
4481 core::map<u16, RemoteClient*>::Node *n;
4482 n = m_clients.find(c.peer_id);
4483 // The client should exist
4487 Mark objects to be not known by the client
4489 RemoteClient *client = n->getValue();
4491 for(core::map<u16, bool>::Iterator
4492 i = client->m_known_objects.getIterator();
4493 i.atEnd()==false; i++)
4496 u16 id = i.getNode()->getKey();
4497 ServerActiveObject* obj = m_env->getActiveObject(id);
4499 if(obj && obj->m_known_by_count > 0)
4500 obj->m_known_by_count--;
4503 ServerRemotePlayer* player =
4504 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4506 // Collect information about leaving in chat
4507 std::wstring message;
4511 std::wstring name = narrow_to_wide(player->getName());
4514 message += L" left game";
4516 message += L" (timed out)";
4520 // Remove from environment
4522 player->m_removed = true;
4524 // Set player client disconnected
4526 player->peer_id = 0;
4534 std::ostringstream os(std::ios_base::binary);
4535 for(core::map<u16, RemoteClient*>::Iterator
4536 i = m_clients.getIterator();
4537 i.atEnd() == false; i++)
4539 RemoteClient *client = i.getNode()->getValue();
4540 assert(client->peer_id == i.getNode()->getKey());
4541 if(client->serialization_version == SER_FMT_VER_INVALID)
4544 Player *player = m_env->getPlayer(client->peer_id);
4547 // Get name of player
4548 os<<player->getName()<<" ";
4551 actionstream<<player->getName()<<" "
4552 <<(c.timeout?"times out.":"leaves game.")
4553 <<" List of players: "
4554 <<os.str()<<std::endl;
4559 delete m_clients[c.peer_id];
4560 m_clients.remove(c.peer_id);
4562 // Send player info to all remaining clients
4563 //SendPlayerInfos();
4565 // Send leave chat message to all remaining clients
4566 if(message.length() != 0)
4567 BroadcastChatMessage(message);
4576 void Server::handlePeerChanges()
4578 while(m_peer_change_queue.size() > 0)
4580 PeerChange c = m_peer_change_queue.pop_front();
4582 verbosestream<<"Server: Handling peer change: "
4583 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4586 handlePeerChange(c);
4590 u64 Server::getPlayerPrivs(Player *player)
4594 std::string playername = player->getName();
4595 return getPlayerEffectivePrivs(playername);
4598 void dedicated_server_loop(Server &server, bool &kill)
4600 DSTACK(__FUNCTION_NAME);
4602 verbosestream<<"dedicated_server_loop()"<<std::endl;
4604 IntervalLimiter m_profiler_interval;
4608 float steplen = g_settings->getFloat("dedicated_server_step");
4609 // This is kind of a hack but can be done like this
4610 // because server.step() is very light
4612 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4613 sleep_ms((int)(steplen*1000.0));
4615 server.step(steplen);
4617 if(server.getShutdownRequested() || kill)
4619 infostream<<"Dedicated server quitting"<<std::endl;
4626 float profiler_print_interval =
4627 g_settings->getFloat("profiler_print_interval");
4628 if(profiler_print_interval != 0)
4630 if(m_profiler_interval.step(steplen, profiler_print_interval))
4632 infostream<<"Profiler:"<<std::endl;
4633 g_profiler->print(infostream);
4634 g_profiler->clear();