3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "jmutexautolock.h"
28 #include "constants.h"
31 #include "servercommand.h"
33 #include "content_mapnode.h"
34 #include "content_nodemeta.h"
36 #include "serverobject.h"
41 #include "scriptapi.h"
46 #include "content_abm.h"
51 #include "utility_string.h"
53 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
55 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
57 class MapEditEventIgnorer
60 MapEditEventIgnorer(bool *flag):
69 ~MapEditEventIgnorer()
82 void * ServerThread::Thread()
86 log_register_thread("ServerThread");
88 DSTACK(__FUNCTION_NAME);
90 BEGIN_DEBUG_EXCEPTION_HANDLER
95 //TimeTaker timer("AsyncRunStep() + Receive()");
98 //TimeTaker timer("AsyncRunStep()");
99 m_server->AsyncRunStep();
102 //infostream<<"Running m_server->Receive()"<<std::endl;
105 catch(con::NoIncomingDataException &e)
108 catch(con::PeerNotFoundException &e)
110 infostream<<"Server: PeerNotFoundException"<<std::endl;
114 END_DEBUG_EXCEPTION_HANDLER(errorstream)
119 void * EmergeThread::Thread()
123 log_register_thread("EmergeThread");
125 DSTACK(__FUNCTION_NAME);
127 BEGIN_DEBUG_EXCEPTION_HANDLER
129 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
132 Get block info from queue, emerge them and send them
135 After queue is empty, exit.
139 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
143 SharedPtr<QueuedBlockEmerge> q(qptr);
149 Do not generate over-limit
151 if(blockpos_over_limit(p))
154 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
156 //TimeTaker timer("block emerge");
159 Try to emerge it from somewhere.
161 If it is only wanted as optional, only loading from disk
166 Check if any peer wants it as non-optional. In that case it
169 Also decrement the emerge queue count in clients.
172 bool only_from_disk = true;
175 core::map<u16, u8>::Iterator i;
176 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
178 //u16 peer_id = i.getNode()->getKey();
181 u8 flags = i.getNode()->getValue();
182 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
183 only_from_disk = false;
188 if(enable_mapgen_debug_info)
189 infostream<<"EmergeThread: p="
190 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
191 <<"only_from_disk="<<only_from_disk<<std::endl;
193 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
195 MapBlock *block = NULL;
196 bool got_block = true;
197 core::map<v3s16, MapBlock*> modified_blocks;
200 Try to fetch block from memory or disk.
201 If not found and asked to generate, initialize generator.
204 bool started_generate = false;
205 mapgen::BlockMakeData data;
208 JMutexAutoLock envlock(m_server->m_env_mutex);
210 // Load sector if it isn't loaded
211 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
212 map.loadSectorMeta(p2d);
214 // Attempt to load block
215 block = map.getBlockNoCreateNoEx(p);
216 if(!block || block->isDummy() || !block->isGenerated())
218 if(enable_mapgen_debug_info)
219 infostream<<"EmergeThread: not in memory, "
220 <<"attempting to load from disk"<<std::endl;
222 block = map.loadBlock(p);
225 // If could not load and allowed to generate, start generation
226 // inside this same envlock
227 if(only_from_disk == false &&
228 (block == NULL || block->isGenerated() == false)){
229 if(enable_mapgen_debug_info)
230 infostream<<"EmergeThread: generating"<<std::endl;
231 started_generate = true;
233 map.initBlockMake(&data, p);
238 If generator was initialized, generate now when envlock is free.
243 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
245 TimeTaker t("mapgen::make_block()");
247 mapgen::make_block(&data);
249 if(enable_mapgen_debug_info == false)
250 t.stop(true); // Hide output
254 // Lock environment again to access the map
255 JMutexAutoLock envlock(m_server->m_env_mutex);
257 ScopeProfiler sp(g_profiler, "EmergeThread: after "
258 "mapgen::make_block (envlock)", SPT_AVG);
260 // Blit data back on map, update lighting, add mobs and
261 // whatever this does
262 map.finishBlockMake(&data, modified_blocks);
265 block = map.getBlockNoCreateNoEx(p);
267 // If block doesn't exist, don't try doing anything with it
268 // This happens if the block is not in generation boundaries
273 Do some post-generate stuff
276 v3s16 minp = block->getPos()*MAP_BLOCKSIZE;
277 v3s16 maxp = minp + v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
278 scriptapi_environment_on_generated(m_server->m_lua,
281 if(enable_mapgen_debug_info)
282 infostream<<"EmergeThread: ended up with: "
283 <<analyze_block(block)<<std::endl;
286 Ignore map edit events, they will not need to be
287 sent to anybody because the block hasn't been sent
290 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
292 // Activate objects and stuff
293 m_server->m_env->activateBlock(block, 0);
301 Set sent status of modified blocks on clients
304 // NOTE: Server's clients are also behind the connection mutex
305 JMutexAutoLock lock(m_server->m_con_mutex);
308 Add the originally fetched block to the modified list
312 modified_blocks.insert(p, block);
316 Set the modified blocks unsent for all the clients
319 for(core::map<u16, RemoteClient*>::Iterator
320 i = m_server->m_clients.getIterator();
321 i.atEnd() == false; i++)
323 RemoteClient *client = i.getNode()->getValue();
325 if(modified_blocks.size() > 0)
327 // Remove block from sent history
328 client->SetBlocksNotSent(modified_blocks);
334 END_DEBUG_EXCEPTION_HANDLER(errorstream)
336 log_deregister_thread();
341 void RemoteClient::GetNextBlocks(Server *server, float dtime,
342 core::array<PrioritySortedBlockTransfer> &dest)
344 DSTACK(__FUNCTION_NAME);
347 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
350 m_nothing_to_send_pause_timer -= dtime;
351 m_nearest_unsent_reset_timer += dtime;
353 if(m_nothing_to_send_pause_timer >= 0)
358 // Won't send anything if already sending
359 if(m_blocks_sending.size() >= g_settings->getU16
360 ("max_simultaneous_block_sends_per_client"))
362 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
366 //TimeTaker timer("RemoteClient::GetNextBlocks");
368 Player *player = server->m_env->getPlayer(peer_id);
370 assert(player != NULL);
372 v3f playerpos = player->getPosition();
373 v3f playerspeed = player->getSpeed();
374 v3f playerspeeddir(0,0,0);
375 if(playerspeed.getLength() > 1.0*BS)
376 playerspeeddir = playerspeed / playerspeed.getLength();
377 // Predict to next block
378 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
380 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
382 v3s16 center = getNodeBlockPos(center_nodepos);
384 // Camera position and direction
385 v3f camera_pos = player->getEyePosition();
386 v3f camera_dir = v3f(0,0,1);
387 camera_dir.rotateYZBy(player->getPitch());
388 camera_dir.rotateXZBy(player->getYaw());
390 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
391 <<camera_dir.Z<<")"<<std::endl;*/
394 Get the starting value of the block finder radius.
397 if(m_last_center != center)
399 m_nearest_unsent_d = 0;
400 m_last_center = center;
403 /*infostream<<"m_nearest_unsent_reset_timer="
404 <<m_nearest_unsent_reset_timer<<std::endl;*/
406 // Reset periodically to workaround for some bugs or stuff
407 if(m_nearest_unsent_reset_timer > 20.0)
409 m_nearest_unsent_reset_timer = 0;
410 m_nearest_unsent_d = 0;
411 //infostream<<"Resetting m_nearest_unsent_d for "
412 // <<server->getPlayerName(peer_id)<<std::endl;
415 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
416 s16 d_start = m_nearest_unsent_d;
418 //infostream<<"d_start="<<d_start<<std::endl;
420 u16 max_simul_sends_setting = g_settings->getU16
421 ("max_simultaneous_block_sends_per_client");
422 u16 max_simul_sends_usually = max_simul_sends_setting;
425 Check the time from last addNode/removeNode.
427 Decrease send rate if player is building stuff.
429 m_time_from_building += dtime;
430 if(m_time_from_building < g_settings->getFloat(
431 "full_block_send_enable_min_time_from_building"))
433 max_simul_sends_usually
434 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
438 Number of blocks sending + number of blocks selected for sending
440 u32 num_blocks_selected = m_blocks_sending.size();
443 next time d will be continued from the d from which the nearest
444 unsent block was found this time.
446 This is because not necessarily any of the blocks found this
447 time are actually sent.
449 s32 new_nearest_unsent_d = -1;
451 s16 d_max = g_settings->getS16("max_block_send_distance");
452 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
454 // Don't loop very much at a time
455 s16 max_d_increment_at_time = 2;
456 if(d_max > d_start + max_d_increment_at_time)
457 d_max = d_start + max_d_increment_at_time;
458 /*if(d_max_gen > d_start+2)
459 d_max_gen = d_start+2;*/
461 //infostream<<"Starting from "<<d_start<<std::endl;
463 s32 nearest_emerged_d = -1;
464 s32 nearest_emergefull_d = -1;
465 s32 nearest_sent_d = -1;
466 bool queue_is_full = false;
469 for(d = d_start; d <= d_max; d++)
471 /*errorstream<<"checking d="<<d<<" for "
472 <<server->getPlayerName(peer_id)<<std::endl;*/
473 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
476 If m_nearest_unsent_d was changed by the EmergeThread
477 (it can change it to 0 through SetBlockNotSent),
479 Else update m_nearest_unsent_d
481 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
483 d = m_nearest_unsent_d;
484 last_nearest_unsent_d = m_nearest_unsent_d;
488 Get the border/face dot coordinates of a "d-radiused"
491 core::list<v3s16> list;
492 getFacePositions(list, d);
494 core::list<v3s16>::Iterator li;
495 for(li=list.begin(); li!=list.end(); li++)
497 v3s16 p = *li + center;
501 - Don't allow too many simultaneous transfers
502 - EXCEPT when the blocks are very close
504 Also, don't send blocks that are already flying.
507 // Start with the usual maximum
508 u16 max_simul_dynamic = max_simul_sends_usually;
510 // If block is very close, allow full maximum
511 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
512 max_simul_dynamic = max_simul_sends_setting;
514 // Don't select too many blocks for sending
515 if(num_blocks_selected >= max_simul_dynamic)
517 queue_is_full = true;
518 goto queue_full_break;
521 // Don't send blocks that are currently being transferred
522 if(m_blocks_sending.find(p) != NULL)
528 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
529 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
530 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
531 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
532 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
533 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
536 // If this is true, inexistent block will be made from scratch
537 bool generate = d <= d_max_gen;
540 /*// Limit the generating area vertically to 2/3
541 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
544 // Limit the send area vertically to 1/2
545 if(abs(p.Y - center.Y) > d_max / 2)
551 If block is far away, don't generate it unless it is
557 // Block center y in nodes
558 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
559 // Don't generate if it's very high or very low
560 if(y < -64 || y > 64)
564 v2s16 p2d_nodes_center(
568 // Get ground height in nodes
569 s16 gh = server->m_env->getServerMap().findGroundLevel(
572 // If differs a lot, don't generate
573 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
575 // Actually, don't even send it
581 //infostream<<"d="<<d<<std::endl;
584 Don't generate or send if not in sight
585 FIXME This only works if the client uses a small enough
586 FOV setting. The default of 72 degrees is fine.
589 float camera_fov = (72.0*PI/180) * 4./3.;
590 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
596 Don't send already sent blocks
599 if(m_blocks_sent.find(p) != NULL)
606 Check if map has this block
608 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
610 bool surely_not_found_on_disk = false;
611 bool block_is_invalid = false;
614 // Reset usage timer, this block will be of use in the future.
615 block->resetUsageTimer();
617 // Block is dummy if data doesn't exist.
618 // It means it has been not found from disk and not generated
621 surely_not_found_on_disk = true;
624 // Block is valid if lighting is up-to-date and data exists
625 if(block->isValid() == false)
627 block_is_invalid = true;
630 /*if(block->isFullyGenerated() == false)
632 block_is_invalid = true;
637 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
638 v2s16 chunkpos = map->sector_to_chunk(p2d);
639 if(map->chunkNonVolatile(chunkpos) == false)
640 block_is_invalid = true;
642 if(block->isGenerated() == false)
643 block_is_invalid = true;
646 If block is not close, don't send it unless it is near
649 Block is near ground level if night-time mesh
650 differs from day-time mesh.
654 if(block->dayNightDiffed() == false)
661 If block has been marked to not exist on disk (dummy)
662 and generating new ones is not wanted, skip block.
664 if(generate == false && surely_not_found_on_disk == true)
671 Add inexistent block to emerge queue.
673 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
675 //TODO: Get value from somewhere
676 // Allow only one block in emerge queue
677 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
678 // Allow two blocks in queue per client
679 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
681 // Make it more responsive when needing to generate stuff
682 if(surely_not_found_on_disk)
684 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
686 //infostream<<"Adding block to emerge queue"<<std::endl;
688 // Add it to the emerge queue and trigger the thread
691 if(generate == false)
692 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
694 server->m_emerge_queue.addBlock(peer_id, p, flags);
695 server->m_emergethread.trigger();
697 if(nearest_emerged_d == -1)
698 nearest_emerged_d = d;
700 if(nearest_emergefull_d == -1)
701 nearest_emergefull_d = d;
708 if(nearest_sent_d == -1)
712 Add block to send queue
715 /*errorstream<<"sending from d="<<d<<" to "
716 <<server->getPlayerName(peer_id)<<std::endl;*/
718 PrioritySortedBlockTransfer q((float)d, p, peer_id);
722 num_blocks_selected += 1;
727 //infostream<<"Stopped at "<<d<<std::endl;
729 // If nothing was found for sending and nothing was queued for
730 // emerging, continue next time browsing from here
731 if(nearest_emerged_d != -1){
732 new_nearest_unsent_d = nearest_emerged_d;
733 } else if(nearest_emergefull_d != -1){
734 new_nearest_unsent_d = nearest_emergefull_d;
736 if(d > g_settings->getS16("max_block_send_distance")){
737 new_nearest_unsent_d = 0;
738 m_nothing_to_send_pause_timer = 2.0;
739 /*infostream<<"GetNextBlocks(): d wrapped around for "
740 <<server->getPlayerName(peer_id)
741 <<"; setting to 0 and pausing"<<std::endl;*/
743 if(nearest_sent_d != -1)
744 new_nearest_unsent_d = nearest_sent_d;
746 new_nearest_unsent_d = d;
750 if(new_nearest_unsent_d != -1)
751 m_nearest_unsent_d = new_nearest_unsent_d;
753 /*timer_result = timer.stop(true);
754 if(timer_result != 0)
755 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
758 void RemoteClient::GotBlock(v3s16 p)
760 if(m_blocks_sending.find(p) != NULL)
761 m_blocks_sending.remove(p);
764 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
765 " m_blocks_sending"<<std::endl;*/
766 m_excess_gotblocks++;
768 m_blocks_sent.insert(p, true);
771 void RemoteClient::SentBlock(v3s16 p)
773 if(m_blocks_sending.find(p) == NULL)
774 m_blocks_sending.insert(p, 0.0);
776 infostream<<"RemoteClient::SentBlock(): Sent block"
777 " already in m_blocks_sending"<<std::endl;
780 void RemoteClient::SetBlockNotSent(v3s16 p)
782 m_nearest_unsent_d = 0;
784 if(m_blocks_sending.find(p) != NULL)
785 m_blocks_sending.remove(p);
786 if(m_blocks_sent.find(p) != NULL)
787 m_blocks_sent.remove(p);
790 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
792 m_nearest_unsent_d = 0;
794 for(core::map<v3s16, MapBlock*>::Iterator
795 i = blocks.getIterator();
796 i.atEnd()==false; i++)
798 v3s16 p = i.getNode()->getKey();
800 if(m_blocks_sending.find(p) != NULL)
801 m_blocks_sending.remove(p);
802 if(m_blocks_sent.find(p) != NULL)
803 m_blocks_sent.remove(p);
811 PlayerInfo::PlayerInfo()
817 void PlayerInfo::PrintLine(std::ostream *s)
820 (*s)<<"\""<<name<<"\" ("
821 <<(position.X/10)<<","<<(position.Y/10)
822 <<","<<(position.Z/10)<<") ";
824 (*s)<<" avg_rtt="<<avg_rtt;
833 const std::string &path_world,
834 const std::string &path_config,
835 const SubgameSpec &gamespec
837 m_path_world(path_world),
838 m_path_config(path_config),
839 m_gamespec(gamespec),
841 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
842 m_authmanager(path_world+DIR_DELIM+"auth.txt"),
843 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
845 m_itemdef(createItemDefManager()),
846 m_nodedef(createNodeDefManager()),
847 m_craftdef(createCraftDefManager()),
849 m_emergethread(this),
851 m_time_of_day_send_timer(0),
853 m_shutdown_requested(false),
854 m_ignore_map_edit_events(false),
855 m_ignore_map_edit_events_peer_id(0)
857 m_liquid_transform_timer = 0.0;
858 m_print_info_timer = 0.0;
859 m_objectdata_timer = 0.0;
860 m_emergethread_trigger_timer = 0.0;
861 m_savemap_timer = 0.0;
865 m_step_dtime_mutex.Init();
868 if(!gamespec.isValid())
869 throw ServerError("Supplied invalid gamespec");
871 // Figure out some paths
873 m_path_share = porting::path_share + DIR_DELIM + "server";
875 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\""<<std::endl;
876 infostream<<"- world: "<<m_path_world<<std::endl;
877 infostream<<"- config: "<<m_path_config<<std::endl;
878 infostream<<"- game: "<<m_gamespec.path<<std::endl;
879 for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
880 i != m_gamespec.addon_paths.end(); i++)
881 infostream<<"- addons: "<<(*i)<<std::endl;
883 // Path to builtin.lua
884 std::string builtinpath = m_path_share + DIR_DELIM + "builtin.lua";
886 // Add default global mod search path
887 m_modspaths.push_front(m_gamespec.path + DIR_DELIM "mods");
888 // Add world mod search path
889 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
890 // Add addon mod search path
891 for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
892 i != m_gamespec.addon_paths.end(); i++)
893 m_modspaths.push_front((*i) + DIR_DELIM + "mods");
895 // Print out mod search paths
896 for(core::list<std::string>::Iterator i = m_modspaths.begin();
897 i != m_modspaths.end(); i++){
898 std::string modspath = *i;
899 infostream<<"- mods: "<<modspath<<std::endl;
903 JMutexAutoLock envlock(m_env_mutex);
904 JMutexAutoLock conlock(m_con_mutex);
906 // Initialize scripting
908 infostream<<"Server: Initializing Lua"<<std::endl;
909 m_lua = script_init();
912 scriptapi_export(m_lua, this);
913 // Load and run builtin.lua
914 infostream<<"Server: Loading builtin.lua [\""
915 <<builtinpath<<"\"]"<<std::endl;
916 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
918 errorstream<<"Server: Failed to load and run "
919 <<builtinpath<<std::endl;
920 throw ModError("Failed to load and run "+builtinpath);
922 // Find mods in mod search paths
923 m_mods = getMods(m_modspaths);
925 infostream<<"Server: Loading mods: ";
926 for(core::list<ModSpec>::Iterator i = m_mods.begin();
927 i != m_mods.end(); i++){
928 const ModSpec &mod = *i;
929 infostream<<mod.name<<" ";
931 infostream<<std::endl;
932 // Load and run "mod" scripts
933 for(core::list<ModSpec>::Iterator i = m_mods.begin();
934 i != m_mods.end(); i++){
935 const ModSpec &mod = *i;
936 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
937 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
938 <<scriptpath<<"\"]"<<std::endl;
939 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
941 errorstream<<"Server: Failed to load and run "
942 <<scriptpath<<std::endl;
943 throw ModError("Failed to load and run "+scriptpath);
947 // Read Textures and calculate sha1 sums
950 // Apply item aliases in the node definition manager
951 m_nodedef->updateAliases(m_itemdef);
953 // Initialize Environment
955 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
958 // Give environment reference to scripting api
959 scriptapi_add_environment(m_lua, m_env);
961 // Register us to receive map edit events
962 m_env->getMap().addEventReceiver(this);
964 // If file exists, load environment metadata
965 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
967 infostream<<"Server: Loading environment metadata"<<std::endl;
968 m_env->loadMeta(m_path_world);
972 infostream<<"Server: Loading players"<<std::endl;
973 m_env->deSerializePlayers(m_path_world);
976 Add some test ActiveBlockModifiers to environment
978 add_legacy_abms(m_env, m_nodedef);
983 infostream<<"Server destructing"<<std::endl;
986 Send shutdown message
989 JMutexAutoLock conlock(m_con_mutex);
991 std::wstring line = L"*** Server shutting down";
994 Send the message to clients
996 for(core::map<u16, RemoteClient*>::Iterator
997 i = m_clients.getIterator();
998 i.atEnd() == false; i++)
1000 // Get client and check that it is valid
1001 RemoteClient *client = i.getNode()->getValue();
1002 assert(client->peer_id == i.getNode()->getKey());
1003 if(client->serialization_version == SER_FMT_VER_INVALID)
1007 SendChatMessage(client->peer_id, line);
1009 catch(con::PeerNotFoundException &e)
1015 JMutexAutoLock envlock(m_env_mutex);
1020 infostream<<"Server: Saving players"<<std::endl;
1021 m_env->serializePlayers(m_path_world);
1024 Save environment metadata
1026 infostream<<"Server: Saving environment metadata"<<std::endl;
1027 m_env->saveMeta(m_path_world);
1039 JMutexAutoLock clientslock(m_con_mutex);
1041 for(core::map<u16, RemoteClient*>::Iterator
1042 i = m_clients.getIterator();
1043 i.atEnd() == false; i++)
1046 // NOTE: These are removed by env destructor
1048 u16 peer_id = i.getNode()->getKey();
1049 JMutexAutoLock envlock(m_env_mutex);
1050 m_env->removePlayer(peer_id);
1054 delete i.getNode()->getValue();
1058 // Delete Environment
1065 // Deinitialize scripting
1066 infostream<<"Server: Deinitializing scripting"<<std::endl;
1067 script_deinit(m_lua);
1070 void Server::start(unsigned short port)
1072 DSTACK(__FUNCTION_NAME);
1073 // Stop thread if already running
1076 // Initialize connection
1077 m_con.SetTimeoutMs(30);
1081 m_thread.setRun(true);
1084 // ASCII art for the win!
1086 <<" .__ __ __ "<<std::endl
1087 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1088 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1089 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1090 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1091 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1092 actionstream<<"Server for gameid=\""<<m_gamespec.id
1093 <<"\" listening on port "<<port<<"."<<std::endl;
1098 DSTACK(__FUNCTION_NAME);
1100 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1102 // Stop threads (set run=false first so both start stopping)
1103 m_thread.setRun(false);
1104 m_emergethread.setRun(false);
1106 m_emergethread.stop();
1108 infostream<<"Server: Threads stopped"<<std::endl;
1111 void Server::step(float dtime)
1113 DSTACK(__FUNCTION_NAME);
1118 JMutexAutoLock lock(m_step_dtime_mutex);
1119 m_step_dtime += dtime;
1123 void Server::AsyncRunStep()
1125 DSTACK(__FUNCTION_NAME);
1127 g_profiler->add("Server::AsyncRunStep (num)", 1);
1131 JMutexAutoLock lock1(m_step_dtime_mutex);
1132 dtime = m_step_dtime;
1136 // Send blocks to clients
1143 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1145 //infostream<<"Server steps "<<dtime<<std::endl;
1146 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1149 JMutexAutoLock lock1(m_step_dtime_mutex);
1150 m_step_dtime -= dtime;
1157 m_uptime.set(m_uptime.get() + dtime);
1161 // Process connection's timeouts
1162 JMutexAutoLock lock2(m_con_mutex);
1163 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1164 m_con.RunTimeouts(dtime);
1168 // This has to be called so that the client list gets synced
1169 // with the peer list of the connection
1170 handlePeerChanges();
1174 Update m_time_of_day and overall game time
1177 JMutexAutoLock envlock(m_env_mutex);
1179 m_time_counter += dtime;
1180 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1181 u32 units = (u32)(m_time_counter*speed);
1182 m_time_counter -= (f32)units / speed;
1184 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1186 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1189 Send to clients at constant intervals
1192 m_time_of_day_send_timer -= dtime;
1193 if(m_time_of_day_send_timer < 0.0)
1195 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1197 //JMutexAutoLock envlock(m_env_mutex);
1198 JMutexAutoLock conlock(m_con_mutex);
1200 for(core::map<u16, RemoteClient*>::Iterator
1201 i = m_clients.getIterator();
1202 i.atEnd() == false; i++)
1204 RemoteClient *client = i.getNode()->getValue();
1205 //Player *player = m_env->getPlayer(client->peer_id);
1207 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1208 m_env->getTimeOfDay());
1210 m_con.Send(client->peer_id, 0, data, true);
1216 JMutexAutoLock lock(m_env_mutex);
1218 ScopeProfiler sp(g_profiler, "SEnv step");
1219 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1223 const float map_timer_and_unload_dtime = 2.92;
1224 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1226 JMutexAutoLock lock(m_env_mutex);
1227 // Run Map's timers and unload unused data
1228 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1229 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1230 g_settings->getFloat("server_unload_unused_data_timeout"));
1241 JMutexAutoLock lock(m_env_mutex);
1242 JMutexAutoLock lock2(m_con_mutex);
1244 ScopeProfiler sp(g_profiler, "Server: handle players");
1246 //float player_max_speed = BS * 4.0; // Normal speed
1247 float player_max_speed = BS * 20; // Fast speed
1248 float player_max_speed_up = BS * 20;
1250 player_max_speed *= 2.5; // Tolerance
1251 player_max_speed_up *= 2.5;
1253 for(core::map<u16, RemoteClient*>::Iterator
1254 i = m_clients.getIterator();
1255 i.atEnd() == false; i++)
1257 RemoteClient *client = i.getNode()->getValue();
1258 ServerRemotePlayer *player =
1259 static_cast<ServerRemotePlayer*>
1260 (m_env->getPlayer(client->peer_id));
1265 Check player movements
1267 NOTE: Actually the server should handle player physics like the
1268 client does and compare player's position to what is calculated
1269 on our side. This is required when eg. players fly due to an
1272 player->m_last_good_position_age += dtime;
1273 if(player->m_last_good_position_age >= 1.0){
1274 float age = player->m_last_good_position_age;
1275 v3f diff = (player->getPosition() - player->m_last_good_position);
1276 float d_vert = diff.Y;
1278 float d_horiz = diff.getLength();
1279 /*infostream<<player->getName()<<"'s horizontal speed is "
1280 <<(d_horiz/age)<<std::endl;*/
1281 if(d_horiz <= age * player_max_speed &&
1282 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1283 player->m_last_good_position = player->getPosition();
1285 actionstream<<"Player "<<player->getName()
1286 <<" moved too fast; resetting position"
1288 player->setPosition(player->m_last_good_position);
1289 SendMovePlayer(player);
1291 player->m_last_good_position_age = 0;
1295 Handle player HPs (die if hp=0)
1297 if(player->hp == 0 && player->m_hp_not_sent)
1301 Send player inventories and HPs if necessary
1303 if(player->m_inventory_not_sent){
1304 UpdateCrafting(player->peer_id);
1305 SendInventory(player->peer_id);
1307 if(player->m_hp_not_sent){
1308 SendPlayerHP(player);
1314 if(!player->m_is_in_environment){
1315 player->m_removed = false;
1317 m_env->addActiveObject(player);
1322 /* Transform liquids */
1323 m_liquid_transform_timer += dtime;
1324 if(m_liquid_transform_timer >= 1.00)
1326 m_liquid_transform_timer -= 1.00;
1328 JMutexAutoLock lock(m_env_mutex);
1330 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1332 core::map<v3s16, MapBlock*> modified_blocks;
1333 m_env->getMap().transformLiquids(modified_blocks);
1338 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1339 ServerMap &map = ((ServerMap&)m_env->getMap());
1340 map.updateLighting(modified_blocks, lighting_modified_blocks);
1342 // Add blocks modified by lighting to modified_blocks
1343 for(core::map<v3s16, MapBlock*>::Iterator
1344 i = lighting_modified_blocks.getIterator();
1345 i.atEnd() == false; i++)
1347 MapBlock *block = i.getNode()->getValue();
1348 modified_blocks.insert(block->getPos(), block);
1352 Set the modified blocks unsent for all the clients
1355 JMutexAutoLock lock2(m_con_mutex);
1357 for(core::map<u16, RemoteClient*>::Iterator
1358 i = m_clients.getIterator();
1359 i.atEnd() == false; i++)
1361 RemoteClient *client = i.getNode()->getValue();
1363 if(modified_blocks.size() > 0)
1365 // Remove block from sent history
1366 client->SetBlocksNotSent(modified_blocks);
1371 // Periodically print some info
1373 float &counter = m_print_info_timer;
1379 JMutexAutoLock lock2(m_con_mutex);
1381 if(m_clients.size() != 0)
1382 infostream<<"Players:"<<std::endl;
1383 for(core::map<u16, RemoteClient*>::Iterator
1384 i = m_clients.getIterator();
1385 i.atEnd() == false; i++)
1387 //u16 peer_id = i.getNode()->getKey();
1388 RemoteClient *client = i.getNode()->getValue();
1389 Player *player = m_env->getPlayer(client->peer_id);
1392 infostream<<"* "<<player->getName()<<"\t";
1393 client->PrintInfo(infostream);
1398 //if(g_settings->getBool("enable_experimental"))
1402 Check added and deleted active objects
1405 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1406 JMutexAutoLock envlock(m_env_mutex);
1407 JMutexAutoLock conlock(m_con_mutex);
1409 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1411 // Radius inside which objects are active
1412 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1413 radius *= MAP_BLOCKSIZE;
1415 for(core::map<u16, RemoteClient*>::Iterator
1416 i = m_clients.getIterator();
1417 i.atEnd() == false; i++)
1419 RemoteClient *client = i.getNode()->getValue();
1421 // If definitions and textures have not been sent, don't
1422 // send objects either
1423 if(!client->definitions_sent)
1426 Player *player = m_env->getPlayer(client->peer_id);
1429 // This can happen if the client timeouts somehow
1430 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1432 <<" has no associated player"<<std::endl;*/
1435 v3s16 pos = floatToInt(player->getPosition(), BS);
1437 core::map<u16, bool> removed_objects;
1438 core::map<u16, bool> added_objects;
1439 m_env->getRemovedActiveObjects(pos, radius,
1440 client->m_known_objects, removed_objects);
1441 m_env->getAddedActiveObjects(pos, radius,
1442 client->m_known_objects, added_objects);
1444 // Ignore if nothing happened
1445 if(removed_objects.size() == 0 && added_objects.size() == 0)
1447 //infostream<<"active objects: none changed"<<std::endl;
1451 std::string data_buffer;
1455 // Handle removed objects
1456 writeU16((u8*)buf, removed_objects.size());
1457 data_buffer.append(buf, 2);
1458 for(core::map<u16, bool>::Iterator
1459 i = removed_objects.getIterator();
1460 i.atEnd()==false; i++)
1463 u16 id = i.getNode()->getKey();
1464 ServerActiveObject* obj = m_env->getActiveObject(id);
1466 // Add to data buffer for sending
1467 writeU16((u8*)buf, i.getNode()->getKey());
1468 data_buffer.append(buf, 2);
1470 // Remove from known objects
1471 client->m_known_objects.remove(i.getNode()->getKey());
1473 if(obj && obj->m_known_by_count > 0)
1474 obj->m_known_by_count--;
1477 // Handle added objects
1478 writeU16((u8*)buf, added_objects.size());
1479 data_buffer.append(buf, 2);
1480 for(core::map<u16, bool>::Iterator
1481 i = added_objects.getIterator();
1482 i.atEnd()==false; i++)
1485 u16 id = i.getNode()->getKey();
1486 ServerActiveObject* obj = m_env->getActiveObject(id);
1489 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1491 infostream<<"WARNING: "<<__FUNCTION_NAME
1492 <<": NULL object"<<std::endl;
1494 type = obj->getType();
1496 // Add to data buffer for sending
1497 writeU16((u8*)buf, id);
1498 data_buffer.append(buf, 2);
1499 writeU8((u8*)buf, type);
1500 data_buffer.append(buf, 1);
1503 data_buffer.append(serializeLongString(
1504 obj->getClientInitializationData()));
1506 data_buffer.append(serializeLongString(""));
1508 // Add to known objects
1509 client->m_known_objects.insert(i.getNode()->getKey(), false);
1512 obj->m_known_by_count++;
1516 SharedBuffer<u8> reply(2 + data_buffer.size());
1517 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1518 memcpy((char*)&reply[2], data_buffer.c_str(),
1519 data_buffer.size());
1521 m_con.Send(client->peer_id, 0, reply, true);
1523 verbosestream<<"Server: Sent object remove/add: "
1524 <<removed_objects.size()<<" removed, "
1525 <<added_objects.size()<<" added, "
1526 <<"packet size is "<<reply.getSize()<<std::endl;
1531 Collect a list of all the objects known by the clients
1532 and report it back to the environment.
1535 core::map<u16, bool> all_known_objects;
1537 for(core::map<u16, RemoteClient*>::Iterator
1538 i = m_clients.getIterator();
1539 i.atEnd() == false; i++)
1541 RemoteClient *client = i.getNode()->getValue();
1542 // Go through all known objects of client
1543 for(core::map<u16, bool>::Iterator
1544 i = client->m_known_objects.getIterator();
1545 i.atEnd()==false; i++)
1547 u16 id = i.getNode()->getKey();
1548 all_known_objects[id] = true;
1552 m_env->setKnownActiveObjects(whatever);
1558 Send object messages
1561 JMutexAutoLock envlock(m_env_mutex);
1562 JMutexAutoLock conlock(m_con_mutex);
1564 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1567 // Value = data sent by object
1568 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1570 // Get active object messages from environment
1573 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1577 core::list<ActiveObjectMessage>* message_list = NULL;
1578 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1579 n = buffered_messages.find(aom.id);
1582 message_list = new core::list<ActiveObjectMessage>;
1583 buffered_messages.insert(aom.id, message_list);
1587 message_list = n->getValue();
1589 message_list->push_back(aom);
1592 // Route data to every client
1593 for(core::map<u16, RemoteClient*>::Iterator
1594 i = m_clients.getIterator();
1595 i.atEnd()==false; i++)
1597 RemoteClient *client = i.getNode()->getValue();
1598 std::string reliable_data;
1599 std::string unreliable_data;
1600 // Go through all objects in message buffer
1601 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1602 j = buffered_messages.getIterator();
1603 j.atEnd()==false; j++)
1605 // If object is not known by client, skip it
1606 u16 id = j.getNode()->getKey();
1607 if(client->m_known_objects.find(id) == NULL)
1609 // Get message list of object
1610 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1611 // Go through every message
1612 for(core::list<ActiveObjectMessage>::Iterator
1613 k = list->begin(); k != list->end(); k++)
1615 // Compose the full new data with header
1616 ActiveObjectMessage aom = *k;
1617 std::string new_data;
1620 writeU16((u8*)&buf[0], aom.id);
1621 new_data.append(buf, 2);
1623 new_data += serializeString(aom.datastring);
1624 // Add data to buffer
1626 reliable_data += new_data;
1628 unreliable_data += new_data;
1632 reliable_data and unreliable_data are now ready.
1635 if(reliable_data.size() > 0)
1637 SharedBuffer<u8> reply(2 + reliable_data.size());
1638 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1639 memcpy((char*)&reply[2], reliable_data.c_str(),
1640 reliable_data.size());
1642 m_con.Send(client->peer_id, 0, reply, true);
1644 if(unreliable_data.size() > 0)
1646 SharedBuffer<u8> reply(2 + unreliable_data.size());
1647 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1648 memcpy((char*)&reply[2], unreliable_data.c_str(),
1649 unreliable_data.size());
1650 // Send as unreliable
1651 m_con.Send(client->peer_id, 0, reply, false);
1654 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1656 infostream<<"Server: Size of object message data: "
1657 <<"reliable: "<<reliable_data.size()
1658 <<", unreliable: "<<unreliable_data.size()
1663 // Clear buffered_messages
1664 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1665 i = buffered_messages.getIterator();
1666 i.atEnd()==false; i++)
1668 delete i.getNode()->getValue();
1672 } // enable_experimental
1675 Send queued-for-sending map edit events.
1678 // Don't send too many at a time
1681 // Single change sending is disabled if queue size is not small
1682 bool disable_single_change_sending = false;
1683 if(m_unsent_map_edit_queue.size() >= 4)
1684 disable_single_change_sending = true;
1686 int event_count = m_unsent_map_edit_queue.size();
1688 // We'll log the amount of each
1691 while(m_unsent_map_edit_queue.size() != 0)
1693 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1695 // Players far away from the change are stored here.
1696 // Instead of sending the changes, MapBlocks are set not sent
1698 core::list<u16> far_players;
1700 if(event->type == MEET_ADDNODE)
1702 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1703 prof.add("MEET_ADDNODE", 1);
1704 if(disable_single_change_sending)
1705 sendAddNode(event->p, event->n, event->already_known_by_peer,
1708 sendAddNode(event->p, event->n, event->already_known_by_peer,
1711 else if(event->type == MEET_REMOVENODE)
1713 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1714 prof.add("MEET_REMOVENODE", 1);
1715 if(disable_single_change_sending)
1716 sendRemoveNode(event->p, event->already_known_by_peer,
1719 sendRemoveNode(event->p, event->already_known_by_peer,
1722 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1724 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1725 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1726 setBlockNotSent(event->p);
1728 else if(event->type == MEET_OTHER)
1730 infostream<<"Server: MEET_OTHER"<<std::endl;
1731 prof.add("MEET_OTHER", 1);
1732 for(core::map<v3s16, bool>::Iterator
1733 i = event->modified_blocks.getIterator();
1734 i.atEnd()==false; i++)
1736 v3s16 p = i.getNode()->getKey();
1742 prof.add("unknown", 1);
1743 infostream<<"WARNING: Server: Unknown MapEditEvent "
1744 <<((u32)event->type)<<std::endl;
1748 Set blocks not sent to far players
1750 if(far_players.size() > 0)
1752 // Convert list format to that wanted by SetBlocksNotSent
1753 core::map<v3s16, MapBlock*> modified_blocks2;
1754 for(core::map<v3s16, bool>::Iterator
1755 i = event->modified_blocks.getIterator();
1756 i.atEnd()==false; i++)
1758 v3s16 p = i.getNode()->getKey();
1759 modified_blocks2.insert(p,
1760 m_env->getMap().getBlockNoCreateNoEx(p));
1762 // Set blocks not sent
1763 for(core::list<u16>::Iterator
1764 i = far_players.begin();
1765 i != far_players.end(); i++)
1768 RemoteClient *client = getClient(peer_id);
1771 client->SetBlocksNotSent(modified_blocks2);
1777 /*// Don't send too many at a time
1779 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1783 if(event_count >= 5){
1784 infostream<<"Server: MapEditEvents:"<<std::endl;
1785 prof.print(infostream);
1786 } else if(event_count != 0){
1787 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1788 prof.print(verbosestream);
1794 Trigger emergethread (it somehow gets to a non-triggered but
1795 bysy state sometimes)
1798 float &counter = m_emergethread_trigger_timer;
1804 m_emergethread.trigger();
1808 // Save map, players and auth stuff
1810 float &counter = m_savemap_timer;
1812 if(counter >= g_settings->getFloat("server_map_save_interval"))
1815 JMutexAutoLock lock(m_env_mutex);
1817 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1820 if(m_authmanager.isModified())
1821 m_authmanager.save();
1824 if(m_banmanager.isModified())
1825 m_banmanager.save();
1827 // Save changed parts of map
1828 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1831 m_env->serializePlayers(m_path_world);
1833 // Save environment metadata
1834 m_env->saveMeta(m_path_world);
1839 void Server::Receive()
1841 DSTACK(__FUNCTION_NAME);
1842 SharedBuffer<u8> data;
1847 JMutexAutoLock conlock(m_con_mutex);
1848 datasize = m_con.Receive(peer_id, data);
1851 // This has to be called so that the client list gets synced
1852 // with the peer list of the connection
1853 handlePeerChanges();
1855 ProcessData(*data, datasize, peer_id);
1857 catch(con::InvalidIncomingDataException &e)
1859 infostream<<"Server::Receive(): "
1860 "InvalidIncomingDataException: what()="
1861 <<e.what()<<std::endl;
1863 catch(con::PeerNotFoundException &e)
1865 //NOTE: This is not needed anymore
1867 // The peer has been disconnected.
1868 // Find the associated player and remove it.
1870 /*JMutexAutoLock envlock(m_env_mutex);
1872 infostream<<"ServerThread: peer_id="<<peer_id
1873 <<" has apparently closed connection. "
1874 <<"Removing player."<<std::endl;
1876 m_env->removePlayer(peer_id);*/
1880 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1882 DSTACK(__FUNCTION_NAME);
1883 // Environment is locked first.
1884 JMutexAutoLock envlock(m_env_mutex);
1885 JMutexAutoLock conlock(m_con_mutex);
1887 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1890 Address address = m_con.GetPeerAddress(peer_id);
1892 // drop player if is ip is banned
1893 if(m_banmanager.isIpBanned(address.serializeString())){
1894 SendAccessDenied(m_con, peer_id,
1895 L"Your ip is banned. Banned name was "
1896 +narrow_to_wide(m_banmanager.getBanName(
1897 address.serializeString())));
1898 m_con.DeletePeer(peer_id);
1902 catch(con::PeerNotFoundException &e)
1904 infostream<<"Server::ProcessData(): Cancelling: peer "
1905 <<peer_id<<" not found"<<std::endl;
1909 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1911 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1919 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1921 if(command == TOSERVER_INIT)
1923 // [0] u16 TOSERVER_INIT
1924 // [2] u8 SER_FMT_VER_HIGHEST
1925 // [3] u8[20] player_name
1926 // [23] u8[28] password <--- can be sent without this, from old versions
1928 if(datasize < 2+1+PLAYERNAME_SIZE)
1931 verbosestream<<"Server: Got TOSERVER_INIT from "
1932 <<peer_id<<std::endl;
1934 // First byte after command is maximum supported
1935 // serialization version
1936 u8 client_max = data[2];
1937 u8 our_max = SER_FMT_VER_HIGHEST;
1938 // Use the highest version supported by both
1939 u8 deployed = core::min_(client_max, our_max);
1940 // If it's lower than the lowest supported, give up.
1941 if(deployed < SER_FMT_VER_LOWEST)
1942 deployed = SER_FMT_VER_INVALID;
1944 //peer->serialization_version = deployed;
1945 getClient(peer_id)->pending_serialization_version = deployed;
1947 if(deployed == SER_FMT_VER_INVALID)
1949 actionstream<<"Server: A mismatched client tried to connect from "
1950 <<addr_s<<std::endl;
1951 infostream<<"Server: Cannot negotiate "
1952 "serialization version with peer "
1953 <<peer_id<<std::endl;
1954 SendAccessDenied(m_con, peer_id, std::wstring(
1955 L"Your client's version is not supported.\n"
1956 L"Server version is ")
1957 + narrow_to_wide(VERSION_STRING) + L"."
1963 Read and check network protocol version
1966 u16 net_proto_version = 0;
1967 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1969 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1972 getClient(peer_id)->net_proto_version = net_proto_version;
1974 if(net_proto_version == 0)
1976 actionstream<<"Server: An old tried to connect from "<<addr_s
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"."
1986 if(g_settings->getBool("strict_protocol_version_checking"))
1988 if(net_proto_version != PROTOCOL_VERSION)
1990 actionstream<<"Server: A mismatched client tried to connect"
1991 <<" from "<<addr_s<<std::endl;
1992 SendAccessDenied(m_con, peer_id, std::wstring(
1993 L"Your client's version is not supported.\n"
1994 L"Server version is ")
1995 + narrow_to_wide(VERSION_STRING) + L",\n"
1996 + L"server's PROTOCOL_VERSION is "
1997 + narrow_to_wide(itos(PROTOCOL_VERSION))
1998 + L", client's PROTOCOL_VERSION is "
1999 + narrow_to_wide(itos(net_proto_version))
2010 char playername[PLAYERNAME_SIZE];
2011 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2013 playername[i] = data[3+i];
2015 playername[PLAYERNAME_SIZE-1] = 0;
2017 if(playername[0]=='\0')
2019 actionstream<<"Server: Player with an empty name "
2020 <<"tried to connect from "<<addr_s<<std::endl;
2021 SendAccessDenied(m_con, peer_id,
2026 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2028 actionstream<<"Server: Player with an invalid name "
2029 <<"tried to connect from "<<addr_s<<std::endl;
2030 SendAccessDenied(m_con, peer_id,
2031 L"Name contains unallowed characters");
2035 infostream<<"Server: New connection: \""<<playername<<"\" from "
2036 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2039 char password[PASSWORD_SIZE];
2040 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2042 // old version - assume blank password
2047 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2049 password[i] = data[23+i];
2051 password[PASSWORD_SIZE-1] = 0;
2054 // Add player to auth manager
2055 if(m_authmanager.exists(playername) == false)
2057 std::wstring default_password =
2058 narrow_to_wide(g_settings->get("default_password"));
2059 std::string translated_default_password =
2060 translatePassword(playername, default_password);
2062 // If default_password is empty, allow any initial password
2063 if (default_password.length() == 0)
2064 translated_default_password = password;
2066 infostream<<"Server: adding player "<<playername
2067 <<" to auth manager"<<std::endl;
2068 m_authmanager.add(playername);
2069 m_authmanager.setPassword(playername, translated_default_password);
2070 m_authmanager.setPrivs(playername,
2071 stringToPrivs(g_settings->get("default_privs")));
2072 m_authmanager.save();
2075 std::string checkpwd = m_authmanager.getPassword(playername);
2077 /*infostream<<"Server: Client gave password '"<<password
2078 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2080 if(password != checkpwd)
2082 infostream<<"Server: peer_id="<<peer_id
2083 <<": supplied invalid password for "
2084 <<playername<<std::endl;
2085 SendAccessDenied(m_con, peer_id, L"Invalid password");
2089 // Enforce user limit.
2090 // Don't enforce for users that have some admin right
2091 if(m_clients.size() >= g_settings->getU16("max_users") &&
2092 (m_authmanager.getPrivs(playername)
2093 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2094 playername != g_settings->get("name"))
2096 actionstream<<"Server: "<<playername<<" tried to join, but there"
2097 <<" are already max_users="
2098 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2099 SendAccessDenied(m_con, peer_id, L"Too many users.");
2104 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2106 // If failed, cancel
2109 errorstream<<"Server: peer_id="<<peer_id
2110 <<": failed to emerge player"<<std::endl;
2115 Answer with a TOCLIENT_INIT
2118 SharedBuffer<u8> reply(2+1+6+8);
2119 writeU16(&reply[0], TOCLIENT_INIT);
2120 writeU8(&reply[2], deployed);
2121 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2122 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2125 m_con.Send(peer_id, 0, reply, true);
2129 Send complete position information
2131 SendMovePlayer(player);
2136 if(command == TOSERVER_INIT2)
2138 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2139 <<peer_id<<std::endl;
2142 getClient(peer_id)->serialization_version
2143 = getClient(peer_id)->pending_serialization_version;
2146 Send some initialization data
2149 infostream<<"Server: Sending content to "
2150 <<getPlayerName(peer_id)<<std::endl;
2152 // Send item definitions
2153 SendItemDef(m_con, peer_id, m_itemdef);
2155 // Send node definitions
2156 SendNodeDef(m_con, peer_id, m_nodedef);
2158 // Send texture announcement
2159 SendTextureAnnouncement(peer_id);
2161 // Send player info to all players
2162 //SendPlayerInfos();
2164 // Send inventory to player
2165 UpdateCrafting(peer_id);
2166 SendInventory(peer_id);
2168 // Send player items to all players
2171 Player *player = m_env->getPlayer(peer_id);
2174 SendPlayerHP(player);
2176 // Show death screen if necessary
2178 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2182 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2183 m_env->getTimeOfDay());
2184 m_con.Send(peer_id, 0, data, true);
2187 // Send information about server to player in chat
2188 SendChatMessage(peer_id, getStatusString());
2190 // Send information about joining in chat
2192 std::wstring name = L"unknown";
2193 Player *player = m_env->getPlayer(peer_id);
2195 name = narrow_to_wide(player->getName());
2197 std::wstring message;
2200 message += L" joined game";
2201 BroadcastChatMessage(message);
2204 // Warnings about protocol version can be issued here
2205 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2207 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2214 std::ostringstream os(std::ios_base::binary);
2215 for(core::map<u16, RemoteClient*>::Iterator
2216 i = m_clients.getIterator();
2217 i.atEnd() == false; i++)
2219 RemoteClient *client = i.getNode()->getValue();
2220 assert(client->peer_id == i.getNode()->getKey());
2221 if(client->serialization_version == SER_FMT_VER_INVALID)
2224 Player *player = m_env->getPlayer(client->peer_id);
2227 // Get name of player
2228 os<<player->getName()<<" ";
2231 actionstream<<player->getName()<<" joins game. List of players: "
2232 <<os.str()<<std::endl;
2238 if(peer_ser_ver == SER_FMT_VER_INVALID)
2240 infostream<<"Server::ProcessData(): Cancelling: Peer"
2241 " serialization format invalid or not initialized."
2242 " Skipping incoming command="<<command<<std::endl;
2246 Player *player = m_env->getPlayer(peer_id);
2247 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2250 infostream<<"Server::ProcessData(): Cancelling: "
2251 "No player for peer_id="<<peer_id
2255 if(command == TOSERVER_PLAYERPOS)
2257 if(datasize < 2+12+12+4+4)
2261 v3s32 ps = readV3S32(&data[start+2]);
2262 v3s32 ss = readV3S32(&data[start+2+12]);
2263 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2264 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2265 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2266 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2267 pitch = wrapDegrees(pitch);
2268 yaw = wrapDegrees(yaw);
2270 player->setPosition(position);
2271 player->setSpeed(speed);
2272 player->setPitch(pitch);
2273 player->setYaw(yaw);
2275 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2276 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2277 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2279 else if(command == TOSERVER_GOTBLOCKS)
2292 u16 count = data[2];
2293 for(u16 i=0; i<count; i++)
2295 if((s16)datasize < 2+1+(i+1)*6)
2296 throw con::InvalidIncomingDataException
2297 ("GOTBLOCKS length is too short");
2298 v3s16 p = readV3S16(&data[2+1+i*6]);
2299 /*infostream<<"Server: GOTBLOCKS ("
2300 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2301 RemoteClient *client = getClient(peer_id);
2302 client->GotBlock(p);
2305 else if(command == TOSERVER_DELETEDBLOCKS)
2318 u16 count = data[2];
2319 for(u16 i=0; i<count; i++)
2321 if((s16)datasize < 2+1+(i+1)*6)
2322 throw con::InvalidIncomingDataException
2323 ("DELETEDBLOCKS length is too short");
2324 v3s16 p = readV3S16(&data[2+1+i*6]);
2325 /*infostream<<"Server: DELETEDBLOCKS ("
2326 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2327 RemoteClient *client = getClient(peer_id);
2328 client->SetBlockNotSent(p);
2331 else if(command == TOSERVER_CLICK_OBJECT)
2333 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2336 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2338 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2341 else if(command == TOSERVER_GROUND_ACTION)
2343 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2347 else if(command == TOSERVER_RELEASE)
2349 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2352 else if(command == TOSERVER_SIGNTEXT)
2354 infostream<<"Server: SIGNTEXT not supported anymore"
2358 else if(command == TOSERVER_SIGNNODETEXT)
2360 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2368 std::string datastring((char*)&data[2], datasize-2);
2369 std::istringstream is(datastring, std::ios_base::binary);
2372 is.read((char*)buf, 6);
2373 v3s16 p = readV3S16(buf);
2374 is.read((char*)buf, 2);
2375 u16 textlen = readU16(buf);
2377 for(u16 i=0; i<textlen; i++)
2379 is.read((char*)buf, 1);
2380 text += (char)buf[0];
2383 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2387 meta->setText(text);
2389 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2390 <<" at "<<PP(p)<<std::endl;
2392 v3s16 blockpos = getNodeBlockPos(p);
2393 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2396 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2400 setBlockNotSent(blockpos);
2402 else if(command == TOSERVER_INVENTORY_ACTION)
2404 // Strip command and create a stream
2405 std::string datastring((char*)&data[2], datasize-2);
2406 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2407 std::istringstream is(datastring, std::ios_base::binary);
2409 InventoryAction *a = InventoryAction::deSerialize(is);
2412 infostream<<"TOSERVER_INVENTORY_ACTION: "
2413 <<"InventoryAction::deSerialize() returned NULL"
2419 Note: Always set inventory not sent, to repair cases
2420 where the client made a bad prediction.
2424 Handle restrictions and special cases of the move action
2426 if(a->getType() == IACTION_MOVE)
2428 IMoveAction *ma = (IMoveAction*)a;
2430 ma->from_inv.applyCurrentPlayer(player->getName());
2431 ma->to_inv.applyCurrentPlayer(player->getName());
2433 setInventoryModified(ma->from_inv);
2434 setInventoryModified(ma->to_inv);
2436 bool from_inv_is_current_player =
2437 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2438 (ma->from_inv.name == player->getName());
2440 bool to_inv_is_current_player =
2441 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2442 (ma->to_inv.name == player->getName());
2445 Disable moving items out of craftpreview
2447 if(ma->from_list == "craftpreview")
2449 infostream<<"Ignoring IMoveAction from "
2450 <<(ma->from_inv.dump())<<":"<<ma->from_list
2451 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2452 <<" because src is "<<ma->from_list<<std::endl;
2458 Disable moving items into craftresult and craftpreview
2460 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2462 infostream<<"Ignoring IMoveAction from "
2463 <<(ma->from_inv.dump())<<":"<<ma->from_list
2464 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2465 <<" because dst is "<<ma->to_list<<std::endl;
2470 // Disallow moving items in elsewhere than player's inventory
2471 // if not allowed to interact
2472 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2473 && (!from_inv_is_current_player
2474 || !to_inv_is_current_player))
2476 infostream<<"Cannot move outside of player's inventory: "
2477 <<"No interact privilege"<<std::endl;
2482 // If player is not an admin, check for ownership of src and dst
2483 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2485 std::string owner_from = getInventoryOwner(ma->from_inv);
2486 if(owner_from != "" && owner_from != player->getName())
2488 infostream<<"WARNING: "<<player->getName()
2489 <<" tried to access an inventory that"
2490 <<" belongs to "<<owner_from<<std::endl;
2495 std::string owner_to = getInventoryOwner(ma->to_inv);
2496 if(owner_to != "" && owner_to != player->getName())
2498 infostream<<"WARNING: "<<player->getName()
2499 <<" tried to access an inventory that"
2500 <<" belongs to "<<owner_to<<std::endl;
2507 Handle restrictions and special cases of the drop action
2509 else if(a->getType() == IACTION_DROP)
2511 IDropAction *da = (IDropAction*)a;
2513 da->from_inv.applyCurrentPlayer(player->getName());
2515 setInventoryModified(da->from_inv);
2517 // Disallow dropping items if not allowed to interact
2518 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2523 // If player is not an admin, check for ownership
2524 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2526 std::string owner_from = getInventoryOwner(da->from_inv);
2527 if(owner_from != "" && owner_from != player->getName())
2529 infostream<<"WARNING: "<<player->getName()
2530 <<" tried to access an inventory that"
2531 <<" belongs to "<<owner_from<<std::endl;
2538 Handle restrictions and special cases of the craft action
2540 else if(a->getType() == IACTION_CRAFT)
2542 ICraftAction *ca = (ICraftAction*)a;
2544 ca->craft_inv.applyCurrentPlayer(player->getName());
2546 setInventoryModified(ca->craft_inv);
2548 //bool craft_inv_is_current_player =
2549 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2550 // (ca->craft_inv.name == player->getName());
2552 // Disallow crafting if not allowed to interact
2553 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2555 infostream<<"Cannot craft: "
2556 <<"No interact privilege"<<std::endl;
2561 // If player is not an admin, check for ownership of inventory
2562 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2564 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2565 if(owner_craft != "" && owner_craft != player->getName())
2567 infostream<<"WARNING: "<<player->getName()
2568 <<" tried to access an inventory that"
2569 <<" belongs to "<<owner_craft<<std::endl;
2577 a->apply(this, srp, this);
2581 else if(command == TOSERVER_CHAT_MESSAGE)
2589 std::string datastring((char*)&data[2], datasize-2);
2590 std::istringstream is(datastring, std::ios_base::binary);
2593 is.read((char*)buf, 2);
2594 u16 len = readU16(buf);
2596 std::wstring message;
2597 for(u16 i=0; i<len; i++)
2599 is.read((char*)buf, 2);
2600 message += (wchar_t)readU16(buf);
2603 // Get player name of this client
2604 std::wstring name = narrow_to_wide(player->getName());
2607 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2608 wide_to_narrow(message));
2609 // If script ate the message, don't proceed
2613 // Line to send to players
2615 // Whether to send to the player that sent the line
2616 bool send_to_sender = false;
2617 // Whether to send to other players
2618 bool send_to_others = false;
2620 // Local player gets all privileges regardless of
2621 // what's set on their account.
2622 u64 privs = getPlayerPrivs(player);
2625 if(message[0] == L'/')
2627 size_t strip_size = 1;
2628 if (message[1] == L'#') // support old-style commans
2630 message = message.substr(strip_size);
2632 WStrfnd f1(message);
2633 f1.next(L" "); // Skip over /#whatever
2634 std::wstring paramstring = f1.next(L"");
2636 ServerCommandContext *ctx = new ServerCommandContext(
2637 str_split(message, L' '),
2644 std::wstring reply(processServerCommand(ctx));
2645 send_to_sender = ctx->flags & SEND_TO_SENDER;
2646 send_to_others = ctx->flags & SEND_TO_OTHERS;
2648 if (ctx->flags & SEND_NO_PREFIX)
2651 line += L"Server: " + reply;
2658 if(privs & PRIV_SHOUT)
2664 send_to_others = true;
2668 line += L"Server: You are not allowed to shout";
2669 send_to_sender = true;
2676 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2679 Send the message to clients
2681 for(core::map<u16, RemoteClient*>::Iterator
2682 i = m_clients.getIterator();
2683 i.atEnd() == false; i++)
2685 // Get client and check that it is valid
2686 RemoteClient *client = i.getNode()->getValue();
2687 assert(client->peer_id == i.getNode()->getKey());
2688 if(client->serialization_version == SER_FMT_VER_INVALID)
2692 bool sender_selected = (peer_id == client->peer_id);
2693 if(sender_selected == true && send_to_sender == false)
2695 if(sender_selected == false && send_to_others == false)
2698 SendChatMessage(client->peer_id, line);
2702 else if(command == TOSERVER_DAMAGE)
2704 std::string datastring((char*)&data[2], datasize-2);
2705 std::istringstream is(datastring, std::ios_base::binary);
2706 u8 damage = readU8(is);
2708 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2710 if(g_settings->getBool("enable_damage"))
2712 actionstream<<player->getName()<<" damaged by "
2713 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2716 srp->setHP(srp->getHP() - damage);
2718 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2721 if(srp->m_hp_not_sent)
2722 SendPlayerHP(player);
2726 // Force send (to correct the client's predicted HP)
2727 SendPlayerHP(player);
2730 else if(command == TOSERVER_PASSWORD)
2733 [0] u16 TOSERVER_PASSWORD
2734 [2] u8[28] old password
2735 [30] u8[28] new password
2738 if(datasize != 2+PASSWORD_SIZE*2)
2740 /*char password[PASSWORD_SIZE];
2741 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2742 password[i] = data[2+i];
2743 password[PASSWORD_SIZE-1] = 0;*/
2745 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2753 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2755 char c = data[2+PASSWORD_SIZE+i];
2761 infostream<<"Server: Client requests a password change from "
2762 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2764 std::string playername = player->getName();
2766 if(m_authmanager.exists(playername) == false)
2768 infostream<<"Server: playername not found in authmanager"<<std::endl;
2769 // Wrong old password supplied!!
2770 SendChatMessage(peer_id, L"playername not found in authmanager");
2774 std::string checkpwd = m_authmanager.getPassword(playername);
2776 if(oldpwd != checkpwd)
2778 infostream<<"Server: invalid old password"<<std::endl;
2779 // Wrong old password supplied!!
2780 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2784 actionstream<<player->getName()<<" changes password"<<std::endl;
2786 m_authmanager.setPassword(playername, newpwd);
2788 infostream<<"Server: password change successful for "<<playername
2790 SendChatMessage(peer_id, L"Password change successful");
2792 else if(command == TOSERVER_PLAYERITEM)
2797 u16 item = readU16(&data[2]);
2798 srp->setWieldIndex(item);
2799 SendWieldedItem(srp);
2801 else if(command == TOSERVER_RESPAWN)
2806 RespawnPlayer(player);
2808 actionstream<<player->getName()<<" respawns at "
2809 <<PP(player->getPosition()/BS)<<std::endl;
2811 // ActiveObject is added to environment in AsyncRunStep after
2812 // the previous addition has been succesfully removed
2814 else if(command == TOSERVER_REQUEST_TEXTURES) {
2815 std::string datastring((char*)&data[2], datasize-2);
2816 std::istringstream is(datastring, std::ios_base::binary);
2819 core::list<TextureRequest> tosend;
2820 u16 numtextures = readU16(is);
2822 infostream<<"Sending "<<numtextures<<" textures to "
2823 <<getPlayerName(peer_id)<<std::endl;
2824 verbosestream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2826 for(int i = 0; i < numtextures; i++) {
2827 std::string name = deSerializeString(is);
2828 tosend.push_back(TextureRequest(name));
2829 verbosestream<<"TOSERVER_REQUEST_TEXTURES: requested texture "
2833 SendTexturesRequested(peer_id, tosend);
2835 // Now the client should know about everything
2836 // (definitions and textures)
2837 getClient(peer_id)->definitions_sent = true;
2839 else if(command == TOSERVER_INTERACT)
2841 std::string datastring((char*)&data[2], datasize-2);
2842 std::istringstream is(datastring, std::ios_base::binary);
2848 [5] u32 length of the next item
2849 [9] serialized PointedThing
2851 0: start digging (from undersurface) or use
2852 1: stop digging (all parameters ignored)
2853 2: digging completed
2854 3: place block or item (to abovesurface)
2857 u8 action = readU8(is);
2858 u16 item_i = readU16(is);
2859 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2860 PointedThing pointed;
2861 pointed.deSerialize(tmp_is);
2863 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2864 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2868 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2869 <<" tried to interact, but is dead!"<<std::endl;
2873 v3f player_pos = srp->m_last_good_position;
2875 // Update wielded item
2876 if(srp->getWieldIndex() != item_i)
2878 srp->setWieldIndex(item_i);
2879 SendWieldedItem(srp);
2882 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2883 v3s16 p_under = pointed.node_undersurface;
2884 v3s16 p_above = pointed.node_abovesurface;
2886 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2887 ServerActiveObject *pointed_object = NULL;
2888 if(pointed.type == POINTEDTHING_OBJECT)
2890 pointed_object = m_env->getActiveObject(pointed.object_id);
2891 if(pointed_object == NULL)
2893 verbosestream<<"TOSERVER_INTERACT: "
2894 "pointed object is NULL"<<std::endl;
2900 v3f pointed_pos_under = player_pos;
2901 v3f pointed_pos_above = player_pos;
2902 if(pointed.type == POINTEDTHING_NODE)
2904 pointed_pos_under = intToFloat(p_under, BS);
2905 pointed_pos_above = intToFloat(p_above, BS);
2907 else if(pointed.type == POINTEDTHING_OBJECT)
2909 pointed_pos_under = pointed_object->getBasePosition();
2910 pointed_pos_above = pointed_pos_under;
2914 Check that target is reasonably close
2915 (only when digging or placing things)
2917 if(action == 0 || action == 2 || action == 3)
2919 float d = player_pos.getDistanceFrom(pointed_pos_under);
2920 float max_d = BS * 14; // Just some large enough value
2922 actionstream<<"Player "<<player->getName()
2923 <<" tried to access "<<pointed.dump()
2925 <<"d="<<d<<", max_d="<<max_d
2926 <<". ignoring."<<std::endl;
2927 // Re-send block to revert change on client-side
2928 RemoteClient *client = getClient(peer_id);
2929 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2930 client->SetBlockNotSent(blockpos);
2937 Make sure the player is allowed to do it
2939 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2941 infostream<<"Ignoring interaction from player "<<player->getName()
2942 <<" because privileges are "<<getPlayerPrivs(player)
2948 0: start digging or punch object
2952 if(pointed.type == POINTEDTHING_NODE)
2955 NOTE: This can be used in the future to check if
2956 somebody is cheating, by checking the timing.
2958 MapNode n(CONTENT_IGNORE);
2961 n = m_env->getMap().getNode(p_under);
2963 catch(InvalidPositionException &e)
2965 infostream<<"Server: Not punching: Node not found."
2966 <<" Adding block to emerge queue."
2968 m_emerge_queue.addBlock(peer_id,
2969 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2971 if(n.getContent() != CONTENT_IGNORE)
2972 scriptapi_node_on_punch(m_lua, p_under, n, srp);
2974 else if(pointed.type == POINTEDTHING_OBJECT)
2976 // Skip if object has been removed
2977 if(pointed_object->m_removed)
2980 actionstream<<player->getName()<<" punches object "
2981 <<pointed.object_id<<": "
2982 <<pointed_object->getDescription()<<std::endl;
2984 ItemStack punchitem = srp->getWieldedItem();
2985 ToolCapabilities toolcap =
2986 punchitem.getToolCapabilities(m_itemdef);
2987 v3f dir = (pointed_object->getBasePosition() -
2988 (srp->getPosition() + srp->getEyeOffset())
2990 pointed_object->punch(dir, &toolcap, srp,
2991 srp->m_time_from_last_punch);
2992 srp->m_time_from_last_punch = 0;
3000 else if(action == 1)
3005 2: Digging completed
3007 else if(action == 2)
3009 // Only complete digging of nodes
3010 if(pointed.type == POINTEDTHING_NODE)
3012 MapNode n(CONTENT_IGNORE);
3015 n = m_env->getMap().getNode(p_under);
3017 catch(InvalidPositionException &e)
3019 infostream<<"Server: Not finishing digging: Node not found."
3020 <<" Adding block to emerge queue."
3022 m_emerge_queue.addBlock(peer_id,
3023 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3025 if(n.getContent() != CONTENT_IGNORE)
3026 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3031 3: place block or right-click object
3033 else if(action == 3)
3035 ItemStack item = srp->getWieldedItem();
3037 // Reset build time counter
3038 if(pointed.type == POINTEDTHING_NODE &&
3039 item.getDefinition(m_itemdef).type == ITEM_NODE)
3040 getClient(peer_id)->m_time_from_building = 0.0;
3042 if(pointed.type == POINTEDTHING_OBJECT)
3044 // Right click object
3046 // Skip if object has been removed
3047 if(pointed_object->m_removed)
3050 actionstream<<player->getName()<<" right-clicks object "
3051 <<pointed.object_id<<": "
3052 <<pointed_object->getDescription()<<std::endl;
3055 pointed_object->rightClick(srp);
3057 else if(scriptapi_item_on_place(m_lua,
3058 item, srp, pointed))
3060 // Placement was handled in lua
3062 // Apply returned ItemStack
3063 if(g_settings->getBool("creative_mode") == false)
3064 srp->setWieldedItem(item);
3072 else if(action == 4)
3074 ItemStack item = srp->getWieldedItem();
3076 actionstream<<player->getName()<<" uses "<<item.name
3077 <<", pointing at "<<pointed.dump()<<std::endl;
3079 if(scriptapi_item_on_use(m_lua,
3080 item, srp, pointed))
3082 // Apply returned ItemStack
3083 if(g_settings->getBool("creative_mode") == false)
3084 srp->setWieldedItem(item);
3090 Catch invalid actions
3094 infostream<<"WARNING: Server: Invalid action "
3095 <<action<<std::endl;
3100 infostream<<"Server::ProcessData(): Ignoring "
3101 "unknown command "<<command<<std::endl;
3105 catch(SendFailedException &e)
3107 errorstream<<"Server::ProcessData(): SendFailedException: "
3113 void Server::onMapEditEvent(MapEditEvent *event)
3115 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3116 if(m_ignore_map_edit_events)
3118 MapEditEvent *e = event->clone();
3119 m_unsent_map_edit_queue.push_back(e);
3122 Inventory* Server::getInventory(const InventoryLocation &loc)
3125 case InventoryLocation::UNDEFINED:
3128 case InventoryLocation::CURRENT_PLAYER:
3131 case InventoryLocation::PLAYER:
3133 Player *player = m_env->getPlayer(loc.name.c_str());
3136 return &player->inventory;
3139 case InventoryLocation::NODEMETA:
3141 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3144 return meta->getInventory();
3152 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3155 case InventoryLocation::UNDEFINED:
3158 case InventoryLocation::CURRENT_PLAYER:
3161 case InventoryLocation::PLAYER:
3166 case InventoryLocation::NODEMETA:
3168 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3171 return meta->getOwner();
3179 void Server::setInventoryModified(const InventoryLocation &loc)
3182 case InventoryLocation::UNDEFINED:
3185 case InventoryLocation::PLAYER:
3187 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3188 (m_env->getPlayer(loc.name.c_str()));
3191 srp->m_inventory_not_sent = true;
3194 case InventoryLocation::NODEMETA:
3196 v3s16 blockpos = getNodeBlockPos(loc.p);
3198 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3200 meta->inventoryModified();
3202 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3204 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3206 setBlockNotSent(blockpos);
3214 core::list<PlayerInfo> Server::getPlayerInfo()
3216 DSTACK(__FUNCTION_NAME);
3217 JMutexAutoLock envlock(m_env_mutex);
3218 JMutexAutoLock conlock(m_con_mutex);
3220 core::list<PlayerInfo> list;
3222 core::list<Player*> players = m_env->getPlayers();
3224 core::list<Player*>::Iterator i;
3225 for(i = players.begin();
3226 i != players.end(); i++)
3230 Player *player = *i;
3233 // Copy info from connection to info struct
3234 info.id = player->peer_id;
3235 info.address = m_con.GetPeerAddress(player->peer_id);
3236 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3238 catch(con::PeerNotFoundException &e)
3240 // Set dummy peer info
3242 info.address = Address(0,0,0,0,0);
3246 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3247 info.position = player->getPosition();
3249 list.push_back(info);
3256 void Server::peerAdded(con::Peer *peer)
3258 DSTACK(__FUNCTION_NAME);
3259 verbosestream<<"Server::peerAdded(): peer->id="
3260 <<peer->id<<std::endl;
3263 c.type = PEER_ADDED;
3264 c.peer_id = peer->id;
3266 m_peer_change_queue.push_back(c);
3269 void Server::deletingPeer(con::Peer *peer, bool timeout)
3271 DSTACK(__FUNCTION_NAME);
3272 verbosestream<<"Server::deletingPeer(): peer->id="
3273 <<peer->id<<", timeout="<<timeout<<std::endl;
3276 c.type = PEER_REMOVED;
3277 c.peer_id = peer->id;
3278 c.timeout = timeout;
3279 m_peer_change_queue.push_back(c);
3286 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3288 DSTACK(__FUNCTION_NAME);
3289 std::ostringstream os(std::ios_base::binary);
3291 writeU16(os, TOCLIENT_HP);
3295 std::string s = os.str();
3296 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3298 con.Send(peer_id, 0, data, true);
3301 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3302 const std::wstring &reason)
3304 DSTACK(__FUNCTION_NAME);
3305 std::ostringstream os(std::ios_base::binary);
3307 writeU16(os, TOCLIENT_ACCESS_DENIED);
3308 os<<serializeWideString(reason);
3311 std::string s = os.str();
3312 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3314 con.Send(peer_id, 0, data, true);
3317 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3318 bool set_camera_point_target, v3f camera_point_target)
3320 DSTACK(__FUNCTION_NAME);
3321 std::ostringstream os(std::ios_base::binary);
3323 writeU16(os, TOCLIENT_DEATHSCREEN);
3324 writeU8(os, set_camera_point_target);
3325 writeV3F1000(os, camera_point_target);
3328 std::string s = os.str();
3329 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3331 con.Send(peer_id, 0, data, true);
3334 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3335 IItemDefManager *itemdef)
3337 DSTACK(__FUNCTION_NAME);
3338 std::ostringstream os(std::ios_base::binary);
3342 u32 length of the next item
3343 zlib-compressed serialized ItemDefManager
3345 writeU16(os, TOCLIENT_ITEMDEF);
3346 std::ostringstream tmp_os(std::ios::binary);
3347 itemdef->serialize(tmp_os);
3348 std::ostringstream tmp_os2(std::ios::binary);
3349 compressZlib(tmp_os.str(), tmp_os2);
3350 os<<serializeLongString(tmp_os2.str());
3353 std::string s = os.str();
3354 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3355 <<"): size="<<s.size()<<std::endl;
3356 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3358 con.Send(peer_id, 0, data, true);
3361 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3362 INodeDefManager *nodedef)
3364 DSTACK(__FUNCTION_NAME);
3365 std::ostringstream os(std::ios_base::binary);
3369 u32 length of the next item
3370 zlib-compressed serialized NodeDefManager
3372 writeU16(os, TOCLIENT_NODEDEF);
3373 std::ostringstream tmp_os(std::ios::binary);
3374 nodedef->serialize(tmp_os);
3375 std::ostringstream tmp_os2(std::ios::binary);
3376 compressZlib(tmp_os.str(), tmp_os2);
3377 os<<serializeLongString(tmp_os2.str());
3380 std::string s = os.str();
3381 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3382 <<"): size="<<s.size()<<std::endl;
3383 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3385 con.Send(peer_id, 0, data, true);
3389 Non-static send methods
3392 void Server::SendInventory(u16 peer_id)
3394 DSTACK(__FUNCTION_NAME);
3396 ServerRemotePlayer* player =
3397 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3400 player->m_inventory_not_sent = false;
3406 std::ostringstream os;
3407 //os.imbue(std::locale("C"));
3409 player->inventory.serialize(os);
3411 std::string s = os.str();
3413 SharedBuffer<u8> data(s.size()+2);
3414 writeU16(&data[0], TOCLIENT_INVENTORY);
3415 memcpy(&data[2], s.c_str(), s.size());
3418 m_con.Send(peer_id, 0, data, true);
3421 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3423 DSTACK(__FUNCTION_NAME);
3427 std::ostringstream os(std::ios_base::binary);
3429 writeU16(os, TOCLIENT_PLAYERITEM);
3431 writeU16(os, srp->peer_id);
3432 os<<serializeString(srp->getWieldedItem().getItemString());
3435 std::string s = os.str();
3436 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3438 m_con.SendToAll(0, data, true);
3441 void Server::SendPlayerItems()
3443 DSTACK(__FUNCTION_NAME);
3445 std::ostringstream os(std::ios_base::binary);
3446 core::list<Player *> players = m_env->getPlayers(true);
3448 writeU16(os, TOCLIENT_PLAYERITEM);
3449 writeU16(os, players.size());
3450 core::list<Player *>::Iterator i;
3451 for(i = players.begin(); i != players.end(); ++i)
3454 ServerRemotePlayer *srp =
3455 static_cast<ServerRemotePlayer*>(p);
3456 writeU16(os, p->peer_id);
3457 os<<serializeString(srp->getWieldedItem().getItemString());
3461 std::string s = os.str();
3462 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3464 m_con.SendToAll(0, data, true);
3467 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3469 DSTACK(__FUNCTION_NAME);
3471 std::ostringstream os(std::ios_base::binary);
3475 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3476 os.write((char*)buf, 2);
3479 writeU16(buf, message.size());
3480 os.write((char*)buf, 2);
3483 for(u32 i=0; i<message.size(); i++)
3487 os.write((char*)buf, 2);
3491 std::string s = os.str();
3492 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3494 m_con.Send(peer_id, 0, data, true);
3497 void Server::BroadcastChatMessage(const std::wstring &message)
3499 for(core::map<u16, RemoteClient*>::Iterator
3500 i = m_clients.getIterator();
3501 i.atEnd() == false; i++)
3503 // Get client and check that it is valid
3504 RemoteClient *client = i.getNode()->getValue();
3505 assert(client->peer_id == i.getNode()->getKey());
3506 if(client->serialization_version == SER_FMT_VER_INVALID)
3509 SendChatMessage(client->peer_id, message);
3513 void Server::SendPlayerHP(Player *player)
3515 SendHP(m_con, player->peer_id, player->hp);
3516 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3519 void Server::SendMovePlayer(Player *player)
3521 DSTACK(__FUNCTION_NAME);
3522 std::ostringstream os(std::ios_base::binary);
3524 writeU16(os, TOCLIENT_MOVE_PLAYER);
3525 writeV3F1000(os, player->getPosition());
3526 writeF1000(os, player->getPitch());
3527 writeF1000(os, player->getYaw());
3530 v3f pos = player->getPosition();
3531 f32 pitch = player->getPitch();
3532 f32 yaw = player->getYaw();
3533 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3534 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3541 std::string s = os.str();
3542 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3544 m_con.Send(player->peer_id, 0, data, true);
3547 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3548 core::list<u16> *far_players, float far_d_nodes)
3550 float maxd = far_d_nodes*BS;
3551 v3f p_f = intToFloat(p, BS);
3555 SharedBuffer<u8> reply(replysize);
3556 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3557 writeS16(&reply[2], p.X);
3558 writeS16(&reply[4], p.Y);
3559 writeS16(&reply[6], p.Z);
3561 for(core::map<u16, RemoteClient*>::Iterator
3562 i = m_clients.getIterator();
3563 i.atEnd() == false; i++)
3565 // Get client and check that it is valid
3566 RemoteClient *client = i.getNode()->getValue();
3567 assert(client->peer_id == i.getNode()->getKey());
3568 if(client->serialization_version == SER_FMT_VER_INVALID)
3571 // Don't send if it's the same one
3572 if(client->peer_id == ignore_id)
3578 Player *player = m_env->getPlayer(client->peer_id);
3581 // If player is far away, only set modified blocks not sent
3582 v3f player_pos = player->getPosition();
3583 if(player_pos.getDistanceFrom(p_f) > maxd)
3585 far_players->push_back(client->peer_id);
3592 m_con.Send(client->peer_id, 0, reply, true);
3596 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3597 core::list<u16> *far_players, float far_d_nodes)
3599 float maxd = far_d_nodes*BS;
3600 v3f p_f = intToFloat(p, BS);
3602 for(core::map<u16, RemoteClient*>::Iterator
3603 i = m_clients.getIterator();
3604 i.atEnd() == false; i++)
3606 // Get client and check that it is valid
3607 RemoteClient *client = i.getNode()->getValue();
3608 assert(client->peer_id == i.getNode()->getKey());
3609 if(client->serialization_version == SER_FMT_VER_INVALID)
3612 // Don't send if it's the same one
3613 if(client->peer_id == ignore_id)
3619 Player *player = m_env->getPlayer(client->peer_id);
3622 // If player is far away, only set modified blocks not sent
3623 v3f player_pos = player->getPosition();
3624 if(player_pos.getDistanceFrom(p_f) > maxd)
3626 far_players->push_back(client->peer_id);
3633 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3634 SharedBuffer<u8> reply(replysize);
3635 writeU16(&reply[0], TOCLIENT_ADDNODE);
3636 writeS16(&reply[2], p.X);
3637 writeS16(&reply[4], p.Y);
3638 writeS16(&reply[6], p.Z);
3639 n.serialize(&reply[8], client->serialization_version);
3642 m_con.Send(client->peer_id, 0, reply, true);
3646 void Server::setBlockNotSent(v3s16 p)
3648 for(core::map<u16, RemoteClient*>::Iterator
3649 i = m_clients.getIterator();
3650 i.atEnd()==false; i++)
3652 RemoteClient *client = i.getNode()->getValue();
3653 client->SetBlockNotSent(p);
3657 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3659 DSTACK(__FUNCTION_NAME);
3661 v3s16 p = block->getPos();
3665 bool completely_air = true;
3666 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3667 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3668 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3670 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3672 completely_air = false;
3673 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3678 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3680 infostream<<"[completely air] ";
3681 infostream<<std::endl;
3685 Create a packet with the block in the right format
3688 std::ostringstream os(std::ios_base::binary);
3689 block->serialize(os, ver, false);
3690 std::string s = os.str();
3691 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3693 u32 replysize = 8 + blockdata.getSize();
3694 SharedBuffer<u8> reply(replysize);
3695 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3696 writeS16(&reply[2], p.X);
3697 writeS16(&reply[4], p.Y);
3698 writeS16(&reply[6], p.Z);
3699 memcpy(&reply[8], *blockdata, blockdata.getSize());
3701 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3702 <<": \tpacket size: "<<replysize<<std::endl;*/
3707 m_con.Send(peer_id, 1, reply, true);
3710 void Server::SendBlocks(float dtime)
3712 DSTACK(__FUNCTION_NAME);
3714 JMutexAutoLock envlock(m_env_mutex);
3715 JMutexAutoLock conlock(m_con_mutex);
3717 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3719 core::array<PrioritySortedBlockTransfer> queue;
3721 s32 total_sending = 0;
3724 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3726 for(core::map<u16, RemoteClient*>::Iterator
3727 i = m_clients.getIterator();
3728 i.atEnd() == false; i++)
3730 RemoteClient *client = i.getNode()->getValue();
3731 assert(client->peer_id == i.getNode()->getKey());
3733 // If definitions and textures have not been sent, don't
3734 // send MapBlocks either
3735 if(!client->definitions_sent)
3738 total_sending += client->SendingCount();
3740 if(client->serialization_version == SER_FMT_VER_INVALID)
3743 client->GetNextBlocks(this, dtime, queue);
3748 // Lowest priority number comes first.
3749 // Lowest is most important.
3752 for(u32 i=0; i<queue.size(); i++)
3754 //TODO: Calculate limit dynamically
3755 if(total_sending >= g_settings->getS32
3756 ("max_simultaneous_block_sends_server_total"))
3759 PrioritySortedBlockTransfer q = queue[i];
3761 MapBlock *block = NULL;
3764 block = m_env->getMap().getBlockNoCreate(q.pos);
3766 catch(InvalidPositionException &e)
3771 RemoteClient *client = getClient(q.peer_id);
3773 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3775 client->SentBlock(q.pos);
3781 void Server::PrepareTextures()
3783 DSTACK(__FUNCTION_NAME);
3785 infostream<<"Server: Calculating texture checksums"<<std::endl;
3787 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3788 i != m_mods.end(); i++){
3789 const ModSpec &mod = *i;
3790 std::string texturepath = mod.path + DIR_DELIM + "textures";
3791 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3792 for(u32 j=0; j<dirlist.size(); j++){
3793 if(dirlist[j].dir) // Ignode dirs
3795 std::string tname = dirlist[j].name;
3796 // if name contains illegal characters, ignore the texture
3797 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3798 errorstream<<"Server: ignoring illegal texture name: \""
3799 <<tname<<"\""<<std::endl;
3802 std::string tpath = texturepath + DIR_DELIM + tname;
3804 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3805 if(fis.good() == false){
3806 errorstream<<"Server::PrepareTextures(): Could not open \""
3807 <<tname<<"\" for reading"<<std::endl;
3810 std::ostringstream tmp_os(std::ios_base::binary);
3814 fis.read(buf, 1024);
3815 std::streamsize len = fis.gcount();
3816 tmp_os.write(buf, len);
3825 errorstream<<"Server::PrepareTextures(): Failed to read \""
3826 <<tname<<"\""<<std::endl;
3829 if(tmp_os.str().length() == 0){
3830 errorstream<<"Server::PrepareTextures(): Empty file \""
3831 <<tpath<<"\""<<std::endl;
3836 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3838 unsigned char *digest = sha1.getDigest();
3839 std::string digest_string = base64_encode(digest, 20);
3844 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3845 verbosestream<<"Server: sha1 for "<<tname<<"\tis "<<std::endl;
3850 struct SendableTextureAnnouncement
3853 std::string sha1_digest;
3855 SendableTextureAnnouncement(const std::string name_="",
3856 const std::string sha1_digest_=""):
3858 sha1_digest(sha1_digest_)
3863 void Server::SendTextureAnnouncement(u16 peer_id){
3864 DSTACK(__FUNCTION_NAME);
3866 verbosestream<<"Server: Announcing textures to id("<<peer_id<<")"
3869 core::list<SendableTextureAnnouncement> texture_announcements;
3871 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3874 texture_announcements.push_back(
3875 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3878 //send announcements
3882 u32 number of textures
3886 u16 length of digest string
3890 std::ostringstream os(std::ios_base::binary);
3892 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3893 writeU16(os, texture_announcements.size());
3895 for(core::list<SendableTextureAnnouncement>::Iterator
3896 j = texture_announcements.begin();
3897 j != texture_announcements.end(); j++){
3898 os<<serializeString(j->name);
3899 os<<serializeString(j->sha1_digest);
3903 std::string s = os.str();
3904 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3907 m_con.Send(peer_id, 0, data, true);
3911 struct SendableTexture
3917 SendableTexture(const std::string &name_="", const std::string path_="",
3918 const std::string &data_=""):
3925 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3926 DSTACK(__FUNCTION_NAME);
3928 verbosestream<<"Server::SendTexturesRequested(): "
3929 <<"Sending textures to client"<<std::endl;
3933 // Put 5kB in one bunch (this is not accurate)
3934 u32 bytes_per_bunch = 5000;
3936 core::array< core::list<SendableTexture> > texture_bunches;
3937 texture_bunches.push_back(core::list<SendableTexture>());
3939 u32 texture_size_bunch_total = 0;
3941 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3942 if(m_Textures.find(i->name) == m_Textures.end()){
3943 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3944 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3948 //TODO get path + name
3949 std::string tpath = m_Textures[(*i).name].path;
3952 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3953 if(fis.good() == false){
3954 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3955 <<tpath<<"\" for reading"<<std::endl;
3958 std::ostringstream tmp_os(std::ios_base::binary);
3962 fis.read(buf, 1024);
3963 std::streamsize len = fis.gcount();
3964 tmp_os.write(buf, len);
3965 texture_size_bunch_total += len;
3974 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
3975 <<(*i).name<<"\""<<std::endl;
3978 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
3979 <<tname<<"\""<<std::endl;*/
3981 texture_bunches[texture_bunches.size()-1].push_back(
3982 SendableTexture((*i).name, tpath, tmp_os.str()));
3984 // Start next bunch if got enough data
3985 if(texture_size_bunch_total >= bytes_per_bunch){
3986 texture_bunches.push_back(core::list<SendableTexture>());
3987 texture_size_bunch_total = 0;
3992 /* Create and send packets */
3994 u32 num_bunches = texture_bunches.size();
3995 for(u32 i=0; i<num_bunches; i++)
3999 u16 total number of texture bunches
4000 u16 index of this bunch
4001 u32 number of textures in this bunch
4009 std::ostringstream os(std::ios_base::binary);
4011 writeU16(os, TOCLIENT_TEXTURES);
4012 writeU16(os, num_bunches);
4014 writeU32(os, texture_bunches[i].size());
4016 for(core::list<SendableTexture>::Iterator
4017 j = texture_bunches[i].begin();
4018 j != texture_bunches[i].end(); j++){
4019 os<<serializeString(j->name);
4020 os<<serializeLongString(j->data);
4024 std::string s = os.str();
4025 verbosestream<<"Server::SendTexturesRequested(): bunch "
4026 <<i<<"/"<<num_bunches
4027 <<" textures="<<texture_bunches[i].size()
4028 <<" size=" <<s.size()<<std::endl;
4029 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4031 m_con.Send(peer_id, 0, data, true);
4041 void Server::DiePlayer(Player *player)
4043 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4045 infostream<<"Server::DiePlayer(): Player "
4046 <<player->getName()<<" dies"<<std::endl;
4050 // Trigger scripted stuff
4051 scriptapi_on_dieplayer(m_lua, srp);
4053 // Handle players that are not connected
4054 if(player->peer_id == PEER_ID_INEXISTENT){
4055 RespawnPlayer(player);
4059 SendPlayerHP(player);
4060 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4063 void Server::RespawnPlayer(Player *player)
4065 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4067 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4069 v3f pos = findSpawnPos(m_env->getServerMap());
4070 player->setPosition(pos);
4071 srp->m_last_good_position = pos;
4072 srp->m_last_good_position_age = 0;
4074 SendMovePlayer(player);
4075 SendPlayerHP(player);
4078 void Server::UpdateCrafting(u16 peer_id)
4080 DSTACK(__FUNCTION_NAME);
4082 Player* player = m_env->getPlayer(peer_id);
4085 // Get a preview for crafting
4087 // No crafting in creative mode
4088 if(g_settings->getBool("creative_mode") == false)
4089 getCraftingResult(&player->inventory, preview, false, this);
4091 // Put the new preview in
4092 InventoryList *plist = player->inventory.getList("craftpreview");
4094 assert(plist->getSize() >= 1);
4095 plist->changeItem(0, preview);
4098 RemoteClient* Server::getClient(u16 peer_id)
4100 DSTACK(__FUNCTION_NAME);
4101 //JMutexAutoLock lock(m_con_mutex);
4102 core::map<u16, RemoteClient*>::Node *n;
4103 n = m_clients.find(peer_id);
4104 // A client should exist for all peers
4106 return n->getValue();
4109 std::wstring Server::getStatusString()
4111 std::wostringstream os(std::ios_base::binary);
4114 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4116 os<<L", uptime="<<m_uptime.get();
4117 // Information about clients
4119 for(core::map<u16, RemoteClient*>::Iterator
4120 i = m_clients.getIterator();
4121 i.atEnd() == false; i++)
4123 // Get client and check that it is valid
4124 RemoteClient *client = i.getNode()->getValue();
4125 assert(client->peer_id == i.getNode()->getKey());
4126 if(client->serialization_version == SER_FMT_VER_INVALID)
4129 Player *player = m_env->getPlayer(client->peer_id);
4130 // Get name of player
4131 std::wstring name = L"unknown";
4133 name = narrow_to_wide(player->getName());
4134 // Add name to information string
4138 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4139 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4140 if(g_settings->get("motd") != "")
4141 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4145 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4147 // Add player to auth manager
4148 if(m_authmanager.exists(name) == false)
4150 infostream<<"Server: adding player "<<name
4151 <<" to auth manager"<<std::endl;
4152 m_authmanager.add(name);
4153 m_authmanager.setPrivs(name,
4154 stringToPrivs(g_settings->get("default_privs")));
4156 // Change password and save
4157 m_authmanager.setPassword(name, translatePassword(name, password));
4158 m_authmanager.save();
4161 // Saves g_settings to configpath given at initialization
4162 void Server::saveConfig()
4164 if(m_path_config != "")
4165 g_settings->updateConfigFile(m_path_config.c_str());
4168 void Server::notifyPlayer(const char *name, const std::wstring msg)
4170 Player *player = m_env->getPlayer(name);
4173 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4176 void Server::notifyPlayers(const std::wstring msg)
4178 BroadcastChatMessage(msg);
4181 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4185 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4186 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4189 // IGameDef interface
4191 IItemDefManager* Server::getItemDefManager()
4195 INodeDefManager* Server::getNodeDefManager()
4199 ICraftDefManager* Server::getCraftDefManager()
4203 ITextureSource* Server::getTextureSource()
4207 u16 Server::allocateUnknownNodeId(const std::string &name)
4209 return m_nodedef->allocateDummy(name);
4212 IWritableItemDefManager* Server::getWritableItemDefManager()
4216 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4220 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4225 const ModSpec* Server::getModSpec(const std::string &modname)
4227 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4228 i != m_mods.end(); i++){
4229 const ModSpec &mod = *i;
4230 if(mod.name == modname)
4236 v3f findSpawnPos(ServerMap &map)
4238 //return v3f(50,50,50)*BS;
4243 nodepos = v2s16(0,0);
4248 // Try to find a good place a few times
4249 for(s32 i=0; i<1000; i++)
4252 // We're going to try to throw the player to this position
4253 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4254 -range + (myrand()%(range*2)));
4255 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4256 // Get ground height at point (fallbacks to heightmap function)
4257 s16 groundheight = map.findGroundLevel(nodepos2d);
4258 // Don't go underwater
4259 if(groundheight < WATER_LEVEL)
4261 //infostream<<"-> Underwater"<<std::endl;
4264 // Don't go to high places
4265 if(groundheight > WATER_LEVEL + 4)
4267 //infostream<<"-> Underwater"<<std::endl;
4271 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4272 bool is_good = false;
4274 for(s32 i=0; i<10; i++){
4275 v3s16 blockpos = getNodeBlockPos(nodepos);
4276 map.emergeBlock(blockpos, true);
4277 MapNode n = map.getNodeNoEx(nodepos);
4278 if(n.getContent() == CONTENT_AIR){
4289 // Found a good place
4290 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4296 return intToFloat(nodepos, BS);
4299 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4302 Try to get an existing player
4304 ServerRemotePlayer *player =
4305 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4308 // If player is already connected, cancel
4309 if(player->peer_id != 0)
4311 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4316 player->peer_id = peer_id;
4318 // Re-add player to environment
4319 if(player->m_removed)
4321 player->m_removed = false;
4323 m_env->addActiveObject(player);
4326 // Reset inventory to creative if in creative mode
4327 if(g_settings->getBool("creative_mode"))
4329 // Warning: double code below
4330 // Backup actual inventory
4331 player->inventory_backup = new Inventory(m_itemdef);
4332 *(player->inventory_backup) = player->inventory;
4333 // Set creative inventory
4334 player->resetInventory();
4335 scriptapi_get_creative_inventory(m_lua, player);
4342 If player with the wanted peer_id already exists, cancel.
4344 if(m_env->getPlayer(peer_id) != NULL)
4346 infostream<<"emergePlayer(): Player with wrong name but same"
4347 " peer_id already exists"<<std::endl;
4355 /* Set player position */
4357 infostream<<"Server: Finding spawn place for player \""
4358 <<name<<"\""<<std::endl;
4360 v3f pos = findSpawnPos(m_env->getServerMap());
4362 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4363 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4365 /* Add player to environment */
4366 m_env->addPlayer(player);
4367 m_env->addActiveObject(srp);
4370 scriptapi_on_newplayer(m_lua, srp);
4372 /* Add stuff to inventory */
4373 if(g_settings->getBool("creative_mode"))
4375 // Warning: double code above
4376 // Backup actual inventory
4377 player->inventory_backup = new Inventory(m_itemdef);
4378 *(player->inventory_backup) = player->inventory;
4379 // Set creative inventory
4380 player->resetInventory();
4381 scriptapi_get_creative_inventory(m_lua, player);
4386 } // create new player
4389 void Server::handlePeerChange(PeerChange &c)
4391 JMutexAutoLock envlock(m_env_mutex);
4392 JMutexAutoLock conlock(m_con_mutex);
4394 if(c.type == PEER_ADDED)
4401 core::map<u16, RemoteClient*>::Node *n;
4402 n = m_clients.find(c.peer_id);
4403 // The client shouldn't already exist
4407 RemoteClient *client = new RemoteClient();
4408 client->peer_id = c.peer_id;
4409 m_clients.insert(client->peer_id, client);
4412 else if(c.type == PEER_REMOVED)
4419 core::map<u16, RemoteClient*>::Node *n;
4420 n = m_clients.find(c.peer_id);
4421 // The client should exist
4425 Mark objects to be not known by the client
4427 RemoteClient *client = n->getValue();
4429 for(core::map<u16, bool>::Iterator
4430 i = client->m_known_objects.getIterator();
4431 i.atEnd()==false; i++)
4434 u16 id = i.getNode()->getKey();
4435 ServerActiveObject* obj = m_env->getActiveObject(id);
4437 if(obj && obj->m_known_by_count > 0)
4438 obj->m_known_by_count--;
4441 ServerRemotePlayer* player =
4442 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4444 // Collect information about leaving in chat
4445 std::wstring message;
4449 std::wstring name = narrow_to_wide(player->getName());
4452 message += L" left game";
4454 message += L" (timed out)";
4458 // Remove from environment
4460 player->m_removed = true;
4462 // Set player client disconnected
4464 player->peer_id = 0;
4472 std::ostringstream os(std::ios_base::binary);
4473 for(core::map<u16, RemoteClient*>::Iterator
4474 i = m_clients.getIterator();
4475 i.atEnd() == false; i++)
4477 RemoteClient *client = i.getNode()->getValue();
4478 assert(client->peer_id == i.getNode()->getKey());
4479 if(client->serialization_version == SER_FMT_VER_INVALID)
4482 Player *player = m_env->getPlayer(client->peer_id);
4485 // Get name of player
4486 os<<player->getName()<<" ";
4489 actionstream<<player->getName()<<" "
4490 <<(c.timeout?"times out.":"leaves game.")
4491 <<" List of players: "
4492 <<os.str()<<std::endl;
4497 delete m_clients[c.peer_id];
4498 m_clients.remove(c.peer_id);
4500 // Send player info to all remaining clients
4501 //SendPlayerInfos();
4503 // Send leave chat message to all remaining clients
4504 if(message.length() != 0)
4505 BroadcastChatMessage(message);
4514 void Server::handlePeerChanges()
4516 while(m_peer_change_queue.size() > 0)
4518 PeerChange c = m_peer_change_queue.pop_front();
4520 verbosestream<<"Server: Handling peer change: "
4521 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4524 handlePeerChange(c);
4528 u64 Server::getPlayerPrivs(Player *player)
4532 std::string playername = player->getName();
4533 // Local player gets all privileges regardless of
4534 // what's set on their account.
4535 if(g_settings->get("name") == playername)
4541 return getPlayerAuthPrivs(playername);
4545 void dedicated_server_loop(Server &server, bool &kill)
4547 DSTACK(__FUNCTION_NAME);
4549 verbosestream<<"dedicated_server_loop()"<<std::endl;
4551 IntervalLimiter m_profiler_interval;
4555 float steplen = g_settings->getFloat("dedicated_server_step");
4556 // This is kind of a hack but can be done like this
4557 // because server.step() is very light
4559 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4560 sleep_ms((int)(steplen*1000.0));
4562 server.step(steplen);
4564 if(server.getShutdownRequested() || kill)
4566 infostream<<"Dedicated server quitting"<<std::endl;
4573 float profiler_print_interval =
4574 g_settings->getFloat("profiler_print_interval");
4575 if(profiler_print_interval != 0)
4577 if(m_profiler_interval.step(steplen, profiler_print_interval))
4579 infostream<<"Profiler:"<<std::endl;
4580 g_profiler->print(infostream);
4581 g_profiler->clear();