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"
52 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
54 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
56 class MapEditEventIgnorer
59 MapEditEventIgnorer(bool *flag):
68 ~MapEditEventIgnorer()
81 void * ServerThread::Thread()
85 log_register_thread("ServerThread");
87 DSTACK(__FUNCTION_NAME);
89 BEGIN_DEBUG_EXCEPTION_HANDLER
94 //TimeTaker timer("AsyncRunStep() + Receive()");
97 //TimeTaker timer("AsyncRunStep()");
98 m_server->AsyncRunStep();
101 //infostream<<"Running m_server->Receive()"<<std::endl;
104 catch(con::NoIncomingDataException &e)
107 catch(con::PeerNotFoundException &e)
109 infostream<<"Server: PeerNotFoundException"<<std::endl;
113 END_DEBUG_EXCEPTION_HANDLER(errorstream)
118 void * EmergeThread::Thread()
122 log_register_thread("EmergeThread");
124 DSTACK(__FUNCTION_NAME);
126 BEGIN_DEBUG_EXCEPTION_HANDLER
128 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
131 Get block info from queue, emerge them and send them
134 After queue is empty, exit.
138 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
142 SharedPtr<QueuedBlockEmerge> q(qptr);
148 Do not generate over-limit
150 if(blockpos_over_limit(p))
153 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
155 //TimeTaker timer("block emerge");
158 Try to emerge it from somewhere.
160 If it is only wanted as optional, only loading from disk
165 Check if any peer wants it as non-optional. In that case it
168 Also decrement the emerge queue count in clients.
171 bool only_from_disk = true;
174 core::map<u16, u8>::Iterator i;
175 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
177 //u16 peer_id = i.getNode()->getKey();
180 u8 flags = i.getNode()->getValue();
181 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
182 only_from_disk = false;
187 if(enable_mapgen_debug_info)
188 infostream<<"EmergeThread: p="
189 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
190 <<"only_from_disk="<<only_from_disk<<std::endl;
192 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
194 MapBlock *block = NULL;
195 bool got_block = true;
196 core::map<v3s16, MapBlock*> modified_blocks;
199 Try to fetch block from memory or disk.
200 If not found and asked to generate, initialize generator.
203 bool started_generate = false;
204 mapgen::BlockMakeData data;
207 JMutexAutoLock envlock(m_server->m_env_mutex);
209 // Load sector if it isn't loaded
210 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
211 map.loadSectorMeta(p2d);
213 // Attempt to load block
214 block = map.getBlockNoCreateNoEx(p);
215 if(!block || block->isDummy() || !block->isGenerated())
217 if(enable_mapgen_debug_info)
218 infostream<<"EmergeThread: not in memory, "
219 <<"attempting to load from disk"<<std::endl;
221 block = map.loadBlock(p);
224 // If could not load and allowed to generate, start generation
225 // inside this same envlock
226 if(only_from_disk == false &&
227 (block == NULL || block->isGenerated() == false)){
228 if(enable_mapgen_debug_info)
229 infostream<<"EmergeThread: generating"<<std::endl;
230 started_generate = true;
232 map.initBlockMake(&data, p);
237 If generator was initialized, generate now when envlock is free.
242 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
244 TimeTaker t("mapgen::make_block()");
246 mapgen::make_block(&data);
248 if(enable_mapgen_debug_info == false)
249 t.stop(true); // Hide output
253 // Lock environment again to access the map
254 JMutexAutoLock envlock(m_server->m_env_mutex);
256 ScopeProfiler sp(g_profiler, "EmergeThread: after "
257 "mapgen::make_block (envlock)", SPT_AVG);
259 // Blit data back on map, update lighting, add mobs and
260 // whatever this does
261 map.finishBlockMake(&data, modified_blocks);
264 block = map.getBlockNoCreateNoEx(p);
266 // If block doesn't exist, don't try doing anything with it
267 // This happens if the block is not in generation boundaries
272 Do some post-generate stuff
275 v3s16 minp = block->getPos()*MAP_BLOCKSIZE;
276 v3s16 maxp = minp + v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
277 scriptapi_environment_on_generated(m_server->m_lua,
280 if(enable_mapgen_debug_info)
281 infostream<<"EmergeThread: ended up with: "
282 <<analyze_block(block)<<std::endl;
285 Ignore map edit events, they will not need to be
286 sent to anybody because the block hasn't been sent
289 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
291 // Activate objects and stuff
292 m_server->m_env->activateBlock(block, 0);
300 Set sent status of modified blocks on clients
303 // NOTE: Server's clients are also behind the connection mutex
304 JMutexAutoLock lock(m_server->m_con_mutex);
307 Add the originally fetched block to the modified list
311 modified_blocks.insert(p, block);
315 Set the modified blocks unsent for all the clients
318 for(core::map<u16, RemoteClient*>::Iterator
319 i = m_server->m_clients.getIterator();
320 i.atEnd() == false; i++)
322 RemoteClient *client = i.getNode()->getValue();
324 if(modified_blocks.size() > 0)
326 // Remove block from sent history
327 client->SetBlocksNotSent(modified_blocks);
333 END_DEBUG_EXCEPTION_HANDLER(errorstream)
335 log_deregister_thread();
340 void RemoteClient::GetNextBlocks(Server *server, float dtime,
341 core::array<PrioritySortedBlockTransfer> &dest)
343 DSTACK(__FUNCTION_NAME);
346 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
349 m_nothing_to_send_pause_timer -= dtime;
350 m_nearest_unsent_reset_timer += dtime;
352 if(m_nothing_to_send_pause_timer >= 0)
357 // Won't send anything if already sending
358 if(m_blocks_sending.size() >= g_settings->getU16
359 ("max_simultaneous_block_sends_per_client"))
361 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
365 //TimeTaker timer("RemoteClient::GetNextBlocks");
367 Player *player = server->m_env->getPlayer(peer_id);
369 assert(player != NULL);
371 v3f playerpos = player->getPosition();
372 v3f playerspeed = player->getSpeed();
373 v3f playerspeeddir(0,0,0);
374 if(playerspeed.getLength() > 1.0*BS)
375 playerspeeddir = playerspeed / playerspeed.getLength();
376 // Predict to next block
377 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
379 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
381 v3s16 center = getNodeBlockPos(center_nodepos);
383 // Camera position and direction
384 v3f camera_pos = player->getEyePosition();
385 v3f camera_dir = v3f(0,0,1);
386 camera_dir.rotateYZBy(player->getPitch());
387 camera_dir.rotateXZBy(player->getYaw());
389 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
390 <<camera_dir.Z<<")"<<std::endl;*/
393 Get the starting value of the block finder radius.
396 if(m_last_center != center)
398 m_nearest_unsent_d = 0;
399 m_last_center = center;
402 /*infostream<<"m_nearest_unsent_reset_timer="
403 <<m_nearest_unsent_reset_timer<<std::endl;*/
405 // Reset periodically to workaround for some bugs or stuff
406 if(m_nearest_unsent_reset_timer > 20.0)
408 m_nearest_unsent_reset_timer = 0;
409 m_nearest_unsent_d = 0;
410 //infostream<<"Resetting m_nearest_unsent_d for "
411 // <<server->getPlayerName(peer_id)<<std::endl;
414 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
415 s16 d_start = m_nearest_unsent_d;
417 //infostream<<"d_start="<<d_start<<std::endl;
419 u16 max_simul_sends_setting = g_settings->getU16
420 ("max_simultaneous_block_sends_per_client");
421 u16 max_simul_sends_usually = max_simul_sends_setting;
424 Check the time from last addNode/removeNode.
426 Decrease send rate if player is building stuff.
428 m_time_from_building += dtime;
429 if(m_time_from_building < g_settings->getFloat(
430 "full_block_send_enable_min_time_from_building"))
432 max_simul_sends_usually
433 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
437 Number of blocks sending + number of blocks selected for sending
439 u32 num_blocks_selected = m_blocks_sending.size();
442 next time d will be continued from the d from which the nearest
443 unsent block was found this time.
445 This is because not necessarily any of the blocks found this
446 time are actually sent.
448 s32 new_nearest_unsent_d = -1;
450 s16 d_max = g_settings->getS16("max_block_send_distance");
451 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
453 // Don't loop very much at a time
454 s16 max_d_increment_at_time = 2;
455 if(d_max > d_start + max_d_increment_at_time)
456 d_max = d_start + max_d_increment_at_time;
457 /*if(d_max_gen > d_start+2)
458 d_max_gen = d_start+2;*/
460 //infostream<<"Starting from "<<d_start<<std::endl;
462 s32 nearest_emerged_d = -1;
463 s32 nearest_emergefull_d = -1;
464 s32 nearest_sent_d = -1;
465 bool queue_is_full = false;
468 for(d = d_start; d <= d_max; d++)
470 /*errorstream<<"checking d="<<d<<" for "
471 <<server->getPlayerName(peer_id)<<std::endl;*/
472 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
475 If m_nearest_unsent_d was changed by the EmergeThread
476 (it can change it to 0 through SetBlockNotSent),
478 Else update m_nearest_unsent_d
480 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
482 d = m_nearest_unsent_d;
483 last_nearest_unsent_d = m_nearest_unsent_d;
487 Get the border/face dot coordinates of a "d-radiused"
490 core::list<v3s16> list;
491 getFacePositions(list, d);
493 core::list<v3s16>::Iterator li;
494 for(li=list.begin(); li!=list.end(); li++)
496 v3s16 p = *li + center;
500 - Don't allow too many simultaneous transfers
501 - EXCEPT when the blocks are very close
503 Also, don't send blocks that are already flying.
506 // Start with the usual maximum
507 u16 max_simul_dynamic = max_simul_sends_usually;
509 // If block is very close, allow full maximum
510 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
511 max_simul_dynamic = max_simul_sends_setting;
513 // Don't select too many blocks for sending
514 if(num_blocks_selected >= max_simul_dynamic)
516 queue_is_full = true;
517 goto queue_full_break;
520 // Don't send blocks that are currently being transferred
521 if(m_blocks_sending.find(p) != NULL)
527 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
528 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
529 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
530 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
531 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
532 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
535 // If this is true, inexistent block will be made from scratch
536 bool generate = d <= d_max_gen;
539 /*// Limit the generating area vertically to 2/3
540 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
543 // Limit the send area vertically to 1/2
544 if(abs(p.Y - center.Y) > d_max / 2)
550 If block is far away, don't generate it unless it is
556 // Block center y in nodes
557 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
558 // Don't generate if it's very high or very low
559 if(y < -64 || y > 64)
563 v2s16 p2d_nodes_center(
567 // Get ground height in nodes
568 s16 gh = server->m_env->getServerMap().findGroundLevel(
571 // If differs a lot, don't generate
572 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
574 // Actually, don't even send it
580 //infostream<<"d="<<d<<std::endl;
583 Don't generate or send if not in sight
584 FIXME This only works if the client uses a small enough
585 FOV setting. The default of 72 degrees is fine.
588 float camera_fov = (72.0*PI/180) * 4./3.;
589 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
595 Don't send already sent blocks
598 if(m_blocks_sent.find(p) != NULL)
605 Check if map has this block
607 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
609 bool surely_not_found_on_disk = false;
610 bool block_is_invalid = false;
613 // Reset usage timer, this block will be of use in the future.
614 block->resetUsageTimer();
616 // Block is dummy if data doesn't exist.
617 // It means it has been not found from disk and not generated
620 surely_not_found_on_disk = true;
623 // Block is valid if lighting is up-to-date and data exists
624 if(block->isValid() == false)
626 block_is_invalid = true;
629 /*if(block->isFullyGenerated() == false)
631 block_is_invalid = true;
636 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
637 v2s16 chunkpos = map->sector_to_chunk(p2d);
638 if(map->chunkNonVolatile(chunkpos) == false)
639 block_is_invalid = true;
641 if(block->isGenerated() == false)
642 block_is_invalid = true;
645 If block is not close, don't send it unless it is near
648 Block is near ground level if night-time mesh
649 differs from day-time mesh.
653 if(block->dayNightDiffed() == false)
660 If block has been marked to not exist on disk (dummy)
661 and generating new ones is not wanted, skip block.
663 if(generate == false && surely_not_found_on_disk == true)
670 Add inexistent block to emerge queue.
672 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
674 //TODO: Get value from somewhere
675 // Allow only one block in emerge queue
676 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
677 // Allow two blocks in queue per client
678 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
680 // Make it more responsive when needing to generate stuff
681 if(surely_not_found_on_disk)
683 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
685 //infostream<<"Adding block to emerge queue"<<std::endl;
687 // Add it to the emerge queue and trigger the thread
690 if(generate == false)
691 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
693 server->m_emerge_queue.addBlock(peer_id, p, flags);
694 server->m_emergethread.trigger();
696 if(nearest_emerged_d == -1)
697 nearest_emerged_d = d;
699 if(nearest_emergefull_d == -1)
700 nearest_emergefull_d = d;
707 if(nearest_sent_d == -1)
711 Add block to send queue
714 /*errorstream<<"sending from d="<<d<<" to "
715 <<server->getPlayerName(peer_id)<<std::endl;*/
717 PrioritySortedBlockTransfer q((float)d, p, peer_id);
721 num_blocks_selected += 1;
726 //infostream<<"Stopped at "<<d<<std::endl;
728 // If nothing was found for sending and nothing was queued for
729 // emerging, continue next time browsing from here
730 if(nearest_emerged_d != -1){
731 new_nearest_unsent_d = nearest_emerged_d;
732 } else if(nearest_emergefull_d != -1){
733 new_nearest_unsent_d = nearest_emergefull_d;
735 if(d > g_settings->getS16("max_block_send_distance")){
736 new_nearest_unsent_d = 0;
737 m_nothing_to_send_pause_timer = 2.0;
738 /*infostream<<"GetNextBlocks(): d wrapped around for "
739 <<server->getPlayerName(peer_id)
740 <<"; setting to 0 and pausing"<<std::endl;*/
742 if(nearest_sent_d != -1)
743 new_nearest_unsent_d = nearest_sent_d;
745 new_nearest_unsent_d = d;
749 if(new_nearest_unsent_d != -1)
750 m_nearest_unsent_d = new_nearest_unsent_d;
752 /*timer_result = timer.stop(true);
753 if(timer_result != 0)
754 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
757 void RemoteClient::GotBlock(v3s16 p)
759 if(m_blocks_sending.find(p) != NULL)
760 m_blocks_sending.remove(p);
763 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
764 " m_blocks_sending"<<std::endl;*/
765 m_excess_gotblocks++;
767 m_blocks_sent.insert(p, true);
770 void RemoteClient::SentBlock(v3s16 p)
772 if(m_blocks_sending.find(p) == NULL)
773 m_blocks_sending.insert(p, 0.0);
775 infostream<<"RemoteClient::SentBlock(): Sent block"
776 " already in m_blocks_sending"<<std::endl;
779 void RemoteClient::SetBlockNotSent(v3s16 p)
781 m_nearest_unsent_d = 0;
783 if(m_blocks_sending.find(p) != NULL)
784 m_blocks_sending.remove(p);
785 if(m_blocks_sent.find(p) != NULL)
786 m_blocks_sent.remove(p);
789 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
791 m_nearest_unsent_d = 0;
793 for(core::map<v3s16, MapBlock*>::Iterator
794 i = blocks.getIterator();
795 i.atEnd()==false; i++)
797 v3s16 p = i.getNode()->getKey();
799 if(m_blocks_sending.find(p) != NULL)
800 m_blocks_sending.remove(p);
801 if(m_blocks_sent.find(p) != NULL)
802 m_blocks_sent.remove(p);
810 PlayerInfo::PlayerInfo()
816 void PlayerInfo::PrintLine(std::ostream *s)
819 (*s)<<"\""<<name<<"\" ("
820 <<(position.X/10)<<","<<(position.Y/10)
821 <<","<<(position.Z/10)<<") ";
823 (*s)<<" avg_rtt="<<avg_rtt;
827 u32 PIChecksum(core::list<PlayerInfo> &l)
829 core::list<PlayerInfo>::Iterator i;
832 for(i=l.begin(); i!=l.end(); i++)
834 checksum += a * (i->id+1);
835 checksum ^= 0x435aafcd;
846 std::string path_world,
847 std::string path_config,
850 m_gamename(gamename),
851 m_path_world(path_world),
852 m_path_config(path_config),
854 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
855 m_authmanager(path_world+DIR_DELIM+"auth.txt"),
856 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
858 m_itemdef(createItemDefManager()),
859 m_nodedef(createNodeDefManager()),
860 m_craftdef(createCraftDefManager()),
862 m_emergethread(this),
864 m_time_of_day_send_timer(0),
866 m_shutdown_requested(false),
867 m_ignore_map_edit_events(false),
868 m_ignore_map_edit_events_peer_id(0)
870 infostream<<"Server created."<<std::endl;
871 infostream<<"- path_world = "<<path_world<<std::endl;
872 infostream<<"- path_config = "<<path_config<<std::endl;
873 infostream<<"- gamename = "<<gamename<<std::endl;
875 m_liquid_transform_timer = 0.0;
876 m_print_info_timer = 0.0;
877 m_objectdata_timer = 0.0;
878 m_emergethread_trigger_timer = 0.0;
879 m_savemap_timer = 0.0;
883 m_step_dtime_mutex.Init();
886 // Figure out some paths
887 m_path_share = porting::path_share + DIR_DELIM + "server";
888 m_path_game = m_path_share + DIR_DELIM + "games" + DIR_DELIM + m_gamename;
890 // Path to builtin.lua
891 std::string builtinpath = m_path_share + DIR_DELIM + "builtin.lua";
893 // Add default global mod search path
894 m_modspaths.push_front(m_path_game + DIR_DELIM "mods");
895 // Add world mod search path
896 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
897 // Add addon mod search path
898 for(std::set<std::string>::const_iterator i = m_path_addons.begin();
899 i != m_path_addons.end(); i++){
900 m_modspaths.push_front((*i) + DIR_DELIM + "mods");
903 // Print out mod search paths
904 infostream<<"- mod search paths:"<<std::endl;
905 for(core::list<std::string>::Iterator i = m_modspaths.begin();
906 i != m_modspaths.end(); i++){
907 std::string modspath = *i;
908 infostream<<" "<<modspath<<std::endl;
912 JMutexAutoLock envlock(m_env_mutex);
913 JMutexAutoLock conlock(m_con_mutex);
915 // Initialize scripting
917 infostream<<"Server: Initializing scripting"<<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 stuff from \""<<builtinpath
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 // Load and run "mod" scripts
932 m_mods = getMods(m_modspaths);
933 for(core::list<ModSpec>::Iterator i = m_mods.begin();
934 i != m_mods.end(); i++){
935 const ModSpec &mod = *i;
936 infostream<<"Server: Loading mod \""<<mod.name<<"\""<<std::endl;
937 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
938 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
940 errorstream<<"Server: Failed to load and run "
941 <<scriptpath<<std::endl;
942 throw ModError("Failed to load and run "+scriptpath);
946 // Read Textures and calculate sha1 sums
949 // Apply item aliases in the node definition manager
950 m_nodedef->updateAliases(m_itemdef);
952 // Initialize Environment
954 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
957 // Give environment reference to scripting api
958 scriptapi_add_environment(m_lua, m_env);
960 // Register us to receive map edit events
961 m_env->getMap().addEventReceiver(this);
963 // If file exists, load environment metadata
964 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
966 infostream<<"Server: Loading environment metadata"<<std::endl;
967 m_env->loadMeta(m_path_world);
971 infostream<<"Server: Loading players"<<std::endl;
972 m_env->deSerializePlayers(m_path_world);
975 Add some test ActiveBlockModifiers to environment
977 add_legacy_abms(m_env, m_nodedef);
982 infostream<<"Server::~Server()"<<std::endl;
985 Send shutdown message
988 JMutexAutoLock conlock(m_con_mutex);
990 std::wstring line = L"*** Server shutting down";
993 Send the message to clients
995 for(core::map<u16, RemoteClient*>::Iterator
996 i = m_clients.getIterator();
997 i.atEnd() == false; i++)
999 // Get client and check that it is valid
1000 RemoteClient *client = i.getNode()->getValue();
1001 assert(client->peer_id == i.getNode()->getKey());
1002 if(client->serialization_version == SER_FMT_VER_INVALID)
1006 SendChatMessage(client->peer_id, line);
1008 catch(con::PeerNotFoundException &e)
1014 JMutexAutoLock envlock(m_env_mutex);
1019 infostream<<"Server: Saving players"<<std::endl;
1020 m_env->serializePlayers(m_path_world);
1023 Save environment metadata
1025 infostream<<"Server: Saving environment metadata"<<std::endl;
1026 m_env->saveMeta(m_path_world);
1038 JMutexAutoLock clientslock(m_con_mutex);
1040 for(core::map<u16, RemoteClient*>::Iterator
1041 i = m_clients.getIterator();
1042 i.atEnd() == false; i++)
1045 // NOTE: These are removed by env destructor
1047 u16 peer_id = i.getNode()->getKey();
1048 JMutexAutoLock envlock(m_env_mutex);
1049 m_env->removePlayer(peer_id);
1053 delete i.getNode()->getValue();
1057 // Delete Environment
1064 // Deinitialize scripting
1065 infostream<<"Server: Deinitializing scripting"<<std::endl;
1066 script_deinit(m_lua);
1069 void Server::start(unsigned short port)
1071 DSTACK(__FUNCTION_NAME);
1072 // Stop thread if already running
1075 // Initialize connection
1076 m_con.SetTimeoutMs(30);
1080 m_thread.setRun(true);
1083 infostream<<"Server started on port "<<port<<"."<<std::endl;
1088 DSTACK(__FUNCTION_NAME);
1090 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1092 // Stop threads (set run=false first so both start stopping)
1093 m_thread.setRun(false);
1094 m_emergethread.setRun(false);
1096 m_emergethread.stop();
1098 infostream<<"Server: Threads stopped"<<std::endl;
1101 void Server::step(float dtime)
1103 DSTACK(__FUNCTION_NAME);
1108 JMutexAutoLock lock(m_step_dtime_mutex);
1109 m_step_dtime += dtime;
1113 void Server::AsyncRunStep()
1115 DSTACK(__FUNCTION_NAME);
1117 g_profiler->add("Server::AsyncRunStep (num)", 1);
1121 JMutexAutoLock lock1(m_step_dtime_mutex);
1122 dtime = m_step_dtime;
1126 // Send blocks to clients
1133 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1135 //infostream<<"Server steps "<<dtime<<std::endl;
1136 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1139 JMutexAutoLock lock1(m_step_dtime_mutex);
1140 m_step_dtime -= dtime;
1147 m_uptime.set(m_uptime.get() + dtime);
1151 // Process connection's timeouts
1152 JMutexAutoLock lock2(m_con_mutex);
1153 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1154 m_con.RunTimeouts(dtime);
1158 // This has to be called so that the client list gets synced
1159 // with the peer list of the connection
1160 handlePeerChanges();
1164 Update m_time_of_day and overall game time
1167 JMutexAutoLock envlock(m_env_mutex);
1169 m_time_counter += dtime;
1170 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1171 u32 units = (u32)(m_time_counter*speed);
1172 m_time_counter -= (f32)units / speed;
1174 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1176 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1179 Send to clients at constant intervals
1182 m_time_of_day_send_timer -= dtime;
1183 if(m_time_of_day_send_timer < 0.0)
1185 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1187 //JMutexAutoLock envlock(m_env_mutex);
1188 JMutexAutoLock conlock(m_con_mutex);
1190 for(core::map<u16, RemoteClient*>::Iterator
1191 i = m_clients.getIterator();
1192 i.atEnd() == false; i++)
1194 RemoteClient *client = i.getNode()->getValue();
1195 //Player *player = m_env->getPlayer(client->peer_id);
1197 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1198 m_env->getTimeOfDay());
1200 m_con.Send(client->peer_id, 0, data, true);
1206 JMutexAutoLock lock(m_env_mutex);
1208 ScopeProfiler sp(g_profiler, "SEnv step");
1209 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1213 const float map_timer_and_unload_dtime = 2.92;
1214 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1216 JMutexAutoLock lock(m_env_mutex);
1217 // Run Map's timers and unload unused data
1218 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1219 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1220 g_settings->getFloat("server_unload_unused_data_timeout"));
1231 JMutexAutoLock lock(m_env_mutex);
1232 JMutexAutoLock lock2(m_con_mutex);
1234 ScopeProfiler sp(g_profiler, "Server: handle players");
1236 //float player_max_speed = BS * 4.0; // Normal speed
1237 float player_max_speed = BS * 20; // Fast speed
1238 float player_max_speed_up = BS * 20;
1240 player_max_speed *= 2.5; // Tolerance
1241 player_max_speed_up *= 2.5;
1243 for(core::map<u16, RemoteClient*>::Iterator
1244 i = m_clients.getIterator();
1245 i.atEnd() == false; i++)
1247 RemoteClient *client = i.getNode()->getValue();
1248 ServerRemotePlayer *player =
1249 static_cast<ServerRemotePlayer*>
1250 (m_env->getPlayer(client->peer_id));
1255 Check player movements
1257 NOTE: Actually the server should handle player physics like the
1258 client does and compare player's position to what is calculated
1259 on our side. This is required when eg. players fly due to an
1262 player->m_last_good_position_age += dtime;
1263 if(player->m_last_good_position_age >= 1.0){
1264 float age = player->m_last_good_position_age;
1265 v3f diff = (player->getPosition() - player->m_last_good_position);
1266 float d_vert = diff.Y;
1268 float d_horiz = diff.getLength();
1269 /*infostream<<player->getName()<<"'s horizontal speed is "
1270 <<(d_horiz/age)<<std::endl;*/
1271 if(d_horiz <= age * player_max_speed &&
1272 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1273 player->m_last_good_position = player->getPosition();
1275 actionstream<<"Player "<<player->getName()
1276 <<" moved too fast; resetting position"
1278 player->setPosition(player->m_last_good_position);
1279 SendMovePlayer(player);
1281 player->m_last_good_position_age = 0;
1285 Handle player HPs (die if hp=0)
1287 if(player->hp == 0 && player->m_hp_not_sent)
1291 Send player inventories and HPs if necessary
1293 if(player->m_inventory_not_sent){
1294 UpdateCrafting(player->peer_id);
1295 SendInventory(player->peer_id);
1297 if(player->m_hp_not_sent){
1298 SendPlayerHP(player);
1304 if(!player->m_is_in_environment){
1305 player->m_removed = false;
1307 m_env->addActiveObject(player);
1312 /* Transform liquids */
1313 m_liquid_transform_timer += dtime;
1314 if(m_liquid_transform_timer >= 1.00)
1316 m_liquid_transform_timer -= 1.00;
1318 JMutexAutoLock lock(m_env_mutex);
1320 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1322 core::map<v3s16, MapBlock*> modified_blocks;
1323 m_env->getMap().transformLiquids(modified_blocks);
1328 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1329 ServerMap &map = ((ServerMap&)m_env->getMap());
1330 map.updateLighting(modified_blocks, lighting_modified_blocks);
1332 // Add blocks modified by lighting to modified_blocks
1333 for(core::map<v3s16, MapBlock*>::Iterator
1334 i = lighting_modified_blocks.getIterator();
1335 i.atEnd() == false; i++)
1337 MapBlock *block = i.getNode()->getValue();
1338 modified_blocks.insert(block->getPos(), block);
1342 Set the modified blocks unsent for all the clients
1345 JMutexAutoLock lock2(m_con_mutex);
1347 for(core::map<u16, RemoteClient*>::Iterator
1348 i = m_clients.getIterator();
1349 i.atEnd() == false; i++)
1351 RemoteClient *client = i.getNode()->getValue();
1353 if(modified_blocks.size() > 0)
1355 // Remove block from sent history
1356 client->SetBlocksNotSent(modified_blocks);
1361 // Periodically print some info
1363 float &counter = m_print_info_timer;
1369 JMutexAutoLock lock2(m_con_mutex);
1371 if(m_clients.size() != 0)
1372 infostream<<"Players:"<<std::endl;
1373 for(core::map<u16, RemoteClient*>::Iterator
1374 i = m_clients.getIterator();
1375 i.atEnd() == false; i++)
1377 //u16 peer_id = i.getNode()->getKey();
1378 RemoteClient *client = i.getNode()->getValue();
1379 Player *player = m_env->getPlayer(client->peer_id);
1382 infostream<<"* "<<player->getName()<<"\t";
1383 client->PrintInfo(infostream);
1388 //if(g_settings->getBool("enable_experimental"))
1392 Check added and deleted active objects
1395 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1396 JMutexAutoLock envlock(m_env_mutex);
1397 JMutexAutoLock conlock(m_con_mutex);
1399 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1401 // Radius inside which objects are active
1402 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1403 radius *= MAP_BLOCKSIZE;
1405 for(core::map<u16, RemoteClient*>::Iterator
1406 i = m_clients.getIterator();
1407 i.atEnd() == false; i++)
1409 RemoteClient *client = i.getNode()->getValue();
1411 // If definitions and textures have not been sent, don't
1412 // send objects either
1413 if(!client->definitions_sent)
1416 Player *player = m_env->getPlayer(client->peer_id);
1419 // This can happen if the client timeouts somehow
1420 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1422 <<" has no associated player"<<std::endl;*/
1425 v3s16 pos = floatToInt(player->getPosition(), BS);
1427 core::map<u16, bool> removed_objects;
1428 core::map<u16, bool> added_objects;
1429 m_env->getRemovedActiveObjects(pos, radius,
1430 client->m_known_objects, removed_objects);
1431 m_env->getAddedActiveObjects(pos, radius,
1432 client->m_known_objects, added_objects);
1434 // Ignore if nothing happened
1435 if(removed_objects.size() == 0 && added_objects.size() == 0)
1437 //infostream<<"active objects: none changed"<<std::endl;
1441 std::string data_buffer;
1445 // Handle removed objects
1446 writeU16((u8*)buf, removed_objects.size());
1447 data_buffer.append(buf, 2);
1448 for(core::map<u16, bool>::Iterator
1449 i = removed_objects.getIterator();
1450 i.atEnd()==false; i++)
1453 u16 id = i.getNode()->getKey();
1454 ServerActiveObject* obj = m_env->getActiveObject(id);
1456 // Add to data buffer for sending
1457 writeU16((u8*)buf, i.getNode()->getKey());
1458 data_buffer.append(buf, 2);
1460 // Remove from known objects
1461 client->m_known_objects.remove(i.getNode()->getKey());
1463 if(obj && obj->m_known_by_count > 0)
1464 obj->m_known_by_count--;
1467 // Handle added objects
1468 writeU16((u8*)buf, added_objects.size());
1469 data_buffer.append(buf, 2);
1470 for(core::map<u16, bool>::Iterator
1471 i = added_objects.getIterator();
1472 i.atEnd()==false; i++)
1475 u16 id = i.getNode()->getKey();
1476 ServerActiveObject* obj = m_env->getActiveObject(id);
1479 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1481 infostream<<"WARNING: "<<__FUNCTION_NAME
1482 <<": NULL object"<<std::endl;
1484 type = obj->getType();
1486 // Add to data buffer for sending
1487 writeU16((u8*)buf, id);
1488 data_buffer.append(buf, 2);
1489 writeU8((u8*)buf, type);
1490 data_buffer.append(buf, 1);
1493 data_buffer.append(serializeLongString(
1494 obj->getClientInitializationData()));
1496 data_buffer.append(serializeLongString(""));
1498 // Add to known objects
1499 client->m_known_objects.insert(i.getNode()->getKey(), false);
1502 obj->m_known_by_count++;
1506 SharedBuffer<u8> reply(2 + data_buffer.size());
1507 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1508 memcpy((char*)&reply[2], data_buffer.c_str(),
1509 data_buffer.size());
1511 m_con.Send(client->peer_id, 0, reply, true);
1513 infostream<<"Server: Sent object remove/add: "
1514 <<removed_objects.size()<<" removed, "
1515 <<added_objects.size()<<" added, "
1516 <<"packet size is "<<reply.getSize()<<std::endl;
1521 Collect a list of all the objects known by the clients
1522 and report it back to the environment.
1525 core::map<u16, bool> all_known_objects;
1527 for(core::map<u16, RemoteClient*>::Iterator
1528 i = m_clients.getIterator();
1529 i.atEnd() == false; i++)
1531 RemoteClient *client = i.getNode()->getValue();
1532 // Go through all known objects of client
1533 for(core::map<u16, bool>::Iterator
1534 i = client->m_known_objects.getIterator();
1535 i.atEnd()==false; i++)
1537 u16 id = i.getNode()->getKey();
1538 all_known_objects[id] = true;
1542 m_env->setKnownActiveObjects(whatever);
1548 Send object messages
1551 JMutexAutoLock envlock(m_env_mutex);
1552 JMutexAutoLock conlock(m_con_mutex);
1554 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1557 // Value = data sent by object
1558 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1560 // Get active object messages from environment
1563 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1567 core::list<ActiveObjectMessage>* message_list = NULL;
1568 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1569 n = buffered_messages.find(aom.id);
1572 message_list = new core::list<ActiveObjectMessage>;
1573 buffered_messages.insert(aom.id, message_list);
1577 message_list = n->getValue();
1579 message_list->push_back(aom);
1582 // Route data to every client
1583 for(core::map<u16, RemoteClient*>::Iterator
1584 i = m_clients.getIterator();
1585 i.atEnd()==false; i++)
1587 RemoteClient *client = i.getNode()->getValue();
1588 std::string reliable_data;
1589 std::string unreliable_data;
1590 // Go through all objects in message buffer
1591 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1592 j = buffered_messages.getIterator();
1593 j.atEnd()==false; j++)
1595 // If object is not known by client, skip it
1596 u16 id = j.getNode()->getKey();
1597 if(client->m_known_objects.find(id) == NULL)
1599 // Get message list of object
1600 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1601 // Go through every message
1602 for(core::list<ActiveObjectMessage>::Iterator
1603 k = list->begin(); k != list->end(); k++)
1605 // Compose the full new data with header
1606 ActiveObjectMessage aom = *k;
1607 std::string new_data;
1610 writeU16((u8*)&buf[0], aom.id);
1611 new_data.append(buf, 2);
1613 new_data += serializeString(aom.datastring);
1614 // Add data to buffer
1616 reliable_data += new_data;
1618 unreliable_data += new_data;
1622 reliable_data and unreliable_data are now ready.
1625 if(reliable_data.size() > 0)
1627 SharedBuffer<u8> reply(2 + reliable_data.size());
1628 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1629 memcpy((char*)&reply[2], reliable_data.c_str(),
1630 reliable_data.size());
1632 m_con.Send(client->peer_id, 0, reply, true);
1634 if(unreliable_data.size() > 0)
1636 SharedBuffer<u8> reply(2 + unreliable_data.size());
1637 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1638 memcpy((char*)&reply[2], unreliable_data.c_str(),
1639 unreliable_data.size());
1640 // Send as unreliable
1641 m_con.Send(client->peer_id, 0, reply, false);
1644 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1646 infostream<<"Server: Size of object message data: "
1647 <<"reliable: "<<reliable_data.size()
1648 <<", unreliable: "<<unreliable_data.size()
1653 // Clear buffered_messages
1654 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1655 i = buffered_messages.getIterator();
1656 i.atEnd()==false; i++)
1658 delete i.getNode()->getValue();
1662 } // enable_experimental
1665 Send queued-for-sending map edit events.
1668 // Don't send too many at a time
1671 // Single change sending is disabled if queue size is not small
1672 bool disable_single_change_sending = false;
1673 if(m_unsent_map_edit_queue.size() >= 4)
1674 disable_single_change_sending = true;
1676 bool got_any_events = false;
1678 // We'll log the amount of each
1681 while(m_unsent_map_edit_queue.size() != 0)
1683 got_any_events = true;
1685 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1687 // Players far away from the change are stored here.
1688 // Instead of sending the changes, MapBlocks are set not sent
1690 core::list<u16> far_players;
1692 if(event->type == MEET_ADDNODE)
1694 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1695 prof.add("MEET_ADDNODE", 1);
1696 if(disable_single_change_sending)
1697 sendAddNode(event->p, event->n, event->already_known_by_peer,
1700 sendAddNode(event->p, event->n, event->already_known_by_peer,
1703 else if(event->type == MEET_REMOVENODE)
1705 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1706 prof.add("MEET_REMOVENODE", 1);
1707 if(disable_single_change_sending)
1708 sendRemoveNode(event->p, event->already_known_by_peer,
1711 sendRemoveNode(event->p, event->already_known_by_peer,
1714 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1716 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1717 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1718 setBlockNotSent(event->p);
1720 else if(event->type == MEET_OTHER)
1722 infostream<<"Server: MEET_OTHER"<<std::endl;
1723 prof.add("MEET_OTHER", 1);
1724 for(core::map<v3s16, bool>::Iterator
1725 i = event->modified_blocks.getIterator();
1726 i.atEnd()==false; i++)
1728 v3s16 p = i.getNode()->getKey();
1734 prof.add("unknown", 1);
1735 infostream<<"WARNING: Server: Unknown MapEditEvent "
1736 <<((u32)event->type)<<std::endl;
1740 Set blocks not sent to far players
1742 if(far_players.size() > 0)
1744 // Convert list format to that wanted by SetBlocksNotSent
1745 core::map<v3s16, MapBlock*> modified_blocks2;
1746 for(core::map<v3s16, bool>::Iterator
1747 i = event->modified_blocks.getIterator();
1748 i.atEnd()==false; i++)
1750 v3s16 p = i.getNode()->getKey();
1751 modified_blocks2.insert(p,
1752 m_env->getMap().getBlockNoCreateNoEx(p));
1754 // Set blocks not sent
1755 for(core::list<u16>::Iterator
1756 i = far_players.begin();
1757 i != far_players.end(); i++)
1760 RemoteClient *client = getClient(peer_id);
1763 client->SetBlocksNotSent(modified_blocks2);
1769 /*// Don't send too many at a time
1771 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1777 infostream<<"Server: MapEditEvents:"<<std::endl;
1778 prof.print(infostream);
1784 Trigger emergethread (it somehow gets to a non-triggered but
1785 bysy state sometimes)
1788 float &counter = m_emergethread_trigger_timer;
1794 m_emergethread.trigger();
1798 // Save map, players and auth stuff
1800 float &counter = m_savemap_timer;
1802 if(counter >= g_settings->getFloat("server_map_save_interval"))
1805 JMutexAutoLock lock(m_env_mutex);
1807 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1810 if(m_authmanager.isModified())
1811 m_authmanager.save();
1814 if(m_banmanager.isModified())
1815 m_banmanager.save();
1817 // Save changed parts of map
1818 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1821 m_env->serializePlayers(m_path_world);
1823 // Save environment metadata
1824 m_env->saveMeta(m_path_world);
1829 void Server::Receive()
1831 DSTACK(__FUNCTION_NAME);
1832 SharedBuffer<u8> data;
1837 JMutexAutoLock conlock(m_con_mutex);
1838 datasize = m_con.Receive(peer_id, data);
1841 // This has to be called so that the client list gets synced
1842 // with the peer list of the connection
1843 handlePeerChanges();
1845 ProcessData(*data, datasize, peer_id);
1847 catch(con::InvalidIncomingDataException &e)
1849 infostream<<"Server::Receive(): "
1850 "InvalidIncomingDataException: what()="
1851 <<e.what()<<std::endl;
1853 catch(con::PeerNotFoundException &e)
1855 //NOTE: This is not needed anymore
1857 // The peer has been disconnected.
1858 // Find the associated player and remove it.
1860 /*JMutexAutoLock envlock(m_env_mutex);
1862 infostream<<"ServerThread: peer_id="<<peer_id
1863 <<" has apparently closed connection. "
1864 <<"Removing player."<<std::endl;
1866 m_env->removePlayer(peer_id);*/
1870 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1872 DSTACK(__FUNCTION_NAME);
1873 // Environment is locked first.
1874 JMutexAutoLock envlock(m_env_mutex);
1875 JMutexAutoLock conlock(m_con_mutex);
1877 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1880 Address address = m_con.GetPeerAddress(peer_id);
1882 // drop player if is ip is banned
1883 if(m_banmanager.isIpBanned(address.serializeString())){
1884 SendAccessDenied(m_con, peer_id,
1885 L"Your ip is banned. Banned name was "
1886 +narrow_to_wide(m_banmanager.getBanName(
1887 address.serializeString())));
1888 m_con.DeletePeer(peer_id);
1892 catch(con::PeerNotFoundException &e)
1894 infostream<<"Server::ProcessData(): Cancelling: peer "
1895 <<peer_id<<" not found"<<std::endl;
1899 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1907 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1909 if(command == TOSERVER_INIT)
1911 // [0] u16 TOSERVER_INIT
1912 // [2] u8 SER_FMT_VER_HIGHEST
1913 // [3] u8[20] player_name
1914 // [23] u8[28] password <--- can be sent without this, from old versions
1916 if(datasize < 2+1+PLAYERNAME_SIZE)
1919 infostream<<"Server: Got TOSERVER_INIT from "
1920 <<peer_id<<std::endl;
1922 // First byte after command is maximum supported
1923 // serialization version
1924 u8 client_max = data[2];
1925 u8 our_max = SER_FMT_VER_HIGHEST;
1926 // Use the highest version supported by both
1927 u8 deployed = core::min_(client_max, our_max);
1928 // If it's lower than the lowest supported, give up.
1929 if(deployed < SER_FMT_VER_LOWEST)
1930 deployed = SER_FMT_VER_INVALID;
1932 //peer->serialization_version = deployed;
1933 getClient(peer_id)->pending_serialization_version = deployed;
1935 if(deployed == SER_FMT_VER_INVALID)
1937 infostream<<"Server: Cannot negotiate "
1938 "serialization version with peer "
1939 <<peer_id<<std::endl;
1940 SendAccessDenied(m_con, peer_id, std::wstring(
1941 L"Your client's version is not supported.\n"
1942 L"Server version is ")
1943 + narrow_to_wide(VERSION_STRING) + L"."
1949 Read and check network protocol version
1952 u16 net_proto_version = 0;
1953 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1955 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1958 getClient(peer_id)->net_proto_version = net_proto_version;
1960 if(net_proto_version == 0)
1962 SendAccessDenied(m_con, peer_id, std::wstring(
1963 L"Your client's version is not supported.\n"
1964 L"Server version is ")
1965 + narrow_to_wide(VERSION_STRING) + L"."
1970 if(g_settings->getBool("strict_protocol_version_checking"))
1972 if(net_proto_version != PROTOCOL_VERSION)
1974 SendAccessDenied(m_con, peer_id, std::wstring(
1975 L"Your client's version is not supported.\n"
1976 L"Server version is ")
1977 + narrow_to_wide(VERSION_STRING) + L",\n"
1978 + L"server's PROTOCOL_VERSION is "
1979 + narrow_to_wide(itos(PROTOCOL_VERSION))
1980 + L", client's PROTOCOL_VERSION is "
1981 + narrow_to_wide(itos(net_proto_version))
1992 char playername[PLAYERNAME_SIZE];
1993 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1995 playername[i] = data[3+i];
1997 playername[PLAYERNAME_SIZE-1] = 0;
1999 if(playername[0]=='\0')
2001 infostream<<"Server: Player has empty name"<<std::endl;
2002 SendAccessDenied(m_con, peer_id,
2007 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2009 infostream<<"Server: Player has invalid name"<<std::endl;
2010 SendAccessDenied(m_con, peer_id,
2011 L"Name contains unallowed characters");
2016 char password[PASSWORD_SIZE];
2017 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2019 // old version - assume blank password
2024 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2026 password[i] = data[23+i];
2028 password[PASSWORD_SIZE-1] = 0;
2031 // Add player to auth manager
2032 if(m_authmanager.exists(playername) == false)
2034 std::wstring default_password =
2035 narrow_to_wide(g_settings->get("default_password"));
2036 std::string translated_default_password =
2037 translatePassword(playername, default_password);
2039 // If default_password is empty, allow any initial password
2040 if (default_password.length() == 0)
2041 translated_default_password = password;
2043 infostream<<"Server: adding player "<<playername
2044 <<" to auth manager"<<std::endl;
2045 m_authmanager.add(playername);
2046 m_authmanager.setPassword(playername, translated_default_password);
2047 m_authmanager.setPrivs(playername,
2048 stringToPrivs(g_settings->get("default_privs")));
2049 m_authmanager.save();
2052 std::string checkpwd = m_authmanager.getPassword(playername);
2054 /*infostream<<"Server: Client gave password '"<<password
2055 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2057 if(password != checkpwd)
2059 infostream<<"Server: peer_id="<<peer_id
2060 <<": supplied invalid password for "
2061 <<playername<<std::endl;
2062 SendAccessDenied(m_con, peer_id, L"Invalid password");
2066 // Enforce user limit.
2067 // Don't enforce for users that have some admin right
2068 if(m_clients.size() >= g_settings->getU16("max_users") &&
2069 (m_authmanager.getPrivs(playername)
2070 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2071 playername != g_settings->get("name"))
2073 SendAccessDenied(m_con, peer_id, L"Too many users.");
2078 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2080 // If failed, cancel
2083 infostream<<"Server: peer_id="<<peer_id
2084 <<": failed to emerge player"<<std::endl;
2089 Answer with a TOCLIENT_INIT
2092 SharedBuffer<u8> reply(2+1+6+8);
2093 writeU16(&reply[0], TOCLIENT_INIT);
2094 writeU8(&reply[2], deployed);
2095 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2096 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2099 m_con.Send(peer_id, 0, reply, true);
2103 Send complete position information
2105 SendMovePlayer(player);
2110 if(command == TOSERVER_INIT2)
2112 infostream<<"Server: Got TOSERVER_INIT2 from "
2113 <<peer_id<<std::endl;
2116 getClient(peer_id)->serialization_version
2117 = getClient(peer_id)->pending_serialization_version;
2120 Send some initialization data
2123 // Send item definitions
2124 SendItemDef(m_con, peer_id, m_itemdef);
2126 // Send node definitions
2127 SendNodeDef(m_con, peer_id, m_nodedef);
2129 // Send texture announcement
2130 SendTextureAnnouncement(peer_id);
2132 // Send player info to all players
2133 //SendPlayerInfos();
2135 // Send inventory to player
2136 UpdateCrafting(peer_id);
2137 SendInventory(peer_id);
2139 // Send player items to all players
2142 Player *player = m_env->getPlayer(peer_id);
2145 SendPlayerHP(player);
2147 // Show death screen if necessary
2149 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2153 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2154 m_env->getTimeOfDay());
2155 m_con.Send(peer_id, 0, data, true);
2158 // Send information about server to player in chat
2159 SendChatMessage(peer_id, getStatusString());
2161 // Send information about joining in chat
2163 std::wstring name = L"unknown";
2164 Player *player = m_env->getPlayer(peer_id);
2166 name = narrow_to_wide(player->getName());
2168 std::wstring message;
2171 message += L" joined game";
2172 BroadcastChatMessage(message);
2175 // Warnings about protocol version can be issued here
2176 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2178 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2185 std::ostringstream os(std::ios_base::binary);
2186 for(core::map<u16, RemoteClient*>::Iterator
2187 i = m_clients.getIterator();
2188 i.atEnd() == false; i++)
2190 RemoteClient *client = i.getNode()->getValue();
2191 assert(client->peer_id == i.getNode()->getKey());
2192 if(client->serialization_version == SER_FMT_VER_INVALID)
2195 Player *player = m_env->getPlayer(client->peer_id);
2198 // Get name of player
2199 os<<player->getName()<<" ";
2202 actionstream<<player->getName()<<" joins game. List of players: "
2203 <<os.str()<<std::endl;
2209 if(peer_ser_ver == SER_FMT_VER_INVALID)
2211 infostream<<"Server::ProcessData(): Cancelling: Peer"
2212 " serialization format invalid or not initialized."
2213 " Skipping incoming command="<<command<<std::endl;
2217 Player *player = m_env->getPlayer(peer_id);
2218 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2221 infostream<<"Server::ProcessData(): Cancelling: "
2222 "No player for peer_id="<<peer_id
2226 if(command == TOSERVER_PLAYERPOS)
2228 if(datasize < 2+12+12+4+4)
2232 v3s32 ps = readV3S32(&data[start+2]);
2233 v3s32 ss = readV3S32(&data[start+2+12]);
2234 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2235 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2236 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2237 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2238 pitch = wrapDegrees(pitch);
2239 yaw = wrapDegrees(yaw);
2241 player->setPosition(position);
2242 player->setSpeed(speed);
2243 player->setPitch(pitch);
2244 player->setYaw(yaw);
2246 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2247 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2248 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2250 else if(command == TOSERVER_GOTBLOCKS)
2263 u16 count = data[2];
2264 for(u16 i=0; i<count; i++)
2266 if((s16)datasize < 2+1+(i+1)*6)
2267 throw con::InvalidIncomingDataException
2268 ("GOTBLOCKS length is too short");
2269 v3s16 p = readV3S16(&data[2+1+i*6]);
2270 /*infostream<<"Server: GOTBLOCKS ("
2271 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2272 RemoteClient *client = getClient(peer_id);
2273 client->GotBlock(p);
2276 else if(command == TOSERVER_DELETEDBLOCKS)
2289 u16 count = data[2];
2290 for(u16 i=0; i<count; i++)
2292 if((s16)datasize < 2+1+(i+1)*6)
2293 throw con::InvalidIncomingDataException
2294 ("DELETEDBLOCKS length is too short");
2295 v3s16 p = readV3S16(&data[2+1+i*6]);
2296 /*infostream<<"Server: DELETEDBLOCKS ("
2297 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2298 RemoteClient *client = getClient(peer_id);
2299 client->SetBlockNotSent(p);
2302 else if(command == TOSERVER_CLICK_OBJECT)
2304 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2307 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2309 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2312 else if(command == TOSERVER_GROUND_ACTION)
2314 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2318 else if(command == TOSERVER_RELEASE)
2320 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2323 else if(command == TOSERVER_SIGNTEXT)
2325 infostream<<"Server: SIGNTEXT not supported anymore"
2329 else if(command == TOSERVER_SIGNNODETEXT)
2331 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2339 std::string datastring((char*)&data[2], datasize-2);
2340 std::istringstream is(datastring, std::ios_base::binary);
2343 is.read((char*)buf, 6);
2344 v3s16 p = readV3S16(buf);
2345 is.read((char*)buf, 2);
2346 u16 textlen = readU16(buf);
2348 for(u16 i=0; i<textlen; i++)
2350 is.read((char*)buf, 1);
2351 text += (char)buf[0];
2354 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2358 meta->setText(text);
2360 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2361 <<" at "<<PP(p)<<std::endl;
2363 v3s16 blockpos = getNodeBlockPos(p);
2364 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2367 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2371 setBlockNotSent(blockpos);
2373 else if(command == TOSERVER_INVENTORY_ACTION)
2375 // Strip command and create a stream
2376 std::string datastring((char*)&data[2], datasize-2);
2377 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2378 std::istringstream is(datastring, std::ios_base::binary);
2380 InventoryAction *a = InventoryAction::deSerialize(is);
2383 infostream<<"TOSERVER_INVENTORY_ACTION: "
2384 <<"InventoryAction::deSerialize() returned NULL"
2390 Note: Always set inventory not sent, to repair cases
2391 where the client made a bad prediction.
2395 Handle restrictions and special cases of the move action
2397 if(a->getType() == IACTION_MOVE)
2399 IMoveAction *ma = (IMoveAction*)a;
2401 ma->from_inv.applyCurrentPlayer(player->getName());
2402 ma->to_inv.applyCurrentPlayer(player->getName());
2404 setInventoryModified(ma->from_inv);
2405 setInventoryModified(ma->to_inv);
2407 bool from_inv_is_current_player =
2408 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2409 (ma->from_inv.name == player->getName());
2411 bool to_inv_is_current_player =
2412 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2413 (ma->to_inv.name == player->getName());
2416 Disable moving items out of craftpreview
2418 if(ma->from_list == "craftpreview")
2420 infostream<<"Ignoring IMoveAction from "
2421 <<(ma->from_inv.dump())<<":"<<ma->from_list
2422 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2423 <<" because src is "<<ma->from_list<<std::endl;
2429 Disable moving items into craftresult and craftpreview
2431 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2433 infostream<<"Ignoring IMoveAction from "
2434 <<(ma->from_inv.dump())<<":"<<ma->from_list
2435 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2436 <<" because dst is "<<ma->to_list<<std::endl;
2441 // Disallow moving items in elsewhere than player's inventory
2442 // if not allowed to interact
2443 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2444 && (!from_inv_is_current_player
2445 || !to_inv_is_current_player))
2447 infostream<<"Cannot move outside of player's inventory: "
2448 <<"No interact privilege"<<std::endl;
2453 // If player is not an admin, check for ownership of src and dst
2454 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2456 std::string owner_from = getInventoryOwner(ma->from_inv);
2457 if(owner_from != "" && owner_from != player->getName())
2459 infostream<<"WARNING: "<<player->getName()
2460 <<" tried to access an inventory that"
2461 <<" belongs to "<<owner_from<<std::endl;
2466 std::string owner_to = getInventoryOwner(ma->to_inv);
2467 if(owner_to != "" && owner_to != player->getName())
2469 infostream<<"WARNING: "<<player->getName()
2470 <<" tried to access an inventory that"
2471 <<" belongs to "<<owner_to<<std::endl;
2478 Handle restrictions and special cases of the drop action
2480 else if(a->getType() == IACTION_DROP)
2482 IDropAction *da = (IDropAction*)a;
2484 da->from_inv.applyCurrentPlayer(player->getName());
2486 setInventoryModified(da->from_inv);
2488 // Disallow dropping items if not allowed to interact
2489 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2494 // If player is not an admin, check for ownership
2495 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2497 std::string owner_from = getInventoryOwner(da->from_inv);
2498 if(owner_from != "" && owner_from != player->getName())
2500 infostream<<"WARNING: "<<player->getName()
2501 <<" tried to access an inventory that"
2502 <<" belongs to "<<owner_from<<std::endl;
2509 Handle restrictions and special cases of the craft action
2511 else if(a->getType() == IACTION_CRAFT)
2513 ICraftAction *ca = (ICraftAction*)a;
2515 ca->craft_inv.applyCurrentPlayer(player->getName());
2517 setInventoryModified(ca->craft_inv);
2519 //bool craft_inv_is_current_player =
2520 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2521 // (ca->craft_inv.name == player->getName());
2523 // Disallow crafting if not allowed to interact
2524 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2526 infostream<<"Cannot craft: "
2527 <<"No interact privilege"<<std::endl;
2532 // If player is not an admin, check for ownership of inventory
2533 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2535 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2536 if(owner_craft != "" && owner_craft != player->getName())
2538 infostream<<"WARNING: "<<player->getName()
2539 <<" tried to access an inventory that"
2540 <<" belongs to "<<owner_craft<<std::endl;
2548 a->apply(this, srp, this);
2552 else if(command == TOSERVER_CHAT_MESSAGE)
2560 std::string datastring((char*)&data[2], datasize-2);
2561 std::istringstream is(datastring, std::ios_base::binary);
2564 is.read((char*)buf, 2);
2565 u16 len = readU16(buf);
2567 std::wstring message;
2568 for(u16 i=0; i<len; i++)
2570 is.read((char*)buf, 2);
2571 message += (wchar_t)readU16(buf);
2574 // Get player name of this client
2575 std::wstring name = narrow_to_wide(player->getName());
2578 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2579 wide_to_narrow(message));
2580 // If script ate the message, don't proceed
2584 // Line to send to players
2586 // Whether to send to the player that sent the line
2587 bool send_to_sender = false;
2588 // Whether to send to other players
2589 bool send_to_others = false;
2591 // Local player gets all privileges regardless of
2592 // what's set on their account.
2593 u64 privs = getPlayerPrivs(player);
2596 if(message[0] == L'/')
2598 size_t strip_size = 1;
2599 if (message[1] == L'#') // support old-style commans
2601 message = message.substr(strip_size);
2603 WStrfnd f1(message);
2604 f1.next(L" "); // Skip over /#whatever
2605 std::wstring paramstring = f1.next(L"");
2607 ServerCommandContext *ctx = new ServerCommandContext(
2608 str_split(message, L' '),
2615 std::wstring reply(processServerCommand(ctx));
2616 send_to_sender = ctx->flags & SEND_TO_SENDER;
2617 send_to_others = ctx->flags & SEND_TO_OTHERS;
2619 if (ctx->flags & SEND_NO_PREFIX)
2622 line += L"Server: " + reply;
2629 if(privs & PRIV_SHOUT)
2635 send_to_others = true;
2639 line += L"Server: You are not allowed to shout";
2640 send_to_sender = true;
2647 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2650 Send the message to clients
2652 for(core::map<u16, RemoteClient*>::Iterator
2653 i = m_clients.getIterator();
2654 i.atEnd() == false; i++)
2656 // Get client and check that it is valid
2657 RemoteClient *client = i.getNode()->getValue();
2658 assert(client->peer_id == i.getNode()->getKey());
2659 if(client->serialization_version == SER_FMT_VER_INVALID)
2663 bool sender_selected = (peer_id == client->peer_id);
2664 if(sender_selected == true && send_to_sender == false)
2666 if(sender_selected == false && send_to_others == false)
2669 SendChatMessage(client->peer_id, line);
2673 else if(command == TOSERVER_DAMAGE)
2675 std::string datastring((char*)&data[2], datasize-2);
2676 std::istringstream is(datastring, std::ios_base::binary);
2677 u8 damage = readU8(is);
2679 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2681 if(g_settings->getBool("enable_damage"))
2683 actionstream<<player->getName()<<" damaged by "
2684 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2687 srp->setHP(srp->getHP() - damage);
2689 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2692 if(srp->m_hp_not_sent)
2693 SendPlayerHP(player);
2697 // Force send (to correct the client's predicted HP)
2698 SendPlayerHP(player);
2701 else if(command == TOSERVER_PASSWORD)
2704 [0] u16 TOSERVER_PASSWORD
2705 [2] u8[28] old password
2706 [30] u8[28] new password
2709 if(datasize != 2+PASSWORD_SIZE*2)
2711 /*char password[PASSWORD_SIZE];
2712 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2713 password[i] = data[2+i];
2714 password[PASSWORD_SIZE-1] = 0;*/
2716 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2724 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2726 char c = data[2+PASSWORD_SIZE+i];
2732 infostream<<"Server: Client requests a password change from "
2733 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2735 std::string playername = player->getName();
2737 if(m_authmanager.exists(playername) == false)
2739 infostream<<"Server: playername not found in authmanager"<<std::endl;
2740 // Wrong old password supplied!!
2741 SendChatMessage(peer_id, L"playername not found in authmanager");
2745 std::string checkpwd = m_authmanager.getPassword(playername);
2747 if(oldpwd != checkpwd)
2749 infostream<<"Server: invalid old password"<<std::endl;
2750 // Wrong old password supplied!!
2751 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2755 actionstream<<player->getName()<<" changes password"<<std::endl;
2757 m_authmanager.setPassword(playername, newpwd);
2759 infostream<<"Server: password change successful for "<<playername
2761 SendChatMessage(peer_id, L"Password change successful");
2763 else if(command == TOSERVER_PLAYERITEM)
2768 u16 item = readU16(&data[2]);
2769 srp->setWieldIndex(item);
2770 SendWieldedItem(srp);
2772 else if(command == TOSERVER_RESPAWN)
2777 RespawnPlayer(player);
2779 actionstream<<player->getName()<<" respawns at "
2780 <<PP(player->getPosition()/BS)<<std::endl;
2782 // ActiveObject is added to environment in AsyncRunStep after
2783 // the previous addition has been succesfully removed
2785 else if(command == TOSERVER_REQUEST_TEXTURES) {
2786 std::string datastring((char*)&data[2], datasize-2);
2787 std::istringstream is(datastring, std::ios_base::binary);
2789 infostream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2791 core::list<TextureRequest> tosend;
2793 u16 numtextures = readU16(is);
2795 for(int i = 0; i < numtextures; i++) {
2797 std::string name = deSerializeString(is);
2799 tosend.push_back(TextureRequest(name));
2800 infostream<<"TOSERVER_REQUEST_TEXTURES: requested texture " << name <<std::endl;
2803 SendTexturesRequested(peer_id, tosend);
2805 // Now the client should know about everything
2806 // (definitions and textures)
2807 getClient(peer_id)->definitions_sent = true;
2809 else if(command == TOSERVER_INTERACT)
2811 std::string datastring((char*)&data[2], datasize-2);
2812 std::istringstream is(datastring, std::ios_base::binary);
2818 [5] u32 length of the next item
2819 [9] serialized PointedThing
2821 0: start digging (from undersurface) or use
2822 1: stop digging (all parameters ignored)
2823 2: digging completed
2824 3: place block or item (to abovesurface)
2827 u8 action = readU8(is);
2828 u16 item_i = readU16(is);
2829 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2830 PointedThing pointed;
2831 pointed.deSerialize(tmp_is);
2833 infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<<item_i<<", pointed="<<pointed.dump()<<std::endl;
2837 infostream<<"TOSERVER_INTERACT: "<<srp->getName()
2838 <<" tried to interact, but is dead!"<<std::endl;
2842 v3f player_pos = srp->m_last_good_position;
2844 // Update wielded item
2845 if(srp->getWieldIndex() != item_i)
2847 srp->setWieldIndex(item_i);
2848 SendWieldedItem(srp);
2851 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2852 v3s16 p_under = pointed.node_undersurface;
2853 v3s16 p_above = pointed.node_abovesurface;
2855 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2856 ServerActiveObject *pointed_object = NULL;
2857 if(pointed.type == POINTEDTHING_OBJECT)
2859 pointed_object = m_env->getActiveObject(pointed.object_id);
2860 if(pointed_object == NULL)
2862 infostream<<"TOSERVER_INTERACT: "
2863 "pointed object is NULL"<<std::endl;
2869 v3f pointed_pos_under = player_pos;
2870 v3f pointed_pos_above = player_pos;
2871 if(pointed.type == POINTEDTHING_NODE)
2873 pointed_pos_under = intToFloat(p_under, BS);
2874 pointed_pos_above = intToFloat(p_above, BS);
2876 else if(pointed.type == POINTEDTHING_OBJECT)
2878 pointed_pos_under = pointed_object->getBasePosition();
2879 pointed_pos_above = pointed_pos_under;
2883 Check that target is reasonably close
2884 (only when digging or placing things)
2886 if(action == 0 || action == 2 || action == 3)
2888 float d = player_pos.getDistanceFrom(pointed_pos_under);
2889 float max_d = BS * 14; // Just some large enough value
2891 actionstream<<"Player "<<player->getName()
2892 <<" tried to access "<<pointed.dump()
2894 <<"d="<<d<<", max_d="<<max_d
2895 <<". ignoring."<<std::endl;
2896 // Re-send block to revert change on client-side
2897 RemoteClient *client = getClient(peer_id);
2898 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2899 client->SetBlockNotSent(blockpos);
2906 Make sure the player is allowed to do it
2908 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2910 infostream<<"Ignoring interaction from player "<<player->getName()
2911 <<" because privileges are "<<getPlayerPrivs(player)
2917 0: start digging or punch object
2921 if(pointed.type == POINTEDTHING_NODE)
2924 NOTE: This can be used in the future to check if
2925 somebody is cheating, by checking the timing.
2927 MapNode n(CONTENT_IGNORE);
2930 n = m_env->getMap().getNode(p_under);
2932 catch(InvalidPositionException &e)
2934 infostream<<"Server: Not punching: Node not found."
2935 <<" Adding block to emerge queue."
2937 m_emerge_queue.addBlock(peer_id,
2938 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2940 if(n.getContent() != CONTENT_IGNORE)
2941 scriptapi_node_on_punch(m_lua, p_under, n, srp);
2943 else if(pointed.type == POINTEDTHING_OBJECT)
2945 // Skip if object has been removed
2946 if(pointed_object->m_removed)
2949 actionstream<<player->getName()<<" punches object "
2950 <<pointed.object_id<<std::endl;
2952 ItemStack punchitem = srp->getWieldedItem();
2953 ToolCapabilities toolcap =
2954 punchitem.getToolCapabilities(m_itemdef);
2955 v3f dir = (pointed_object->getBasePosition() -
2956 (srp->getPosition() + srp->getEyeOffset())
2958 pointed_object->punch(dir, &toolcap, srp,
2959 srp->m_time_from_last_punch);
2960 srp->m_time_from_last_punch = 0;
2968 else if(action == 1)
2973 2: Digging completed
2975 else if(action == 2)
2977 // Only complete digging of nodes
2978 if(pointed.type == POINTEDTHING_NODE)
2980 MapNode n(CONTENT_IGNORE);
2983 n = m_env->getMap().getNode(p_under);
2985 catch(InvalidPositionException &e)
2987 infostream<<"Server: Not finishing digging: Node not found."
2988 <<" Adding block to emerge queue."
2990 m_emerge_queue.addBlock(peer_id,
2991 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2993 if(n.getContent() != CONTENT_IGNORE)
2994 scriptapi_node_on_dig(m_lua, p_under, n, srp);
2999 3: place block or right-click object
3001 else if(action == 3)
3003 ItemStack item = srp->getWieldedItem();
3005 // Reset build time counter
3006 if(pointed.type == POINTEDTHING_NODE &&
3007 item.getDefinition(m_itemdef).type == ITEM_NODE)
3008 getClient(peer_id)->m_time_from_building = 0.0;
3010 if(pointed.type == POINTEDTHING_OBJECT)
3012 // Right click object
3014 // Skip if object has been removed
3015 if(pointed_object->m_removed)
3018 actionstream<<player->getName()<<" right-clicks object "
3019 <<pointed.object_id<<std::endl;
3022 pointed_object->rightClick(srp);
3024 else if(scriptapi_item_on_place(m_lua,
3025 item, srp, pointed))
3027 // Placement was handled in lua
3029 // Apply returned ItemStack
3030 if(g_settings->getBool("creative_mode") == false)
3031 srp->setWieldedItem(item);
3039 else if(action == 4)
3041 ItemStack item = srp->getWieldedItem();
3043 actionstream<<player->getName()<<" uses "<<item.name
3044 <<", pointing at "<<pointed.dump()<<std::endl;
3046 if(scriptapi_item_on_use(m_lua,
3047 item, srp, pointed))
3049 // Apply returned ItemStack
3050 if(g_settings->getBool("creative_mode") == false)
3051 srp->setWieldedItem(item);
3057 Catch invalid actions
3061 infostream<<"WARNING: Server: Invalid action "
3062 <<action<<std::endl;
3067 infostream<<"Server::ProcessData(): Ignoring "
3068 "unknown command "<<command<<std::endl;
3072 catch(SendFailedException &e)
3074 errorstream<<"Server::ProcessData(): SendFailedException: "
3080 void Server::onMapEditEvent(MapEditEvent *event)
3082 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3083 if(m_ignore_map_edit_events)
3085 MapEditEvent *e = event->clone();
3086 m_unsent_map_edit_queue.push_back(e);
3089 Inventory* Server::getInventory(const InventoryLocation &loc)
3092 case InventoryLocation::UNDEFINED:
3095 case InventoryLocation::CURRENT_PLAYER:
3098 case InventoryLocation::PLAYER:
3100 Player *player = m_env->getPlayer(loc.name.c_str());
3103 return &player->inventory;
3106 case InventoryLocation::NODEMETA:
3108 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3111 return meta->getInventory();
3119 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3122 case InventoryLocation::UNDEFINED:
3125 case InventoryLocation::CURRENT_PLAYER:
3128 case InventoryLocation::PLAYER:
3133 case InventoryLocation::NODEMETA:
3135 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3138 return meta->getOwner();
3146 void Server::setInventoryModified(const InventoryLocation &loc)
3149 case InventoryLocation::UNDEFINED:
3152 case InventoryLocation::PLAYER:
3154 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3155 (m_env->getPlayer(loc.name.c_str()));
3158 srp->m_inventory_not_sent = true;
3161 case InventoryLocation::NODEMETA:
3163 v3s16 blockpos = getNodeBlockPos(loc.p);
3165 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3167 meta->inventoryModified();
3169 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3171 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3173 setBlockNotSent(blockpos);
3181 core::list<PlayerInfo> Server::getPlayerInfo()
3183 DSTACK(__FUNCTION_NAME);
3184 JMutexAutoLock envlock(m_env_mutex);
3185 JMutexAutoLock conlock(m_con_mutex);
3187 core::list<PlayerInfo> list;
3189 core::list<Player*> players = m_env->getPlayers();
3191 core::list<Player*>::Iterator i;
3192 for(i = players.begin();
3193 i != players.end(); i++)
3197 Player *player = *i;
3200 // Copy info from connection to info struct
3201 info.id = player->peer_id;
3202 info.address = m_con.GetPeerAddress(player->peer_id);
3203 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3205 catch(con::PeerNotFoundException &e)
3207 // Set dummy peer info
3209 info.address = Address(0,0,0,0,0);
3213 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3214 info.position = player->getPosition();
3216 list.push_back(info);
3223 void Server::peerAdded(con::Peer *peer)
3225 DSTACK(__FUNCTION_NAME);
3226 infostream<<"Server::peerAdded(): peer->id="
3227 <<peer->id<<std::endl;
3230 c.type = PEER_ADDED;
3231 c.peer_id = peer->id;
3233 m_peer_change_queue.push_back(c);
3236 void Server::deletingPeer(con::Peer *peer, bool timeout)
3238 DSTACK(__FUNCTION_NAME);
3239 infostream<<"Server::deletingPeer(): peer->id="
3240 <<peer->id<<", timeout="<<timeout<<std::endl;
3243 c.type = PEER_REMOVED;
3244 c.peer_id = peer->id;
3245 c.timeout = timeout;
3246 m_peer_change_queue.push_back(c);
3253 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3255 DSTACK(__FUNCTION_NAME);
3256 std::ostringstream os(std::ios_base::binary);
3258 writeU16(os, TOCLIENT_HP);
3262 std::string s = os.str();
3263 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3265 con.Send(peer_id, 0, data, true);
3268 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3269 const std::wstring &reason)
3271 DSTACK(__FUNCTION_NAME);
3272 std::ostringstream os(std::ios_base::binary);
3274 writeU16(os, TOCLIENT_ACCESS_DENIED);
3275 os<<serializeWideString(reason);
3278 std::string s = os.str();
3279 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3281 con.Send(peer_id, 0, data, true);
3284 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3285 bool set_camera_point_target, v3f camera_point_target)
3287 DSTACK(__FUNCTION_NAME);
3288 std::ostringstream os(std::ios_base::binary);
3290 writeU16(os, TOCLIENT_DEATHSCREEN);
3291 writeU8(os, set_camera_point_target);
3292 writeV3F1000(os, camera_point_target);
3295 std::string s = os.str();
3296 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3298 con.Send(peer_id, 0, data, true);
3301 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3302 IItemDefManager *itemdef)
3304 DSTACK(__FUNCTION_NAME);
3305 std::ostringstream os(std::ios_base::binary);
3309 u32 length of the next item
3310 zlib-compressed serialized ItemDefManager
3312 writeU16(os, TOCLIENT_ITEMDEF);
3313 std::ostringstream tmp_os(std::ios::binary);
3314 itemdef->serialize(tmp_os);
3315 std::ostringstream tmp_os2(std::ios::binary);
3316 compressZlib(tmp_os.str(), tmp_os2);
3317 os<<serializeLongString(tmp_os2.str());
3320 std::string s = os.str();
3321 infostream<<"Server::SendItemDef(): Sending item definitions: size="
3322 <<s.size()<<std::endl;
3323 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3325 con.Send(peer_id, 0, data, true);
3328 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3329 INodeDefManager *nodedef)
3331 DSTACK(__FUNCTION_NAME);
3332 std::ostringstream os(std::ios_base::binary);
3336 u32 length of the next item
3337 zlib-compressed serialized NodeDefManager
3339 writeU16(os, TOCLIENT_NODEDEF);
3340 std::ostringstream tmp_os(std::ios::binary);
3341 nodedef->serialize(tmp_os);
3342 std::ostringstream tmp_os2(std::ios::binary);
3343 compressZlib(tmp_os.str(), tmp_os2);
3344 os<<serializeLongString(tmp_os2.str());
3347 std::string s = os.str();
3348 infostream<<"Server::SendNodeDef(): Sending node definitions: size="
3349 <<s.size()<<std::endl;
3350 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3352 con.Send(peer_id, 0, data, true);
3356 Non-static send methods
3359 void Server::SendInventory(u16 peer_id)
3361 DSTACK(__FUNCTION_NAME);
3363 ServerRemotePlayer* player =
3364 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3367 player->m_inventory_not_sent = false;
3373 std::ostringstream os;
3374 //os.imbue(std::locale("C"));
3376 player->inventory.serialize(os);
3378 std::string s = os.str();
3380 SharedBuffer<u8> data(s.size()+2);
3381 writeU16(&data[0], TOCLIENT_INVENTORY);
3382 memcpy(&data[2], s.c_str(), s.size());
3385 m_con.Send(peer_id, 0, data, true);
3388 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3390 DSTACK(__FUNCTION_NAME);
3394 std::ostringstream os(std::ios_base::binary);
3396 writeU16(os, TOCLIENT_PLAYERITEM);
3398 writeU16(os, srp->peer_id);
3399 os<<serializeString(srp->getWieldedItem().getItemString());
3402 std::string s = os.str();
3403 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3405 m_con.SendToAll(0, data, true);
3408 void Server::SendPlayerItems()
3410 DSTACK(__FUNCTION_NAME);
3412 std::ostringstream os(std::ios_base::binary);
3413 core::list<Player *> players = m_env->getPlayers(true);
3415 writeU16(os, TOCLIENT_PLAYERITEM);
3416 writeU16(os, players.size());
3417 core::list<Player *>::Iterator i;
3418 for(i = players.begin(); i != players.end(); ++i)
3421 ServerRemotePlayer *srp =
3422 static_cast<ServerRemotePlayer*>(p);
3423 writeU16(os, p->peer_id);
3424 os<<serializeString(srp->getWieldedItem().getItemString());
3428 std::string s = os.str();
3429 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3431 m_con.SendToAll(0, data, true);
3434 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3436 DSTACK(__FUNCTION_NAME);
3438 std::ostringstream os(std::ios_base::binary);
3442 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3443 os.write((char*)buf, 2);
3446 writeU16(buf, message.size());
3447 os.write((char*)buf, 2);
3450 for(u32 i=0; i<message.size(); i++)
3454 os.write((char*)buf, 2);
3458 std::string s = os.str();
3459 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3461 m_con.Send(peer_id, 0, data, true);
3464 void Server::BroadcastChatMessage(const std::wstring &message)
3466 for(core::map<u16, RemoteClient*>::Iterator
3467 i = m_clients.getIterator();
3468 i.atEnd() == false; i++)
3470 // Get client and check that it is valid
3471 RemoteClient *client = i.getNode()->getValue();
3472 assert(client->peer_id == i.getNode()->getKey());
3473 if(client->serialization_version == SER_FMT_VER_INVALID)
3476 SendChatMessage(client->peer_id, message);
3480 void Server::SendPlayerHP(Player *player)
3482 SendHP(m_con, player->peer_id, player->hp);
3483 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3486 void Server::SendMovePlayer(Player *player)
3488 DSTACK(__FUNCTION_NAME);
3489 std::ostringstream os(std::ios_base::binary);
3491 writeU16(os, TOCLIENT_MOVE_PLAYER);
3492 writeV3F1000(os, player->getPosition());
3493 writeF1000(os, player->getPitch());
3494 writeF1000(os, player->getYaw());
3497 v3f pos = player->getPosition();
3498 f32 pitch = player->getPitch();
3499 f32 yaw = player->getYaw();
3500 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
3501 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3508 std::string s = os.str();
3509 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3511 m_con.Send(player->peer_id, 0, data, true);
3514 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3515 core::list<u16> *far_players, float far_d_nodes)
3517 float maxd = far_d_nodes*BS;
3518 v3f p_f = intToFloat(p, BS);
3522 SharedBuffer<u8> reply(replysize);
3523 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3524 writeS16(&reply[2], p.X);
3525 writeS16(&reply[4], p.Y);
3526 writeS16(&reply[6], p.Z);
3528 for(core::map<u16, RemoteClient*>::Iterator
3529 i = m_clients.getIterator();
3530 i.atEnd() == false; i++)
3532 // Get client and check that it is valid
3533 RemoteClient *client = i.getNode()->getValue();
3534 assert(client->peer_id == i.getNode()->getKey());
3535 if(client->serialization_version == SER_FMT_VER_INVALID)
3538 // Don't send if it's the same one
3539 if(client->peer_id == ignore_id)
3545 Player *player = m_env->getPlayer(client->peer_id);
3548 // If player is far away, only set modified blocks not sent
3549 v3f player_pos = player->getPosition();
3550 if(player_pos.getDistanceFrom(p_f) > maxd)
3552 far_players->push_back(client->peer_id);
3559 m_con.Send(client->peer_id, 0, reply, true);
3563 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3564 core::list<u16> *far_players, float far_d_nodes)
3566 float maxd = far_d_nodes*BS;
3567 v3f p_f = intToFloat(p, BS);
3569 for(core::map<u16, RemoteClient*>::Iterator
3570 i = m_clients.getIterator();
3571 i.atEnd() == false; i++)
3573 // Get client and check that it is valid
3574 RemoteClient *client = i.getNode()->getValue();
3575 assert(client->peer_id == i.getNode()->getKey());
3576 if(client->serialization_version == SER_FMT_VER_INVALID)
3579 // Don't send if it's the same one
3580 if(client->peer_id == ignore_id)
3586 Player *player = m_env->getPlayer(client->peer_id);
3589 // If player is far away, only set modified blocks not sent
3590 v3f player_pos = player->getPosition();
3591 if(player_pos.getDistanceFrom(p_f) > maxd)
3593 far_players->push_back(client->peer_id);
3600 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3601 SharedBuffer<u8> reply(replysize);
3602 writeU16(&reply[0], TOCLIENT_ADDNODE);
3603 writeS16(&reply[2], p.X);
3604 writeS16(&reply[4], p.Y);
3605 writeS16(&reply[6], p.Z);
3606 n.serialize(&reply[8], client->serialization_version);
3609 m_con.Send(client->peer_id, 0, reply, true);
3613 void Server::setBlockNotSent(v3s16 p)
3615 for(core::map<u16, RemoteClient*>::Iterator
3616 i = m_clients.getIterator();
3617 i.atEnd()==false; i++)
3619 RemoteClient *client = i.getNode()->getValue();
3620 client->SetBlockNotSent(p);
3624 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3626 DSTACK(__FUNCTION_NAME);
3628 v3s16 p = block->getPos();
3632 bool completely_air = true;
3633 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3634 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3635 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3637 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3639 completely_air = false;
3640 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3645 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3647 infostream<<"[completely air] ";
3648 infostream<<std::endl;
3652 Create a packet with the block in the right format
3655 std::ostringstream os(std::ios_base::binary);
3656 block->serialize(os, ver, false);
3657 std::string s = os.str();
3658 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3660 u32 replysize = 8 + blockdata.getSize();
3661 SharedBuffer<u8> reply(replysize);
3662 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3663 writeS16(&reply[2], p.X);
3664 writeS16(&reply[4], p.Y);
3665 writeS16(&reply[6], p.Z);
3666 memcpy(&reply[8], *blockdata, blockdata.getSize());
3668 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3669 <<": \tpacket size: "<<replysize<<std::endl;*/
3674 m_con.Send(peer_id, 1, reply, true);
3677 void Server::SendBlocks(float dtime)
3679 DSTACK(__FUNCTION_NAME);
3681 JMutexAutoLock envlock(m_env_mutex);
3682 JMutexAutoLock conlock(m_con_mutex);
3684 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3686 core::array<PrioritySortedBlockTransfer> queue;
3688 s32 total_sending = 0;
3691 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3693 for(core::map<u16, RemoteClient*>::Iterator
3694 i = m_clients.getIterator();
3695 i.atEnd() == false; i++)
3697 RemoteClient *client = i.getNode()->getValue();
3698 assert(client->peer_id == i.getNode()->getKey());
3700 // If definitions and textures have not been sent, don't
3701 // send MapBlocks either
3702 if(!client->definitions_sent)
3705 total_sending += client->SendingCount();
3707 if(client->serialization_version == SER_FMT_VER_INVALID)
3710 client->GetNextBlocks(this, dtime, queue);
3715 // Lowest priority number comes first.
3716 // Lowest is most important.
3719 for(u32 i=0; i<queue.size(); i++)
3721 //TODO: Calculate limit dynamically
3722 if(total_sending >= g_settings->getS32
3723 ("max_simultaneous_block_sends_server_total"))
3726 PrioritySortedBlockTransfer q = queue[i];
3728 MapBlock *block = NULL;
3731 block = m_env->getMap().getBlockNoCreate(q.pos);
3733 catch(InvalidPositionException &e)
3738 RemoteClient *client = getClient(q.peer_id);
3740 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3742 client->SentBlock(q.pos);
3748 void Server::PrepareTextures() {
3749 DSTACK(__FUNCTION_NAME);
3751 infostream<<"Server::PrepareTextures(): Calculate sha1 sums of textures"<<std::endl;
3753 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3754 i != m_mods.end(); i++){
3755 const ModSpec &mod = *i;
3756 std::string texturepath = mod.path + DIR_DELIM + "textures";
3757 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3758 for(u32 j=0; j<dirlist.size(); j++){
3759 if(dirlist[j].dir) // Ignode dirs
3761 std::string tname = dirlist[j].name;
3762 // if name contains illegal characters, ignore the texture
3763 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3764 errorstream<<"Server: ignoring illegal texture name: \""
3765 <<tname<<"\""<<std::endl;
3768 std::string tpath = texturepath + DIR_DELIM + tname;
3770 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3771 if(fis.good() == false){
3772 errorstream<<"Server::PrepareTextures(): Could not open \""
3773 <<tname<<"\" for reading"<<std::endl;
3776 std::ostringstream tmp_os(std::ios_base::binary);
3780 fis.read(buf, 1024);
3781 std::streamsize len = fis.gcount();
3782 tmp_os.write(buf, len);
3791 errorstream<<"Server::PrepareTextures(): Failed to read \""
3792 <<tname<<"\""<<std::endl;
3795 if(tmp_os.str().length() == 0){
3796 errorstream<<"Server::PrepareTextures(): Empty file \""
3797 <<tpath<<"\""<<std::endl;
3802 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3804 unsigned char *digest = sha1.getDigest();
3805 std::string digest_string = base64_encode(digest, 20);
3810 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3811 infostream<<"Server::PrepareTextures(): added sha1 for "<< tname <<std::endl;
3816 struct SendableTextureAnnouncement
3819 std::string sha1_digest;
3821 SendableTextureAnnouncement(const std::string name_="",
3822 const std::string sha1_digest_=""):
3824 sha1_digest(sha1_digest_)
3829 void Server::SendTextureAnnouncement(u16 peer_id){
3830 DSTACK(__FUNCTION_NAME);
3832 infostream<<"Server::SendTextureAnnouncement()"<<std::endl;
3834 core::list<SendableTextureAnnouncement> texture_announcements;
3836 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3839 texture_announcements.push_back(
3840 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3843 //send announcements
3847 u32 number of textures
3851 u16 length of digest string
3855 std::ostringstream os(std::ios_base::binary);
3857 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3858 writeU16(os, texture_announcements.size());
3860 for(core::list<SendableTextureAnnouncement>::Iterator
3861 j = texture_announcements.begin();
3862 j != texture_announcements.end(); j++){
3863 os<<serializeString(j->name);
3864 os<<serializeString(j->sha1_digest);
3868 std::string s = os.str();
3869 infostream<<"Server::SendTextureAnnouncement(): Send to client"<<std::endl;
3870 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3873 m_con.Send(peer_id, 0, data, true);
3877 struct SendableTexture
3883 SendableTexture(const std::string &name_="", const std::string path_="",
3884 const std::string &data_=""):
3891 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3892 DSTACK(__FUNCTION_NAME);
3894 infostream<<"Server::SendTexturesRequested(): Sending textures to client"<<std::endl;
3898 // Put 5kB in one bunch (this is not accurate)
3899 u32 bytes_per_bunch = 5000;
3901 core::array< core::list<SendableTexture> > texture_bunches;
3902 texture_bunches.push_back(core::list<SendableTexture>());
3904 u32 texture_size_bunch_total = 0;
3906 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3907 if(m_Textures.find(i->name) == m_Textures.end()){
3908 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3909 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3913 //TODO get path + name
3914 std::string tpath = m_Textures[(*i).name].path;
3917 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3918 if(fis.good() == false){
3919 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3920 <<tpath<<"\" for reading"<<std::endl;
3923 std::ostringstream tmp_os(std::ios_base::binary);
3927 fis.read(buf, 1024);
3928 std::streamsize len = fis.gcount();
3929 tmp_os.write(buf, len);
3930 texture_size_bunch_total += len;
3939 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
3940 <<(*i).name<<"\""<<std::endl;
3943 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
3944 <<tname<<"\""<<std::endl;*/
3946 texture_bunches[texture_bunches.size()-1].push_back(
3947 SendableTexture((*i).name, tpath, tmp_os.str()));
3949 // Start next bunch if got enough data
3950 if(texture_size_bunch_total >= bytes_per_bunch){
3951 texture_bunches.push_back(core::list<SendableTexture>());
3952 texture_size_bunch_total = 0;
3957 /* Create and send packets */
3959 u32 num_bunches = texture_bunches.size();
3960 for(u32 i=0; i<num_bunches; i++)
3964 u16 total number of texture bunches
3965 u16 index of this bunch
3966 u32 number of textures in this bunch
3974 std::ostringstream os(std::ios_base::binary);
3976 writeU16(os, TOCLIENT_TEXTURES);
3977 writeU16(os, num_bunches);
3979 writeU32(os, texture_bunches[i].size());
3981 for(core::list<SendableTexture>::Iterator
3982 j = texture_bunches[i].begin();
3983 j != texture_bunches[i].end(); j++){
3984 os<<serializeString(j->name);
3985 os<<serializeLongString(j->data);
3989 std::string s = os.str();
3990 infostream<<"Server::SendTexturesRequested(): bunch "<<i<<"/"<<num_bunches
3991 <<" textures="<<texture_bunches[i].size()
3992 <<" size=" <<s.size()<<std::endl;
3993 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3995 m_con.Send(peer_id, 0, data, true);
4005 void Server::DiePlayer(Player *player)
4007 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4009 infostream<<"Server::DiePlayer(): Player "
4010 <<player->getName()<<" dies"<<std::endl;
4014 // Trigger scripted stuff
4015 scriptapi_on_dieplayer(m_lua, srp);
4017 // Handle players that are not connected
4018 if(player->peer_id == PEER_ID_INEXISTENT){
4019 RespawnPlayer(player);
4023 SendPlayerHP(player);
4024 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4027 void Server::RespawnPlayer(Player *player)
4029 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4031 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4033 v3f pos = findSpawnPos(m_env->getServerMap());
4034 player->setPosition(pos);
4035 srp->m_last_good_position = pos;
4036 srp->m_last_good_position_age = 0;
4038 SendMovePlayer(player);
4039 SendPlayerHP(player);
4042 void Server::UpdateCrafting(u16 peer_id)
4044 DSTACK(__FUNCTION_NAME);
4046 Player* player = m_env->getPlayer(peer_id);
4049 // Get a preview for crafting
4051 // No crafting in creative mode
4052 if(g_settings->getBool("creative_mode") == false)
4053 getCraftingResult(&player->inventory, preview, false, this);
4055 // Put the new preview in
4056 InventoryList *plist = player->inventory.getList("craftpreview");
4058 assert(plist->getSize() >= 1);
4059 plist->changeItem(0, preview);
4062 RemoteClient* Server::getClient(u16 peer_id)
4064 DSTACK(__FUNCTION_NAME);
4065 //JMutexAutoLock lock(m_con_mutex);
4066 core::map<u16, RemoteClient*>::Node *n;
4067 n = m_clients.find(peer_id);
4068 // A client should exist for all peers
4070 return n->getValue();
4073 std::wstring Server::getStatusString()
4075 std::wostringstream os(std::ios_base::binary);
4078 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4080 os<<L", uptime="<<m_uptime.get();
4081 // Information about clients
4083 for(core::map<u16, RemoteClient*>::Iterator
4084 i = m_clients.getIterator();
4085 i.atEnd() == false; i++)
4087 // Get client and check that it is valid
4088 RemoteClient *client = i.getNode()->getValue();
4089 assert(client->peer_id == i.getNode()->getKey());
4090 if(client->serialization_version == SER_FMT_VER_INVALID)
4093 Player *player = m_env->getPlayer(client->peer_id);
4094 // Get name of player
4095 std::wstring name = L"unknown";
4097 name = narrow_to_wide(player->getName());
4098 // Add name to information string
4102 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4103 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4104 if(g_settings->get("motd") != "")
4105 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4109 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4111 // Add player to auth manager
4112 if(m_authmanager.exists(name) == false)
4114 infostream<<"Server: adding player "<<name
4115 <<" to auth manager"<<std::endl;
4116 m_authmanager.add(name);
4117 m_authmanager.setPrivs(name,
4118 stringToPrivs(g_settings->get("default_privs")));
4120 // Change password and save
4121 m_authmanager.setPassword(name, translatePassword(name, password));
4122 m_authmanager.save();
4125 // Saves g_settings to configpath given at initialization
4126 void Server::saveConfig()
4128 if(m_path_config != "")
4129 g_settings->updateConfigFile(m_path_config.c_str());
4132 void Server::notifyPlayer(const char *name, const std::wstring msg)
4134 Player *player = m_env->getPlayer(name);
4137 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4140 void Server::notifyPlayers(const std::wstring msg)
4142 BroadcastChatMessage(msg);
4145 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4149 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4150 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4153 // IGameDef interface
4155 IItemDefManager* Server::getItemDefManager()
4159 INodeDefManager* Server::getNodeDefManager()
4163 ICraftDefManager* Server::getCraftDefManager()
4167 ITextureSource* Server::getTextureSource()
4171 u16 Server::allocateUnknownNodeId(const std::string &name)
4173 return m_nodedef->allocateDummy(name);
4176 IWritableItemDefManager* Server::getWritableItemDefManager()
4180 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4184 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4189 const ModSpec* Server::getModSpec(const std::string &modname)
4191 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4192 i != m_mods.end(); i++){
4193 const ModSpec &mod = *i;
4194 if(mod.name == modname)
4200 v3f findSpawnPos(ServerMap &map)
4202 //return v3f(50,50,50)*BS;
4207 nodepos = v2s16(0,0);
4212 // Try to find a good place a few times
4213 for(s32 i=0; i<1000; i++)
4216 // We're going to try to throw the player to this position
4217 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4218 -range + (myrand()%(range*2)));
4219 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4220 // Get ground height at point (fallbacks to heightmap function)
4221 s16 groundheight = map.findGroundLevel(nodepos2d);
4222 // Don't go underwater
4223 if(groundheight < WATER_LEVEL)
4225 //infostream<<"-> Underwater"<<std::endl;
4228 // Don't go to high places
4229 if(groundheight > WATER_LEVEL + 4)
4231 //infostream<<"-> Underwater"<<std::endl;
4235 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4236 bool is_good = false;
4238 for(s32 i=0; i<10; i++){
4239 v3s16 blockpos = getNodeBlockPos(nodepos);
4240 map.emergeBlock(blockpos, true);
4241 MapNode n = map.getNodeNoEx(nodepos);
4242 if(n.getContent() == CONTENT_AIR){
4253 // Found a good place
4254 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4260 return intToFloat(nodepos, BS);
4263 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4266 Try to get an existing player
4268 ServerRemotePlayer *player =
4269 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4272 // If player is already connected, cancel
4273 if(player->peer_id != 0)
4275 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4280 player->peer_id = peer_id;
4282 // Re-add player to environment
4283 if(player->m_removed)
4285 player->m_removed = false;
4287 m_env->addActiveObject(player);
4290 // Reset inventory to creative if in creative mode
4291 if(g_settings->getBool("creative_mode"))
4293 // Warning: double code below
4294 // Backup actual inventory
4295 player->inventory_backup = new Inventory(m_itemdef);
4296 *(player->inventory_backup) = player->inventory;
4297 // Set creative inventory
4298 player->resetInventory();
4299 scriptapi_get_creative_inventory(m_lua, player);
4306 If player with the wanted peer_id already exists, cancel.
4308 if(m_env->getPlayer(peer_id) != NULL)
4310 infostream<<"emergePlayer(): Player with wrong name but same"
4311 " peer_id already exists"<<std::endl;
4319 /* Set player position */
4321 infostream<<"Server: Finding spawn place for player \""
4322 <<name<<"\""<<std::endl;
4324 v3f pos = findSpawnPos(m_env->getServerMap());
4326 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4327 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4329 /* Add player to environment */
4330 m_env->addPlayer(player);
4331 m_env->addActiveObject(srp);
4334 scriptapi_on_newplayer(m_lua, srp);
4336 /* Add stuff to inventory */
4337 if(g_settings->getBool("creative_mode"))
4339 // Warning: double code above
4340 // Backup actual inventory
4341 player->inventory_backup = new Inventory(m_itemdef);
4342 *(player->inventory_backup) = player->inventory;
4343 // Set creative inventory
4344 player->resetInventory();
4345 scriptapi_get_creative_inventory(m_lua, player);
4350 } // create new player
4353 void Server::handlePeerChange(PeerChange &c)
4355 JMutexAutoLock envlock(m_env_mutex);
4356 JMutexAutoLock conlock(m_con_mutex);
4358 if(c.type == PEER_ADDED)
4365 core::map<u16, RemoteClient*>::Node *n;
4366 n = m_clients.find(c.peer_id);
4367 // The client shouldn't already exist
4371 RemoteClient *client = new RemoteClient();
4372 client->peer_id = c.peer_id;
4373 m_clients.insert(client->peer_id, client);
4376 else if(c.type == PEER_REMOVED)
4383 core::map<u16, RemoteClient*>::Node *n;
4384 n = m_clients.find(c.peer_id);
4385 // The client should exist
4389 Mark objects to be not known by the client
4391 RemoteClient *client = n->getValue();
4393 for(core::map<u16, bool>::Iterator
4394 i = client->m_known_objects.getIterator();
4395 i.atEnd()==false; i++)
4398 u16 id = i.getNode()->getKey();
4399 ServerActiveObject* obj = m_env->getActiveObject(id);
4401 if(obj && obj->m_known_by_count > 0)
4402 obj->m_known_by_count--;
4405 ServerRemotePlayer* player =
4406 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4408 // Collect information about leaving in chat
4409 std::wstring message;
4413 std::wstring name = narrow_to_wide(player->getName());
4416 message += L" left game";
4418 message += L" (timed out)";
4422 // Remove from environment
4424 player->m_removed = true;
4426 // Set player client disconnected
4428 player->peer_id = 0;
4436 std::ostringstream os(std::ios_base::binary);
4437 for(core::map<u16, RemoteClient*>::Iterator
4438 i = m_clients.getIterator();
4439 i.atEnd() == false; i++)
4441 RemoteClient *client = i.getNode()->getValue();
4442 assert(client->peer_id == i.getNode()->getKey());
4443 if(client->serialization_version == SER_FMT_VER_INVALID)
4446 Player *player = m_env->getPlayer(client->peer_id);
4449 // Get name of player
4450 os<<player->getName()<<" ";
4453 actionstream<<player->getName()<<" "
4454 <<(c.timeout?"times out.":"leaves game.")
4455 <<" List of players: "
4456 <<os.str()<<std::endl;
4461 delete m_clients[c.peer_id];
4462 m_clients.remove(c.peer_id);
4464 // Send player info to all remaining clients
4465 //SendPlayerInfos();
4467 // Send leave chat message to all remaining clients
4468 if(message.length() != 0)
4469 BroadcastChatMessage(message);
4478 void Server::handlePeerChanges()
4480 while(m_peer_change_queue.size() > 0)
4482 PeerChange c = m_peer_change_queue.pop_front();
4484 infostream<<"Server: Handling peer change: "
4485 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4488 handlePeerChange(c);
4492 u64 Server::getPlayerPrivs(Player *player)
4496 std::string playername = player->getName();
4497 // Local player gets all privileges regardless of
4498 // what's set on their account.
4499 if(g_settings->get("name") == playername)
4505 return getPlayerAuthPrivs(playername);
4509 void dedicated_server_loop(Server &server, bool &kill)
4511 DSTACK(__FUNCTION_NAME);
4513 infostream<<DTIME<<std::endl;
4514 infostream<<"========================"<<std::endl;
4515 infostream<<"Running dedicated server"<<std::endl;
4516 infostream<<"========================"<<std::endl;
4517 infostream<<std::endl;
4519 IntervalLimiter m_profiler_interval;
4523 float steplen = g_settings->getFloat("dedicated_server_step");
4524 // This is kind of a hack but can be done like this
4525 // because server.step() is very light
4527 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4528 sleep_ms((int)(steplen*1000.0));
4530 server.step(steplen);
4532 if(server.getShutdownRequested() || kill)
4534 infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4541 float profiler_print_interval =
4542 g_settings->getFloat("profiler_print_interval");
4543 if(profiler_print_interval != 0)
4545 if(m_profiler_interval.step(steplen, profiler_print_interval))
4547 infostream<<"Profiler:"<<std::endl;
4548 g_profiler->print(infostream);
4549 g_profiler->clear();
4556 static int counter = 0;
4562 core::list<PlayerInfo> list = server.getPlayerInfo();
4563 core::list<PlayerInfo>::Iterator i;
4564 static u32 sum_old = 0;
4565 u32 sum = PIChecksum(list);
4568 infostream<<DTIME<<"Player info:"<<std::endl;
4569 for(i=list.begin(); i!=list.end(); i++)
4571 i->PrintLine(&infostream);