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;
889 m_path_addons.insert(m_path_share + DIR_DELIM + "addons"
890 + DIR_DELIM + m_gamename);
891 m_path_addons.insert(porting::path_user + DIR_DELIM + "server"
892 + DIR_DELIM + "addons" + DIR_DELIM + m_gamename);
894 // Path to builtin.lua
895 std::string builtinpath = m_path_share + DIR_DELIM + "builtin.lua";
897 // Add default global mod search path
898 m_modspaths.push_front(m_path_game + DIR_DELIM "mods");
899 // Add world mod search path
900 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
901 // Add addon mod search path
902 for(std::set<std::string>::const_iterator i = m_path_addons.begin();
903 i != m_path_addons.end(); i++){
904 m_modspaths.push_front((*i) + DIR_DELIM + "mods");
907 // Print out mod search paths
908 infostream<<"- mod search paths:"<<std::endl;
909 for(core::list<std::string>::Iterator i = m_modspaths.begin();
910 i != m_modspaths.end(); i++){
911 std::string modspath = *i;
912 infostream<<" "<<modspath<<std::endl;
916 JMutexAutoLock envlock(m_env_mutex);
917 JMutexAutoLock conlock(m_con_mutex);
919 // Initialize scripting
921 infostream<<"Server: Initializing scripting"<<std::endl;
922 m_lua = script_init();
925 scriptapi_export(m_lua, this);
926 // Load and run builtin.lua
927 infostream<<"Server: Loading builtin Lua stuff from \""<<builtinpath
929 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
931 errorstream<<"Server: Failed to load and run "
932 <<builtinpath<<std::endl;
933 throw ModError("Failed to load and run "+builtinpath);
935 // Load and run "mod" scripts
936 m_mods = getMods(m_modspaths);
937 for(core::list<ModSpec>::Iterator i = m_mods.begin();
938 i != m_mods.end(); i++){
939 const ModSpec &mod = *i;
940 infostream<<"Server: Loading mod \""<<mod.name<<"\""<<std::endl;
941 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
942 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
944 errorstream<<"Server: Failed to load and run "
945 <<scriptpath<<std::endl;
946 throw ModError("Failed to load and run "+scriptpath);
950 // Read Textures and calculate sha1 sums
953 // Apply item aliases in the node definition manager
954 m_nodedef->updateAliases(m_itemdef);
956 // Initialize Environment
958 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
961 // Give environment reference to scripting api
962 scriptapi_add_environment(m_lua, m_env);
964 // Register us to receive map edit events
965 m_env->getMap().addEventReceiver(this);
967 // If file exists, load environment metadata
968 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
970 infostream<<"Server: Loading environment metadata"<<std::endl;
971 m_env->loadMeta(m_path_world);
975 infostream<<"Server: Loading players"<<std::endl;
976 m_env->deSerializePlayers(m_path_world);
979 Add some test ActiveBlockModifiers to environment
981 add_legacy_abms(m_env, m_nodedef);
986 infostream<<"Server::~Server()"<<std::endl;
989 Send shutdown message
992 JMutexAutoLock conlock(m_con_mutex);
994 std::wstring line = L"*** Server shutting down";
997 Send the message to clients
999 for(core::map<u16, RemoteClient*>::Iterator
1000 i = m_clients.getIterator();
1001 i.atEnd() == false; i++)
1003 // Get client and check that it is valid
1004 RemoteClient *client = i.getNode()->getValue();
1005 assert(client->peer_id == i.getNode()->getKey());
1006 if(client->serialization_version == SER_FMT_VER_INVALID)
1010 SendChatMessage(client->peer_id, line);
1012 catch(con::PeerNotFoundException &e)
1018 JMutexAutoLock envlock(m_env_mutex);
1023 infostream<<"Server: Saving players"<<std::endl;
1024 m_env->serializePlayers(m_path_world);
1027 Save environment metadata
1029 infostream<<"Server: Saving environment metadata"<<std::endl;
1030 m_env->saveMeta(m_path_world);
1042 JMutexAutoLock clientslock(m_con_mutex);
1044 for(core::map<u16, RemoteClient*>::Iterator
1045 i = m_clients.getIterator();
1046 i.atEnd() == false; i++)
1049 // NOTE: These are removed by env destructor
1051 u16 peer_id = i.getNode()->getKey();
1052 JMutexAutoLock envlock(m_env_mutex);
1053 m_env->removePlayer(peer_id);
1057 delete i.getNode()->getValue();
1061 // Delete Environment
1068 // Deinitialize scripting
1069 infostream<<"Server: Deinitializing scripting"<<std::endl;
1070 script_deinit(m_lua);
1073 void Server::start(unsigned short port)
1075 DSTACK(__FUNCTION_NAME);
1076 // Stop thread if already running
1079 // Initialize connection
1080 m_con.SetTimeoutMs(30);
1084 m_thread.setRun(true);
1087 infostream<<"Server started on port "<<port<<"."<<std::endl;
1092 DSTACK(__FUNCTION_NAME);
1094 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1096 // Stop threads (set run=false first so both start stopping)
1097 m_thread.setRun(false);
1098 m_emergethread.setRun(false);
1100 m_emergethread.stop();
1102 infostream<<"Server: Threads stopped"<<std::endl;
1105 void Server::step(float dtime)
1107 DSTACK(__FUNCTION_NAME);
1112 JMutexAutoLock lock(m_step_dtime_mutex);
1113 m_step_dtime += dtime;
1117 void Server::AsyncRunStep()
1119 DSTACK(__FUNCTION_NAME);
1121 g_profiler->add("Server::AsyncRunStep (num)", 1);
1125 JMutexAutoLock lock1(m_step_dtime_mutex);
1126 dtime = m_step_dtime;
1130 // Send blocks to clients
1137 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1139 //infostream<<"Server steps "<<dtime<<std::endl;
1140 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1143 JMutexAutoLock lock1(m_step_dtime_mutex);
1144 m_step_dtime -= dtime;
1151 m_uptime.set(m_uptime.get() + dtime);
1155 // Process connection's timeouts
1156 JMutexAutoLock lock2(m_con_mutex);
1157 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1158 m_con.RunTimeouts(dtime);
1162 // This has to be called so that the client list gets synced
1163 // with the peer list of the connection
1164 handlePeerChanges();
1168 Update m_time_of_day and overall game time
1171 JMutexAutoLock envlock(m_env_mutex);
1173 m_time_counter += dtime;
1174 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1175 u32 units = (u32)(m_time_counter*speed);
1176 m_time_counter -= (f32)units / speed;
1178 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1180 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1183 Send to clients at constant intervals
1186 m_time_of_day_send_timer -= dtime;
1187 if(m_time_of_day_send_timer < 0.0)
1189 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1191 //JMutexAutoLock envlock(m_env_mutex);
1192 JMutexAutoLock conlock(m_con_mutex);
1194 for(core::map<u16, RemoteClient*>::Iterator
1195 i = m_clients.getIterator();
1196 i.atEnd() == false; i++)
1198 RemoteClient *client = i.getNode()->getValue();
1199 //Player *player = m_env->getPlayer(client->peer_id);
1201 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1202 m_env->getTimeOfDay());
1204 m_con.Send(client->peer_id, 0, data, true);
1210 JMutexAutoLock lock(m_env_mutex);
1212 ScopeProfiler sp(g_profiler, "SEnv step");
1213 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1217 const float map_timer_and_unload_dtime = 2.92;
1218 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1220 JMutexAutoLock lock(m_env_mutex);
1221 // Run Map's timers and unload unused data
1222 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1223 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1224 g_settings->getFloat("server_unload_unused_data_timeout"));
1235 JMutexAutoLock lock(m_env_mutex);
1236 JMutexAutoLock lock2(m_con_mutex);
1238 ScopeProfiler sp(g_profiler, "Server: handle players");
1240 //float player_max_speed = BS * 4.0; // Normal speed
1241 float player_max_speed = BS * 20; // Fast speed
1242 float player_max_speed_up = BS * 20;
1244 player_max_speed *= 2.5; // Tolerance
1245 player_max_speed_up *= 2.5;
1247 for(core::map<u16, RemoteClient*>::Iterator
1248 i = m_clients.getIterator();
1249 i.atEnd() == false; i++)
1251 RemoteClient *client = i.getNode()->getValue();
1252 ServerRemotePlayer *player =
1253 static_cast<ServerRemotePlayer*>
1254 (m_env->getPlayer(client->peer_id));
1259 Check player movements
1261 NOTE: Actually the server should handle player physics like the
1262 client does and compare player's position to what is calculated
1263 on our side. This is required when eg. players fly due to an
1266 player->m_last_good_position_age += dtime;
1267 if(player->m_last_good_position_age >= 1.0){
1268 float age = player->m_last_good_position_age;
1269 v3f diff = (player->getPosition() - player->m_last_good_position);
1270 float d_vert = diff.Y;
1272 float d_horiz = diff.getLength();
1273 /*infostream<<player->getName()<<"'s horizontal speed is "
1274 <<(d_horiz/age)<<std::endl;*/
1275 if(d_horiz <= age * player_max_speed &&
1276 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1277 player->m_last_good_position = player->getPosition();
1279 actionstream<<"Player "<<player->getName()
1280 <<" moved too fast; resetting position"
1282 player->setPosition(player->m_last_good_position);
1283 SendMovePlayer(player);
1285 player->m_last_good_position_age = 0;
1289 Handle player HPs (die if hp=0)
1291 if(player->hp == 0 && player->m_hp_not_sent)
1295 Send player inventories and HPs if necessary
1297 if(player->m_inventory_not_sent){
1298 UpdateCrafting(player->peer_id);
1299 SendInventory(player->peer_id);
1301 if(player->m_hp_not_sent){
1302 SendPlayerHP(player);
1308 if(!player->m_is_in_environment){
1309 player->m_removed = false;
1311 m_env->addActiveObject(player);
1316 /* Transform liquids */
1317 m_liquid_transform_timer += dtime;
1318 if(m_liquid_transform_timer >= 1.00)
1320 m_liquid_transform_timer -= 1.00;
1322 JMutexAutoLock lock(m_env_mutex);
1324 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1326 core::map<v3s16, MapBlock*> modified_blocks;
1327 m_env->getMap().transformLiquids(modified_blocks);
1332 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1333 ServerMap &map = ((ServerMap&)m_env->getMap());
1334 map.updateLighting(modified_blocks, lighting_modified_blocks);
1336 // Add blocks modified by lighting to modified_blocks
1337 for(core::map<v3s16, MapBlock*>::Iterator
1338 i = lighting_modified_blocks.getIterator();
1339 i.atEnd() == false; i++)
1341 MapBlock *block = i.getNode()->getValue();
1342 modified_blocks.insert(block->getPos(), block);
1346 Set the modified blocks unsent for all the clients
1349 JMutexAutoLock lock2(m_con_mutex);
1351 for(core::map<u16, RemoteClient*>::Iterator
1352 i = m_clients.getIterator();
1353 i.atEnd() == false; i++)
1355 RemoteClient *client = i.getNode()->getValue();
1357 if(modified_blocks.size() > 0)
1359 // Remove block from sent history
1360 client->SetBlocksNotSent(modified_blocks);
1365 // Periodically print some info
1367 float &counter = m_print_info_timer;
1373 JMutexAutoLock lock2(m_con_mutex);
1375 if(m_clients.size() != 0)
1376 infostream<<"Players:"<<std::endl;
1377 for(core::map<u16, RemoteClient*>::Iterator
1378 i = m_clients.getIterator();
1379 i.atEnd() == false; i++)
1381 //u16 peer_id = i.getNode()->getKey();
1382 RemoteClient *client = i.getNode()->getValue();
1383 Player *player = m_env->getPlayer(client->peer_id);
1386 infostream<<"* "<<player->getName()<<"\t";
1387 client->PrintInfo(infostream);
1392 //if(g_settings->getBool("enable_experimental"))
1396 Check added and deleted active objects
1399 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1400 JMutexAutoLock envlock(m_env_mutex);
1401 JMutexAutoLock conlock(m_con_mutex);
1403 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1405 // Radius inside which objects are active
1406 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1407 radius *= MAP_BLOCKSIZE;
1409 for(core::map<u16, RemoteClient*>::Iterator
1410 i = m_clients.getIterator();
1411 i.atEnd() == false; i++)
1413 RemoteClient *client = i.getNode()->getValue();
1415 // If definitions and textures have not been sent, don't
1416 // send objects either
1417 if(!client->definitions_sent)
1420 Player *player = m_env->getPlayer(client->peer_id);
1423 // This can happen if the client timeouts somehow
1424 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1426 <<" has no associated player"<<std::endl;*/
1429 v3s16 pos = floatToInt(player->getPosition(), BS);
1431 core::map<u16, bool> removed_objects;
1432 core::map<u16, bool> added_objects;
1433 m_env->getRemovedActiveObjects(pos, radius,
1434 client->m_known_objects, removed_objects);
1435 m_env->getAddedActiveObjects(pos, radius,
1436 client->m_known_objects, added_objects);
1438 // Ignore if nothing happened
1439 if(removed_objects.size() == 0 && added_objects.size() == 0)
1441 //infostream<<"active objects: none changed"<<std::endl;
1445 std::string data_buffer;
1449 // Handle removed objects
1450 writeU16((u8*)buf, removed_objects.size());
1451 data_buffer.append(buf, 2);
1452 for(core::map<u16, bool>::Iterator
1453 i = removed_objects.getIterator();
1454 i.atEnd()==false; i++)
1457 u16 id = i.getNode()->getKey();
1458 ServerActiveObject* obj = m_env->getActiveObject(id);
1460 // Add to data buffer for sending
1461 writeU16((u8*)buf, i.getNode()->getKey());
1462 data_buffer.append(buf, 2);
1464 // Remove from known objects
1465 client->m_known_objects.remove(i.getNode()->getKey());
1467 if(obj && obj->m_known_by_count > 0)
1468 obj->m_known_by_count--;
1471 // Handle added objects
1472 writeU16((u8*)buf, added_objects.size());
1473 data_buffer.append(buf, 2);
1474 for(core::map<u16, bool>::Iterator
1475 i = added_objects.getIterator();
1476 i.atEnd()==false; i++)
1479 u16 id = i.getNode()->getKey();
1480 ServerActiveObject* obj = m_env->getActiveObject(id);
1483 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1485 infostream<<"WARNING: "<<__FUNCTION_NAME
1486 <<": NULL object"<<std::endl;
1488 type = obj->getType();
1490 // Add to data buffer for sending
1491 writeU16((u8*)buf, id);
1492 data_buffer.append(buf, 2);
1493 writeU8((u8*)buf, type);
1494 data_buffer.append(buf, 1);
1497 data_buffer.append(serializeLongString(
1498 obj->getClientInitializationData()));
1500 data_buffer.append(serializeLongString(""));
1502 // Add to known objects
1503 client->m_known_objects.insert(i.getNode()->getKey(), false);
1506 obj->m_known_by_count++;
1510 SharedBuffer<u8> reply(2 + data_buffer.size());
1511 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1512 memcpy((char*)&reply[2], data_buffer.c_str(),
1513 data_buffer.size());
1515 m_con.Send(client->peer_id, 0, reply, true);
1517 infostream<<"Server: Sent object remove/add: "
1518 <<removed_objects.size()<<" removed, "
1519 <<added_objects.size()<<" added, "
1520 <<"packet size is "<<reply.getSize()<<std::endl;
1525 Collect a list of all the objects known by the clients
1526 and report it back to the environment.
1529 core::map<u16, bool> all_known_objects;
1531 for(core::map<u16, RemoteClient*>::Iterator
1532 i = m_clients.getIterator();
1533 i.atEnd() == false; i++)
1535 RemoteClient *client = i.getNode()->getValue();
1536 // Go through all known objects of client
1537 for(core::map<u16, bool>::Iterator
1538 i = client->m_known_objects.getIterator();
1539 i.atEnd()==false; i++)
1541 u16 id = i.getNode()->getKey();
1542 all_known_objects[id] = true;
1546 m_env->setKnownActiveObjects(whatever);
1552 Send object messages
1555 JMutexAutoLock envlock(m_env_mutex);
1556 JMutexAutoLock conlock(m_con_mutex);
1558 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1561 // Value = data sent by object
1562 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1564 // Get active object messages from environment
1567 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1571 core::list<ActiveObjectMessage>* message_list = NULL;
1572 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1573 n = buffered_messages.find(aom.id);
1576 message_list = new core::list<ActiveObjectMessage>;
1577 buffered_messages.insert(aom.id, message_list);
1581 message_list = n->getValue();
1583 message_list->push_back(aom);
1586 // Route data to every client
1587 for(core::map<u16, RemoteClient*>::Iterator
1588 i = m_clients.getIterator();
1589 i.atEnd()==false; i++)
1591 RemoteClient *client = i.getNode()->getValue();
1592 std::string reliable_data;
1593 std::string unreliable_data;
1594 // Go through all objects in message buffer
1595 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1596 j = buffered_messages.getIterator();
1597 j.atEnd()==false; j++)
1599 // If object is not known by client, skip it
1600 u16 id = j.getNode()->getKey();
1601 if(client->m_known_objects.find(id) == NULL)
1603 // Get message list of object
1604 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1605 // Go through every message
1606 for(core::list<ActiveObjectMessage>::Iterator
1607 k = list->begin(); k != list->end(); k++)
1609 // Compose the full new data with header
1610 ActiveObjectMessage aom = *k;
1611 std::string new_data;
1614 writeU16((u8*)&buf[0], aom.id);
1615 new_data.append(buf, 2);
1617 new_data += serializeString(aom.datastring);
1618 // Add data to buffer
1620 reliable_data += new_data;
1622 unreliable_data += new_data;
1626 reliable_data and unreliable_data are now ready.
1629 if(reliable_data.size() > 0)
1631 SharedBuffer<u8> reply(2 + reliable_data.size());
1632 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1633 memcpy((char*)&reply[2], reliable_data.c_str(),
1634 reliable_data.size());
1636 m_con.Send(client->peer_id, 0, reply, true);
1638 if(unreliable_data.size() > 0)
1640 SharedBuffer<u8> reply(2 + unreliable_data.size());
1641 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1642 memcpy((char*)&reply[2], unreliable_data.c_str(),
1643 unreliable_data.size());
1644 // Send as unreliable
1645 m_con.Send(client->peer_id, 0, reply, false);
1648 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1650 infostream<<"Server: Size of object message data: "
1651 <<"reliable: "<<reliable_data.size()
1652 <<", unreliable: "<<unreliable_data.size()
1657 // Clear buffered_messages
1658 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1659 i = buffered_messages.getIterator();
1660 i.atEnd()==false; i++)
1662 delete i.getNode()->getValue();
1666 } // enable_experimental
1669 Send queued-for-sending map edit events.
1672 // Don't send too many at a time
1675 // Single change sending is disabled if queue size is not small
1676 bool disable_single_change_sending = false;
1677 if(m_unsent_map_edit_queue.size() >= 4)
1678 disable_single_change_sending = true;
1680 bool got_any_events = false;
1682 // We'll log the amount of each
1685 while(m_unsent_map_edit_queue.size() != 0)
1687 got_any_events = true;
1689 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1691 // Players far away from the change are stored here.
1692 // Instead of sending the changes, MapBlocks are set not sent
1694 core::list<u16> far_players;
1696 if(event->type == MEET_ADDNODE)
1698 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1699 prof.add("MEET_ADDNODE", 1);
1700 if(disable_single_change_sending)
1701 sendAddNode(event->p, event->n, event->already_known_by_peer,
1704 sendAddNode(event->p, event->n, event->already_known_by_peer,
1707 else if(event->type == MEET_REMOVENODE)
1709 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1710 prof.add("MEET_REMOVENODE", 1);
1711 if(disable_single_change_sending)
1712 sendRemoveNode(event->p, event->already_known_by_peer,
1715 sendRemoveNode(event->p, event->already_known_by_peer,
1718 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1720 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1721 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1722 setBlockNotSent(event->p);
1724 else if(event->type == MEET_OTHER)
1726 infostream<<"Server: MEET_OTHER"<<std::endl;
1727 prof.add("MEET_OTHER", 1);
1728 for(core::map<v3s16, bool>::Iterator
1729 i = event->modified_blocks.getIterator();
1730 i.atEnd()==false; i++)
1732 v3s16 p = i.getNode()->getKey();
1738 prof.add("unknown", 1);
1739 infostream<<"WARNING: Server: Unknown MapEditEvent "
1740 <<((u32)event->type)<<std::endl;
1744 Set blocks not sent to far players
1746 if(far_players.size() > 0)
1748 // Convert list format to that wanted by SetBlocksNotSent
1749 core::map<v3s16, MapBlock*> modified_blocks2;
1750 for(core::map<v3s16, bool>::Iterator
1751 i = event->modified_blocks.getIterator();
1752 i.atEnd()==false; i++)
1754 v3s16 p = i.getNode()->getKey();
1755 modified_blocks2.insert(p,
1756 m_env->getMap().getBlockNoCreateNoEx(p));
1758 // Set blocks not sent
1759 for(core::list<u16>::Iterator
1760 i = far_players.begin();
1761 i != far_players.end(); i++)
1764 RemoteClient *client = getClient(peer_id);
1767 client->SetBlocksNotSent(modified_blocks2);
1773 /*// Don't send too many at a time
1775 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1781 infostream<<"Server: MapEditEvents:"<<std::endl;
1782 prof.print(infostream);
1788 Trigger emergethread (it somehow gets to a non-triggered but
1789 bysy state sometimes)
1792 float &counter = m_emergethread_trigger_timer;
1798 m_emergethread.trigger();
1802 // Save map, players and auth stuff
1804 float &counter = m_savemap_timer;
1806 if(counter >= g_settings->getFloat("server_map_save_interval"))
1809 JMutexAutoLock lock(m_env_mutex);
1811 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1814 if(m_authmanager.isModified())
1815 m_authmanager.save();
1818 if(m_banmanager.isModified())
1819 m_banmanager.save();
1821 // Save changed parts of map
1822 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1825 m_env->serializePlayers(m_path_world);
1827 // Save environment metadata
1828 m_env->saveMeta(m_path_world);
1833 void Server::Receive()
1835 DSTACK(__FUNCTION_NAME);
1836 SharedBuffer<u8> data;
1841 JMutexAutoLock conlock(m_con_mutex);
1842 datasize = m_con.Receive(peer_id, data);
1845 // This has to be called so that the client list gets synced
1846 // with the peer list of the connection
1847 handlePeerChanges();
1849 ProcessData(*data, datasize, peer_id);
1851 catch(con::InvalidIncomingDataException &e)
1853 infostream<<"Server::Receive(): "
1854 "InvalidIncomingDataException: what()="
1855 <<e.what()<<std::endl;
1857 catch(con::PeerNotFoundException &e)
1859 //NOTE: This is not needed anymore
1861 // The peer has been disconnected.
1862 // Find the associated player and remove it.
1864 /*JMutexAutoLock envlock(m_env_mutex);
1866 infostream<<"ServerThread: peer_id="<<peer_id
1867 <<" has apparently closed connection. "
1868 <<"Removing player."<<std::endl;
1870 m_env->removePlayer(peer_id);*/
1874 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1876 DSTACK(__FUNCTION_NAME);
1877 // Environment is locked first.
1878 JMutexAutoLock envlock(m_env_mutex);
1879 JMutexAutoLock conlock(m_con_mutex);
1881 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1884 Address address = m_con.GetPeerAddress(peer_id);
1886 // drop player if is ip is banned
1887 if(m_banmanager.isIpBanned(address.serializeString())){
1888 SendAccessDenied(m_con, peer_id,
1889 L"Your ip is banned. Banned name was "
1890 +narrow_to_wide(m_banmanager.getBanName(
1891 address.serializeString())));
1892 m_con.DeletePeer(peer_id);
1896 catch(con::PeerNotFoundException &e)
1898 infostream<<"Server::ProcessData(): Cancelling: peer "
1899 <<peer_id<<" not found"<<std::endl;
1903 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1911 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1913 if(command == TOSERVER_INIT)
1915 // [0] u16 TOSERVER_INIT
1916 // [2] u8 SER_FMT_VER_HIGHEST
1917 // [3] u8[20] player_name
1918 // [23] u8[28] password <--- can be sent without this, from old versions
1920 if(datasize < 2+1+PLAYERNAME_SIZE)
1923 infostream<<"Server: Got TOSERVER_INIT from "
1924 <<peer_id<<std::endl;
1926 // First byte after command is maximum supported
1927 // serialization version
1928 u8 client_max = data[2];
1929 u8 our_max = SER_FMT_VER_HIGHEST;
1930 // Use the highest version supported by both
1931 u8 deployed = core::min_(client_max, our_max);
1932 // If it's lower than the lowest supported, give up.
1933 if(deployed < SER_FMT_VER_LOWEST)
1934 deployed = SER_FMT_VER_INVALID;
1936 //peer->serialization_version = deployed;
1937 getClient(peer_id)->pending_serialization_version = deployed;
1939 if(deployed == SER_FMT_VER_INVALID)
1941 infostream<<"Server: Cannot negotiate "
1942 "serialization version with peer "
1943 <<peer_id<<std::endl;
1944 SendAccessDenied(m_con, peer_id, std::wstring(
1945 L"Your client's version is not supported.\n"
1946 L"Server version is ")
1947 + narrow_to_wide(VERSION_STRING) + L"."
1953 Read and check network protocol version
1956 u16 net_proto_version = 0;
1957 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1959 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1962 getClient(peer_id)->net_proto_version = net_proto_version;
1964 if(net_proto_version == 0)
1966 SendAccessDenied(m_con, peer_id, std::wstring(
1967 L"Your client's version is not supported.\n"
1968 L"Server version is ")
1969 + narrow_to_wide(VERSION_STRING) + L"."
1974 if(g_settings->getBool("strict_protocol_version_checking"))
1976 if(net_proto_version != PROTOCOL_VERSION)
1978 SendAccessDenied(m_con, peer_id, std::wstring(
1979 L"Your client's version is not supported.\n"
1980 L"Server version is ")
1981 + narrow_to_wide(VERSION_STRING) + L",\n"
1982 + L"server's PROTOCOL_VERSION is "
1983 + narrow_to_wide(itos(PROTOCOL_VERSION))
1984 + L", client's PROTOCOL_VERSION is "
1985 + narrow_to_wide(itos(net_proto_version))
1996 char playername[PLAYERNAME_SIZE];
1997 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1999 playername[i] = data[3+i];
2001 playername[PLAYERNAME_SIZE-1] = 0;
2003 if(playername[0]=='\0')
2005 infostream<<"Server: Player has empty name"<<std::endl;
2006 SendAccessDenied(m_con, peer_id,
2011 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2013 infostream<<"Server: Player has invalid name"<<std::endl;
2014 SendAccessDenied(m_con, peer_id,
2015 L"Name contains unallowed characters");
2020 char password[PASSWORD_SIZE];
2021 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2023 // old version - assume blank password
2028 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2030 password[i] = data[23+i];
2032 password[PASSWORD_SIZE-1] = 0;
2035 // Add player to auth manager
2036 if(m_authmanager.exists(playername) == false)
2038 std::wstring default_password =
2039 narrow_to_wide(g_settings->get("default_password"));
2040 std::string translated_default_password =
2041 translatePassword(playername, default_password);
2043 // If default_password is empty, allow any initial password
2044 if (default_password.length() == 0)
2045 translated_default_password = password;
2047 infostream<<"Server: adding player "<<playername
2048 <<" to auth manager"<<std::endl;
2049 m_authmanager.add(playername);
2050 m_authmanager.setPassword(playername, translated_default_password);
2051 m_authmanager.setPrivs(playername,
2052 stringToPrivs(g_settings->get("default_privs")));
2053 m_authmanager.save();
2056 std::string checkpwd = m_authmanager.getPassword(playername);
2058 /*infostream<<"Server: Client gave password '"<<password
2059 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2061 if(password != checkpwd)
2063 infostream<<"Server: peer_id="<<peer_id
2064 <<": supplied invalid password for "
2065 <<playername<<std::endl;
2066 SendAccessDenied(m_con, peer_id, L"Invalid password");
2070 // Enforce user limit.
2071 // Don't enforce for users that have some admin right
2072 if(m_clients.size() >= g_settings->getU16("max_users") &&
2073 (m_authmanager.getPrivs(playername)
2074 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2075 playername != g_settings->get("name"))
2077 SendAccessDenied(m_con, peer_id, L"Too many users.");
2082 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2084 // If failed, cancel
2087 infostream<<"Server: peer_id="<<peer_id
2088 <<": failed to emerge player"<<std::endl;
2093 Answer with a TOCLIENT_INIT
2096 SharedBuffer<u8> reply(2+1+6+8);
2097 writeU16(&reply[0], TOCLIENT_INIT);
2098 writeU8(&reply[2], deployed);
2099 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2100 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2103 m_con.Send(peer_id, 0, reply, true);
2107 Send complete position information
2109 SendMovePlayer(player);
2114 if(command == TOSERVER_INIT2)
2116 infostream<<"Server: Got TOSERVER_INIT2 from "
2117 <<peer_id<<std::endl;
2120 getClient(peer_id)->serialization_version
2121 = getClient(peer_id)->pending_serialization_version;
2124 Send some initialization data
2127 // Send item definitions
2128 SendItemDef(m_con, peer_id, m_itemdef);
2130 // Send node definitions
2131 SendNodeDef(m_con, peer_id, m_nodedef);
2133 // Send texture announcement
2134 SendTextureAnnouncement(peer_id);
2136 // Send player info to all players
2137 //SendPlayerInfos();
2139 // Send inventory to player
2140 UpdateCrafting(peer_id);
2141 SendInventory(peer_id);
2143 // Send player items to all players
2146 Player *player = m_env->getPlayer(peer_id);
2149 SendPlayerHP(player);
2151 // Show death screen if necessary
2153 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2157 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2158 m_env->getTimeOfDay());
2159 m_con.Send(peer_id, 0, data, true);
2162 // Send information about server to player in chat
2163 SendChatMessage(peer_id, getStatusString());
2165 // Send information about joining in chat
2167 std::wstring name = L"unknown";
2168 Player *player = m_env->getPlayer(peer_id);
2170 name = narrow_to_wide(player->getName());
2172 std::wstring message;
2175 message += L" joined game";
2176 BroadcastChatMessage(message);
2179 // Warnings about protocol version can be issued here
2180 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2182 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2189 std::ostringstream os(std::ios_base::binary);
2190 for(core::map<u16, RemoteClient*>::Iterator
2191 i = m_clients.getIterator();
2192 i.atEnd() == false; i++)
2194 RemoteClient *client = i.getNode()->getValue();
2195 assert(client->peer_id == i.getNode()->getKey());
2196 if(client->serialization_version == SER_FMT_VER_INVALID)
2199 Player *player = m_env->getPlayer(client->peer_id);
2202 // Get name of player
2203 os<<player->getName()<<" ";
2206 actionstream<<player->getName()<<" joins game. List of players: "
2207 <<os.str()<<std::endl;
2213 if(peer_ser_ver == SER_FMT_VER_INVALID)
2215 infostream<<"Server::ProcessData(): Cancelling: Peer"
2216 " serialization format invalid or not initialized."
2217 " Skipping incoming command="<<command<<std::endl;
2221 Player *player = m_env->getPlayer(peer_id);
2222 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2225 infostream<<"Server::ProcessData(): Cancelling: "
2226 "No player for peer_id="<<peer_id
2230 if(command == TOSERVER_PLAYERPOS)
2232 if(datasize < 2+12+12+4+4)
2236 v3s32 ps = readV3S32(&data[start+2]);
2237 v3s32 ss = readV3S32(&data[start+2+12]);
2238 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2239 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2240 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2241 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2242 pitch = wrapDegrees(pitch);
2243 yaw = wrapDegrees(yaw);
2245 player->setPosition(position);
2246 player->setSpeed(speed);
2247 player->setPitch(pitch);
2248 player->setYaw(yaw);
2250 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2251 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2252 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2254 else if(command == TOSERVER_GOTBLOCKS)
2267 u16 count = data[2];
2268 for(u16 i=0; i<count; i++)
2270 if((s16)datasize < 2+1+(i+1)*6)
2271 throw con::InvalidIncomingDataException
2272 ("GOTBLOCKS length is too short");
2273 v3s16 p = readV3S16(&data[2+1+i*6]);
2274 /*infostream<<"Server: GOTBLOCKS ("
2275 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2276 RemoteClient *client = getClient(peer_id);
2277 client->GotBlock(p);
2280 else if(command == TOSERVER_DELETEDBLOCKS)
2293 u16 count = data[2];
2294 for(u16 i=0; i<count; i++)
2296 if((s16)datasize < 2+1+(i+1)*6)
2297 throw con::InvalidIncomingDataException
2298 ("DELETEDBLOCKS length is too short");
2299 v3s16 p = readV3S16(&data[2+1+i*6]);
2300 /*infostream<<"Server: DELETEDBLOCKS ("
2301 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2302 RemoteClient *client = getClient(peer_id);
2303 client->SetBlockNotSent(p);
2306 else if(command == TOSERVER_CLICK_OBJECT)
2308 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2311 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2313 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2316 else if(command == TOSERVER_GROUND_ACTION)
2318 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2322 else if(command == TOSERVER_RELEASE)
2324 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2327 else if(command == TOSERVER_SIGNTEXT)
2329 infostream<<"Server: SIGNTEXT not supported anymore"
2333 else if(command == TOSERVER_SIGNNODETEXT)
2335 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2343 std::string datastring((char*)&data[2], datasize-2);
2344 std::istringstream is(datastring, std::ios_base::binary);
2347 is.read((char*)buf, 6);
2348 v3s16 p = readV3S16(buf);
2349 is.read((char*)buf, 2);
2350 u16 textlen = readU16(buf);
2352 for(u16 i=0; i<textlen; i++)
2354 is.read((char*)buf, 1);
2355 text += (char)buf[0];
2358 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2362 meta->setText(text);
2364 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2365 <<" at "<<PP(p)<<std::endl;
2367 v3s16 blockpos = getNodeBlockPos(p);
2368 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2371 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2375 setBlockNotSent(blockpos);
2377 else if(command == TOSERVER_INVENTORY_ACTION)
2379 // Strip command and create a stream
2380 std::string datastring((char*)&data[2], datasize-2);
2381 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2382 std::istringstream is(datastring, std::ios_base::binary);
2384 InventoryAction *a = InventoryAction::deSerialize(is);
2387 infostream<<"TOSERVER_INVENTORY_ACTION: "
2388 <<"InventoryAction::deSerialize() returned NULL"
2394 Note: Always set inventory not sent, to repair cases
2395 where the client made a bad prediction.
2399 Handle restrictions and special cases of the move action
2401 if(a->getType() == IACTION_MOVE)
2403 IMoveAction *ma = (IMoveAction*)a;
2405 ma->from_inv.applyCurrentPlayer(player->getName());
2406 ma->to_inv.applyCurrentPlayer(player->getName());
2408 setInventoryModified(ma->from_inv);
2409 setInventoryModified(ma->to_inv);
2411 bool from_inv_is_current_player =
2412 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2413 (ma->from_inv.name == player->getName());
2415 bool to_inv_is_current_player =
2416 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2417 (ma->to_inv.name == player->getName());
2420 Disable moving items out of craftpreview
2422 if(ma->from_list == "craftpreview")
2424 infostream<<"Ignoring IMoveAction from "
2425 <<(ma->from_inv.dump())<<":"<<ma->from_list
2426 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2427 <<" because src is "<<ma->from_list<<std::endl;
2433 Disable moving items into craftresult and craftpreview
2435 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2437 infostream<<"Ignoring IMoveAction from "
2438 <<(ma->from_inv.dump())<<":"<<ma->from_list
2439 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2440 <<" because dst is "<<ma->to_list<<std::endl;
2445 // Disallow moving items in elsewhere than player's inventory
2446 // if not allowed to interact
2447 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2448 && (!from_inv_is_current_player
2449 || !to_inv_is_current_player))
2451 infostream<<"Cannot move outside of player's inventory: "
2452 <<"No interact privilege"<<std::endl;
2457 // If player is not an admin, check for ownership of src and dst
2458 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2460 std::string owner_from = getInventoryOwner(ma->from_inv);
2461 if(owner_from != "" && owner_from != player->getName())
2463 infostream<<"WARNING: "<<player->getName()
2464 <<" tried to access an inventory that"
2465 <<" belongs to "<<owner_from<<std::endl;
2470 std::string owner_to = getInventoryOwner(ma->to_inv);
2471 if(owner_to != "" && owner_to != player->getName())
2473 infostream<<"WARNING: "<<player->getName()
2474 <<" tried to access an inventory that"
2475 <<" belongs to "<<owner_to<<std::endl;
2482 Handle restrictions and special cases of the drop action
2484 else if(a->getType() == IACTION_DROP)
2486 IDropAction *da = (IDropAction*)a;
2488 da->from_inv.applyCurrentPlayer(player->getName());
2490 setInventoryModified(da->from_inv);
2492 // Disallow dropping items if not allowed to interact
2493 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2498 // If player is not an admin, check for ownership
2499 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2501 std::string owner_from = getInventoryOwner(da->from_inv);
2502 if(owner_from != "" && owner_from != player->getName())
2504 infostream<<"WARNING: "<<player->getName()
2505 <<" tried to access an inventory that"
2506 <<" belongs to "<<owner_from<<std::endl;
2513 Handle restrictions and special cases of the craft action
2515 else if(a->getType() == IACTION_CRAFT)
2517 ICraftAction *ca = (ICraftAction*)a;
2519 ca->craft_inv.applyCurrentPlayer(player->getName());
2521 setInventoryModified(ca->craft_inv);
2523 //bool craft_inv_is_current_player =
2524 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2525 // (ca->craft_inv.name == player->getName());
2527 // Disallow crafting if not allowed to interact
2528 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2530 infostream<<"Cannot craft: "
2531 <<"No interact privilege"<<std::endl;
2536 // If player is not an admin, check for ownership of inventory
2537 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2539 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2540 if(owner_craft != "" && owner_craft != player->getName())
2542 infostream<<"WARNING: "<<player->getName()
2543 <<" tried to access an inventory that"
2544 <<" belongs to "<<owner_craft<<std::endl;
2552 a->apply(this, srp, this);
2556 else if(command == TOSERVER_CHAT_MESSAGE)
2564 std::string datastring((char*)&data[2], datasize-2);
2565 std::istringstream is(datastring, std::ios_base::binary);
2568 is.read((char*)buf, 2);
2569 u16 len = readU16(buf);
2571 std::wstring message;
2572 for(u16 i=0; i<len; i++)
2574 is.read((char*)buf, 2);
2575 message += (wchar_t)readU16(buf);
2578 // Get player name of this client
2579 std::wstring name = narrow_to_wide(player->getName());
2582 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2583 wide_to_narrow(message));
2584 // If script ate the message, don't proceed
2588 // Line to send to players
2590 // Whether to send to the player that sent the line
2591 bool send_to_sender = false;
2592 // Whether to send to other players
2593 bool send_to_others = false;
2595 // Local player gets all privileges regardless of
2596 // what's set on their account.
2597 u64 privs = getPlayerPrivs(player);
2600 if(message[0] == L'/')
2602 size_t strip_size = 1;
2603 if (message[1] == L'#') // support old-style commans
2605 message = message.substr(strip_size);
2607 WStrfnd f1(message);
2608 f1.next(L" "); // Skip over /#whatever
2609 std::wstring paramstring = f1.next(L"");
2611 ServerCommandContext *ctx = new ServerCommandContext(
2612 str_split(message, L' '),
2619 std::wstring reply(processServerCommand(ctx));
2620 send_to_sender = ctx->flags & SEND_TO_SENDER;
2621 send_to_others = ctx->flags & SEND_TO_OTHERS;
2623 if (ctx->flags & SEND_NO_PREFIX)
2626 line += L"Server: " + reply;
2633 if(privs & PRIV_SHOUT)
2639 send_to_others = true;
2643 line += L"Server: You are not allowed to shout";
2644 send_to_sender = true;
2651 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2654 Send the message to clients
2656 for(core::map<u16, RemoteClient*>::Iterator
2657 i = m_clients.getIterator();
2658 i.atEnd() == false; i++)
2660 // Get client and check that it is valid
2661 RemoteClient *client = i.getNode()->getValue();
2662 assert(client->peer_id == i.getNode()->getKey());
2663 if(client->serialization_version == SER_FMT_VER_INVALID)
2667 bool sender_selected = (peer_id == client->peer_id);
2668 if(sender_selected == true && send_to_sender == false)
2670 if(sender_selected == false && send_to_others == false)
2673 SendChatMessage(client->peer_id, line);
2677 else if(command == TOSERVER_DAMAGE)
2679 std::string datastring((char*)&data[2], datasize-2);
2680 std::istringstream is(datastring, std::ios_base::binary);
2681 u8 damage = readU8(is);
2683 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2685 if(g_settings->getBool("enable_damage"))
2687 actionstream<<player->getName()<<" damaged by "
2688 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2691 srp->setHP(srp->getHP() - damage);
2693 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2696 if(srp->m_hp_not_sent)
2697 SendPlayerHP(player);
2701 // Force send (to correct the client's predicted HP)
2702 SendPlayerHP(player);
2705 else if(command == TOSERVER_PASSWORD)
2708 [0] u16 TOSERVER_PASSWORD
2709 [2] u8[28] old password
2710 [30] u8[28] new password
2713 if(datasize != 2+PASSWORD_SIZE*2)
2715 /*char password[PASSWORD_SIZE];
2716 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2717 password[i] = data[2+i];
2718 password[PASSWORD_SIZE-1] = 0;*/
2720 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2728 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2730 char c = data[2+PASSWORD_SIZE+i];
2736 infostream<<"Server: Client requests a password change from "
2737 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2739 std::string playername = player->getName();
2741 if(m_authmanager.exists(playername) == false)
2743 infostream<<"Server: playername not found in authmanager"<<std::endl;
2744 // Wrong old password supplied!!
2745 SendChatMessage(peer_id, L"playername not found in authmanager");
2749 std::string checkpwd = m_authmanager.getPassword(playername);
2751 if(oldpwd != checkpwd)
2753 infostream<<"Server: invalid old password"<<std::endl;
2754 // Wrong old password supplied!!
2755 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2759 actionstream<<player->getName()<<" changes password"<<std::endl;
2761 m_authmanager.setPassword(playername, newpwd);
2763 infostream<<"Server: password change successful for "<<playername
2765 SendChatMessage(peer_id, L"Password change successful");
2767 else if(command == TOSERVER_PLAYERITEM)
2772 u16 item = readU16(&data[2]);
2773 srp->setWieldIndex(item);
2774 SendWieldedItem(srp);
2776 else if(command == TOSERVER_RESPAWN)
2781 RespawnPlayer(player);
2783 actionstream<<player->getName()<<" respawns at "
2784 <<PP(player->getPosition()/BS)<<std::endl;
2786 // ActiveObject is added to environment in AsyncRunStep after
2787 // the previous addition has been succesfully removed
2789 else if(command == TOSERVER_REQUEST_TEXTURES) {
2790 std::string datastring((char*)&data[2], datasize-2);
2791 std::istringstream is(datastring, std::ios_base::binary);
2793 infostream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2795 core::list<TextureRequest> tosend;
2797 u16 numtextures = readU16(is);
2799 for(int i = 0; i < numtextures; i++) {
2801 std::string name = deSerializeString(is);
2803 tosend.push_back(TextureRequest(name));
2804 infostream<<"TOSERVER_REQUEST_TEXTURES: requested texture " << name <<std::endl;
2807 SendTexturesRequested(peer_id, tosend);
2809 // Now the client should know about everything
2810 // (definitions and textures)
2811 getClient(peer_id)->definitions_sent = true;
2813 else if(command == TOSERVER_INTERACT)
2815 std::string datastring((char*)&data[2], datasize-2);
2816 std::istringstream is(datastring, std::ios_base::binary);
2822 [5] u32 length of the next item
2823 [9] serialized PointedThing
2825 0: start digging (from undersurface) or use
2826 1: stop digging (all parameters ignored)
2827 2: digging completed
2828 3: place block or item (to abovesurface)
2831 u8 action = readU8(is);
2832 u16 item_i = readU16(is);
2833 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2834 PointedThing pointed;
2835 pointed.deSerialize(tmp_is);
2837 infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<<item_i<<", pointed="<<pointed.dump()<<std::endl;
2841 infostream<<"TOSERVER_INTERACT: "<<srp->getName()
2842 <<" tried to interact, but is dead!"<<std::endl;
2846 v3f player_pos = srp->m_last_good_position;
2848 // Update wielded item
2849 if(srp->getWieldIndex() != item_i)
2851 srp->setWieldIndex(item_i);
2852 SendWieldedItem(srp);
2855 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2856 v3s16 p_under = pointed.node_undersurface;
2857 v3s16 p_above = pointed.node_abovesurface;
2859 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2860 ServerActiveObject *pointed_object = NULL;
2861 if(pointed.type == POINTEDTHING_OBJECT)
2863 pointed_object = m_env->getActiveObject(pointed.object_id);
2864 if(pointed_object == NULL)
2866 infostream<<"TOSERVER_INTERACT: "
2867 "pointed object is NULL"<<std::endl;
2873 v3f pointed_pos_under = player_pos;
2874 v3f pointed_pos_above = player_pos;
2875 if(pointed.type == POINTEDTHING_NODE)
2877 pointed_pos_under = intToFloat(p_under, BS);
2878 pointed_pos_above = intToFloat(p_above, BS);
2880 else if(pointed.type == POINTEDTHING_OBJECT)
2882 pointed_pos_under = pointed_object->getBasePosition();
2883 pointed_pos_above = pointed_pos_under;
2887 Check that target is reasonably close
2888 (only when digging or placing things)
2890 if(action == 0 || action == 2 || action == 3)
2892 float d = player_pos.getDistanceFrom(pointed_pos_under);
2893 float max_d = BS * 14; // Just some large enough value
2895 actionstream<<"Player "<<player->getName()
2896 <<" tried to access "<<pointed.dump()
2898 <<"d="<<d<<", max_d="<<max_d
2899 <<". ignoring."<<std::endl;
2900 // Re-send block to revert change on client-side
2901 RemoteClient *client = getClient(peer_id);
2902 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2903 client->SetBlockNotSent(blockpos);
2910 Make sure the player is allowed to do it
2912 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2914 infostream<<"Ignoring interaction from player "<<player->getName()
2915 <<" because privileges are "<<getPlayerPrivs(player)
2921 0: start digging or punch object
2925 if(pointed.type == POINTEDTHING_NODE)
2928 NOTE: This can be used in the future to check if
2929 somebody is cheating, by checking the timing.
2931 MapNode n(CONTENT_IGNORE);
2934 n = m_env->getMap().getNode(p_under);
2936 catch(InvalidPositionException &e)
2938 infostream<<"Server: Not punching: Node not found."
2939 <<" Adding block to emerge queue."
2941 m_emerge_queue.addBlock(peer_id,
2942 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2944 if(n.getContent() != CONTENT_IGNORE)
2945 scriptapi_node_on_punch(m_lua, p_under, n, srp);
2947 else if(pointed.type == POINTEDTHING_OBJECT)
2949 // Skip if object has been removed
2950 if(pointed_object->m_removed)
2953 actionstream<<player->getName()<<" punches object "
2954 <<pointed.object_id<<std::endl;
2956 ItemStack punchitem = srp->getWieldedItem();
2957 ToolCapabilities toolcap =
2958 punchitem.getToolCapabilities(m_itemdef);
2959 v3f dir = (pointed_object->getBasePosition() -
2960 (srp->getPosition() + srp->getEyeOffset())
2962 pointed_object->punch(dir, &toolcap, srp,
2963 srp->m_time_from_last_punch);
2964 srp->m_time_from_last_punch = 0;
2972 else if(action == 1)
2977 2: Digging completed
2979 else if(action == 2)
2981 // Only complete digging of nodes
2982 if(pointed.type == POINTEDTHING_NODE)
2984 MapNode n(CONTENT_IGNORE);
2987 n = m_env->getMap().getNode(p_under);
2989 catch(InvalidPositionException &e)
2991 infostream<<"Server: Not finishing digging: Node not found."
2992 <<" Adding block to emerge queue."
2994 m_emerge_queue.addBlock(peer_id,
2995 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2997 if(n.getContent() != CONTENT_IGNORE)
2998 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3003 3: place block or right-click object
3005 else if(action == 3)
3007 ItemStack item = srp->getWieldedItem();
3009 // Reset build time counter
3010 if(pointed.type == POINTEDTHING_NODE &&
3011 item.getDefinition(m_itemdef).type == ITEM_NODE)
3012 getClient(peer_id)->m_time_from_building = 0.0;
3014 if(pointed.type == POINTEDTHING_OBJECT)
3016 // Right click object
3018 // Skip if object has been removed
3019 if(pointed_object->m_removed)
3022 actionstream<<player->getName()<<" right-clicks object "
3023 <<pointed.object_id<<std::endl;
3026 pointed_object->rightClick(srp);
3028 else if(scriptapi_item_on_place(m_lua,
3029 item, srp, pointed))
3031 // Placement was handled in lua
3033 // Apply returned ItemStack
3034 if(g_settings->getBool("creative_mode") == false)
3035 srp->setWieldedItem(item);
3043 else if(action == 4)
3045 ItemStack item = srp->getWieldedItem();
3047 actionstream<<player->getName()<<" uses "<<item.name
3048 <<", pointing at "<<pointed.dump()<<std::endl;
3050 if(scriptapi_item_on_use(m_lua,
3051 item, srp, pointed))
3053 // Apply returned ItemStack
3054 if(g_settings->getBool("creative_mode") == false)
3055 srp->setWieldedItem(item);
3061 Catch invalid actions
3065 infostream<<"WARNING: Server: Invalid action "
3066 <<action<<std::endl;
3071 infostream<<"Server::ProcessData(): Ignoring "
3072 "unknown command "<<command<<std::endl;
3076 catch(SendFailedException &e)
3078 errorstream<<"Server::ProcessData(): SendFailedException: "
3084 void Server::onMapEditEvent(MapEditEvent *event)
3086 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3087 if(m_ignore_map_edit_events)
3089 MapEditEvent *e = event->clone();
3090 m_unsent_map_edit_queue.push_back(e);
3093 Inventory* Server::getInventory(const InventoryLocation &loc)
3096 case InventoryLocation::UNDEFINED:
3099 case InventoryLocation::CURRENT_PLAYER:
3102 case InventoryLocation::PLAYER:
3104 Player *player = m_env->getPlayer(loc.name.c_str());
3107 return &player->inventory;
3110 case InventoryLocation::NODEMETA:
3112 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3115 return meta->getInventory();
3123 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3126 case InventoryLocation::UNDEFINED:
3129 case InventoryLocation::CURRENT_PLAYER:
3132 case InventoryLocation::PLAYER:
3137 case InventoryLocation::NODEMETA:
3139 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3142 return meta->getOwner();
3150 void Server::setInventoryModified(const InventoryLocation &loc)
3153 case InventoryLocation::UNDEFINED:
3156 case InventoryLocation::PLAYER:
3158 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3159 (m_env->getPlayer(loc.name.c_str()));
3162 srp->m_inventory_not_sent = true;
3165 case InventoryLocation::NODEMETA:
3167 v3s16 blockpos = getNodeBlockPos(loc.p);
3169 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3171 meta->inventoryModified();
3173 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3175 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3177 setBlockNotSent(blockpos);
3185 core::list<PlayerInfo> Server::getPlayerInfo()
3187 DSTACK(__FUNCTION_NAME);
3188 JMutexAutoLock envlock(m_env_mutex);
3189 JMutexAutoLock conlock(m_con_mutex);
3191 core::list<PlayerInfo> list;
3193 core::list<Player*> players = m_env->getPlayers();
3195 core::list<Player*>::Iterator i;
3196 for(i = players.begin();
3197 i != players.end(); i++)
3201 Player *player = *i;
3204 // Copy info from connection to info struct
3205 info.id = player->peer_id;
3206 info.address = m_con.GetPeerAddress(player->peer_id);
3207 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3209 catch(con::PeerNotFoundException &e)
3211 // Set dummy peer info
3213 info.address = Address(0,0,0,0,0);
3217 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3218 info.position = player->getPosition();
3220 list.push_back(info);
3227 void Server::peerAdded(con::Peer *peer)
3229 DSTACK(__FUNCTION_NAME);
3230 infostream<<"Server::peerAdded(): peer->id="
3231 <<peer->id<<std::endl;
3234 c.type = PEER_ADDED;
3235 c.peer_id = peer->id;
3237 m_peer_change_queue.push_back(c);
3240 void Server::deletingPeer(con::Peer *peer, bool timeout)
3242 DSTACK(__FUNCTION_NAME);
3243 infostream<<"Server::deletingPeer(): peer->id="
3244 <<peer->id<<", timeout="<<timeout<<std::endl;
3247 c.type = PEER_REMOVED;
3248 c.peer_id = peer->id;
3249 c.timeout = timeout;
3250 m_peer_change_queue.push_back(c);
3257 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3259 DSTACK(__FUNCTION_NAME);
3260 std::ostringstream os(std::ios_base::binary);
3262 writeU16(os, TOCLIENT_HP);
3266 std::string s = os.str();
3267 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3269 con.Send(peer_id, 0, data, true);
3272 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3273 const std::wstring &reason)
3275 DSTACK(__FUNCTION_NAME);
3276 std::ostringstream os(std::ios_base::binary);
3278 writeU16(os, TOCLIENT_ACCESS_DENIED);
3279 os<<serializeWideString(reason);
3282 std::string s = os.str();
3283 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3285 con.Send(peer_id, 0, data, true);
3288 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3289 bool set_camera_point_target, v3f camera_point_target)
3291 DSTACK(__FUNCTION_NAME);
3292 std::ostringstream os(std::ios_base::binary);
3294 writeU16(os, TOCLIENT_DEATHSCREEN);
3295 writeU8(os, set_camera_point_target);
3296 writeV3F1000(os, camera_point_target);
3299 std::string s = os.str();
3300 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3302 con.Send(peer_id, 0, data, true);
3305 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3306 IItemDefManager *itemdef)
3308 DSTACK(__FUNCTION_NAME);
3309 std::ostringstream os(std::ios_base::binary);
3313 u32 length of the next item
3314 zlib-compressed serialized ItemDefManager
3316 writeU16(os, TOCLIENT_ITEMDEF);
3317 std::ostringstream tmp_os(std::ios::binary);
3318 itemdef->serialize(tmp_os);
3319 std::ostringstream tmp_os2(std::ios::binary);
3320 compressZlib(tmp_os.str(), tmp_os2);
3321 os<<serializeLongString(tmp_os2.str());
3324 std::string s = os.str();
3325 infostream<<"Server::SendItemDef(): Sending item definitions: size="
3326 <<s.size()<<std::endl;
3327 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3329 con.Send(peer_id, 0, data, true);
3332 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3333 INodeDefManager *nodedef)
3335 DSTACK(__FUNCTION_NAME);
3336 std::ostringstream os(std::ios_base::binary);
3340 u32 length of the next item
3341 zlib-compressed serialized NodeDefManager
3343 writeU16(os, TOCLIENT_NODEDEF);
3344 std::ostringstream tmp_os(std::ios::binary);
3345 nodedef->serialize(tmp_os);
3346 std::ostringstream tmp_os2(std::ios::binary);
3347 compressZlib(tmp_os.str(), tmp_os2);
3348 os<<serializeLongString(tmp_os2.str());
3351 std::string s = os.str();
3352 infostream<<"Server::SendNodeDef(): Sending node definitions: size="
3353 <<s.size()<<std::endl;
3354 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3356 con.Send(peer_id, 0, data, true);
3360 Non-static send methods
3363 void Server::SendInventory(u16 peer_id)
3365 DSTACK(__FUNCTION_NAME);
3367 ServerRemotePlayer* player =
3368 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3371 player->m_inventory_not_sent = false;
3377 std::ostringstream os;
3378 //os.imbue(std::locale("C"));
3380 player->inventory.serialize(os);
3382 std::string s = os.str();
3384 SharedBuffer<u8> data(s.size()+2);
3385 writeU16(&data[0], TOCLIENT_INVENTORY);
3386 memcpy(&data[2], s.c_str(), s.size());
3389 m_con.Send(peer_id, 0, data, true);
3392 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3394 DSTACK(__FUNCTION_NAME);
3398 std::ostringstream os(std::ios_base::binary);
3400 writeU16(os, TOCLIENT_PLAYERITEM);
3402 writeU16(os, srp->peer_id);
3403 os<<serializeString(srp->getWieldedItem().getItemString());
3406 std::string s = os.str();
3407 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3409 m_con.SendToAll(0, data, true);
3412 void Server::SendPlayerItems()
3414 DSTACK(__FUNCTION_NAME);
3416 std::ostringstream os(std::ios_base::binary);
3417 core::list<Player *> players = m_env->getPlayers(true);
3419 writeU16(os, TOCLIENT_PLAYERITEM);
3420 writeU16(os, players.size());
3421 core::list<Player *>::Iterator i;
3422 for(i = players.begin(); i != players.end(); ++i)
3425 ServerRemotePlayer *srp =
3426 static_cast<ServerRemotePlayer*>(p);
3427 writeU16(os, p->peer_id);
3428 os<<serializeString(srp->getWieldedItem().getItemString());
3432 std::string s = os.str();
3433 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3435 m_con.SendToAll(0, data, true);
3438 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3440 DSTACK(__FUNCTION_NAME);
3442 std::ostringstream os(std::ios_base::binary);
3446 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3447 os.write((char*)buf, 2);
3450 writeU16(buf, message.size());
3451 os.write((char*)buf, 2);
3454 for(u32 i=0; i<message.size(); i++)
3458 os.write((char*)buf, 2);
3462 std::string s = os.str();
3463 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3465 m_con.Send(peer_id, 0, data, true);
3468 void Server::BroadcastChatMessage(const std::wstring &message)
3470 for(core::map<u16, RemoteClient*>::Iterator
3471 i = m_clients.getIterator();
3472 i.atEnd() == false; i++)
3474 // Get client and check that it is valid
3475 RemoteClient *client = i.getNode()->getValue();
3476 assert(client->peer_id == i.getNode()->getKey());
3477 if(client->serialization_version == SER_FMT_VER_INVALID)
3480 SendChatMessage(client->peer_id, message);
3484 void Server::SendPlayerHP(Player *player)
3486 SendHP(m_con, player->peer_id, player->hp);
3487 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3490 void Server::SendMovePlayer(Player *player)
3492 DSTACK(__FUNCTION_NAME);
3493 std::ostringstream os(std::ios_base::binary);
3495 writeU16(os, TOCLIENT_MOVE_PLAYER);
3496 writeV3F1000(os, player->getPosition());
3497 writeF1000(os, player->getPitch());
3498 writeF1000(os, player->getYaw());
3501 v3f pos = player->getPosition();
3502 f32 pitch = player->getPitch();
3503 f32 yaw = player->getYaw();
3504 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
3505 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3512 std::string s = os.str();
3513 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3515 m_con.Send(player->peer_id, 0, data, true);
3518 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3519 core::list<u16> *far_players, float far_d_nodes)
3521 float maxd = far_d_nodes*BS;
3522 v3f p_f = intToFloat(p, BS);
3526 SharedBuffer<u8> reply(replysize);
3527 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3528 writeS16(&reply[2], p.X);
3529 writeS16(&reply[4], p.Y);
3530 writeS16(&reply[6], p.Z);
3532 for(core::map<u16, RemoteClient*>::Iterator
3533 i = m_clients.getIterator();
3534 i.atEnd() == false; i++)
3536 // Get client and check that it is valid
3537 RemoteClient *client = i.getNode()->getValue();
3538 assert(client->peer_id == i.getNode()->getKey());
3539 if(client->serialization_version == SER_FMT_VER_INVALID)
3542 // Don't send if it's the same one
3543 if(client->peer_id == ignore_id)
3549 Player *player = m_env->getPlayer(client->peer_id);
3552 // If player is far away, only set modified blocks not sent
3553 v3f player_pos = player->getPosition();
3554 if(player_pos.getDistanceFrom(p_f) > maxd)
3556 far_players->push_back(client->peer_id);
3563 m_con.Send(client->peer_id, 0, reply, true);
3567 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3568 core::list<u16> *far_players, float far_d_nodes)
3570 float maxd = far_d_nodes*BS;
3571 v3f p_f = intToFloat(p, BS);
3573 for(core::map<u16, RemoteClient*>::Iterator
3574 i = m_clients.getIterator();
3575 i.atEnd() == false; i++)
3577 // Get client and check that it is valid
3578 RemoteClient *client = i.getNode()->getValue();
3579 assert(client->peer_id == i.getNode()->getKey());
3580 if(client->serialization_version == SER_FMT_VER_INVALID)
3583 // Don't send if it's the same one
3584 if(client->peer_id == ignore_id)
3590 Player *player = m_env->getPlayer(client->peer_id);
3593 // If player is far away, only set modified blocks not sent
3594 v3f player_pos = player->getPosition();
3595 if(player_pos.getDistanceFrom(p_f) > maxd)
3597 far_players->push_back(client->peer_id);
3604 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3605 SharedBuffer<u8> reply(replysize);
3606 writeU16(&reply[0], TOCLIENT_ADDNODE);
3607 writeS16(&reply[2], p.X);
3608 writeS16(&reply[4], p.Y);
3609 writeS16(&reply[6], p.Z);
3610 n.serialize(&reply[8], client->serialization_version);
3613 m_con.Send(client->peer_id, 0, reply, true);
3617 void Server::setBlockNotSent(v3s16 p)
3619 for(core::map<u16, RemoteClient*>::Iterator
3620 i = m_clients.getIterator();
3621 i.atEnd()==false; i++)
3623 RemoteClient *client = i.getNode()->getValue();
3624 client->SetBlockNotSent(p);
3628 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3630 DSTACK(__FUNCTION_NAME);
3632 v3s16 p = block->getPos();
3636 bool completely_air = true;
3637 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3638 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3639 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3641 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3643 completely_air = false;
3644 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3649 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3651 infostream<<"[completely air] ";
3652 infostream<<std::endl;
3656 Create a packet with the block in the right format
3659 std::ostringstream os(std::ios_base::binary);
3660 block->serialize(os, ver, false);
3661 std::string s = os.str();
3662 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3664 u32 replysize = 8 + blockdata.getSize();
3665 SharedBuffer<u8> reply(replysize);
3666 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3667 writeS16(&reply[2], p.X);
3668 writeS16(&reply[4], p.Y);
3669 writeS16(&reply[6], p.Z);
3670 memcpy(&reply[8], *blockdata, blockdata.getSize());
3672 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3673 <<": \tpacket size: "<<replysize<<std::endl;*/
3678 m_con.Send(peer_id, 1, reply, true);
3681 void Server::SendBlocks(float dtime)
3683 DSTACK(__FUNCTION_NAME);
3685 JMutexAutoLock envlock(m_env_mutex);
3686 JMutexAutoLock conlock(m_con_mutex);
3688 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3690 core::array<PrioritySortedBlockTransfer> queue;
3692 s32 total_sending = 0;
3695 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3697 for(core::map<u16, RemoteClient*>::Iterator
3698 i = m_clients.getIterator();
3699 i.atEnd() == false; i++)
3701 RemoteClient *client = i.getNode()->getValue();
3702 assert(client->peer_id == i.getNode()->getKey());
3704 // If definitions and textures have not been sent, don't
3705 // send MapBlocks either
3706 if(!client->definitions_sent)
3709 total_sending += client->SendingCount();
3711 if(client->serialization_version == SER_FMT_VER_INVALID)
3714 client->GetNextBlocks(this, dtime, queue);
3719 // Lowest priority number comes first.
3720 // Lowest is most important.
3723 for(u32 i=0; i<queue.size(); i++)
3725 //TODO: Calculate limit dynamically
3726 if(total_sending >= g_settings->getS32
3727 ("max_simultaneous_block_sends_server_total"))
3730 PrioritySortedBlockTransfer q = queue[i];
3732 MapBlock *block = NULL;
3735 block = m_env->getMap().getBlockNoCreate(q.pos);
3737 catch(InvalidPositionException &e)
3742 RemoteClient *client = getClient(q.peer_id);
3744 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3746 client->SentBlock(q.pos);
3752 void Server::PrepareTextures() {
3753 DSTACK(__FUNCTION_NAME);
3755 infostream<<"Server::PrepareTextures(): Calculate sha1 sums of textures"<<std::endl;
3757 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3758 i != m_mods.end(); i++){
3759 const ModSpec &mod = *i;
3760 std::string texturepath = mod.path + DIR_DELIM + "textures";
3761 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3762 for(u32 j=0; j<dirlist.size(); j++){
3763 if(dirlist[j].dir) // Ignode dirs
3765 std::string tname = dirlist[j].name;
3766 // if name contains illegal characters, ignore the texture
3767 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3768 errorstream<<"Server: ignoring illegal texture name: \""
3769 <<tname<<"\""<<std::endl;
3772 std::string tpath = texturepath + DIR_DELIM + tname;
3774 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3775 if(fis.good() == false){
3776 errorstream<<"Server::PrepareTextures(): Could not open \""
3777 <<tname<<"\" for reading"<<std::endl;
3780 std::ostringstream tmp_os(std::ios_base::binary);
3784 fis.read(buf, 1024);
3785 std::streamsize len = fis.gcount();
3786 tmp_os.write(buf, len);
3795 errorstream<<"Server::PrepareTextures(): Failed to read \""
3796 <<tname<<"\""<<std::endl;
3799 if(tmp_os.str().length() == 0){
3800 errorstream<<"Server::PrepareTextures(): Empty file \""
3801 <<tpath<<"\""<<std::endl;
3806 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3808 unsigned char *digest = sha1.getDigest();
3809 std::string digest_string = base64_encode(digest, 20);
3814 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3815 infostream<<"Server::PrepareTextures(): added sha1 for "<< tname <<std::endl;
3820 struct SendableTextureAnnouncement
3823 std::string sha1_digest;
3825 SendableTextureAnnouncement(const std::string name_="",
3826 const std::string sha1_digest_=""):
3828 sha1_digest(sha1_digest_)
3833 void Server::SendTextureAnnouncement(u16 peer_id){
3834 DSTACK(__FUNCTION_NAME);
3836 infostream<<"Server::SendTextureAnnouncement()"<<std::endl;
3838 core::list<SendableTextureAnnouncement> texture_announcements;
3840 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3843 texture_announcements.push_back(
3844 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3847 //send announcements
3851 u32 number of textures
3855 u16 length of digest string
3859 std::ostringstream os(std::ios_base::binary);
3861 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3862 writeU16(os, texture_announcements.size());
3864 for(core::list<SendableTextureAnnouncement>::Iterator
3865 j = texture_announcements.begin();
3866 j != texture_announcements.end(); j++){
3867 os<<serializeString(j->name);
3868 os<<serializeString(j->sha1_digest);
3872 std::string s = os.str();
3873 infostream<<"Server::SendTextureAnnouncement(): Send to client"<<std::endl;
3874 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3877 m_con.Send(peer_id, 0, data, true);
3881 struct SendableTexture
3887 SendableTexture(const std::string &name_="", const std::string path_="",
3888 const std::string &data_=""):
3895 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3896 DSTACK(__FUNCTION_NAME);
3898 infostream<<"Server::SendTexturesRequested(): Sending textures to client"<<std::endl;
3902 // Put 5kB in one bunch (this is not accurate)
3903 u32 bytes_per_bunch = 5000;
3905 core::array< core::list<SendableTexture> > texture_bunches;
3906 texture_bunches.push_back(core::list<SendableTexture>());
3908 u32 texture_size_bunch_total = 0;
3910 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3911 if(m_Textures.find(i->name) == m_Textures.end()){
3912 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3913 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3917 //TODO get path + name
3918 std::string tpath = m_Textures[(*i).name].path;
3921 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3922 if(fis.good() == false){
3923 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3924 <<tpath<<"\" for reading"<<std::endl;
3927 std::ostringstream tmp_os(std::ios_base::binary);
3931 fis.read(buf, 1024);
3932 std::streamsize len = fis.gcount();
3933 tmp_os.write(buf, len);
3934 texture_size_bunch_total += len;
3943 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
3944 <<(*i).name<<"\""<<std::endl;
3947 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
3948 <<tname<<"\""<<std::endl;*/
3950 texture_bunches[texture_bunches.size()-1].push_back(
3951 SendableTexture((*i).name, tpath, tmp_os.str()));
3953 // Start next bunch if got enough data
3954 if(texture_size_bunch_total >= bytes_per_bunch){
3955 texture_bunches.push_back(core::list<SendableTexture>());
3956 texture_size_bunch_total = 0;
3961 /* Create and send packets */
3963 u32 num_bunches = texture_bunches.size();
3964 for(u32 i=0; i<num_bunches; i++)
3968 u16 total number of texture bunches
3969 u16 index of this bunch
3970 u32 number of textures in this bunch
3978 std::ostringstream os(std::ios_base::binary);
3980 writeU16(os, TOCLIENT_TEXTURES);
3981 writeU16(os, num_bunches);
3983 writeU32(os, texture_bunches[i].size());
3985 for(core::list<SendableTexture>::Iterator
3986 j = texture_bunches[i].begin();
3987 j != texture_bunches[i].end(); j++){
3988 os<<serializeString(j->name);
3989 os<<serializeLongString(j->data);
3993 std::string s = os.str();
3994 infostream<<"Server::SendTexturesRequested(): bunch "<<i<<"/"<<num_bunches
3995 <<" textures="<<texture_bunches[i].size()
3996 <<" size=" <<s.size()<<std::endl;
3997 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3999 m_con.Send(peer_id, 0, data, true);
4009 void Server::DiePlayer(Player *player)
4011 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4013 infostream<<"Server::DiePlayer(): Player "
4014 <<player->getName()<<" dies"<<std::endl;
4018 // Trigger scripted stuff
4019 scriptapi_on_dieplayer(m_lua, srp);
4021 // Handle players that are not connected
4022 if(player->peer_id == PEER_ID_INEXISTENT){
4023 RespawnPlayer(player);
4027 SendPlayerHP(player);
4028 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4031 void Server::RespawnPlayer(Player *player)
4033 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4035 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4037 v3f pos = findSpawnPos(m_env->getServerMap());
4038 player->setPosition(pos);
4039 srp->m_last_good_position = pos;
4040 srp->m_last_good_position_age = 0;
4042 SendMovePlayer(player);
4043 SendPlayerHP(player);
4046 void Server::UpdateCrafting(u16 peer_id)
4048 DSTACK(__FUNCTION_NAME);
4050 Player* player = m_env->getPlayer(peer_id);
4053 // Get a preview for crafting
4055 // No crafting in creative mode
4056 if(g_settings->getBool("creative_mode") == false)
4057 getCraftingResult(&player->inventory, preview, false, this);
4059 // Put the new preview in
4060 InventoryList *plist = player->inventory.getList("craftpreview");
4062 assert(plist->getSize() >= 1);
4063 plist->changeItem(0, preview);
4066 RemoteClient* Server::getClient(u16 peer_id)
4068 DSTACK(__FUNCTION_NAME);
4069 //JMutexAutoLock lock(m_con_mutex);
4070 core::map<u16, RemoteClient*>::Node *n;
4071 n = m_clients.find(peer_id);
4072 // A client should exist for all peers
4074 return n->getValue();
4077 std::wstring Server::getStatusString()
4079 std::wostringstream os(std::ios_base::binary);
4082 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4084 os<<L", uptime="<<m_uptime.get();
4085 // Information about clients
4087 for(core::map<u16, RemoteClient*>::Iterator
4088 i = m_clients.getIterator();
4089 i.atEnd() == false; i++)
4091 // Get client and check that it is valid
4092 RemoteClient *client = i.getNode()->getValue();
4093 assert(client->peer_id == i.getNode()->getKey());
4094 if(client->serialization_version == SER_FMT_VER_INVALID)
4097 Player *player = m_env->getPlayer(client->peer_id);
4098 // Get name of player
4099 std::wstring name = L"unknown";
4101 name = narrow_to_wide(player->getName());
4102 // Add name to information string
4106 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4107 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4108 if(g_settings->get("motd") != "")
4109 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4113 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4115 // Add player to auth manager
4116 if(m_authmanager.exists(name) == false)
4118 infostream<<"Server: adding player "<<name
4119 <<" to auth manager"<<std::endl;
4120 m_authmanager.add(name);
4121 m_authmanager.setPrivs(name,
4122 stringToPrivs(g_settings->get("default_privs")));
4124 // Change password and save
4125 m_authmanager.setPassword(name, translatePassword(name, password));
4126 m_authmanager.save();
4129 // Saves g_settings to configpath given at initialization
4130 void Server::saveConfig()
4132 if(m_path_config != "")
4133 g_settings->updateConfigFile(m_path_config.c_str());
4136 void Server::notifyPlayer(const char *name, const std::wstring msg)
4138 Player *player = m_env->getPlayer(name);
4141 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4144 void Server::notifyPlayers(const std::wstring msg)
4146 BroadcastChatMessage(msg);
4149 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4153 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4154 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4157 // IGameDef interface
4159 IItemDefManager* Server::getItemDefManager()
4163 INodeDefManager* Server::getNodeDefManager()
4167 ICraftDefManager* Server::getCraftDefManager()
4171 ITextureSource* Server::getTextureSource()
4175 u16 Server::allocateUnknownNodeId(const std::string &name)
4177 return m_nodedef->allocateDummy(name);
4180 IWritableItemDefManager* Server::getWritableItemDefManager()
4184 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4188 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4193 const ModSpec* Server::getModSpec(const std::string &modname)
4195 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4196 i != m_mods.end(); i++){
4197 const ModSpec &mod = *i;
4198 if(mod.name == modname)
4204 v3f findSpawnPos(ServerMap &map)
4206 //return v3f(50,50,50)*BS;
4211 nodepos = v2s16(0,0);
4216 // Try to find a good place a few times
4217 for(s32 i=0; i<1000; i++)
4220 // We're going to try to throw the player to this position
4221 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4222 -range + (myrand()%(range*2)));
4223 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4224 // Get ground height at point (fallbacks to heightmap function)
4225 s16 groundheight = map.findGroundLevel(nodepos2d);
4226 // Don't go underwater
4227 if(groundheight < WATER_LEVEL)
4229 //infostream<<"-> Underwater"<<std::endl;
4232 // Don't go to high places
4233 if(groundheight > WATER_LEVEL + 4)
4235 //infostream<<"-> Underwater"<<std::endl;
4239 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4240 bool is_good = false;
4242 for(s32 i=0; i<10; i++){
4243 v3s16 blockpos = getNodeBlockPos(nodepos);
4244 map.emergeBlock(blockpos, true);
4245 MapNode n = map.getNodeNoEx(nodepos);
4246 if(n.getContent() == CONTENT_AIR){
4257 // Found a good place
4258 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4264 return intToFloat(nodepos, BS);
4267 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4270 Try to get an existing player
4272 ServerRemotePlayer *player =
4273 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4276 // If player is already connected, cancel
4277 if(player->peer_id != 0)
4279 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4284 player->peer_id = peer_id;
4286 // Re-add player to environment
4287 if(player->m_removed)
4289 player->m_removed = false;
4291 m_env->addActiveObject(player);
4294 // Reset inventory to creative if in creative mode
4295 if(g_settings->getBool("creative_mode"))
4297 // Warning: double code below
4298 // Backup actual inventory
4299 player->inventory_backup = new Inventory(m_itemdef);
4300 *(player->inventory_backup) = player->inventory;
4301 // Set creative inventory
4302 player->resetInventory();
4303 scriptapi_get_creative_inventory(m_lua, player);
4310 If player with the wanted peer_id already exists, cancel.
4312 if(m_env->getPlayer(peer_id) != NULL)
4314 infostream<<"emergePlayer(): Player with wrong name but same"
4315 " peer_id already exists"<<std::endl;
4323 /* Set player position */
4325 infostream<<"Server: Finding spawn place for player \""
4326 <<name<<"\""<<std::endl;
4328 v3f pos = findSpawnPos(m_env->getServerMap());
4330 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4331 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4333 /* Add player to environment */
4334 m_env->addPlayer(player);
4335 m_env->addActiveObject(srp);
4338 scriptapi_on_newplayer(m_lua, srp);
4340 /* Add stuff to inventory */
4341 if(g_settings->getBool("creative_mode"))
4343 // Warning: double code above
4344 // Backup actual inventory
4345 player->inventory_backup = new Inventory(m_itemdef);
4346 *(player->inventory_backup) = player->inventory;
4347 // Set creative inventory
4348 player->resetInventory();
4349 scriptapi_get_creative_inventory(m_lua, player);
4354 } // create new player
4357 void Server::handlePeerChange(PeerChange &c)
4359 JMutexAutoLock envlock(m_env_mutex);
4360 JMutexAutoLock conlock(m_con_mutex);
4362 if(c.type == PEER_ADDED)
4369 core::map<u16, RemoteClient*>::Node *n;
4370 n = m_clients.find(c.peer_id);
4371 // The client shouldn't already exist
4375 RemoteClient *client = new RemoteClient();
4376 client->peer_id = c.peer_id;
4377 m_clients.insert(client->peer_id, client);
4380 else if(c.type == PEER_REMOVED)
4387 core::map<u16, RemoteClient*>::Node *n;
4388 n = m_clients.find(c.peer_id);
4389 // The client should exist
4393 Mark objects to be not known by the client
4395 RemoteClient *client = n->getValue();
4397 for(core::map<u16, bool>::Iterator
4398 i = client->m_known_objects.getIterator();
4399 i.atEnd()==false; i++)
4402 u16 id = i.getNode()->getKey();
4403 ServerActiveObject* obj = m_env->getActiveObject(id);
4405 if(obj && obj->m_known_by_count > 0)
4406 obj->m_known_by_count--;
4409 ServerRemotePlayer* player =
4410 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4412 // Collect information about leaving in chat
4413 std::wstring message;
4417 std::wstring name = narrow_to_wide(player->getName());
4420 message += L" left game";
4422 message += L" (timed out)";
4426 // Remove from environment
4428 player->m_removed = true;
4430 // Set player client disconnected
4432 player->peer_id = 0;
4440 std::ostringstream os(std::ios_base::binary);
4441 for(core::map<u16, RemoteClient*>::Iterator
4442 i = m_clients.getIterator();
4443 i.atEnd() == false; i++)
4445 RemoteClient *client = i.getNode()->getValue();
4446 assert(client->peer_id == i.getNode()->getKey());
4447 if(client->serialization_version == SER_FMT_VER_INVALID)
4450 Player *player = m_env->getPlayer(client->peer_id);
4453 // Get name of player
4454 os<<player->getName()<<" ";
4457 actionstream<<player->getName()<<" "
4458 <<(c.timeout?"times out.":"leaves game.")
4459 <<" List of players: "
4460 <<os.str()<<std::endl;
4465 delete m_clients[c.peer_id];
4466 m_clients.remove(c.peer_id);
4468 // Send player info to all remaining clients
4469 //SendPlayerInfos();
4471 // Send leave chat message to all remaining clients
4472 if(message.length() != 0)
4473 BroadcastChatMessage(message);
4482 void Server::handlePeerChanges()
4484 while(m_peer_change_queue.size() > 0)
4486 PeerChange c = m_peer_change_queue.pop_front();
4488 infostream<<"Server: Handling peer change: "
4489 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4492 handlePeerChange(c);
4496 u64 Server::getPlayerPrivs(Player *player)
4500 std::string playername = player->getName();
4501 // Local player gets all privileges regardless of
4502 // what's set on their account.
4503 if(g_settings->get("name") == playername)
4509 return getPlayerAuthPrivs(playername);
4513 void dedicated_server_loop(Server &server, bool &kill)
4515 DSTACK(__FUNCTION_NAME);
4517 infostream<<DTIME<<std::endl;
4518 infostream<<"========================"<<std::endl;
4519 infostream<<"Running dedicated server"<<std::endl;
4520 infostream<<"========================"<<std::endl;
4521 infostream<<std::endl;
4523 IntervalLimiter m_profiler_interval;
4527 float steplen = g_settings->getFloat("dedicated_server_step");
4528 // This is kind of a hack but can be done like this
4529 // because server.step() is very light
4531 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4532 sleep_ms((int)(steplen*1000.0));
4534 server.step(steplen);
4536 if(server.getShutdownRequested() || kill)
4538 infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4545 float profiler_print_interval =
4546 g_settings->getFloat("profiler_print_interval");
4547 if(profiler_print_interval != 0)
4549 if(m_profiler_interval.step(steplen, profiler_print_interval))
4551 infostream<<"Profiler:"<<std::endl;
4552 g_profiler->print(infostream);
4553 g_profiler->clear();
4560 static int counter = 0;
4566 core::list<PlayerInfo> list = server.getPlayerInfo();
4567 core::list<PlayerInfo>::Iterator i;
4568 static u32 sum_old = 0;
4569 u32 sum = PIChecksum(list);
4572 infostream<<DTIME<<"Player info:"<<std::endl;
4573 for(i=list.begin(); i!=list.end(); i++)
4575 i->PrintLine(&infostream);