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"
52 #include "sound.h" // dummySoundManager
53 #include "event_manager.h"
56 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
58 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
60 class MapEditEventIgnorer
63 MapEditEventIgnorer(bool *flag):
72 ~MapEditEventIgnorer()
85 void * ServerThread::Thread()
89 log_register_thread("ServerThread");
91 DSTACK(__FUNCTION_NAME);
93 BEGIN_DEBUG_EXCEPTION_HANDLER
98 //TimeTaker timer("AsyncRunStep() + Receive()");
101 //TimeTaker timer("AsyncRunStep()");
102 m_server->AsyncRunStep();
105 //infostream<<"Running m_server->Receive()"<<std::endl;
108 catch(con::NoIncomingDataException &e)
111 catch(con::PeerNotFoundException &e)
113 infostream<<"Server: PeerNotFoundException"<<std::endl;
115 catch(con::ConnectionBindFailed &e)
117 m_server->setAsyncFatalError(e.what());
121 END_DEBUG_EXCEPTION_HANDLER(errorstream)
126 void * EmergeThread::Thread()
130 log_register_thread("EmergeThread");
132 DSTACK(__FUNCTION_NAME);
134 BEGIN_DEBUG_EXCEPTION_HANDLER
136 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
139 Get block info from queue, emerge them and send them
142 After queue is empty, exit.
146 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
150 SharedPtr<QueuedBlockEmerge> q(qptr);
156 Do not generate over-limit
158 if(blockpos_over_limit(p))
161 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
163 //TimeTaker timer("block emerge");
166 Try to emerge it from somewhere.
168 If it is only wanted as optional, only loading from disk
173 Check if any peer wants it as non-optional. In that case it
176 Also decrement the emerge queue count in clients.
179 bool only_from_disk = true;
182 core::map<u16, u8>::Iterator i;
183 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
185 //u16 peer_id = i.getNode()->getKey();
188 u8 flags = i.getNode()->getValue();
189 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
190 only_from_disk = false;
195 if(enable_mapgen_debug_info)
196 infostream<<"EmergeThread: p="
197 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
198 <<"only_from_disk="<<only_from_disk<<std::endl;
200 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
202 MapBlock *block = NULL;
203 bool got_block = true;
204 core::map<v3s16, MapBlock*> modified_blocks;
207 Try to fetch block from memory or disk.
208 If not found and asked to generate, initialize generator.
211 bool started_generate = false;
212 mapgen::BlockMakeData data;
215 JMutexAutoLock envlock(m_server->m_env_mutex);
217 // Load sector if it isn't loaded
218 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
219 map.loadSectorMeta(p2d);
221 // Attempt to load block
222 block = map.getBlockNoCreateNoEx(p);
223 if(!block || block->isDummy() || !block->isGenerated())
225 if(enable_mapgen_debug_info)
226 infostream<<"EmergeThread: not in memory, "
227 <<"attempting to load from disk"<<std::endl;
229 block = map.loadBlock(p);
232 // If could not load and allowed to generate, start generation
233 // inside this same envlock
234 if(only_from_disk == false &&
235 (block == NULL || block->isGenerated() == false)){
236 if(enable_mapgen_debug_info)
237 infostream<<"EmergeThread: generating"<<std::endl;
238 started_generate = true;
240 map.initBlockMake(&data, p);
245 If generator was initialized, generate now when envlock is free.
250 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
252 TimeTaker t("mapgen::make_block()");
254 mapgen::make_block(&data);
256 if(enable_mapgen_debug_info == false)
257 t.stop(true); // Hide output
261 // Lock environment again to access the map
262 JMutexAutoLock envlock(m_server->m_env_mutex);
264 ScopeProfiler sp(g_profiler, "EmergeThread: after "
265 "mapgen::make_block (envlock)", SPT_AVG);
267 // Blit data back on map, update lighting, add mobs and
268 // whatever this does
269 map.finishBlockMake(&data, modified_blocks);
272 block = map.getBlockNoCreateNoEx(p);
274 // If block doesn't exist, don't try doing anything with it
275 // This happens if the block is not in generation boundaries
280 Do some post-generate stuff
283 v3s16 minp = block->getPos()*MAP_BLOCKSIZE;
284 v3s16 maxp = minp + v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
285 scriptapi_environment_on_generated(m_server->m_lua,
288 if(enable_mapgen_debug_info)
289 infostream<<"EmergeThread: ended up with: "
290 <<analyze_block(block)<<std::endl;
293 Ignore map edit events, they will not need to be
294 sent to anybody because the block hasn't been sent
297 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
299 // Activate objects and stuff
300 m_server->m_env->activateBlock(block, 0);
308 Set sent status of modified blocks on clients
311 // NOTE: Server's clients are also behind the connection mutex
312 JMutexAutoLock lock(m_server->m_con_mutex);
315 Add the originally fetched block to the modified list
319 modified_blocks.insert(p, block);
323 Set the modified blocks unsent for all the clients
326 for(core::map<u16, RemoteClient*>::Iterator
327 i = m_server->m_clients.getIterator();
328 i.atEnd() == false; i++)
330 RemoteClient *client = i.getNode()->getValue();
332 if(modified_blocks.size() > 0)
334 // Remove block from sent history
335 client->SetBlocksNotSent(modified_blocks);
341 END_DEBUG_EXCEPTION_HANDLER(errorstream)
343 log_deregister_thread();
348 void RemoteClient::GetNextBlocks(Server *server, float dtime,
349 core::array<PrioritySortedBlockTransfer> &dest)
351 DSTACK(__FUNCTION_NAME);
354 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
357 m_nothing_to_send_pause_timer -= dtime;
358 m_nearest_unsent_reset_timer += dtime;
360 if(m_nothing_to_send_pause_timer >= 0)
365 // Won't send anything if already sending
366 if(m_blocks_sending.size() >= g_settings->getU16
367 ("max_simultaneous_block_sends_per_client"))
369 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
373 //TimeTaker timer("RemoteClient::GetNextBlocks");
375 Player *player = server->m_env->getPlayer(peer_id);
377 assert(player != NULL);
379 v3f playerpos = player->getPosition();
380 v3f playerspeed = player->getSpeed();
381 v3f playerspeeddir(0,0,0);
382 if(playerspeed.getLength() > 1.0*BS)
383 playerspeeddir = playerspeed / playerspeed.getLength();
384 // Predict to next block
385 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
387 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
389 v3s16 center = getNodeBlockPos(center_nodepos);
391 // Camera position and direction
392 v3f camera_pos = player->getEyePosition();
393 v3f camera_dir = v3f(0,0,1);
394 camera_dir.rotateYZBy(player->getPitch());
395 camera_dir.rotateXZBy(player->getYaw());
397 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
398 <<camera_dir.Z<<")"<<std::endl;*/
401 Get the starting value of the block finder radius.
404 if(m_last_center != center)
406 m_nearest_unsent_d = 0;
407 m_last_center = center;
410 /*infostream<<"m_nearest_unsent_reset_timer="
411 <<m_nearest_unsent_reset_timer<<std::endl;*/
413 // Reset periodically to workaround for some bugs or stuff
414 if(m_nearest_unsent_reset_timer > 20.0)
416 m_nearest_unsent_reset_timer = 0;
417 m_nearest_unsent_d = 0;
418 //infostream<<"Resetting m_nearest_unsent_d for "
419 // <<server->getPlayerName(peer_id)<<std::endl;
422 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
423 s16 d_start = m_nearest_unsent_d;
425 //infostream<<"d_start="<<d_start<<std::endl;
427 u16 max_simul_sends_setting = g_settings->getU16
428 ("max_simultaneous_block_sends_per_client");
429 u16 max_simul_sends_usually = max_simul_sends_setting;
432 Check the time from last addNode/removeNode.
434 Decrease send rate if player is building stuff.
436 m_time_from_building += dtime;
437 if(m_time_from_building < g_settings->getFloat(
438 "full_block_send_enable_min_time_from_building"))
440 max_simul_sends_usually
441 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
445 Number of blocks sending + number of blocks selected for sending
447 u32 num_blocks_selected = m_blocks_sending.size();
450 next time d will be continued from the d from which the nearest
451 unsent block was found this time.
453 This is because not necessarily any of the blocks found this
454 time are actually sent.
456 s32 new_nearest_unsent_d = -1;
458 s16 d_max = g_settings->getS16("max_block_send_distance");
459 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
461 // Don't loop very much at a time
462 s16 max_d_increment_at_time = 2;
463 if(d_max > d_start + max_d_increment_at_time)
464 d_max = d_start + max_d_increment_at_time;
465 /*if(d_max_gen > d_start+2)
466 d_max_gen = d_start+2;*/
468 //infostream<<"Starting from "<<d_start<<std::endl;
470 s32 nearest_emerged_d = -1;
471 s32 nearest_emergefull_d = -1;
472 s32 nearest_sent_d = -1;
473 bool queue_is_full = false;
476 for(d = d_start; d <= d_max; d++)
478 /*errorstream<<"checking d="<<d<<" for "
479 <<server->getPlayerName(peer_id)<<std::endl;*/
480 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
483 If m_nearest_unsent_d was changed by the EmergeThread
484 (it can change it to 0 through SetBlockNotSent),
486 Else update m_nearest_unsent_d
488 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
490 d = m_nearest_unsent_d;
491 last_nearest_unsent_d = m_nearest_unsent_d;
495 Get the border/face dot coordinates of a "d-radiused"
498 core::list<v3s16> list;
499 getFacePositions(list, d);
501 core::list<v3s16>::Iterator li;
502 for(li=list.begin(); li!=list.end(); li++)
504 v3s16 p = *li + center;
508 - Don't allow too many simultaneous transfers
509 - EXCEPT when the blocks are very close
511 Also, don't send blocks that are already flying.
514 // Start with the usual maximum
515 u16 max_simul_dynamic = max_simul_sends_usually;
517 // If block is very close, allow full maximum
518 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
519 max_simul_dynamic = max_simul_sends_setting;
521 // Don't select too many blocks for sending
522 if(num_blocks_selected >= max_simul_dynamic)
524 queue_is_full = true;
525 goto queue_full_break;
528 // Don't send blocks that are currently being transferred
529 if(m_blocks_sending.find(p) != NULL)
535 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
536 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
537 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
538 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
539 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
540 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
543 // If this is true, inexistent block will be made from scratch
544 bool generate = d <= d_max_gen;
547 /*// Limit the generating area vertically to 2/3
548 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
551 // Limit the send area vertically to 1/2
552 if(abs(p.Y - center.Y) > d_max / 2)
558 If block is far away, don't generate it unless it is
564 // Block center y in nodes
565 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
566 // Don't generate if it's very high or very low
567 if(y < -64 || y > 64)
571 v2s16 p2d_nodes_center(
575 // Get ground height in nodes
576 s16 gh = server->m_env->getServerMap().findGroundLevel(
579 // If differs a lot, don't generate
580 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
582 // Actually, don't even send it
588 //infostream<<"d="<<d<<std::endl;
591 Don't generate or send if not in sight
592 FIXME This only works if the client uses a small enough
593 FOV setting. The default of 72 degrees is fine.
596 float camera_fov = (72.0*PI/180) * 4./3.;
597 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
603 Don't send already sent blocks
606 if(m_blocks_sent.find(p) != NULL)
613 Check if map has this block
615 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
617 bool surely_not_found_on_disk = false;
618 bool block_is_invalid = false;
621 // Reset usage timer, this block will be of use in the future.
622 block->resetUsageTimer();
624 // Block is dummy if data doesn't exist.
625 // It means it has been not found from disk and not generated
628 surely_not_found_on_disk = true;
631 // Block is valid if lighting is up-to-date and data exists
632 if(block->isValid() == false)
634 block_is_invalid = true;
637 /*if(block->isFullyGenerated() == false)
639 block_is_invalid = true;
644 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
645 v2s16 chunkpos = map->sector_to_chunk(p2d);
646 if(map->chunkNonVolatile(chunkpos) == false)
647 block_is_invalid = true;
649 if(block->isGenerated() == false)
650 block_is_invalid = true;
653 If block is not close, don't send it unless it is near
656 Block is near ground level if night-time mesh
657 differs from day-time mesh.
661 if(block->dayNightDiffed() == false)
668 If block has been marked to not exist on disk (dummy)
669 and generating new ones is not wanted, skip block.
671 if(generate == false && surely_not_found_on_disk == true)
678 Add inexistent block to emerge queue.
680 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
682 //TODO: Get value from somewhere
683 // Allow only one block in emerge queue
684 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
685 // Allow two blocks in queue per client
686 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
688 // Make it more responsive when needing to generate stuff
689 if(surely_not_found_on_disk)
691 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
693 //infostream<<"Adding block to emerge queue"<<std::endl;
695 // Add it to the emerge queue and trigger the thread
698 if(generate == false)
699 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
701 server->m_emerge_queue.addBlock(peer_id, p, flags);
702 server->m_emergethread.trigger();
704 if(nearest_emerged_d == -1)
705 nearest_emerged_d = d;
707 if(nearest_emergefull_d == -1)
708 nearest_emergefull_d = d;
715 if(nearest_sent_d == -1)
719 Add block to send queue
722 /*errorstream<<"sending from d="<<d<<" to "
723 <<server->getPlayerName(peer_id)<<std::endl;*/
725 PrioritySortedBlockTransfer q((float)d, p, peer_id);
729 num_blocks_selected += 1;
734 //infostream<<"Stopped at "<<d<<std::endl;
736 // If nothing was found for sending and nothing was queued for
737 // emerging, continue next time browsing from here
738 if(nearest_emerged_d != -1){
739 new_nearest_unsent_d = nearest_emerged_d;
740 } else if(nearest_emergefull_d != -1){
741 new_nearest_unsent_d = nearest_emergefull_d;
743 if(d > g_settings->getS16("max_block_send_distance")){
744 new_nearest_unsent_d = 0;
745 m_nothing_to_send_pause_timer = 2.0;
746 /*infostream<<"GetNextBlocks(): d wrapped around for "
747 <<server->getPlayerName(peer_id)
748 <<"; setting to 0 and pausing"<<std::endl;*/
750 if(nearest_sent_d != -1)
751 new_nearest_unsent_d = nearest_sent_d;
753 new_nearest_unsent_d = d;
757 if(new_nearest_unsent_d != -1)
758 m_nearest_unsent_d = new_nearest_unsent_d;
760 /*timer_result = timer.stop(true);
761 if(timer_result != 0)
762 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
765 void RemoteClient::GotBlock(v3s16 p)
767 if(m_blocks_sending.find(p) != NULL)
768 m_blocks_sending.remove(p);
771 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
772 " m_blocks_sending"<<std::endl;*/
773 m_excess_gotblocks++;
775 m_blocks_sent.insert(p, true);
778 void RemoteClient::SentBlock(v3s16 p)
780 if(m_blocks_sending.find(p) == NULL)
781 m_blocks_sending.insert(p, 0.0);
783 infostream<<"RemoteClient::SentBlock(): Sent block"
784 " already in m_blocks_sending"<<std::endl;
787 void RemoteClient::SetBlockNotSent(v3s16 p)
789 m_nearest_unsent_d = 0;
791 if(m_blocks_sending.find(p) != NULL)
792 m_blocks_sending.remove(p);
793 if(m_blocks_sent.find(p) != NULL)
794 m_blocks_sent.remove(p);
797 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
799 m_nearest_unsent_d = 0;
801 for(core::map<v3s16, MapBlock*>::Iterator
802 i = blocks.getIterator();
803 i.atEnd()==false; i++)
805 v3s16 p = i.getNode()->getKey();
807 if(m_blocks_sending.find(p) != NULL)
808 m_blocks_sending.remove(p);
809 if(m_blocks_sent.find(p) != NULL)
810 m_blocks_sent.remove(p);
818 PlayerInfo::PlayerInfo()
824 void PlayerInfo::PrintLine(std::ostream *s)
827 (*s)<<"\""<<name<<"\" ("
828 <<(position.X/10)<<","<<(position.Y/10)
829 <<","<<(position.Z/10)<<") ";
831 (*s)<<" avg_rtt="<<avg_rtt;
840 const std::string &path_world,
841 const std::string &path_config,
842 const SubgameSpec &gamespec,
843 bool simple_singleplayer_mode
845 m_path_world(path_world),
846 m_path_config(path_config),
847 m_gamespec(gamespec),
848 m_simple_singleplayer_mode(simple_singleplayer_mode),
849 m_async_fatal_error(""),
851 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
852 m_authmanager(path_world+DIR_DELIM+"auth.txt"),
853 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
855 m_itemdef(createItemDefManager()),
856 m_nodedef(createNodeDefManager()),
857 m_craftdef(createCraftDefManager()),
858 m_event(new EventManager()),
860 m_emergethread(this),
861 m_time_of_day_send_timer(0),
863 m_shutdown_requested(false),
864 m_ignore_map_edit_events(false),
865 m_ignore_map_edit_events_peer_id(0)
867 m_liquid_transform_timer = 0.0;
868 m_print_info_timer = 0.0;
869 m_objectdata_timer = 0.0;
870 m_emergethread_trigger_timer = 0.0;
871 m_savemap_timer = 0.0;
875 m_step_dtime_mutex.Init();
879 throw ServerError("Supplied empty world path");
881 if(!gamespec.isValid())
882 throw ServerError("Supplied invalid gamespec");
884 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
885 if(m_simple_singleplayer_mode)
886 infostream<<" in simple singleplayer mode"<<std::endl;
888 infostream<<std::endl;
889 infostream<<"- world: "<<m_path_world<<std::endl;
890 infostream<<"- config: "<<m_path_config<<std::endl;
891 infostream<<"- game: "<<m_gamespec.path<<std::endl;
893 // Add world mod search path
894 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
895 // Add addon mod search path
896 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
897 i != m_gamespec.mods_paths.end(); i++)
898 m_modspaths.push_front((*i));
900 // Print out mod search paths
901 for(core::list<std::string>::Iterator i = m_modspaths.begin();
902 i != m_modspaths.end(); i++){
903 std::string modspath = *i;
904 infostream<<"- mods: "<<modspath<<std::endl;
907 // Path to builtin.lua
908 std::string builtinpath = porting::path_share + DIR_DELIM + "builtin"
909 + DIR_DELIM + "builtin.lua";
911 // Create world if it doesn't exist
912 if(!initializeWorld(m_path_world, m_gamespec.id))
913 throw ServerError("Failed to initialize world");
916 JMutexAutoLock envlock(m_env_mutex);
917 JMutexAutoLock conlock(m_con_mutex);
919 // Initialize scripting
921 infostream<<"Server: Initializing Lua"<<std::endl;
922 m_lua = script_init();
925 scriptapi_export(m_lua, this);
926 // Load and run builtin.lua
927 infostream<<"Server: Loading builtin.lua [\""
928 <<builtinpath<<"\"]"<<std::endl;
929 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
931 errorstream<<"Server: Failed to load and run "
932 <<builtinpath<<std::endl;
933 throw ModError("Failed to load and run "+builtinpath);
935 // Find mods in mod search paths
936 m_mods = getMods(m_modspaths);
938 infostream<<"Server: Loading mods: ";
939 for(core::list<ModSpec>::Iterator i = m_mods.begin();
940 i != m_mods.end(); i++){
941 const ModSpec &mod = *i;
942 infostream<<mod.name<<" ";
944 infostream<<std::endl;
945 // Load and run "mod" scripts
946 for(core::list<ModSpec>::Iterator i = m_mods.begin();
947 i != m_mods.end(); i++){
948 const ModSpec &mod = *i;
949 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
950 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
951 <<scriptpath<<"\"]"<<std::endl;
952 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
954 errorstream<<"Server: Failed to load and run "
955 <<scriptpath<<std::endl;
956 throw ModError("Failed to load and run "+scriptpath);
960 // Read Textures and calculate sha1 sums
963 // Apply item aliases in the node definition manager
964 m_nodedef->updateAliases(m_itemdef);
966 // Initialize Environment
968 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
971 // Give environment reference to scripting api
972 scriptapi_add_environment(m_lua, m_env);
974 // Register us to receive map edit events
975 m_env->getMap().addEventReceiver(this);
977 // If file exists, load environment metadata
978 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
980 infostream<<"Server: Loading environment metadata"<<std::endl;
981 m_env->loadMeta(m_path_world);
985 infostream<<"Server: Loading players"<<std::endl;
986 m_env->deSerializePlayers(m_path_world);
989 Add some test ActiveBlockModifiers to environment
991 add_legacy_abms(m_env, m_nodedef);
996 infostream<<"Server destructing"<<std::endl;
999 Send shutdown message
1002 JMutexAutoLock conlock(m_con_mutex);
1004 std::wstring line = L"*** Server shutting down";
1007 Send the message to clients
1009 for(core::map<u16, RemoteClient*>::Iterator
1010 i = m_clients.getIterator();
1011 i.atEnd() == false; i++)
1013 // Get client and check that it is valid
1014 RemoteClient *client = i.getNode()->getValue();
1015 assert(client->peer_id == i.getNode()->getKey());
1016 if(client->serialization_version == SER_FMT_VER_INVALID)
1020 SendChatMessage(client->peer_id, line);
1022 catch(con::PeerNotFoundException &e)
1028 JMutexAutoLock envlock(m_env_mutex);
1033 infostream<<"Server: Saving players"<<std::endl;
1034 m_env->serializePlayers(m_path_world);
1037 Save environment metadata
1039 infostream<<"Server: Saving environment metadata"<<std::endl;
1040 m_env->saveMeta(m_path_world);
1052 JMutexAutoLock clientslock(m_con_mutex);
1054 for(core::map<u16, RemoteClient*>::Iterator
1055 i = m_clients.getIterator();
1056 i.atEnd() == false; i++)
1059 // NOTE: These are removed by env destructor
1061 u16 peer_id = i.getNode()->getKey();
1062 JMutexAutoLock envlock(m_env_mutex);
1063 m_env->removePlayer(peer_id);
1067 delete i.getNode()->getValue();
1071 // Delete things in the reverse order of creation
1078 // Deinitialize scripting
1079 infostream<<"Server: Deinitializing scripting"<<std::endl;
1080 script_deinit(m_lua);
1083 void Server::start(unsigned short port)
1085 DSTACK(__FUNCTION_NAME);
1086 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1088 // Stop thread if already running
1091 // Initialize connection
1092 m_con.SetTimeoutMs(30);
1096 m_thread.setRun(true);
1099 // ASCII art for the win!
1101 <<" .__ __ __ "<<std::endl
1102 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1103 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1104 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1105 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1106 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1107 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1108 actionstream<<"Server for gameid=\""<<m_gamespec.id
1109 <<"\" listening on port "<<port<<"."<<std::endl;
1114 DSTACK(__FUNCTION_NAME);
1116 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1118 // Stop threads (set run=false first so both start stopping)
1119 m_thread.setRun(false);
1120 m_emergethread.setRun(false);
1122 m_emergethread.stop();
1124 infostream<<"Server: Threads stopped"<<std::endl;
1127 void Server::step(float dtime)
1129 DSTACK(__FUNCTION_NAME);
1134 JMutexAutoLock lock(m_step_dtime_mutex);
1135 m_step_dtime += dtime;
1137 // Throw if fatal error occurred in thread
1138 std::string async_err = m_async_fatal_error.get();
1139 if(async_err != ""){
1140 throw ServerError(async_err);
1144 void Server::AsyncRunStep()
1146 DSTACK(__FUNCTION_NAME);
1148 g_profiler->add("Server::AsyncRunStep (num)", 1);
1152 JMutexAutoLock lock1(m_step_dtime_mutex);
1153 dtime = m_step_dtime;
1157 // Send blocks to clients
1164 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1166 //infostream<<"Server steps "<<dtime<<std::endl;
1167 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1170 JMutexAutoLock lock1(m_step_dtime_mutex);
1171 m_step_dtime -= dtime;
1178 m_uptime.set(m_uptime.get() + dtime);
1182 // Process connection's timeouts
1183 JMutexAutoLock lock2(m_con_mutex);
1184 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1185 m_con.RunTimeouts(dtime);
1189 // This has to be called so that the client list gets synced
1190 // with the peer list of the connection
1191 handlePeerChanges();
1195 Update time of day and overall game time
1198 JMutexAutoLock envlock(m_env_mutex);
1200 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1203 Send to clients at constant intervals
1206 m_time_of_day_send_timer -= dtime;
1207 if(m_time_of_day_send_timer < 0.0)
1209 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1211 //JMutexAutoLock envlock(m_env_mutex);
1212 JMutexAutoLock conlock(m_con_mutex);
1214 for(core::map<u16, RemoteClient*>::Iterator
1215 i = m_clients.getIterator();
1216 i.atEnd() == false; i++)
1218 RemoteClient *client = i.getNode()->getValue();
1219 //Player *player = m_env->getPlayer(client->peer_id);
1221 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1222 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1224 m_con.Send(client->peer_id, 0, data, true);
1230 JMutexAutoLock lock(m_env_mutex);
1232 ScopeProfiler sp(g_profiler, "SEnv step");
1233 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1237 const float map_timer_and_unload_dtime = 2.92;
1238 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1240 JMutexAutoLock lock(m_env_mutex);
1241 // Run Map's timers and unload unused data
1242 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1243 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1244 g_settings->getFloat("server_unload_unused_data_timeout"));
1255 JMutexAutoLock lock(m_env_mutex);
1256 JMutexAutoLock lock2(m_con_mutex);
1258 ScopeProfiler sp(g_profiler, "Server: handle players");
1260 //float player_max_speed = BS * 4.0; // Normal speed
1261 float player_max_speed = BS * 20; // Fast speed
1262 float player_max_speed_up = BS * 20;
1264 player_max_speed *= 2.5; // Tolerance
1265 player_max_speed_up *= 2.5;
1267 for(core::map<u16, RemoteClient*>::Iterator
1268 i = m_clients.getIterator();
1269 i.atEnd() == false; i++)
1271 RemoteClient *client = i.getNode()->getValue();
1272 ServerRemotePlayer *player =
1273 static_cast<ServerRemotePlayer*>
1274 (m_env->getPlayer(client->peer_id));
1279 Check player movements
1281 NOTE: Actually the server should handle player physics like the
1282 client does and compare player's position to what is calculated
1283 on our side. This is required when eg. players fly due to an
1286 player->m_last_good_position_age += dtime;
1287 if(player->m_last_good_position_age >= 1.0){
1288 float age = player->m_last_good_position_age;
1289 v3f diff = (player->getPosition() - player->m_last_good_position);
1290 float d_vert = diff.Y;
1292 float d_horiz = diff.getLength();
1293 /*infostream<<player->getName()<<"'s horizontal speed is "
1294 <<(d_horiz/age)<<std::endl;*/
1295 if(d_horiz <= age * player_max_speed &&
1296 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1297 player->m_last_good_position = player->getPosition();
1299 actionstream<<"Player "<<player->getName()
1300 <<" moved too fast; resetting position"
1302 player->setPosition(player->m_last_good_position);
1303 SendMovePlayer(player);
1305 player->m_last_good_position_age = 0;
1309 Handle player HPs (die if hp=0)
1311 if(player->hp == 0 && player->m_hp_not_sent)
1315 Send player inventories and HPs if necessary
1317 if(player->m_inventory_not_sent){
1318 UpdateCrafting(player->peer_id);
1319 SendInventory(player->peer_id);
1321 if(player->m_hp_not_sent){
1322 SendPlayerHP(player);
1328 if(!player->m_is_in_environment){
1329 player->m_removed = false;
1331 m_env->addActiveObject(player);
1336 /* Transform liquids */
1337 m_liquid_transform_timer += dtime;
1338 if(m_liquid_transform_timer >= 1.00)
1340 m_liquid_transform_timer -= 1.00;
1342 JMutexAutoLock lock(m_env_mutex);
1344 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1346 core::map<v3s16, MapBlock*> modified_blocks;
1347 m_env->getMap().transformLiquids(modified_blocks);
1352 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1353 ServerMap &map = ((ServerMap&)m_env->getMap());
1354 map.updateLighting(modified_blocks, lighting_modified_blocks);
1356 // Add blocks modified by lighting to modified_blocks
1357 for(core::map<v3s16, MapBlock*>::Iterator
1358 i = lighting_modified_blocks.getIterator();
1359 i.atEnd() == false; i++)
1361 MapBlock *block = i.getNode()->getValue();
1362 modified_blocks.insert(block->getPos(), block);
1366 Set the modified blocks unsent for all the clients
1369 JMutexAutoLock lock2(m_con_mutex);
1371 for(core::map<u16, RemoteClient*>::Iterator
1372 i = m_clients.getIterator();
1373 i.atEnd() == false; i++)
1375 RemoteClient *client = i.getNode()->getValue();
1377 if(modified_blocks.size() > 0)
1379 // Remove block from sent history
1380 client->SetBlocksNotSent(modified_blocks);
1385 // Periodically print some info
1387 float &counter = m_print_info_timer;
1393 JMutexAutoLock lock2(m_con_mutex);
1395 if(m_clients.size() != 0)
1396 infostream<<"Players:"<<std::endl;
1397 for(core::map<u16, RemoteClient*>::Iterator
1398 i = m_clients.getIterator();
1399 i.atEnd() == false; i++)
1401 //u16 peer_id = i.getNode()->getKey();
1402 RemoteClient *client = i.getNode()->getValue();
1403 Player *player = m_env->getPlayer(client->peer_id);
1406 infostream<<"* "<<player->getName()<<"\t";
1407 client->PrintInfo(infostream);
1412 //if(g_settings->getBool("enable_experimental"))
1416 Check added and deleted active objects
1419 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1420 JMutexAutoLock envlock(m_env_mutex);
1421 JMutexAutoLock conlock(m_con_mutex);
1423 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1425 // Radius inside which objects are active
1426 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1427 radius *= MAP_BLOCKSIZE;
1429 for(core::map<u16, RemoteClient*>::Iterator
1430 i = m_clients.getIterator();
1431 i.atEnd() == false; i++)
1433 RemoteClient *client = i.getNode()->getValue();
1435 // If definitions and textures have not been sent, don't
1436 // send objects either
1437 if(!client->definitions_sent)
1440 Player *player = m_env->getPlayer(client->peer_id);
1443 // This can happen if the client timeouts somehow
1444 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1446 <<" has no associated player"<<std::endl;*/
1449 v3s16 pos = floatToInt(player->getPosition(), BS);
1451 core::map<u16, bool> removed_objects;
1452 core::map<u16, bool> added_objects;
1453 m_env->getRemovedActiveObjects(pos, radius,
1454 client->m_known_objects, removed_objects);
1455 m_env->getAddedActiveObjects(pos, radius,
1456 client->m_known_objects, added_objects);
1458 // Ignore if nothing happened
1459 if(removed_objects.size() == 0 && added_objects.size() == 0)
1461 //infostream<<"active objects: none changed"<<std::endl;
1465 std::string data_buffer;
1469 // Handle removed objects
1470 writeU16((u8*)buf, removed_objects.size());
1471 data_buffer.append(buf, 2);
1472 for(core::map<u16, bool>::Iterator
1473 i = removed_objects.getIterator();
1474 i.atEnd()==false; i++)
1477 u16 id = i.getNode()->getKey();
1478 ServerActiveObject* obj = m_env->getActiveObject(id);
1480 // Add to data buffer for sending
1481 writeU16((u8*)buf, i.getNode()->getKey());
1482 data_buffer.append(buf, 2);
1484 // Remove from known objects
1485 client->m_known_objects.remove(i.getNode()->getKey());
1487 if(obj && obj->m_known_by_count > 0)
1488 obj->m_known_by_count--;
1491 // Handle added objects
1492 writeU16((u8*)buf, added_objects.size());
1493 data_buffer.append(buf, 2);
1494 for(core::map<u16, bool>::Iterator
1495 i = added_objects.getIterator();
1496 i.atEnd()==false; i++)
1499 u16 id = i.getNode()->getKey();
1500 ServerActiveObject* obj = m_env->getActiveObject(id);
1503 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1505 infostream<<"WARNING: "<<__FUNCTION_NAME
1506 <<": NULL object"<<std::endl;
1508 type = obj->getType();
1510 // Add to data buffer for sending
1511 writeU16((u8*)buf, id);
1512 data_buffer.append(buf, 2);
1513 writeU8((u8*)buf, type);
1514 data_buffer.append(buf, 1);
1517 data_buffer.append(serializeLongString(
1518 obj->getClientInitializationData()));
1520 data_buffer.append(serializeLongString(""));
1522 // Add to known objects
1523 client->m_known_objects.insert(i.getNode()->getKey(), false);
1526 obj->m_known_by_count++;
1530 SharedBuffer<u8> reply(2 + data_buffer.size());
1531 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1532 memcpy((char*)&reply[2], data_buffer.c_str(),
1533 data_buffer.size());
1535 m_con.Send(client->peer_id, 0, reply, true);
1537 verbosestream<<"Server: Sent object remove/add: "
1538 <<removed_objects.size()<<" removed, "
1539 <<added_objects.size()<<" added, "
1540 <<"packet size is "<<reply.getSize()<<std::endl;
1545 Collect a list of all the objects known by the clients
1546 and report it back to the environment.
1549 core::map<u16, bool> all_known_objects;
1551 for(core::map<u16, RemoteClient*>::Iterator
1552 i = m_clients.getIterator();
1553 i.atEnd() == false; i++)
1555 RemoteClient *client = i.getNode()->getValue();
1556 // Go through all known objects of client
1557 for(core::map<u16, bool>::Iterator
1558 i = client->m_known_objects.getIterator();
1559 i.atEnd()==false; i++)
1561 u16 id = i.getNode()->getKey();
1562 all_known_objects[id] = true;
1566 m_env->setKnownActiveObjects(whatever);
1572 Send object messages
1575 JMutexAutoLock envlock(m_env_mutex);
1576 JMutexAutoLock conlock(m_con_mutex);
1578 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1581 // Value = data sent by object
1582 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1584 // Get active object messages from environment
1587 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1591 core::list<ActiveObjectMessage>* message_list = NULL;
1592 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1593 n = buffered_messages.find(aom.id);
1596 message_list = new core::list<ActiveObjectMessage>;
1597 buffered_messages.insert(aom.id, message_list);
1601 message_list = n->getValue();
1603 message_list->push_back(aom);
1606 // Route data to every client
1607 for(core::map<u16, RemoteClient*>::Iterator
1608 i = m_clients.getIterator();
1609 i.atEnd()==false; i++)
1611 RemoteClient *client = i.getNode()->getValue();
1612 std::string reliable_data;
1613 std::string unreliable_data;
1614 // Go through all objects in message buffer
1615 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1616 j = buffered_messages.getIterator();
1617 j.atEnd()==false; j++)
1619 // If object is not known by client, skip it
1620 u16 id = j.getNode()->getKey();
1621 if(client->m_known_objects.find(id) == NULL)
1623 // Get message list of object
1624 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1625 // Go through every message
1626 for(core::list<ActiveObjectMessage>::Iterator
1627 k = list->begin(); k != list->end(); k++)
1629 // Compose the full new data with header
1630 ActiveObjectMessage aom = *k;
1631 std::string new_data;
1634 writeU16((u8*)&buf[0], aom.id);
1635 new_data.append(buf, 2);
1637 new_data += serializeString(aom.datastring);
1638 // Add data to buffer
1640 reliable_data += new_data;
1642 unreliable_data += new_data;
1646 reliable_data and unreliable_data are now ready.
1649 if(reliable_data.size() > 0)
1651 SharedBuffer<u8> reply(2 + reliable_data.size());
1652 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1653 memcpy((char*)&reply[2], reliable_data.c_str(),
1654 reliable_data.size());
1656 m_con.Send(client->peer_id, 0, reply, true);
1658 if(unreliable_data.size() > 0)
1660 SharedBuffer<u8> reply(2 + unreliable_data.size());
1661 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1662 memcpy((char*)&reply[2], unreliable_data.c_str(),
1663 unreliable_data.size());
1664 // Send as unreliable
1665 m_con.Send(client->peer_id, 0, reply, false);
1668 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1670 infostream<<"Server: Size of object message data: "
1671 <<"reliable: "<<reliable_data.size()
1672 <<", unreliable: "<<unreliable_data.size()
1677 // Clear buffered_messages
1678 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1679 i = buffered_messages.getIterator();
1680 i.atEnd()==false; i++)
1682 delete i.getNode()->getValue();
1686 } // enable_experimental
1689 Send queued-for-sending map edit events.
1692 // Don't send too many at a time
1695 // Single change sending is disabled if queue size is not small
1696 bool disable_single_change_sending = false;
1697 if(m_unsent_map_edit_queue.size() >= 4)
1698 disable_single_change_sending = true;
1700 int event_count = m_unsent_map_edit_queue.size();
1702 // We'll log the amount of each
1705 while(m_unsent_map_edit_queue.size() != 0)
1707 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1709 // Players far away from the change are stored here.
1710 // Instead of sending the changes, MapBlocks are set not sent
1712 core::list<u16> far_players;
1714 if(event->type == MEET_ADDNODE)
1716 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1717 prof.add("MEET_ADDNODE", 1);
1718 if(disable_single_change_sending)
1719 sendAddNode(event->p, event->n, event->already_known_by_peer,
1722 sendAddNode(event->p, event->n, event->already_known_by_peer,
1725 else if(event->type == MEET_REMOVENODE)
1727 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1728 prof.add("MEET_REMOVENODE", 1);
1729 if(disable_single_change_sending)
1730 sendRemoveNode(event->p, event->already_known_by_peer,
1733 sendRemoveNode(event->p, event->already_known_by_peer,
1736 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1738 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1739 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1740 setBlockNotSent(event->p);
1742 else if(event->type == MEET_OTHER)
1744 infostream<<"Server: MEET_OTHER"<<std::endl;
1745 prof.add("MEET_OTHER", 1);
1746 for(core::map<v3s16, bool>::Iterator
1747 i = event->modified_blocks.getIterator();
1748 i.atEnd()==false; i++)
1750 v3s16 p = i.getNode()->getKey();
1756 prof.add("unknown", 1);
1757 infostream<<"WARNING: Server: Unknown MapEditEvent "
1758 <<((u32)event->type)<<std::endl;
1762 Set blocks not sent to far players
1764 if(far_players.size() > 0)
1766 // Convert list format to that wanted by SetBlocksNotSent
1767 core::map<v3s16, MapBlock*> modified_blocks2;
1768 for(core::map<v3s16, bool>::Iterator
1769 i = event->modified_blocks.getIterator();
1770 i.atEnd()==false; i++)
1772 v3s16 p = i.getNode()->getKey();
1773 modified_blocks2.insert(p,
1774 m_env->getMap().getBlockNoCreateNoEx(p));
1776 // Set blocks not sent
1777 for(core::list<u16>::Iterator
1778 i = far_players.begin();
1779 i != far_players.end(); i++)
1782 RemoteClient *client = getClient(peer_id);
1785 client->SetBlocksNotSent(modified_blocks2);
1791 /*// Don't send too many at a time
1793 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1797 if(event_count >= 5){
1798 infostream<<"Server: MapEditEvents:"<<std::endl;
1799 prof.print(infostream);
1800 } else if(event_count != 0){
1801 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1802 prof.print(verbosestream);
1808 Trigger emergethread (it somehow gets to a non-triggered but
1809 bysy state sometimes)
1812 float &counter = m_emergethread_trigger_timer;
1818 m_emergethread.trigger();
1822 // Save map, players and auth stuff
1824 float &counter = m_savemap_timer;
1826 if(counter >= g_settings->getFloat("server_map_save_interval"))
1829 JMutexAutoLock lock(m_env_mutex);
1831 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1834 if(m_authmanager.isModified())
1835 m_authmanager.save();
1838 if(m_banmanager.isModified())
1839 m_banmanager.save();
1841 // Save changed parts of map
1842 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1845 m_env->serializePlayers(m_path_world);
1847 // Save environment metadata
1848 m_env->saveMeta(m_path_world);
1853 void Server::Receive()
1855 DSTACK(__FUNCTION_NAME);
1856 SharedBuffer<u8> data;
1861 JMutexAutoLock conlock(m_con_mutex);
1862 datasize = m_con.Receive(peer_id, data);
1865 // This has to be called so that the client list gets synced
1866 // with the peer list of the connection
1867 handlePeerChanges();
1869 ProcessData(*data, datasize, peer_id);
1871 catch(con::InvalidIncomingDataException &e)
1873 infostream<<"Server::Receive(): "
1874 "InvalidIncomingDataException: what()="
1875 <<e.what()<<std::endl;
1877 catch(con::PeerNotFoundException &e)
1879 //NOTE: This is not needed anymore
1881 // The peer has been disconnected.
1882 // Find the associated player and remove it.
1884 /*JMutexAutoLock envlock(m_env_mutex);
1886 infostream<<"ServerThread: peer_id="<<peer_id
1887 <<" has apparently closed connection. "
1888 <<"Removing player."<<std::endl;
1890 m_env->removePlayer(peer_id);*/
1894 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1896 DSTACK(__FUNCTION_NAME);
1897 // Environment is locked first.
1898 JMutexAutoLock envlock(m_env_mutex);
1899 JMutexAutoLock conlock(m_con_mutex);
1901 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1904 Address address = m_con.GetPeerAddress(peer_id);
1905 std::string addr_s = address.serializeString();
1907 // drop player if is ip is banned
1908 if(m_banmanager.isIpBanned(addr_s)){
1909 infostream<<"Server: A banned client tried to connect from "
1910 <<addr_s<<"; banned name was "
1911 <<m_banmanager.getBanName(addr_s)<<std::endl;
1912 // This actually doesn't seem to transfer to the client
1913 SendAccessDenied(m_con, peer_id,
1914 L"Your ip is banned. Banned name was "
1915 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1916 m_con.DeletePeer(peer_id);
1920 catch(con::PeerNotFoundException &e)
1922 infostream<<"Server::ProcessData(): Cancelling: peer "
1923 <<peer_id<<" not found"<<std::endl;
1927 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1929 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1937 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1939 if(command == TOSERVER_INIT)
1941 // [0] u16 TOSERVER_INIT
1942 // [2] u8 SER_FMT_VER_HIGHEST
1943 // [3] u8[20] player_name
1944 // [23] u8[28] password <--- can be sent without this, from old versions
1946 if(datasize < 2+1+PLAYERNAME_SIZE)
1949 verbosestream<<"Server: Got TOSERVER_INIT from "
1950 <<peer_id<<std::endl;
1952 // First byte after command is maximum supported
1953 // serialization version
1954 u8 client_max = data[2];
1955 u8 our_max = SER_FMT_VER_HIGHEST;
1956 // Use the highest version supported by both
1957 u8 deployed = core::min_(client_max, our_max);
1958 // If it's lower than the lowest supported, give up.
1959 if(deployed < SER_FMT_VER_LOWEST)
1960 deployed = SER_FMT_VER_INVALID;
1962 //peer->serialization_version = deployed;
1963 getClient(peer_id)->pending_serialization_version = deployed;
1965 if(deployed == SER_FMT_VER_INVALID)
1967 actionstream<<"Server: A mismatched client tried to connect from "
1968 <<addr_s<<std::endl;
1969 infostream<<"Server: Cannot negotiate "
1970 "serialization version with peer "
1971 <<peer_id<<std::endl;
1972 SendAccessDenied(m_con, peer_id, std::wstring(
1973 L"Your client's version is not supported.\n"
1974 L"Server version is ")
1975 + narrow_to_wide(VERSION_STRING) + L"."
1981 Read and check network protocol version
1984 u16 net_proto_version = 0;
1985 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1987 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1990 getClient(peer_id)->net_proto_version = net_proto_version;
1992 if(net_proto_version == 0)
1994 actionstream<<"Server: An old tried to connect from "<<addr_s
1996 SendAccessDenied(m_con, peer_id, std::wstring(
1997 L"Your client's version is not supported.\n"
1998 L"Server version is ")
1999 + narrow_to_wide(VERSION_STRING) + L"."
2004 if(g_settings->getBool("strict_protocol_version_checking"))
2006 if(net_proto_version != PROTOCOL_VERSION)
2008 actionstream<<"Server: A mismatched client tried to connect"
2009 <<" from "<<addr_s<<std::endl;
2010 SendAccessDenied(m_con, peer_id, std::wstring(
2011 L"Your client's version is not supported.\n"
2012 L"Server version is ")
2013 + narrow_to_wide(VERSION_STRING) + L",\n"
2014 + L"server's PROTOCOL_VERSION is "
2015 + narrow_to_wide(itos(PROTOCOL_VERSION))
2016 + L", client's PROTOCOL_VERSION is "
2017 + narrow_to_wide(itos(net_proto_version))
2028 char playername[PLAYERNAME_SIZE];
2029 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2031 playername[i] = data[3+i];
2033 playername[PLAYERNAME_SIZE-1] = 0;
2035 if(playername[0]=='\0')
2037 actionstream<<"Server: Player with an empty name "
2038 <<"tried to connect from "<<addr_s<<std::endl;
2039 SendAccessDenied(m_con, peer_id,
2044 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2046 actionstream<<"Server: Player with an invalid name "
2047 <<"tried to connect from "<<addr_s<<std::endl;
2048 SendAccessDenied(m_con, peer_id,
2049 L"Name contains unallowed characters");
2053 infostream<<"Server: New connection: \""<<playername<<"\" from "
2054 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2057 char password[PASSWORD_SIZE];
2058 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2060 // old version - assume blank password
2065 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2067 password[i] = data[23+i];
2069 password[PASSWORD_SIZE-1] = 0;
2072 // Add player to auth manager
2073 if(m_authmanager.exists(playername) == false)
2075 std::wstring default_password =
2076 narrow_to_wide(g_settings->get("default_password"));
2077 std::string translated_default_password =
2078 translatePassword(playername, default_password);
2080 // If default_password is empty, allow any initial password
2081 if (default_password.length() == 0)
2082 translated_default_password = password;
2084 infostream<<"Server: adding player "<<playername
2085 <<" to auth manager"<<std::endl;
2086 m_authmanager.add(playername);
2087 m_authmanager.setPassword(playername, translated_default_password);
2088 m_authmanager.setPrivs(playername,
2089 stringToPrivs(g_settings->get("default_privs")));
2090 m_authmanager.save();
2093 std::string checkpwd = m_authmanager.getPassword(playername);
2095 /*infostream<<"Server: Client gave password '"<<password
2096 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2098 if(password != checkpwd)
2100 infostream<<"Server: peer_id="<<peer_id
2101 <<": supplied invalid password for "
2102 <<playername<<std::endl;
2103 SendAccessDenied(m_con, peer_id, L"Invalid password");
2107 // Do not allow multiple players in simple singleplayer mode.
2108 // This isn't a perfect way to do it, but will suffice for now.
2109 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2110 infostream<<"Server: Not allowing another client to connect in"
2111 <<" simple singleplayer mode"<<std::endl;
2112 SendAccessDenied(m_con, peer_id,
2113 L"Running in simple singleplayer mode.");
2117 // Enforce user limit.
2118 // Don't enforce for users that have some admin right
2119 if(m_clients.size() >= g_settings->getU16("max_users") &&
2120 (m_authmanager.getPrivs(playername)
2121 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2122 playername != g_settings->get("name"))
2124 actionstream<<"Server: "<<playername<<" tried to join, but there"
2125 <<" are already max_users="
2126 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2127 SendAccessDenied(m_con, peer_id, L"Too many users.");
2132 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2134 // If failed, cancel
2137 errorstream<<"Server: peer_id="<<peer_id
2138 <<": failed to emerge player"<<std::endl;
2143 Answer with a TOCLIENT_INIT
2146 SharedBuffer<u8> reply(2+1+6+8);
2147 writeU16(&reply[0], TOCLIENT_INIT);
2148 writeU8(&reply[2], deployed);
2149 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2150 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2153 m_con.Send(peer_id, 0, reply, true);
2157 Send complete position information
2159 SendMovePlayer(player);
2164 if(command == TOSERVER_INIT2)
2166 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2167 <<peer_id<<std::endl;
2170 getClient(peer_id)->serialization_version
2171 = getClient(peer_id)->pending_serialization_version;
2174 Send some initialization data
2177 infostream<<"Server: Sending content to "
2178 <<getPlayerName(peer_id)<<std::endl;
2180 // Send item definitions
2181 SendItemDef(m_con, peer_id, m_itemdef);
2183 // Send node definitions
2184 SendNodeDef(m_con, peer_id, m_nodedef);
2186 // Send texture announcement
2187 sendMediaAnnouncement(peer_id);
2189 // Send player info to all players
2190 //SendPlayerInfos();
2192 // Send inventory to player
2193 UpdateCrafting(peer_id);
2194 SendInventory(peer_id);
2196 // Send player items to all players
2199 Player *player = m_env->getPlayer(peer_id);
2202 SendPlayerHP(player);
2204 // Show death screen if necessary
2206 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2210 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2211 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2212 m_con.Send(peer_id, 0, data, true);
2215 // Note things in chat if not in simple singleplayer mode
2216 if(!m_simple_singleplayer_mode)
2218 // Send information about server to player in chat
2219 SendChatMessage(peer_id, getStatusString());
2221 // Send information about joining in chat
2223 std::wstring name = L"unknown";
2224 Player *player = m_env->getPlayer(peer_id);
2226 name = narrow_to_wide(player->getName());
2228 std::wstring message;
2231 message += L" joined game";
2232 BroadcastChatMessage(message);
2236 // Warnings about protocol version can be issued here
2237 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2239 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2246 std::ostringstream os(std::ios_base::binary);
2247 for(core::map<u16, RemoteClient*>::Iterator
2248 i = m_clients.getIterator();
2249 i.atEnd() == false; i++)
2251 RemoteClient *client = i.getNode()->getValue();
2252 assert(client->peer_id == i.getNode()->getKey());
2253 if(client->serialization_version == SER_FMT_VER_INVALID)
2256 Player *player = m_env->getPlayer(client->peer_id);
2259 // Get name of player
2260 os<<player->getName()<<" ";
2263 actionstream<<player->getName()<<" joins game. List of players: "
2264 <<os.str()<<std::endl;
2270 if(peer_ser_ver == SER_FMT_VER_INVALID)
2272 infostream<<"Server::ProcessData(): Cancelling: Peer"
2273 " serialization format invalid or not initialized."
2274 " Skipping incoming command="<<command<<std::endl;
2278 Player *player = m_env->getPlayer(peer_id);
2279 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2282 infostream<<"Server::ProcessData(): Cancelling: "
2283 "No player for peer_id="<<peer_id
2287 if(command == TOSERVER_PLAYERPOS)
2289 if(datasize < 2+12+12+4+4)
2293 v3s32 ps = readV3S32(&data[start+2]);
2294 v3s32 ss = readV3S32(&data[start+2+12]);
2295 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2296 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2297 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2298 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2299 pitch = wrapDegrees(pitch);
2300 yaw = wrapDegrees(yaw);
2302 player->setPosition(position);
2303 player->setSpeed(speed);
2304 player->setPitch(pitch);
2305 player->setYaw(yaw);
2307 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2308 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2309 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2311 else if(command == TOSERVER_GOTBLOCKS)
2324 u16 count = data[2];
2325 for(u16 i=0; i<count; i++)
2327 if((s16)datasize < 2+1+(i+1)*6)
2328 throw con::InvalidIncomingDataException
2329 ("GOTBLOCKS length is too short");
2330 v3s16 p = readV3S16(&data[2+1+i*6]);
2331 /*infostream<<"Server: GOTBLOCKS ("
2332 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2333 RemoteClient *client = getClient(peer_id);
2334 client->GotBlock(p);
2337 else if(command == TOSERVER_DELETEDBLOCKS)
2350 u16 count = data[2];
2351 for(u16 i=0; i<count; i++)
2353 if((s16)datasize < 2+1+(i+1)*6)
2354 throw con::InvalidIncomingDataException
2355 ("DELETEDBLOCKS length is too short");
2356 v3s16 p = readV3S16(&data[2+1+i*6]);
2357 /*infostream<<"Server: DELETEDBLOCKS ("
2358 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2359 RemoteClient *client = getClient(peer_id);
2360 client->SetBlockNotSent(p);
2363 else if(command == TOSERVER_CLICK_OBJECT)
2365 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2368 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2370 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2373 else if(command == TOSERVER_GROUND_ACTION)
2375 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2379 else if(command == TOSERVER_RELEASE)
2381 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2384 else if(command == TOSERVER_SIGNTEXT)
2386 infostream<<"Server: SIGNTEXT not supported anymore"
2390 else if(command == TOSERVER_SIGNNODETEXT)
2392 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2400 std::string datastring((char*)&data[2], datasize-2);
2401 std::istringstream is(datastring, std::ios_base::binary);
2404 is.read((char*)buf, 6);
2405 v3s16 p = readV3S16(buf);
2406 is.read((char*)buf, 2);
2407 u16 textlen = readU16(buf);
2409 for(u16 i=0; i<textlen; i++)
2411 is.read((char*)buf, 1);
2412 text += (char)buf[0];
2415 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2419 meta->setText(text);
2421 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2422 <<" at "<<PP(p)<<std::endl;
2424 v3s16 blockpos = getNodeBlockPos(p);
2425 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2428 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2432 setBlockNotSent(blockpos);
2434 else if(command == TOSERVER_INVENTORY_ACTION)
2436 // Strip command and create a stream
2437 std::string datastring((char*)&data[2], datasize-2);
2438 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2439 std::istringstream is(datastring, std::ios_base::binary);
2441 InventoryAction *a = InventoryAction::deSerialize(is);
2444 infostream<<"TOSERVER_INVENTORY_ACTION: "
2445 <<"InventoryAction::deSerialize() returned NULL"
2451 Note: Always set inventory not sent, to repair cases
2452 where the client made a bad prediction.
2456 Handle restrictions and special cases of the move action
2458 if(a->getType() == IACTION_MOVE)
2460 IMoveAction *ma = (IMoveAction*)a;
2462 ma->from_inv.applyCurrentPlayer(player->getName());
2463 ma->to_inv.applyCurrentPlayer(player->getName());
2465 setInventoryModified(ma->from_inv);
2466 setInventoryModified(ma->to_inv);
2468 bool from_inv_is_current_player =
2469 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2470 (ma->from_inv.name == player->getName());
2472 bool to_inv_is_current_player =
2473 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2474 (ma->to_inv.name == player->getName());
2477 Disable moving items out of craftpreview
2479 if(ma->from_list == "craftpreview")
2481 infostream<<"Ignoring IMoveAction from "
2482 <<(ma->from_inv.dump())<<":"<<ma->from_list
2483 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2484 <<" because src is "<<ma->from_list<<std::endl;
2490 Disable moving items into craftresult and craftpreview
2492 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2494 infostream<<"Ignoring IMoveAction from "
2495 <<(ma->from_inv.dump())<<":"<<ma->from_list
2496 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2497 <<" because dst is "<<ma->to_list<<std::endl;
2502 // Disallow moving items in elsewhere than player's inventory
2503 // if not allowed to interact
2504 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2505 && (!from_inv_is_current_player
2506 || !to_inv_is_current_player))
2508 infostream<<"Cannot move outside of player's inventory: "
2509 <<"No interact privilege"<<std::endl;
2514 // If player is not an admin, check for ownership of src and dst
2515 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2517 std::string owner_from = getInventoryOwner(ma->from_inv);
2518 if(owner_from != "" && owner_from != player->getName())
2520 infostream<<"WARNING: "<<player->getName()
2521 <<" tried to access an inventory that"
2522 <<" belongs to "<<owner_from<<std::endl;
2527 std::string owner_to = getInventoryOwner(ma->to_inv);
2528 if(owner_to != "" && owner_to != player->getName())
2530 infostream<<"WARNING: "<<player->getName()
2531 <<" tried to access an inventory that"
2532 <<" belongs to "<<owner_to<<std::endl;
2539 Handle restrictions and special cases of the drop action
2541 else if(a->getType() == IACTION_DROP)
2543 IDropAction *da = (IDropAction*)a;
2545 da->from_inv.applyCurrentPlayer(player->getName());
2547 setInventoryModified(da->from_inv);
2549 // Disallow dropping items if not allowed to interact
2550 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2555 // If player is not an admin, check for ownership
2556 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2558 std::string owner_from = getInventoryOwner(da->from_inv);
2559 if(owner_from != "" && owner_from != player->getName())
2561 infostream<<"WARNING: "<<player->getName()
2562 <<" tried to access an inventory that"
2563 <<" belongs to "<<owner_from<<std::endl;
2570 Handle restrictions and special cases of the craft action
2572 else if(a->getType() == IACTION_CRAFT)
2574 ICraftAction *ca = (ICraftAction*)a;
2576 ca->craft_inv.applyCurrentPlayer(player->getName());
2578 setInventoryModified(ca->craft_inv);
2580 //bool craft_inv_is_current_player =
2581 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2582 // (ca->craft_inv.name == player->getName());
2584 // Disallow crafting if not allowed to interact
2585 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2587 infostream<<"Cannot craft: "
2588 <<"No interact privilege"<<std::endl;
2593 // If player is not an admin, check for ownership of inventory
2594 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2596 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2597 if(owner_craft != "" && owner_craft != player->getName())
2599 infostream<<"WARNING: "<<player->getName()
2600 <<" tried to access an inventory that"
2601 <<" belongs to "<<owner_craft<<std::endl;
2609 a->apply(this, srp, this);
2613 else if(command == TOSERVER_CHAT_MESSAGE)
2621 std::string datastring((char*)&data[2], datasize-2);
2622 std::istringstream is(datastring, std::ios_base::binary);
2625 is.read((char*)buf, 2);
2626 u16 len = readU16(buf);
2628 std::wstring message;
2629 for(u16 i=0; i<len; i++)
2631 is.read((char*)buf, 2);
2632 message += (wchar_t)readU16(buf);
2635 // Get player name of this client
2636 std::wstring name = narrow_to_wide(player->getName());
2639 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2640 wide_to_narrow(message));
2641 // If script ate the message, don't proceed
2645 // Line to send to players
2647 // Whether to send to the player that sent the line
2648 bool send_to_sender = false;
2649 // Whether to send to other players
2650 bool send_to_others = false;
2652 // Local player gets all privileges regardless of
2653 // what's set on their account.
2654 u64 privs = getPlayerPrivs(player);
2657 if(message[0] == L'/')
2659 size_t strip_size = 1;
2660 if (message[1] == L'#') // support old-style commans
2662 message = message.substr(strip_size);
2664 WStrfnd f1(message);
2665 f1.next(L" "); // Skip over /#whatever
2666 std::wstring paramstring = f1.next(L"");
2668 ServerCommandContext *ctx = new ServerCommandContext(
2669 str_split(message, L' '),
2676 std::wstring reply(processServerCommand(ctx));
2677 send_to_sender = ctx->flags & SEND_TO_SENDER;
2678 send_to_others = ctx->flags & SEND_TO_OTHERS;
2680 if (ctx->flags & SEND_NO_PREFIX)
2683 line += L"Server: " + reply;
2690 if(privs & PRIV_SHOUT)
2696 send_to_others = true;
2700 line += L"Server: You are not allowed to shout";
2701 send_to_sender = true;
2708 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2711 Send the message to clients
2713 for(core::map<u16, RemoteClient*>::Iterator
2714 i = m_clients.getIterator();
2715 i.atEnd() == false; i++)
2717 // Get client and check that it is valid
2718 RemoteClient *client = i.getNode()->getValue();
2719 assert(client->peer_id == i.getNode()->getKey());
2720 if(client->serialization_version == SER_FMT_VER_INVALID)
2724 bool sender_selected = (peer_id == client->peer_id);
2725 if(sender_selected == true && send_to_sender == false)
2727 if(sender_selected == false && send_to_others == false)
2730 SendChatMessage(client->peer_id, line);
2734 else if(command == TOSERVER_DAMAGE)
2736 std::string datastring((char*)&data[2], datasize-2);
2737 std::istringstream is(datastring, std::ios_base::binary);
2738 u8 damage = readU8(is);
2740 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2742 if(g_settings->getBool("enable_damage"))
2744 actionstream<<player->getName()<<" damaged by "
2745 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2748 srp->setHP(srp->getHP() - damage);
2750 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2753 if(srp->m_hp_not_sent)
2754 SendPlayerHP(player);
2758 // Force send (to correct the client's predicted HP)
2759 SendPlayerHP(player);
2762 else if(command == TOSERVER_PASSWORD)
2765 [0] u16 TOSERVER_PASSWORD
2766 [2] u8[28] old password
2767 [30] u8[28] new password
2770 if(datasize != 2+PASSWORD_SIZE*2)
2772 /*char password[PASSWORD_SIZE];
2773 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2774 password[i] = data[2+i];
2775 password[PASSWORD_SIZE-1] = 0;*/
2777 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2785 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2787 char c = data[2+PASSWORD_SIZE+i];
2793 infostream<<"Server: Client requests a password change from "
2794 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2796 std::string playername = player->getName();
2798 if(m_authmanager.exists(playername) == false)
2800 infostream<<"Server: playername not found in authmanager"<<std::endl;
2801 // Wrong old password supplied!!
2802 SendChatMessage(peer_id, L"playername not found in authmanager");
2806 std::string checkpwd = m_authmanager.getPassword(playername);
2808 if(oldpwd != checkpwd)
2810 infostream<<"Server: invalid old password"<<std::endl;
2811 // Wrong old password supplied!!
2812 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2816 actionstream<<player->getName()<<" changes password"<<std::endl;
2818 m_authmanager.setPassword(playername, newpwd);
2820 infostream<<"Server: password change successful for "<<playername
2822 SendChatMessage(peer_id, L"Password change successful");
2824 else if(command == TOSERVER_PLAYERITEM)
2829 u16 item = readU16(&data[2]);
2830 srp->setWieldIndex(item);
2831 SendWieldedItem(srp);
2833 else if(command == TOSERVER_RESPAWN)
2838 RespawnPlayer(player);
2840 actionstream<<player->getName()<<" respawns at "
2841 <<PP(player->getPosition()/BS)<<std::endl;
2843 // ActiveObject is added to environment in AsyncRunStep after
2844 // the previous addition has been succesfully removed
2846 else if(command == TOSERVER_REQUEST_MEDIA) {
2847 std::string datastring((char*)&data[2], datasize-2);
2848 std::istringstream is(datastring, std::ios_base::binary);
2850 core::list<MediaRequest> tosend;
2851 u16 numfiles = readU16(is);
2853 infostream<<"Sending "<<numfiles<<" files to "
2854 <<getPlayerName(peer_id)<<std::endl;
2855 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2857 for(int i = 0; i < numfiles; i++) {
2858 std::string name = deSerializeString(is);
2859 tosend.push_back(MediaRequest(name));
2860 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2864 sendRequestedMedia(peer_id, tosend);
2866 // Now the client should know about everything
2867 // (definitions and files)
2868 getClient(peer_id)->definitions_sent = true;
2870 else if(command == TOSERVER_INTERACT)
2872 std::string datastring((char*)&data[2], datasize-2);
2873 std::istringstream is(datastring, std::ios_base::binary);
2879 [5] u32 length of the next item
2880 [9] serialized PointedThing
2882 0: start digging (from undersurface) or use
2883 1: stop digging (all parameters ignored)
2884 2: digging completed
2885 3: place block or item (to abovesurface)
2888 u8 action = readU8(is);
2889 u16 item_i = readU16(is);
2890 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2891 PointedThing pointed;
2892 pointed.deSerialize(tmp_is);
2894 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2895 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2899 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2900 <<" tried to interact, but is dead!"<<std::endl;
2904 v3f player_pos = srp->m_last_good_position;
2906 // Update wielded item
2907 if(srp->getWieldIndex() != item_i)
2909 srp->setWieldIndex(item_i);
2910 SendWieldedItem(srp);
2913 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2914 v3s16 p_under = pointed.node_undersurface;
2915 v3s16 p_above = pointed.node_abovesurface;
2917 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2918 ServerActiveObject *pointed_object = NULL;
2919 if(pointed.type == POINTEDTHING_OBJECT)
2921 pointed_object = m_env->getActiveObject(pointed.object_id);
2922 if(pointed_object == NULL)
2924 verbosestream<<"TOSERVER_INTERACT: "
2925 "pointed object is NULL"<<std::endl;
2931 v3f pointed_pos_under = player_pos;
2932 v3f pointed_pos_above = player_pos;
2933 if(pointed.type == POINTEDTHING_NODE)
2935 pointed_pos_under = intToFloat(p_under, BS);
2936 pointed_pos_above = intToFloat(p_above, BS);
2938 else if(pointed.type == POINTEDTHING_OBJECT)
2940 pointed_pos_under = pointed_object->getBasePosition();
2941 pointed_pos_above = pointed_pos_under;
2945 Check that target is reasonably close
2946 (only when digging or placing things)
2948 if(action == 0 || action == 2 || action == 3)
2950 float d = player_pos.getDistanceFrom(pointed_pos_under);
2951 float max_d = BS * 14; // Just some large enough value
2953 actionstream<<"Player "<<player->getName()
2954 <<" tried to access "<<pointed.dump()
2956 <<"d="<<d<<", max_d="<<max_d
2957 <<". ignoring."<<std::endl;
2958 // Re-send block to revert change on client-side
2959 RemoteClient *client = getClient(peer_id);
2960 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2961 client->SetBlockNotSent(blockpos);
2968 Make sure the player is allowed to do it
2970 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2972 infostream<<"Ignoring interaction from player "<<player->getName()
2973 <<" because privileges are "<<getPlayerPrivs(player)
2979 0: start digging or punch object
2983 if(pointed.type == POINTEDTHING_NODE)
2986 NOTE: This can be used in the future to check if
2987 somebody is cheating, by checking the timing.
2989 MapNode n(CONTENT_IGNORE);
2992 n = m_env->getMap().getNode(p_under);
2994 catch(InvalidPositionException &e)
2996 infostream<<"Server: Not punching: Node not found."
2997 <<" Adding block to emerge queue."
2999 m_emerge_queue.addBlock(peer_id,
3000 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3002 if(n.getContent() != CONTENT_IGNORE)
3003 scriptapi_node_on_punch(m_lua, p_under, n, srp);
3005 else if(pointed.type == POINTEDTHING_OBJECT)
3007 // Skip if object has been removed
3008 if(pointed_object->m_removed)
3011 actionstream<<player->getName()<<" punches object "
3012 <<pointed.object_id<<": "
3013 <<pointed_object->getDescription()<<std::endl;
3015 ItemStack punchitem = srp->getWieldedItem();
3016 ToolCapabilities toolcap =
3017 punchitem.getToolCapabilities(m_itemdef);
3018 v3f dir = (pointed_object->getBasePosition() -
3019 (srp->getPosition() + srp->getEyeOffset())
3021 pointed_object->punch(dir, &toolcap, srp,
3022 srp->m_time_from_last_punch);
3023 srp->m_time_from_last_punch = 0;
3031 else if(action == 1)
3036 2: Digging completed
3038 else if(action == 2)
3040 // Only complete digging of nodes
3041 if(pointed.type == POINTEDTHING_NODE)
3043 MapNode n(CONTENT_IGNORE);
3046 n = m_env->getMap().getNode(p_under);
3048 catch(InvalidPositionException &e)
3050 infostream<<"Server: Not finishing digging: Node not found."
3051 <<" Adding block to emerge queue."
3053 m_emerge_queue.addBlock(peer_id,
3054 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3056 if(n.getContent() != CONTENT_IGNORE)
3057 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3062 3: place block or right-click object
3064 else if(action == 3)
3066 ItemStack item = srp->getWieldedItem();
3068 // Reset build time counter
3069 if(pointed.type == POINTEDTHING_NODE &&
3070 item.getDefinition(m_itemdef).type == ITEM_NODE)
3071 getClient(peer_id)->m_time_from_building = 0.0;
3073 if(pointed.type == POINTEDTHING_OBJECT)
3075 // Right click object
3077 // Skip if object has been removed
3078 if(pointed_object->m_removed)
3081 actionstream<<player->getName()<<" right-clicks object "
3082 <<pointed.object_id<<": "
3083 <<pointed_object->getDescription()<<std::endl;
3086 pointed_object->rightClick(srp);
3088 else if(scriptapi_item_on_place(m_lua,
3089 item, srp, pointed))
3091 // Placement was handled in lua
3093 // Apply returned ItemStack
3094 if(g_settings->getBool("creative_mode") == false)
3095 srp->setWieldedItem(item);
3103 else if(action == 4)
3105 ItemStack item = srp->getWieldedItem();
3107 actionstream<<player->getName()<<" uses "<<item.name
3108 <<", pointing at "<<pointed.dump()<<std::endl;
3110 if(scriptapi_item_on_use(m_lua,
3111 item, srp, pointed))
3113 // Apply returned ItemStack
3114 if(g_settings->getBool("creative_mode") == false)
3115 srp->setWieldedItem(item);
3121 Catch invalid actions
3125 infostream<<"WARNING: Server: Invalid action "
3126 <<action<<std::endl;
3129 else if(command == TOSERVER_REMOVED_SOUNDS)
3131 std::string datastring((char*)&data[2], datasize-2);
3132 std::istringstream is(datastring, std::ios_base::binary);
3134 int num = readU16(is);
3135 for(int k=0; k<num; k++){
3136 s32 id = readS32(is);
3137 std::map<s32, ServerPlayingSound>::iterator i =
3138 m_playing_sounds.find(id);
3139 if(i == m_playing_sounds.end())
3141 ServerPlayingSound &psound = i->second;
3142 psound.clients.erase(peer_id);
3143 if(psound.clients.size() == 0)
3144 m_playing_sounds.erase(i++);
3149 infostream<<"Server::ProcessData(): Ignoring "
3150 "unknown command "<<command<<std::endl;
3154 catch(SendFailedException &e)
3156 errorstream<<"Server::ProcessData(): SendFailedException: "
3162 void Server::onMapEditEvent(MapEditEvent *event)
3164 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3165 if(m_ignore_map_edit_events)
3167 MapEditEvent *e = event->clone();
3168 m_unsent_map_edit_queue.push_back(e);
3171 Inventory* Server::getInventory(const InventoryLocation &loc)
3174 case InventoryLocation::UNDEFINED:
3177 case InventoryLocation::CURRENT_PLAYER:
3180 case InventoryLocation::PLAYER:
3182 Player *player = m_env->getPlayer(loc.name.c_str());
3185 return &player->inventory;
3188 case InventoryLocation::NODEMETA:
3190 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3193 return meta->getInventory();
3201 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3204 case InventoryLocation::UNDEFINED:
3207 case InventoryLocation::CURRENT_PLAYER:
3210 case InventoryLocation::PLAYER:
3215 case InventoryLocation::NODEMETA:
3217 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3220 return meta->getOwner();
3228 void Server::setInventoryModified(const InventoryLocation &loc)
3231 case InventoryLocation::UNDEFINED:
3234 case InventoryLocation::PLAYER:
3236 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3237 (m_env->getPlayer(loc.name.c_str()));
3240 srp->m_inventory_not_sent = true;
3243 case InventoryLocation::NODEMETA:
3245 v3s16 blockpos = getNodeBlockPos(loc.p);
3247 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3249 meta->inventoryModified();
3251 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3253 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3255 setBlockNotSent(blockpos);
3263 core::list<PlayerInfo> Server::getPlayerInfo()
3265 DSTACK(__FUNCTION_NAME);
3266 JMutexAutoLock envlock(m_env_mutex);
3267 JMutexAutoLock conlock(m_con_mutex);
3269 core::list<PlayerInfo> list;
3271 core::list<Player*> players = m_env->getPlayers();
3273 core::list<Player*>::Iterator i;
3274 for(i = players.begin();
3275 i != players.end(); i++)
3279 Player *player = *i;
3282 // Copy info from connection to info struct
3283 info.id = player->peer_id;
3284 info.address = m_con.GetPeerAddress(player->peer_id);
3285 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3287 catch(con::PeerNotFoundException &e)
3289 // Set dummy peer info
3291 info.address = Address(0,0,0,0,0);
3295 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3296 info.position = player->getPosition();
3298 list.push_back(info);
3305 void Server::peerAdded(con::Peer *peer)
3307 DSTACK(__FUNCTION_NAME);
3308 verbosestream<<"Server::peerAdded(): peer->id="
3309 <<peer->id<<std::endl;
3312 c.type = PEER_ADDED;
3313 c.peer_id = peer->id;
3315 m_peer_change_queue.push_back(c);
3318 void Server::deletingPeer(con::Peer *peer, bool timeout)
3320 DSTACK(__FUNCTION_NAME);
3321 verbosestream<<"Server::deletingPeer(): peer->id="
3322 <<peer->id<<", timeout="<<timeout<<std::endl;
3325 c.type = PEER_REMOVED;
3326 c.peer_id = peer->id;
3327 c.timeout = timeout;
3328 m_peer_change_queue.push_back(c);
3335 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3337 DSTACK(__FUNCTION_NAME);
3338 std::ostringstream os(std::ios_base::binary);
3340 writeU16(os, TOCLIENT_HP);
3344 std::string s = os.str();
3345 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3347 con.Send(peer_id, 0, data, true);
3350 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3351 const std::wstring &reason)
3353 DSTACK(__FUNCTION_NAME);
3354 std::ostringstream os(std::ios_base::binary);
3356 writeU16(os, TOCLIENT_ACCESS_DENIED);
3357 os<<serializeWideString(reason);
3360 std::string s = os.str();
3361 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3363 con.Send(peer_id, 0, data, true);
3366 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3367 bool set_camera_point_target, v3f camera_point_target)
3369 DSTACK(__FUNCTION_NAME);
3370 std::ostringstream os(std::ios_base::binary);
3372 writeU16(os, TOCLIENT_DEATHSCREEN);
3373 writeU8(os, set_camera_point_target);
3374 writeV3F1000(os, camera_point_target);
3377 std::string s = os.str();
3378 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3380 con.Send(peer_id, 0, data, true);
3383 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3384 IItemDefManager *itemdef)
3386 DSTACK(__FUNCTION_NAME);
3387 std::ostringstream os(std::ios_base::binary);
3391 u32 length of the next item
3392 zlib-compressed serialized ItemDefManager
3394 writeU16(os, TOCLIENT_ITEMDEF);
3395 std::ostringstream tmp_os(std::ios::binary);
3396 itemdef->serialize(tmp_os);
3397 std::ostringstream tmp_os2(std::ios::binary);
3398 compressZlib(tmp_os.str(), tmp_os2);
3399 os<<serializeLongString(tmp_os2.str());
3402 std::string s = os.str();
3403 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3404 <<"): size="<<s.size()<<std::endl;
3405 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3407 con.Send(peer_id, 0, data, true);
3410 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3411 INodeDefManager *nodedef)
3413 DSTACK(__FUNCTION_NAME);
3414 std::ostringstream os(std::ios_base::binary);
3418 u32 length of the next item
3419 zlib-compressed serialized NodeDefManager
3421 writeU16(os, TOCLIENT_NODEDEF);
3422 std::ostringstream tmp_os(std::ios::binary);
3423 nodedef->serialize(tmp_os);
3424 std::ostringstream tmp_os2(std::ios::binary);
3425 compressZlib(tmp_os.str(), tmp_os2);
3426 os<<serializeLongString(tmp_os2.str());
3429 std::string s = os.str();
3430 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3431 <<"): size="<<s.size()<<std::endl;
3432 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3434 con.Send(peer_id, 0, data, true);
3438 Non-static send methods
3441 void Server::SendInventory(u16 peer_id)
3443 DSTACK(__FUNCTION_NAME);
3445 ServerRemotePlayer* player =
3446 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3449 player->m_inventory_not_sent = false;
3455 std::ostringstream os;
3456 //os.imbue(std::locale("C"));
3458 player->inventory.serialize(os);
3460 std::string s = os.str();
3462 SharedBuffer<u8> data(s.size()+2);
3463 writeU16(&data[0], TOCLIENT_INVENTORY);
3464 memcpy(&data[2], s.c_str(), s.size());
3467 m_con.Send(peer_id, 0, data, true);
3470 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3472 DSTACK(__FUNCTION_NAME);
3476 std::ostringstream os(std::ios_base::binary);
3478 writeU16(os, TOCLIENT_PLAYERITEM);
3480 writeU16(os, srp->peer_id);
3481 os<<serializeString(srp->getWieldedItem().getItemString());
3484 std::string s = os.str();
3485 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3487 m_con.SendToAll(0, data, true);
3490 void Server::SendPlayerItems()
3492 DSTACK(__FUNCTION_NAME);
3494 std::ostringstream os(std::ios_base::binary);
3495 core::list<Player *> players = m_env->getPlayers(true);
3497 writeU16(os, TOCLIENT_PLAYERITEM);
3498 writeU16(os, players.size());
3499 core::list<Player *>::Iterator i;
3500 for(i = players.begin(); i != players.end(); ++i)
3503 ServerRemotePlayer *srp =
3504 static_cast<ServerRemotePlayer*>(p);
3505 writeU16(os, p->peer_id);
3506 os<<serializeString(srp->getWieldedItem().getItemString());
3510 std::string s = os.str();
3511 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3513 m_con.SendToAll(0, data, true);
3516 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3518 DSTACK(__FUNCTION_NAME);
3520 std::ostringstream os(std::ios_base::binary);
3524 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3525 os.write((char*)buf, 2);
3528 writeU16(buf, message.size());
3529 os.write((char*)buf, 2);
3532 for(u32 i=0; i<message.size(); i++)
3536 os.write((char*)buf, 2);
3540 std::string s = os.str();
3541 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3543 m_con.Send(peer_id, 0, data, true);
3546 void Server::BroadcastChatMessage(const std::wstring &message)
3548 for(core::map<u16, RemoteClient*>::Iterator
3549 i = m_clients.getIterator();
3550 i.atEnd() == false; i++)
3552 // Get client and check that it is valid
3553 RemoteClient *client = i.getNode()->getValue();
3554 assert(client->peer_id == i.getNode()->getKey());
3555 if(client->serialization_version == SER_FMT_VER_INVALID)
3558 SendChatMessage(client->peer_id, message);
3562 void Server::SendPlayerHP(Player *player)
3564 SendHP(m_con, player->peer_id, player->hp);
3565 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3568 void Server::SendMovePlayer(Player *player)
3570 DSTACK(__FUNCTION_NAME);
3571 std::ostringstream os(std::ios_base::binary);
3573 writeU16(os, TOCLIENT_MOVE_PLAYER);
3574 writeV3F1000(os, player->getPosition());
3575 writeF1000(os, player->getPitch());
3576 writeF1000(os, player->getYaw());
3579 v3f pos = player->getPosition();
3580 f32 pitch = player->getPitch();
3581 f32 yaw = player->getYaw();
3582 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3583 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3590 std::string s = os.str();
3591 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3593 m_con.Send(player->peer_id, 0, data, true);
3596 s32 Server::playSound(const SimpleSoundSpec &spec,
3597 const ServerSoundParams ¶ms)
3599 // Find out initial position of sound
3600 bool pos_exists = false;
3601 v3f pos = params.getPos(m_env, &pos_exists);
3602 // If position is not found while it should be, cancel sound
3603 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3605 // Filter destination clients
3606 std::set<RemoteClient*> dst_clients;
3607 if(params.to_player != "")
3609 Player *player = m_env->getPlayer(params.to_player.c_str());
3611 infostream<<"Server::playSound: Player \""<<params.to_player
3612 <<"\" not found"<<std::endl;
3615 if(player->peer_id == PEER_ID_INEXISTENT){
3616 infostream<<"Server::playSound: Player \""<<params.to_player
3617 <<"\" not connected"<<std::endl;
3620 RemoteClient *client = getClient(player->peer_id);
3621 dst_clients.insert(client);
3625 for(core::map<u16, RemoteClient*>::Iterator
3626 i = m_clients.getIterator(); i.atEnd() == false; i++)
3628 RemoteClient *client = i.getNode()->getValue();
3629 Player *player = m_env->getPlayer(client->peer_id);
3633 if(player->getPosition().getDistanceFrom(pos) >
3634 params.max_hear_distance)
3637 dst_clients.insert(client);
3640 if(dst_clients.size() == 0)
3643 s32 id = m_next_sound_id++;
3644 // The sound will exist as a reference in m_playing_sounds
3645 m_playing_sounds[id] = ServerPlayingSound();
3646 ServerPlayingSound &psound = m_playing_sounds[id];
3647 psound.params = params;
3648 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3649 i != dst_clients.end(); i++)
3650 psound.clients.insert((*i)->peer_id);
3652 std::ostringstream os(std::ios_base::binary);
3653 writeU16(os, TOCLIENT_PLAY_SOUND);
3655 os<<serializeString(spec.name);
3656 writeF1000(os, spec.gain * params.gain);
3657 writeU8(os, params.type);
3658 writeV3F1000(os, pos);
3659 writeU16(os, params.object);
3660 writeU8(os, params.loop);
3662 std::string s = os.str();
3663 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3665 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3666 i != dst_clients.end(); i++){
3668 m_con.Send((*i)->peer_id, 0, data, true);
3672 void Server::stopSound(s32 handle)
3674 // Get sound reference
3675 std::map<s32, ServerPlayingSound>::iterator i =
3676 m_playing_sounds.find(handle);
3677 if(i == m_playing_sounds.end())
3679 ServerPlayingSound &psound = i->second;
3681 std::ostringstream os(std::ios_base::binary);
3682 writeU16(os, TOCLIENT_STOP_SOUND);
3683 writeS32(os, handle);
3685 std::string s = os.str();
3686 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3688 for(std::set<u16>::iterator i = psound.clients.begin();
3689 i != psound.clients.end(); i++){
3691 m_con.Send(*i, 0, data, true);
3693 // Remove sound reference
3694 m_playing_sounds.erase(i);
3697 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3698 core::list<u16> *far_players, float far_d_nodes)
3700 float maxd = far_d_nodes*BS;
3701 v3f p_f = intToFloat(p, BS);
3705 SharedBuffer<u8> reply(replysize);
3706 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3707 writeS16(&reply[2], p.X);
3708 writeS16(&reply[4], p.Y);
3709 writeS16(&reply[6], p.Z);
3711 for(core::map<u16, RemoteClient*>::Iterator
3712 i = m_clients.getIterator();
3713 i.atEnd() == false; i++)
3715 // Get client and check that it is valid
3716 RemoteClient *client = i.getNode()->getValue();
3717 assert(client->peer_id == i.getNode()->getKey());
3718 if(client->serialization_version == SER_FMT_VER_INVALID)
3721 // Don't send if it's the same one
3722 if(client->peer_id == ignore_id)
3728 Player *player = m_env->getPlayer(client->peer_id);
3731 // If player is far away, only set modified blocks not sent
3732 v3f player_pos = player->getPosition();
3733 if(player_pos.getDistanceFrom(p_f) > maxd)
3735 far_players->push_back(client->peer_id);
3742 m_con.Send(client->peer_id, 0, reply, true);
3746 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3747 core::list<u16> *far_players, float far_d_nodes)
3749 float maxd = far_d_nodes*BS;
3750 v3f p_f = intToFloat(p, BS);
3752 for(core::map<u16, RemoteClient*>::Iterator
3753 i = m_clients.getIterator();
3754 i.atEnd() == false; i++)
3756 // Get client and check that it is valid
3757 RemoteClient *client = i.getNode()->getValue();
3758 assert(client->peer_id == i.getNode()->getKey());
3759 if(client->serialization_version == SER_FMT_VER_INVALID)
3762 // Don't send if it's the same one
3763 if(client->peer_id == ignore_id)
3769 Player *player = m_env->getPlayer(client->peer_id);
3772 // If player is far away, only set modified blocks not sent
3773 v3f player_pos = player->getPosition();
3774 if(player_pos.getDistanceFrom(p_f) > maxd)
3776 far_players->push_back(client->peer_id);
3783 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3784 SharedBuffer<u8> reply(replysize);
3785 writeU16(&reply[0], TOCLIENT_ADDNODE);
3786 writeS16(&reply[2], p.X);
3787 writeS16(&reply[4], p.Y);
3788 writeS16(&reply[6], p.Z);
3789 n.serialize(&reply[8], client->serialization_version);
3792 m_con.Send(client->peer_id, 0, reply, true);
3796 void Server::setBlockNotSent(v3s16 p)
3798 for(core::map<u16, RemoteClient*>::Iterator
3799 i = m_clients.getIterator();
3800 i.atEnd()==false; i++)
3802 RemoteClient *client = i.getNode()->getValue();
3803 client->SetBlockNotSent(p);
3807 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3809 DSTACK(__FUNCTION_NAME);
3811 v3s16 p = block->getPos();
3815 bool completely_air = true;
3816 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3817 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3818 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3820 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3822 completely_air = false;
3823 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3828 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3830 infostream<<"[completely air] ";
3831 infostream<<std::endl;
3835 Create a packet with the block in the right format
3838 std::ostringstream os(std::ios_base::binary);
3839 block->serialize(os, ver, false);
3840 std::string s = os.str();
3841 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3843 u32 replysize = 8 + blockdata.getSize();
3844 SharedBuffer<u8> reply(replysize);
3845 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3846 writeS16(&reply[2], p.X);
3847 writeS16(&reply[4], p.Y);
3848 writeS16(&reply[6], p.Z);
3849 memcpy(&reply[8], *blockdata, blockdata.getSize());
3851 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3852 <<": \tpacket size: "<<replysize<<std::endl;*/
3857 m_con.Send(peer_id, 1, reply, true);
3860 void Server::SendBlocks(float dtime)
3862 DSTACK(__FUNCTION_NAME);
3864 JMutexAutoLock envlock(m_env_mutex);
3865 JMutexAutoLock conlock(m_con_mutex);
3867 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3869 core::array<PrioritySortedBlockTransfer> queue;
3871 s32 total_sending = 0;
3874 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3876 for(core::map<u16, RemoteClient*>::Iterator
3877 i = m_clients.getIterator();
3878 i.atEnd() == false; i++)
3880 RemoteClient *client = i.getNode()->getValue();
3881 assert(client->peer_id == i.getNode()->getKey());
3883 // If definitions and textures have not been sent, don't
3884 // send MapBlocks either
3885 if(!client->definitions_sent)
3888 total_sending += client->SendingCount();
3890 if(client->serialization_version == SER_FMT_VER_INVALID)
3893 client->GetNextBlocks(this, dtime, queue);
3898 // Lowest priority number comes first.
3899 // Lowest is most important.
3902 for(u32 i=0; i<queue.size(); i++)
3904 //TODO: Calculate limit dynamically
3905 if(total_sending >= g_settings->getS32
3906 ("max_simultaneous_block_sends_server_total"))
3909 PrioritySortedBlockTransfer q = queue[i];
3911 MapBlock *block = NULL;
3914 block = m_env->getMap().getBlockNoCreate(q.pos);
3916 catch(InvalidPositionException &e)
3921 RemoteClient *client = getClient(q.peer_id);
3923 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3925 client->SentBlock(q.pos);
3931 void Server::fillMediaCache()
3933 DSTACK(__FUNCTION_NAME);
3935 infostream<<"Server: Calculating media file checksums"<<std::endl;
3937 // Collect all media file paths
3938 std::list<std::string> paths;
3939 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3940 i != m_mods.end(); i++){
3941 const ModSpec &mod = *i;
3942 paths.push_back(mod.path + DIR_DELIM + "textures");
3943 paths.push_back(mod.path + DIR_DELIM + "sounds");
3944 paths.push_back(mod.path + DIR_DELIM + "media");
3947 // Collect media file information from paths into cache
3948 for(std::list<std::string>::iterator i = paths.begin();
3949 i != paths.end(); i++)
3951 std::string mediapath = *i;
3952 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3953 for(u32 j=0; j<dirlist.size(); j++){
3954 if(dirlist[j].dir) // Ignode dirs
3956 std::string filename = dirlist[j].name;
3957 // if name contains illegal characters, ignore the file
3958 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3959 errorstream<<"Server: ignoring illegal file name: \""
3960 <<filename<<"\""<<std::endl;
3963 std::string filepath = mediapath + DIR_DELIM + filename;
3965 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3966 if(fis.good() == false){
3967 errorstream<<"Server::fillMediaCache(): Could not open \""
3968 <<filename<<"\" for reading"<<std::endl;
3971 std::ostringstream tmp_os(std::ios_base::binary);
3975 fis.read(buf, 1024);
3976 std::streamsize len = fis.gcount();
3977 tmp_os.write(buf, len);
3986 errorstream<<"Server::fillMediaCache(): Failed to read \""
3987 <<filename<<"\""<<std::endl;
3990 if(tmp_os.str().length() == 0){
3991 errorstream<<"Server::fillMediaCache(): Empty file \""
3992 <<filepath<<"\""<<std::endl;
3997 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3999 unsigned char *digest = sha1.getDigest();
4000 std::string sha1_base64 = base64_encode(digest, 20);
4001 std::string sha1_hex = hex_encode((char*)digest, 20);
4005 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4006 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4011 struct SendableMediaAnnouncement
4014 std::string sha1_digest;
4016 SendableMediaAnnouncement(const std::string name_="",
4017 const std::string sha1_digest_=""):
4019 sha1_digest(sha1_digest_)
4023 void Server::sendMediaAnnouncement(u16 peer_id)
4025 DSTACK(__FUNCTION_NAME);
4027 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4030 core::list<SendableMediaAnnouncement> file_announcements;
4032 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4033 i != m_media.end(); i++){
4035 file_announcements.push_back(
4036 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4040 std::ostringstream os(std::ios_base::binary);
4048 u16 length of sha1_digest
4053 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4054 writeU16(os, file_announcements.size());
4056 for(core::list<SendableMediaAnnouncement>::Iterator
4057 j = file_announcements.begin();
4058 j != file_announcements.end(); j++){
4059 os<<serializeString(j->name);
4060 os<<serializeString(j->sha1_digest);
4064 std::string s = os.str();
4065 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4068 m_con.Send(peer_id, 0, data, true);
4072 struct SendableMedia
4078 SendableMedia(const std::string &name_="", const std::string path_="",
4079 const std::string &data_=""):
4086 void Server::sendRequestedMedia(u16 peer_id,
4087 const core::list<MediaRequest> &tosend)
4089 DSTACK(__FUNCTION_NAME);
4091 verbosestream<<"Server::sendRequestedMedia(): "
4092 <<"Sending files to client"<<std::endl;
4096 // Put 5kB in one bunch (this is not accurate)
4097 u32 bytes_per_bunch = 5000;
4099 core::array< core::list<SendableMedia> > file_bunches;
4100 file_bunches.push_back(core::list<SendableMedia>());
4102 u32 file_size_bunch_total = 0;
4104 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4105 i != tosend.end(); i++)
4107 if(m_media.find(i->name) == m_media.end()){
4108 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4109 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4113 //TODO get path + name
4114 std::string tpath = m_media[(*i).name].path;
4117 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4118 if(fis.good() == false){
4119 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4120 <<tpath<<"\" for reading"<<std::endl;
4123 std::ostringstream tmp_os(std::ios_base::binary);
4127 fis.read(buf, 1024);
4128 std::streamsize len = fis.gcount();
4129 tmp_os.write(buf, len);
4130 file_size_bunch_total += len;
4139 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4140 <<(*i).name<<"\""<<std::endl;
4143 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4144 <<tname<<"\""<<std::endl;*/
4146 file_bunches[file_bunches.size()-1].push_back(
4147 SendableMedia((*i).name, tpath, tmp_os.str()));
4149 // Start next bunch if got enough data
4150 if(file_size_bunch_total >= bytes_per_bunch){
4151 file_bunches.push_back(core::list<SendableMedia>());
4152 file_size_bunch_total = 0;
4157 /* Create and send packets */
4159 u32 num_bunches = file_bunches.size();
4160 for(u32 i=0; i<num_bunches; i++)
4162 std::ostringstream os(std::ios_base::binary);
4166 u16 total number of texture bunches
4167 u16 index of this bunch
4168 u32 number of files in this bunch
4177 writeU16(os, TOCLIENT_MEDIA);
4178 writeU16(os, num_bunches);
4180 writeU32(os, file_bunches[i].size());
4182 for(core::list<SendableMedia>::Iterator
4183 j = file_bunches[i].begin();
4184 j != file_bunches[i].end(); j++){
4185 os<<serializeString(j->name);
4186 os<<serializeLongString(j->data);
4190 std::string s = os.str();
4191 verbosestream<<"Server::sendRequestedMedia(): bunch "
4192 <<i<<"/"<<num_bunches
4193 <<" files="<<file_bunches[i].size()
4194 <<" size=" <<s.size()<<std::endl;
4195 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4197 m_con.Send(peer_id, 0, data, true);
4205 void Server::DiePlayer(Player *player)
4207 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4209 infostream<<"Server::DiePlayer(): Player "
4210 <<player->getName()<<" dies"<<std::endl;
4214 // Trigger scripted stuff
4215 scriptapi_on_dieplayer(m_lua, srp);
4217 // Handle players that are not connected
4218 if(player->peer_id == PEER_ID_INEXISTENT){
4219 RespawnPlayer(player);
4223 SendPlayerHP(player);
4224 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4227 void Server::RespawnPlayer(Player *player)
4229 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4231 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4233 v3f pos = findSpawnPos(m_env->getServerMap());
4234 player->setPosition(pos);
4235 srp->m_last_good_position = pos;
4236 srp->m_last_good_position_age = 0;
4238 SendMovePlayer(player);
4239 SendPlayerHP(player);
4242 void Server::UpdateCrafting(u16 peer_id)
4244 DSTACK(__FUNCTION_NAME);
4246 Player* player = m_env->getPlayer(peer_id);
4249 // Get a preview for crafting
4251 // No crafting in creative mode
4252 if(g_settings->getBool("creative_mode") == false)
4253 getCraftingResult(&player->inventory, preview, false, this);
4255 // Put the new preview in
4256 InventoryList *plist = player->inventory.getList("craftpreview");
4258 assert(plist->getSize() >= 1);
4259 plist->changeItem(0, preview);
4262 RemoteClient* Server::getClient(u16 peer_id)
4264 DSTACK(__FUNCTION_NAME);
4265 //JMutexAutoLock lock(m_con_mutex);
4266 core::map<u16, RemoteClient*>::Node *n;
4267 n = m_clients.find(peer_id);
4268 // A client should exist for all peers
4270 return n->getValue();
4273 std::wstring Server::getStatusString()
4275 std::wostringstream os(std::ios_base::binary);
4278 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4280 os<<L", uptime="<<m_uptime.get();
4281 // Information about clients
4283 for(core::map<u16, RemoteClient*>::Iterator
4284 i = m_clients.getIterator();
4285 i.atEnd() == false; i++)
4287 // Get client and check that it is valid
4288 RemoteClient *client = i.getNode()->getValue();
4289 assert(client->peer_id == i.getNode()->getKey());
4290 if(client->serialization_version == SER_FMT_VER_INVALID)
4293 Player *player = m_env->getPlayer(client->peer_id);
4294 // Get name of player
4295 std::wstring name = L"unknown";
4297 name = narrow_to_wide(player->getName());
4298 // Add name to information string
4302 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4303 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4304 if(g_settings->get("motd") != "")
4305 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4309 u64 Server::getPlayerAuthPrivs(const std::string &name)
4312 return m_authmanager.getPrivs(name);
4314 catch(AuthNotFoundException &e)
4316 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4321 void Server::setPlayerAuthPrivs(const std::string &name, u64 privs)
4324 return m_authmanager.setPrivs(name, privs);
4326 catch(AuthNotFoundException &e)
4328 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4332 u64 Server::getPlayerEffectivePrivs(const std::string &name)
4334 // Local player gets all privileges regardless of
4335 // what's set on their account.
4336 if(m_simple_singleplayer_mode)
4338 if(name == g_settings->get("name"))
4340 return getPlayerAuthPrivs(name);
4343 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4345 // Add player to auth manager
4346 if(m_authmanager.exists(name) == false)
4348 infostream<<"Server: adding player "<<name
4349 <<" to auth manager"<<std::endl;
4350 m_authmanager.add(name);
4351 m_authmanager.setPrivs(name,
4352 stringToPrivs(g_settings->get("default_privs")));
4354 // Change password and save
4355 m_authmanager.setPassword(name, translatePassword(name, password));
4356 m_authmanager.save();
4359 // Saves g_settings to configpath given at initialization
4360 void Server::saveConfig()
4362 if(m_path_config != "")
4363 g_settings->updateConfigFile(m_path_config.c_str());
4366 void Server::notifyPlayer(const char *name, const std::wstring msg)
4368 Player *player = m_env->getPlayer(name);
4371 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4374 void Server::notifyPlayers(const std::wstring msg)
4376 BroadcastChatMessage(msg);
4379 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4383 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4384 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4387 // IGameDef interface
4389 IItemDefManager* Server::getItemDefManager()
4393 INodeDefManager* Server::getNodeDefManager()
4397 ICraftDefManager* Server::getCraftDefManager()
4401 ITextureSource* Server::getTextureSource()
4405 u16 Server::allocateUnknownNodeId(const std::string &name)
4407 return m_nodedef->allocateDummy(name);
4409 ISoundManager* Server::getSoundManager()
4411 return &dummySoundManager;
4413 MtEventManager* Server::getEventManager()
4418 IWritableItemDefManager* Server::getWritableItemDefManager()
4422 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4426 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4431 const ModSpec* Server::getModSpec(const std::string &modname)
4433 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4434 i != m_mods.end(); i++){
4435 const ModSpec &mod = *i;
4436 if(mod.name == modname)
4442 v3f findSpawnPos(ServerMap &map)
4444 //return v3f(50,50,50)*BS;
4449 nodepos = v2s16(0,0);
4454 // Try to find a good place a few times
4455 for(s32 i=0; i<1000; i++)
4458 // We're going to try to throw the player to this position
4459 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4460 -range + (myrand()%(range*2)));
4461 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4462 // Get ground height at point (fallbacks to heightmap function)
4463 s16 groundheight = map.findGroundLevel(nodepos2d);
4464 // Don't go underwater
4465 if(groundheight < WATER_LEVEL)
4467 //infostream<<"-> Underwater"<<std::endl;
4470 // Don't go to high places
4471 if(groundheight > WATER_LEVEL + 4)
4473 //infostream<<"-> Underwater"<<std::endl;
4477 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4478 bool is_good = false;
4480 for(s32 i=0; i<10; i++){
4481 v3s16 blockpos = getNodeBlockPos(nodepos);
4482 map.emergeBlock(blockpos, true);
4483 MapNode n = map.getNodeNoEx(nodepos);
4484 if(n.getContent() == CONTENT_AIR){
4495 // Found a good place
4496 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4502 return intToFloat(nodepos, BS);
4505 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4508 Try to get an existing player
4510 ServerRemotePlayer *player =
4511 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4514 // If player is already connected, cancel
4515 if(player->peer_id != 0)
4517 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4522 player->peer_id = peer_id;
4524 // Re-add player to environment
4525 if(player->m_removed)
4527 player->m_removed = false;
4529 m_env->addActiveObject(player);
4532 // Reset inventory to creative if in creative mode
4533 if(g_settings->getBool("creative_mode"))
4535 // Warning: double code below
4536 // Backup actual inventory
4537 player->inventory_backup = new Inventory(m_itemdef);
4538 *(player->inventory_backup) = player->inventory;
4539 // Set creative inventory
4540 player->resetInventory();
4541 scriptapi_get_creative_inventory(m_lua, player);
4548 If player with the wanted peer_id already exists, cancel.
4550 if(m_env->getPlayer(peer_id) != NULL)
4552 infostream<<"emergePlayer(): Player with wrong name but same"
4553 " peer_id already exists"<<std::endl;
4561 /* Set player position */
4563 infostream<<"Server: Finding spawn place for player \""
4564 <<name<<"\""<<std::endl;
4566 v3f pos = findSpawnPos(m_env->getServerMap());
4568 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4569 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4571 /* Add player to environment */
4572 m_env->addPlayer(player);
4573 m_env->addActiveObject(srp);
4576 scriptapi_on_newplayer(m_lua, srp);
4578 /* Add stuff to inventory */
4579 if(g_settings->getBool("creative_mode"))
4581 // Warning: double code above
4582 // Backup actual inventory
4583 player->inventory_backup = new Inventory(m_itemdef);
4584 *(player->inventory_backup) = player->inventory;
4585 // Set creative inventory
4586 player->resetInventory();
4587 scriptapi_get_creative_inventory(m_lua, player);
4592 } // create new player
4595 void Server::handlePeerChange(PeerChange &c)
4597 JMutexAutoLock envlock(m_env_mutex);
4598 JMutexAutoLock conlock(m_con_mutex);
4600 if(c.type == PEER_ADDED)
4607 core::map<u16, RemoteClient*>::Node *n;
4608 n = m_clients.find(c.peer_id);
4609 // The client shouldn't already exist
4613 RemoteClient *client = new RemoteClient();
4614 client->peer_id = c.peer_id;
4615 m_clients.insert(client->peer_id, client);
4618 else if(c.type == PEER_REMOVED)
4625 core::map<u16, RemoteClient*>::Node *n;
4626 n = m_clients.find(c.peer_id);
4627 // The client should exist
4631 Mark objects to be not known by the client
4633 RemoteClient *client = n->getValue();
4635 for(core::map<u16, bool>::Iterator
4636 i = client->m_known_objects.getIterator();
4637 i.atEnd()==false; i++)
4640 u16 id = i.getNode()->getKey();
4641 ServerActiveObject* obj = m_env->getActiveObject(id);
4643 if(obj && obj->m_known_by_count > 0)
4644 obj->m_known_by_count--;
4648 Clear references to playing sounds
4650 for(std::map<s32, ServerPlayingSound>::iterator
4651 i = m_playing_sounds.begin();
4652 i != m_playing_sounds.end();)
4654 ServerPlayingSound &psound = i->second;
4655 psound.clients.erase(c.peer_id);
4656 if(psound.clients.size() == 0)
4657 m_playing_sounds.erase(i++);
4662 ServerRemotePlayer* player =
4663 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4665 // Collect information about leaving in chat
4666 std::wstring message;
4670 std::wstring name = narrow_to_wide(player->getName());
4673 message += L" left game";
4675 message += L" (timed out)";
4679 // Remove from environment
4681 player->m_removed = true;
4683 // Set player client disconnected
4685 player->peer_id = 0;
4693 std::ostringstream os(std::ios_base::binary);
4694 for(core::map<u16, RemoteClient*>::Iterator
4695 i = m_clients.getIterator();
4696 i.atEnd() == false; i++)
4698 RemoteClient *client = i.getNode()->getValue();
4699 assert(client->peer_id == i.getNode()->getKey());
4700 if(client->serialization_version == SER_FMT_VER_INVALID)
4703 Player *player = m_env->getPlayer(client->peer_id);
4706 // Get name of player
4707 os<<player->getName()<<" ";
4710 actionstream<<player->getName()<<" "
4711 <<(c.timeout?"times out.":"leaves game.")
4712 <<" List of players: "
4713 <<os.str()<<std::endl;
4718 delete m_clients[c.peer_id];
4719 m_clients.remove(c.peer_id);
4721 // Send player info to all remaining clients
4722 //SendPlayerInfos();
4724 // Send leave chat message to all remaining clients
4725 if(message.length() != 0)
4726 BroadcastChatMessage(message);
4735 void Server::handlePeerChanges()
4737 while(m_peer_change_queue.size() > 0)
4739 PeerChange c = m_peer_change_queue.pop_front();
4741 verbosestream<<"Server: Handling peer change: "
4742 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4745 handlePeerChange(c);
4749 u64 Server::getPlayerPrivs(Player *player)
4753 std::string playername = player->getName();
4754 return getPlayerEffectivePrivs(playername);
4757 void dedicated_server_loop(Server &server, bool &kill)
4759 DSTACK(__FUNCTION_NAME);
4761 verbosestream<<"dedicated_server_loop()"<<std::endl;
4763 IntervalLimiter m_profiler_interval;
4767 float steplen = g_settings->getFloat("dedicated_server_step");
4768 // This is kind of a hack but can be done like this
4769 // because server.step() is very light
4771 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4772 sleep_ms((int)(steplen*1000.0));
4774 server.step(steplen);
4776 if(server.getShutdownRequested() || kill)
4778 infostream<<"Dedicated server quitting"<<std::endl;
4785 float profiler_print_interval =
4786 g_settings->getFloat("profiler_print_interval");
4787 if(profiler_print_interval != 0)
4789 if(m_profiler_interval.step(steplen, profiler_print_interval))
4791 infostream<<"Profiler:"<<std::endl;
4792 g_profiler->print(infostream);
4793 g_profiler->clear();