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 // We will be accessing the environment and the connection
1693 JMutexAutoLock lock(m_env_mutex);
1694 JMutexAutoLock conlock(m_con_mutex);
1696 // Don't send too many at a time
1699 // Single change sending is disabled if queue size is not small
1700 bool disable_single_change_sending = false;
1701 if(m_unsent_map_edit_queue.size() >= 4)
1702 disable_single_change_sending = true;
1704 int event_count = m_unsent_map_edit_queue.size();
1706 // We'll log the amount of each
1709 while(m_unsent_map_edit_queue.size() != 0)
1711 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1713 // Players far away from the change are stored here.
1714 // Instead of sending the changes, MapBlocks are set not sent
1716 core::list<u16> far_players;
1718 if(event->type == MEET_ADDNODE)
1720 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1721 prof.add("MEET_ADDNODE", 1);
1722 if(disable_single_change_sending)
1723 sendAddNode(event->p, event->n, event->already_known_by_peer,
1726 sendAddNode(event->p, event->n, event->already_known_by_peer,
1729 else if(event->type == MEET_REMOVENODE)
1731 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1732 prof.add("MEET_REMOVENODE", 1);
1733 if(disable_single_change_sending)
1734 sendRemoveNode(event->p, event->already_known_by_peer,
1737 sendRemoveNode(event->p, event->already_known_by_peer,
1740 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1742 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1743 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1744 setBlockNotSent(event->p);
1746 else if(event->type == MEET_OTHER)
1748 infostream<<"Server: MEET_OTHER"<<std::endl;
1749 prof.add("MEET_OTHER", 1);
1750 for(core::map<v3s16, bool>::Iterator
1751 i = event->modified_blocks.getIterator();
1752 i.atEnd()==false; i++)
1754 v3s16 p = i.getNode()->getKey();
1760 prof.add("unknown", 1);
1761 infostream<<"WARNING: Server: Unknown MapEditEvent "
1762 <<((u32)event->type)<<std::endl;
1766 Set blocks not sent to far players
1768 if(far_players.size() > 0)
1770 // Convert list format to that wanted by SetBlocksNotSent
1771 core::map<v3s16, MapBlock*> modified_blocks2;
1772 for(core::map<v3s16, bool>::Iterator
1773 i = event->modified_blocks.getIterator();
1774 i.atEnd()==false; i++)
1776 v3s16 p = i.getNode()->getKey();
1777 modified_blocks2.insert(p,
1778 m_env->getMap().getBlockNoCreateNoEx(p));
1780 // Set blocks not sent
1781 for(core::list<u16>::Iterator
1782 i = far_players.begin();
1783 i != far_players.end(); i++)
1786 RemoteClient *client = getClient(peer_id);
1789 client->SetBlocksNotSent(modified_blocks2);
1795 /*// Don't send too many at a time
1797 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1801 if(event_count >= 5){
1802 infostream<<"Server: MapEditEvents:"<<std::endl;
1803 prof.print(infostream);
1804 } else if(event_count != 0){
1805 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1806 prof.print(verbosestream);
1812 Trigger emergethread (it somehow gets to a non-triggered but
1813 bysy state sometimes)
1816 float &counter = m_emergethread_trigger_timer;
1822 m_emergethread.trigger();
1826 // Save map, players and auth stuff
1828 float &counter = m_savemap_timer;
1830 if(counter >= g_settings->getFloat("server_map_save_interval"))
1833 JMutexAutoLock lock(m_env_mutex);
1835 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1838 if(m_authmanager.isModified())
1839 m_authmanager.save();
1842 if(m_banmanager.isModified())
1843 m_banmanager.save();
1845 // Save changed parts of map
1846 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1849 m_env->serializePlayers(m_path_world);
1851 // Save environment metadata
1852 m_env->saveMeta(m_path_world);
1857 void Server::Receive()
1859 DSTACK(__FUNCTION_NAME);
1860 SharedBuffer<u8> data;
1865 JMutexAutoLock conlock(m_con_mutex);
1866 datasize = m_con.Receive(peer_id, data);
1869 // This has to be called so that the client list gets synced
1870 // with the peer list of the connection
1871 handlePeerChanges();
1873 ProcessData(*data, datasize, peer_id);
1875 catch(con::InvalidIncomingDataException &e)
1877 infostream<<"Server::Receive(): "
1878 "InvalidIncomingDataException: what()="
1879 <<e.what()<<std::endl;
1881 catch(con::PeerNotFoundException &e)
1883 //NOTE: This is not needed anymore
1885 // The peer has been disconnected.
1886 // Find the associated player and remove it.
1888 /*JMutexAutoLock envlock(m_env_mutex);
1890 infostream<<"ServerThread: peer_id="<<peer_id
1891 <<" has apparently closed connection. "
1892 <<"Removing player."<<std::endl;
1894 m_env->removePlayer(peer_id);*/
1898 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1900 DSTACK(__FUNCTION_NAME);
1901 // Environment is locked first.
1902 JMutexAutoLock envlock(m_env_mutex);
1903 JMutexAutoLock conlock(m_con_mutex);
1905 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1908 Address address = m_con.GetPeerAddress(peer_id);
1909 std::string addr_s = address.serializeString();
1911 // drop player if is ip is banned
1912 if(m_banmanager.isIpBanned(addr_s)){
1913 infostream<<"Server: A banned client tried to connect from "
1914 <<addr_s<<"; banned name was "
1915 <<m_banmanager.getBanName(addr_s)<<std::endl;
1916 // This actually doesn't seem to transfer to the client
1917 SendAccessDenied(m_con, peer_id,
1918 L"Your ip is banned. Banned name was "
1919 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1920 m_con.DeletePeer(peer_id);
1924 catch(con::PeerNotFoundException &e)
1926 infostream<<"Server::ProcessData(): Cancelling: peer "
1927 <<peer_id<<" not found"<<std::endl;
1931 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1933 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1941 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1943 if(command == TOSERVER_INIT)
1945 // [0] u16 TOSERVER_INIT
1946 // [2] u8 SER_FMT_VER_HIGHEST
1947 // [3] u8[20] player_name
1948 // [23] u8[28] password <--- can be sent without this, from old versions
1950 if(datasize < 2+1+PLAYERNAME_SIZE)
1953 verbosestream<<"Server: Got TOSERVER_INIT from "
1954 <<peer_id<<std::endl;
1956 // First byte after command is maximum supported
1957 // serialization version
1958 u8 client_max = data[2];
1959 u8 our_max = SER_FMT_VER_HIGHEST;
1960 // Use the highest version supported by both
1961 u8 deployed = core::min_(client_max, our_max);
1962 // If it's lower than the lowest supported, give up.
1963 if(deployed < SER_FMT_VER_LOWEST)
1964 deployed = SER_FMT_VER_INVALID;
1966 //peer->serialization_version = deployed;
1967 getClient(peer_id)->pending_serialization_version = deployed;
1969 if(deployed == SER_FMT_VER_INVALID)
1971 actionstream<<"Server: A mismatched client tried to connect from "
1972 <<addr_s<<std::endl;
1973 infostream<<"Server: Cannot negotiate "
1974 "serialization version with peer "
1975 <<peer_id<<std::endl;
1976 SendAccessDenied(m_con, peer_id, std::wstring(
1977 L"Your client's version is not supported.\n"
1978 L"Server version is ")
1979 + narrow_to_wide(VERSION_STRING) + L"."
1985 Read and check network protocol version
1988 u16 net_proto_version = 0;
1989 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1991 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1994 getClient(peer_id)->net_proto_version = net_proto_version;
1996 if(net_proto_version == 0)
1998 actionstream<<"Server: An old tried to connect from "<<addr_s
2000 SendAccessDenied(m_con, peer_id, std::wstring(
2001 L"Your client's version is not supported.\n"
2002 L"Server version is ")
2003 + narrow_to_wide(VERSION_STRING) + L"."
2008 if(g_settings->getBool("strict_protocol_version_checking"))
2010 if(net_proto_version != PROTOCOL_VERSION)
2012 actionstream<<"Server: A mismatched client tried to connect"
2013 <<" from "<<addr_s<<std::endl;
2014 SendAccessDenied(m_con, peer_id, std::wstring(
2015 L"Your client's version is not supported.\n"
2016 L"Server version is ")
2017 + narrow_to_wide(VERSION_STRING) + L",\n"
2018 + L"server's PROTOCOL_VERSION is "
2019 + narrow_to_wide(itos(PROTOCOL_VERSION))
2020 + L", client's PROTOCOL_VERSION is "
2021 + narrow_to_wide(itos(net_proto_version))
2032 char playername[PLAYERNAME_SIZE];
2033 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2035 playername[i] = data[3+i];
2037 playername[PLAYERNAME_SIZE-1] = 0;
2039 if(playername[0]=='\0')
2041 actionstream<<"Server: Player with an empty name "
2042 <<"tried to connect from "<<addr_s<<std::endl;
2043 SendAccessDenied(m_con, peer_id,
2048 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2050 actionstream<<"Server: Player with an invalid name "
2051 <<"tried to connect from "<<addr_s<<std::endl;
2052 SendAccessDenied(m_con, peer_id,
2053 L"Name contains unallowed characters");
2057 infostream<<"Server: New connection: \""<<playername<<"\" from "
2058 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2061 char password[PASSWORD_SIZE];
2062 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2064 // old version - assume blank password
2069 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2071 password[i] = data[23+i];
2073 password[PASSWORD_SIZE-1] = 0;
2076 // Add player to auth manager
2077 if(m_authmanager.exists(playername) == false)
2079 std::wstring default_password =
2080 narrow_to_wide(g_settings->get("default_password"));
2081 std::string translated_default_password =
2082 translatePassword(playername, default_password);
2084 // If default_password is empty, allow any initial password
2085 if (default_password.length() == 0)
2086 translated_default_password = password;
2088 infostream<<"Server: adding player "<<playername
2089 <<" to auth manager"<<std::endl;
2090 m_authmanager.add(playername);
2091 m_authmanager.setPassword(playername, translated_default_password);
2092 m_authmanager.setPrivs(playername,
2093 stringToPrivs(g_settings->get("default_privs")));
2094 m_authmanager.save();
2097 std::string checkpwd = m_authmanager.getPassword(playername);
2099 /*infostream<<"Server: Client gave password '"<<password
2100 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2102 if(password != checkpwd)
2104 infostream<<"Server: peer_id="<<peer_id
2105 <<": supplied invalid password for "
2106 <<playername<<std::endl;
2107 SendAccessDenied(m_con, peer_id, L"Invalid password");
2111 // Do not allow multiple players in simple singleplayer mode.
2112 // This isn't a perfect way to do it, but will suffice for now.
2113 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2114 infostream<<"Server: Not allowing another client to connect in"
2115 <<" simple singleplayer mode"<<std::endl;
2116 SendAccessDenied(m_con, peer_id,
2117 L"Running in simple singleplayer mode.");
2121 // Enforce user limit.
2122 // Don't enforce for users that have some admin right
2123 if(m_clients.size() >= g_settings->getU16("max_users") &&
2124 (m_authmanager.getPrivs(playername)
2125 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2126 playername != g_settings->get("name"))
2128 actionstream<<"Server: "<<playername<<" tried to join, but there"
2129 <<" are already max_users="
2130 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2131 SendAccessDenied(m_con, peer_id, L"Too many users.");
2136 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2138 // If failed, cancel
2141 errorstream<<"Server: peer_id="<<peer_id
2142 <<": failed to emerge player"<<std::endl;
2147 Answer with a TOCLIENT_INIT
2150 SharedBuffer<u8> reply(2+1+6+8);
2151 writeU16(&reply[0], TOCLIENT_INIT);
2152 writeU8(&reply[2], deployed);
2153 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2154 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2157 m_con.Send(peer_id, 0, reply, true);
2161 Send complete position information
2163 SendMovePlayer(player);
2168 if(command == TOSERVER_INIT2)
2170 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2171 <<peer_id<<std::endl;
2174 getClient(peer_id)->serialization_version
2175 = getClient(peer_id)->pending_serialization_version;
2178 Send some initialization data
2181 infostream<<"Server: Sending content to "
2182 <<getPlayerName(peer_id)<<std::endl;
2184 // Send item definitions
2185 SendItemDef(m_con, peer_id, m_itemdef);
2187 // Send node definitions
2188 SendNodeDef(m_con, peer_id, m_nodedef);
2190 // Send texture announcement
2191 sendMediaAnnouncement(peer_id);
2193 // Send player info to all players
2194 //SendPlayerInfos();
2196 // Send inventory to player
2197 UpdateCrafting(peer_id);
2198 SendInventory(peer_id);
2200 // Send player items to all players
2203 Player *player = m_env->getPlayer(peer_id);
2206 SendPlayerHP(player);
2208 // Show death screen if necessary
2210 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2214 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2215 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2216 m_con.Send(peer_id, 0, data, true);
2219 // Note things in chat if not in simple singleplayer mode
2220 if(!m_simple_singleplayer_mode)
2222 // Send information about server to player in chat
2223 SendChatMessage(peer_id, getStatusString());
2225 // Send information about joining in chat
2227 std::wstring name = L"unknown";
2228 Player *player = m_env->getPlayer(peer_id);
2230 name = narrow_to_wide(player->getName());
2232 std::wstring message;
2235 message += L" joined game";
2236 BroadcastChatMessage(message);
2240 // Warnings about protocol version can be issued here
2241 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2243 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2250 std::ostringstream os(std::ios_base::binary);
2251 for(core::map<u16, RemoteClient*>::Iterator
2252 i = m_clients.getIterator();
2253 i.atEnd() == false; i++)
2255 RemoteClient *client = i.getNode()->getValue();
2256 assert(client->peer_id == i.getNode()->getKey());
2257 if(client->serialization_version == SER_FMT_VER_INVALID)
2260 Player *player = m_env->getPlayer(client->peer_id);
2263 // Get name of player
2264 os<<player->getName()<<" ";
2267 actionstream<<player->getName()<<" joins game. List of players: "
2268 <<os.str()<<std::endl;
2274 if(peer_ser_ver == SER_FMT_VER_INVALID)
2276 infostream<<"Server::ProcessData(): Cancelling: Peer"
2277 " serialization format invalid or not initialized."
2278 " Skipping incoming command="<<command<<std::endl;
2282 Player *player = m_env->getPlayer(peer_id);
2283 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2286 infostream<<"Server::ProcessData(): Cancelling: "
2287 "No player for peer_id="<<peer_id
2291 if(command == TOSERVER_PLAYERPOS)
2293 if(datasize < 2+12+12+4+4)
2297 v3s32 ps = readV3S32(&data[start+2]);
2298 v3s32 ss = readV3S32(&data[start+2+12]);
2299 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2300 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2301 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2302 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2303 pitch = wrapDegrees(pitch);
2304 yaw = wrapDegrees(yaw);
2306 player->setPosition(position);
2307 player->setSpeed(speed);
2308 player->setPitch(pitch);
2309 player->setYaw(yaw);
2311 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2312 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2313 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2315 else if(command == TOSERVER_GOTBLOCKS)
2328 u16 count = data[2];
2329 for(u16 i=0; i<count; i++)
2331 if((s16)datasize < 2+1+(i+1)*6)
2332 throw con::InvalidIncomingDataException
2333 ("GOTBLOCKS length is too short");
2334 v3s16 p = readV3S16(&data[2+1+i*6]);
2335 /*infostream<<"Server: GOTBLOCKS ("
2336 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2337 RemoteClient *client = getClient(peer_id);
2338 client->GotBlock(p);
2341 else if(command == TOSERVER_DELETEDBLOCKS)
2354 u16 count = data[2];
2355 for(u16 i=0; i<count; i++)
2357 if((s16)datasize < 2+1+(i+1)*6)
2358 throw con::InvalidIncomingDataException
2359 ("DELETEDBLOCKS length is too short");
2360 v3s16 p = readV3S16(&data[2+1+i*6]);
2361 /*infostream<<"Server: DELETEDBLOCKS ("
2362 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2363 RemoteClient *client = getClient(peer_id);
2364 client->SetBlockNotSent(p);
2367 else if(command == TOSERVER_CLICK_OBJECT)
2369 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2372 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2374 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2377 else if(command == TOSERVER_GROUND_ACTION)
2379 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2383 else if(command == TOSERVER_RELEASE)
2385 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2388 else if(command == TOSERVER_SIGNTEXT)
2390 infostream<<"Server: SIGNTEXT not supported anymore"
2394 else if(command == TOSERVER_SIGNNODETEXT)
2396 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2404 std::string datastring((char*)&data[2], datasize-2);
2405 std::istringstream is(datastring, std::ios_base::binary);
2408 is.read((char*)buf, 6);
2409 v3s16 p = readV3S16(buf);
2410 is.read((char*)buf, 2);
2411 u16 textlen = readU16(buf);
2413 for(u16 i=0; i<textlen; i++)
2415 is.read((char*)buf, 1);
2416 text += (char)buf[0];
2419 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2423 meta->setText(text);
2425 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2426 <<" at "<<PP(p)<<std::endl;
2428 v3s16 blockpos = getNodeBlockPos(p);
2429 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2432 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2436 setBlockNotSent(blockpos);
2438 else if(command == TOSERVER_INVENTORY_ACTION)
2440 // Strip command and create a stream
2441 std::string datastring((char*)&data[2], datasize-2);
2442 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2443 std::istringstream is(datastring, std::ios_base::binary);
2445 InventoryAction *a = InventoryAction::deSerialize(is);
2448 infostream<<"TOSERVER_INVENTORY_ACTION: "
2449 <<"InventoryAction::deSerialize() returned NULL"
2455 Note: Always set inventory not sent, to repair cases
2456 where the client made a bad prediction.
2460 Handle restrictions and special cases of the move action
2462 if(a->getType() == IACTION_MOVE)
2464 IMoveAction *ma = (IMoveAction*)a;
2466 ma->from_inv.applyCurrentPlayer(player->getName());
2467 ma->to_inv.applyCurrentPlayer(player->getName());
2469 setInventoryModified(ma->from_inv);
2470 setInventoryModified(ma->to_inv);
2472 bool from_inv_is_current_player =
2473 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2474 (ma->from_inv.name == player->getName());
2476 bool to_inv_is_current_player =
2477 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2478 (ma->to_inv.name == player->getName());
2481 Disable moving items out of craftpreview
2483 if(ma->from_list == "craftpreview")
2485 infostream<<"Ignoring IMoveAction from "
2486 <<(ma->from_inv.dump())<<":"<<ma->from_list
2487 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2488 <<" because src is "<<ma->from_list<<std::endl;
2494 Disable moving items into craftresult and craftpreview
2496 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2498 infostream<<"Ignoring IMoveAction from "
2499 <<(ma->from_inv.dump())<<":"<<ma->from_list
2500 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2501 <<" because dst is "<<ma->to_list<<std::endl;
2506 // Disallow moving items in elsewhere than player's inventory
2507 // if not allowed to interact
2508 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2509 && (!from_inv_is_current_player
2510 || !to_inv_is_current_player))
2512 infostream<<"Cannot move outside of player's inventory: "
2513 <<"No interact privilege"<<std::endl;
2518 // If player is not an admin, check for ownership of src and dst
2519 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2521 std::string owner_from = getInventoryOwner(ma->from_inv);
2522 if(owner_from != "" && owner_from != player->getName())
2524 infostream<<"WARNING: "<<player->getName()
2525 <<" tried to access an inventory that"
2526 <<" belongs to "<<owner_from<<std::endl;
2531 std::string owner_to = getInventoryOwner(ma->to_inv);
2532 if(owner_to != "" && owner_to != player->getName())
2534 infostream<<"WARNING: "<<player->getName()
2535 <<" tried to access an inventory that"
2536 <<" belongs to "<<owner_to<<std::endl;
2543 Handle restrictions and special cases of the drop action
2545 else if(a->getType() == IACTION_DROP)
2547 IDropAction *da = (IDropAction*)a;
2549 da->from_inv.applyCurrentPlayer(player->getName());
2551 setInventoryModified(da->from_inv);
2553 // Disallow dropping items if not allowed to interact
2554 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2559 // If player is not an admin, check for ownership
2560 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2562 std::string owner_from = getInventoryOwner(da->from_inv);
2563 if(owner_from != "" && owner_from != player->getName())
2565 infostream<<"WARNING: "<<player->getName()
2566 <<" tried to access an inventory that"
2567 <<" belongs to "<<owner_from<<std::endl;
2574 Handle restrictions and special cases of the craft action
2576 else if(a->getType() == IACTION_CRAFT)
2578 ICraftAction *ca = (ICraftAction*)a;
2580 ca->craft_inv.applyCurrentPlayer(player->getName());
2582 setInventoryModified(ca->craft_inv);
2584 //bool craft_inv_is_current_player =
2585 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2586 // (ca->craft_inv.name == player->getName());
2588 // Disallow crafting if not allowed to interact
2589 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2591 infostream<<"Cannot craft: "
2592 <<"No interact privilege"<<std::endl;
2597 // If player is not an admin, check for ownership of inventory
2598 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2600 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2601 if(owner_craft != "" && owner_craft != player->getName())
2603 infostream<<"WARNING: "<<player->getName()
2604 <<" tried to access an inventory that"
2605 <<" belongs to "<<owner_craft<<std::endl;
2613 a->apply(this, srp, this);
2617 else if(command == TOSERVER_CHAT_MESSAGE)
2625 std::string datastring((char*)&data[2], datasize-2);
2626 std::istringstream is(datastring, std::ios_base::binary);
2629 is.read((char*)buf, 2);
2630 u16 len = readU16(buf);
2632 std::wstring message;
2633 for(u16 i=0; i<len; i++)
2635 is.read((char*)buf, 2);
2636 message += (wchar_t)readU16(buf);
2639 // Get player name of this client
2640 std::wstring name = narrow_to_wide(player->getName());
2643 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2644 wide_to_narrow(message));
2645 // If script ate the message, don't proceed
2649 // Line to send to players
2651 // Whether to send to the player that sent the line
2652 bool send_to_sender = false;
2653 // Whether to send to other players
2654 bool send_to_others = false;
2656 // Local player gets all privileges regardless of
2657 // what's set on their account.
2658 u64 privs = getPlayerPrivs(player);
2661 if(message[0] == L'/')
2663 size_t strip_size = 1;
2664 if (message[1] == L'#') // support old-style commans
2666 message = message.substr(strip_size);
2668 WStrfnd f1(message);
2669 f1.next(L" "); // Skip over /#whatever
2670 std::wstring paramstring = f1.next(L"");
2672 ServerCommandContext *ctx = new ServerCommandContext(
2673 str_split(message, L' '),
2680 std::wstring reply(processServerCommand(ctx));
2681 send_to_sender = ctx->flags & SEND_TO_SENDER;
2682 send_to_others = ctx->flags & SEND_TO_OTHERS;
2684 if (ctx->flags & SEND_NO_PREFIX)
2687 line += L"Server: " + reply;
2694 if(privs & PRIV_SHOUT)
2700 send_to_others = true;
2704 line += L"Server: You are not allowed to shout";
2705 send_to_sender = true;
2712 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2715 Send the message to clients
2717 for(core::map<u16, RemoteClient*>::Iterator
2718 i = m_clients.getIterator();
2719 i.atEnd() == false; i++)
2721 // Get client and check that it is valid
2722 RemoteClient *client = i.getNode()->getValue();
2723 assert(client->peer_id == i.getNode()->getKey());
2724 if(client->serialization_version == SER_FMT_VER_INVALID)
2728 bool sender_selected = (peer_id == client->peer_id);
2729 if(sender_selected == true && send_to_sender == false)
2731 if(sender_selected == false && send_to_others == false)
2734 SendChatMessage(client->peer_id, line);
2738 else if(command == TOSERVER_DAMAGE)
2740 std::string datastring((char*)&data[2], datasize-2);
2741 std::istringstream is(datastring, std::ios_base::binary);
2742 u8 damage = readU8(is);
2744 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2746 if(g_settings->getBool("enable_damage"))
2748 actionstream<<player->getName()<<" damaged by "
2749 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2752 srp->setHP(srp->getHP() - damage);
2754 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2757 if(srp->m_hp_not_sent)
2758 SendPlayerHP(player);
2762 // Force send (to correct the client's predicted HP)
2763 SendPlayerHP(player);
2766 else if(command == TOSERVER_PASSWORD)
2769 [0] u16 TOSERVER_PASSWORD
2770 [2] u8[28] old password
2771 [30] u8[28] new password
2774 if(datasize != 2+PASSWORD_SIZE*2)
2776 /*char password[PASSWORD_SIZE];
2777 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2778 password[i] = data[2+i];
2779 password[PASSWORD_SIZE-1] = 0;*/
2781 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2789 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2791 char c = data[2+PASSWORD_SIZE+i];
2797 infostream<<"Server: Client requests a password change from "
2798 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2800 std::string playername = player->getName();
2802 if(m_authmanager.exists(playername) == false)
2804 infostream<<"Server: playername not found in authmanager"<<std::endl;
2805 // Wrong old password supplied!!
2806 SendChatMessage(peer_id, L"playername not found in authmanager");
2810 std::string checkpwd = m_authmanager.getPassword(playername);
2812 if(oldpwd != checkpwd)
2814 infostream<<"Server: invalid old password"<<std::endl;
2815 // Wrong old password supplied!!
2816 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2820 actionstream<<player->getName()<<" changes password"<<std::endl;
2822 m_authmanager.setPassword(playername, newpwd);
2824 infostream<<"Server: password change successful for "<<playername
2826 SendChatMessage(peer_id, L"Password change successful");
2828 else if(command == TOSERVER_PLAYERITEM)
2833 u16 item = readU16(&data[2]);
2834 srp->setWieldIndex(item);
2835 SendWieldedItem(srp);
2837 else if(command == TOSERVER_RESPAWN)
2842 RespawnPlayer(player);
2844 actionstream<<player->getName()<<" respawns at "
2845 <<PP(player->getPosition()/BS)<<std::endl;
2847 // ActiveObject is added to environment in AsyncRunStep after
2848 // the previous addition has been succesfully removed
2850 else if(command == TOSERVER_REQUEST_MEDIA) {
2851 std::string datastring((char*)&data[2], datasize-2);
2852 std::istringstream is(datastring, std::ios_base::binary);
2854 core::list<MediaRequest> tosend;
2855 u16 numfiles = readU16(is);
2857 infostream<<"Sending "<<numfiles<<" files to "
2858 <<getPlayerName(peer_id)<<std::endl;
2859 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2861 for(int i = 0; i < numfiles; i++) {
2862 std::string name = deSerializeString(is);
2863 tosend.push_back(MediaRequest(name));
2864 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2868 sendRequestedMedia(peer_id, tosend);
2870 // Now the client should know about everything
2871 // (definitions and files)
2872 getClient(peer_id)->definitions_sent = true;
2874 else if(command == TOSERVER_INTERACT)
2876 std::string datastring((char*)&data[2], datasize-2);
2877 std::istringstream is(datastring, std::ios_base::binary);
2883 [5] u32 length of the next item
2884 [9] serialized PointedThing
2886 0: start digging (from undersurface) or use
2887 1: stop digging (all parameters ignored)
2888 2: digging completed
2889 3: place block or item (to abovesurface)
2892 u8 action = readU8(is);
2893 u16 item_i = readU16(is);
2894 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2895 PointedThing pointed;
2896 pointed.deSerialize(tmp_is);
2898 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2899 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2903 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2904 <<" tried to interact, but is dead!"<<std::endl;
2908 v3f player_pos = srp->m_last_good_position;
2910 // Update wielded item
2911 if(srp->getWieldIndex() != item_i)
2913 srp->setWieldIndex(item_i);
2914 SendWieldedItem(srp);
2917 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2918 v3s16 p_under = pointed.node_undersurface;
2919 v3s16 p_above = pointed.node_abovesurface;
2921 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2922 ServerActiveObject *pointed_object = NULL;
2923 if(pointed.type == POINTEDTHING_OBJECT)
2925 pointed_object = m_env->getActiveObject(pointed.object_id);
2926 if(pointed_object == NULL)
2928 verbosestream<<"TOSERVER_INTERACT: "
2929 "pointed object is NULL"<<std::endl;
2935 v3f pointed_pos_under = player_pos;
2936 v3f pointed_pos_above = player_pos;
2937 if(pointed.type == POINTEDTHING_NODE)
2939 pointed_pos_under = intToFloat(p_under, BS);
2940 pointed_pos_above = intToFloat(p_above, BS);
2942 else if(pointed.type == POINTEDTHING_OBJECT)
2944 pointed_pos_under = pointed_object->getBasePosition();
2945 pointed_pos_above = pointed_pos_under;
2949 Check that target is reasonably close
2950 (only when digging or placing things)
2952 if(action == 0 || action == 2 || action == 3)
2954 float d = player_pos.getDistanceFrom(pointed_pos_under);
2955 float max_d = BS * 14; // Just some large enough value
2957 actionstream<<"Player "<<player->getName()
2958 <<" tried to access "<<pointed.dump()
2960 <<"d="<<d<<", max_d="<<max_d
2961 <<". ignoring."<<std::endl;
2962 // Re-send block to revert change on client-side
2963 RemoteClient *client = getClient(peer_id);
2964 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2965 client->SetBlockNotSent(blockpos);
2972 Make sure the player is allowed to do it
2974 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2976 infostream<<"Ignoring interaction from player "<<player->getName()
2977 <<" because privileges are "<<getPlayerPrivs(player)
2983 0: start digging or punch object
2987 if(pointed.type == POINTEDTHING_NODE)
2990 NOTE: This can be used in the future to check if
2991 somebody is cheating, by checking the timing.
2993 MapNode n(CONTENT_IGNORE);
2996 n = m_env->getMap().getNode(p_under);
2998 catch(InvalidPositionException &e)
3000 infostream<<"Server: Not punching: Node not found."
3001 <<" Adding block to emerge queue."
3003 m_emerge_queue.addBlock(peer_id,
3004 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3006 if(n.getContent() != CONTENT_IGNORE)
3007 scriptapi_node_on_punch(m_lua, p_under, n, srp);
3009 else if(pointed.type == POINTEDTHING_OBJECT)
3011 // Skip if object has been removed
3012 if(pointed_object->m_removed)
3015 actionstream<<player->getName()<<" punches object "
3016 <<pointed.object_id<<": "
3017 <<pointed_object->getDescription()<<std::endl;
3019 ItemStack punchitem = srp->getWieldedItem();
3020 ToolCapabilities toolcap =
3021 punchitem.getToolCapabilities(m_itemdef);
3022 v3f dir = (pointed_object->getBasePosition() -
3023 (srp->getPosition() + srp->getEyeOffset())
3025 pointed_object->punch(dir, &toolcap, srp,
3026 srp->m_time_from_last_punch);
3027 srp->m_time_from_last_punch = 0;
3035 else if(action == 1)
3040 2: Digging completed
3042 else if(action == 2)
3044 // Only complete digging of nodes
3045 if(pointed.type == POINTEDTHING_NODE)
3047 MapNode n(CONTENT_IGNORE);
3050 n = m_env->getMap().getNode(p_under);
3052 catch(InvalidPositionException &e)
3054 infostream<<"Server: Not finishing digging: Node not found."
3055 <<" Adding block to emerge queue."
3057 m_emerge_queue.addBlock(peer_id,
3058 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3060 if(n.getContent() != CONTENT_IGNORE)
3061 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3066 3: place block or right-click object
3068 else if(action == 3)
3070 ItemStack item = srp->getWieldedItem();
3072 // Reset build time counter
3073 if(pointed.type == POINTEDTHING_NODE &&
3074 item.getDefinition(m_itemdef).type == ITEM_NODE)
3075 getClient(peer_id)->m_time_from_building = 0.0;
3077 if(pointed.type == POINTEDTHING_OBJECT)
3079 // Right click object
3081 // Skip if object has been removed
3082 if(pointed_object->m_removed)
3085 actionstream<<player->getName()<<" right-clicks object "
3086 <<pointed.object_id<<": "
3087 <<pointed_object->getDescription()<<std::endl;
3090 pointed_object->rightClick(srp);
3092 else if(scriptapi_item_on_place(m_lua,
3093 item, srp, pointed))
3095 // Placement was handled in lua
3097 // Apply returned ItemStack
3098 if(g_settings->getBool("creative_mode") == false)
3099 srp->setWieldedItem(item);
3107 else if(action == 4)
3109 ItemStack item = srp->getWieldedItem();
3111 actionstream<<player->getName()<<" uses "<<item.name
3112 <<", pointing at "<<pointed.dump()<<std::endl;
3114 if(scriptapi_item_on_use(m_lua,
3115 item, srp, pointed))
3117 // Apply returned ItemStack
3118 if(g_settings->getBool("creative_mode") == false)
3119 srp->setWieldedItem(item);
3125 Catch invalid actions
3129 infostream<<"WARNING: Server: Invalid action "
3130 <<action<<std::endl;
3133 else if(command == TOSERVER_REMOVED_SOUNDS)
3135 std::string datastring((char*)&data[2], datasize-2);
3136 std::istringstream is(datastring, std::ios_base::binary);
3138 int num = readU16(is);
3139 for(int k=0; k<num; k++){
3140 s32 id = readS32(is);
3141 std::map<s32, ServerPlayingSound>::iterator i =
3142 m_playing_sounds.find(id);
3143 if(i == m_playing_sounds.end())
3145 ServerPlayingSound &psound = i->second;
3146 psound.clients.erase(peer_id);
3147 if(psound.clients.size() == 0)
3148 m_playing_sounds.erase(i++);
3153 infostream<<"Server::ProcessData(): Ignoring "
3154 "unknown command "<<command<<std::endl;
3158 catch(SendFailedException &e)
3160 errorstream<<"Server::ProcessData(): SendFailedException: "
3166 void Server::onMapEditEvent(MapEditEvent *event)
3168 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3169 if(m_ignore_map_edit_events)
3171 MapEditEvent *e = event->clone();
3172 m_unsent_map_edit_queue.push_back(e);
3175 Inventory* Server::getInventory(const InventoryLocation &loc)
3178 case InventoryLocation::UNDEFINED:
3181 case InventoryLocation::CURRENT_PLAYER:
3184 case InventoryLocation::PLAYER:
3186 Player *player = m_env->getPlayer(loc.name.c_str());
3189 return &player->inventory;
3192 case InventoryLocation::NODEMETA:
3194 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3197 return meta->getInventory();
3205 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3208 case InventoryLocation::UNDEFINED:
3211 case InventoryLocation::CURRENT_PLAYER:
3214 case InventoryLocation::PLAYER:
3219 case InventoryLocation::NODEMETA:
3221 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3224 return meta->getOwner();
3232 void Server::setInventoryModified(const InventoryLocation &loc)
3235 case InventoryLocation::UNDEFINED:
3238 case InventoryLocation::PLAYER:
3240 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3241 (m_env->getPlayer(loc.name.c_str()));
3244 srp->m_inventory_not_sent = true;
3247 case InventoryLocation::NODEMETA:
3249 v3s16 blockpos = getNodeBlockPos(loc.p);
3251 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3253 meta->inventoryModified();
3255 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3257 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3259 setBlockNotSent(blockpos);
3267 core::list<PlayerInfo> Server::getPlayerInfo()
3269 DSTACK(__FUNCTION_NAME);
3270 JMutexAutoLock envlock(m_env_mutex);
3271 JMutexAutoLock conlock(m_con_mutex);
3273 core::list<PlayerInfo> list;
3275 core::list<Player*> players = m_env->getPlayers();
3277 core::list<Player*>::Iterator i;
3278 for(i = players.begin();
3279 i != players.end(); i++)
3283 Player *player = *i;
3286 // Copy info from connection to info struct
3287 info.id = player->peer_id;
3288 info.address = m_con.GetPeerAddress(player->peer_id);
3289 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3291 catch(con::PeerNotFoundException &e)
3293 // Set dummy peer info
3295 info.address = Address(0,0,0,0,0);
3299 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3300 info.position = player->getPosition();
3302 list.push_back(info);
3309 void Server::peerAdded(con::Peer *peer)
3311 DSTACK(__FUNCTION_NAME);
3312 verbosestream<<"Server::peerAdded(): peer->id="
3313 <<peer->id<<std::endl;
3316 c.type = PEER_ADDED;
3317 c.peer_id = peer->id;
3319 m_peer_change_queue.push_back(c);
3322 void Server::deletingPeer(con::Peer *peer, bool timeout)
3324 DSTACK(__FUNCTION_NAME);
3325 verbosestream<<"Server::deletingPeer(): peer->id="
3326 <<peer->id<<", timeout="<<timeout<<std::endl;
3329 c.type = PEER_REMOVED;
3330 c.peer_id = peer->id;
3331 c.timeout = timeout;
3332 m_peer_change_queue.push_back(c);
3339 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3341 DSTACK(__FUNCTION_NAME);
3342 std::ostringstream os(std::ios_base::binary);
3344 writeU16(os, TOCLIENT_HP);
3348 std::string s = os.str();
3349 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3351 con.Send(peer_id, 0, data, true);
3354 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3355 const std::wstring &reason)
3357 DSTACK(__FUNCTION_NAME);
3358 std::ostringstream os(std::ios_base::binary);
3360 writeU16(os, TOCLIENT_ACCESS_DENIED);
3361 os<<serializeWideString(reason);
3364 std::string s = os.str();
3365 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3367 con.Send(peer_id, 0, data, true);
3370 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3371 bool set_camera_point_target, v3f camera_point_target)
3373 DSTACK(__FUNCTION_NAME);
3374 std::ostringstream os(std::ios_base::binary);
3376 writeU16(os, TOCLIENT_DEATHSCREEN);
3377 writeU8(os, set_camera_point_target);
3378 writeV3F1000(os, camera_point_target);
3381 std::string s = os.str();
3382 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3384 con.Send(peer_id, 0, data, true);
3387 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3388 IItemDefManager *itemdef)
3390 DSTACK(__FUNCTION_NAME);
3391 std::ostringstream os(std::ios_base::binary);
3395 u32 length of the next item
3396 zlib-compressed serialized ItemDefManager
3398 writeU16(os, TOCLIENT_ITEMDEF);
3399 std::ostringstream tmp_os(std::ios::binary);
3400 itemdef->serialize(tmp_os);
3401 std::ostringstream tmp_os2(std::ios::binary);
3402 compressZlib(tmp_os.str(), tmp_os2);
3403 os<<serializeLongString(tmp_os2.str());
3406 std::string s = os.str();
3407 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3408 <<"): size="<<s.size()<<std::endl;
3409 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3411 con.Send(peer_id, 0, data, true);
3414 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3415 INodeDefManager *nodedef)
3417 DSTACK(__FUNCTION_NAME);
3418 std::ostringstream os(std::ios_base::binary);
3422 u32 length of the next item
3423 zlib-compressed serialized NodeDefManager
3425 writeU16(os, TOCLIENT_NODEDEF);
3426 std::ostringstream tmp_os(std::ios::binary);
3427 nodedef->serialize(tmp_os);
3428 std::ostringstream tmp_os2(std::ios::binary);
3429 compressZlib(tmp_os.str(), tmp_os2);
3430 os<<serializeLongString(tmp_os2.str());
3433 std::string s = os.str();
3434 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3435 <<"): size="<<s.size()<<std::endl;
3436 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3438 con.Send(peer_id, 0, data, true);
3442 Non-static send methods
3445 void Server::SendInventory(u16 peer_id)
3447 DSTACK(__FUNCTION_NAME);
3449 ServerRemotePlayer* player =
3450 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3453 player->m_inventory_not_sent = false;
3459 std::ostringstream os;
3460 //os.imbue(std::locale("C"));
3462 player->inventory.serialize(os);
3464 std::string s = os.str();
3466 SharedBuffer<u8> data(s.size()+2);
3467 writeU16(&data[0], TOCLIENT_INVENTORY);
3468 memcpy(&data[2], s.c_str(), s.size());
3471 m_con.Send(peer_id, 0, data, true);
3474 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3476 DSTACK(__FUNCTION_NAME);
3480 std::ostringstream os(std::ios_base::binary);
3482 writeU16(os, TOCLIENT_PLAYERITEM);
3484 writeU16(os, srp->peer_id);
3485 os<<serializeString(srp->getWieldedItem().getItemString());
3488 std::string s = os.str();
3489 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3491 m_con.SendToAll(0, data, true);
3494 void Server::SendPlayerItems()
3496 DSTACK(__FUNCTION_NAME);
3498 std::ostringstream os(std::ios_base::binary);
3499 core::list<Player *> players = m_env->getPlayers(true);
3501 writeU16(os, TOCLIENT_PLAYERITEM);
3502 writeU16(os, players.size());
3503 core::list<Player *>::Iterator i;
3504 for(i = players.begin(); i != players.end(); ++i)
3507 ServerRemotePlayer *srp =
3508 static_cast<ServerRemotePlayer*>(p);
3509 writeU16(os, p->peer_id);
3510 os<<serializeString(srp->getWieldedItem().getItemString());
3514 std::string s = os.str();
3515 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3517 m_con.SendToAll(0, data, true);
3520 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3522 DSTACK(__FUNCTION_NAME);
3524 std::ostringstream os(std::ios_base::binary);
3528 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3529 os.write((char*)buf, 2);
3532 writeU16(buf, message.size());
3533 os.write((char*)buf, 2);
3536 for(u32 i=0; i<message.size(); i++)
3540 os.write((char*)buf, 2);
3544 std::string s = os.str();
3545 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3547 m_con.Send(peer_id, 0, data, true);
3550 void Server::BroadcastChatMessage(const std::wstring &message)
3552 for(core::map<u16, RemoteClient*>::Iterator
3553 i = m_clients.getIterator();
3554 i.atEnd() == false; i++)
3556 // Get client and check that it is valid
3557 RemoteClient *client = i.getNode()->getValue();
3558 assert(client->peer_id == i.getNode()->getKey());
3559 if(client->serialization_version == SER_FMT_VER_INVALID)
3562 SendChatMessage(client->peer_id, message);
3566 void Server::SendPlayerHP(Player *player)
3568 SendHP(m_con, player->peer_id, player->hp);
3569 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3572 void Server::SendMovePlayer(Player *player)
3574 DSTACK(__FUNCTION_NAME);
3575 std::ostringstream os(std::ios_base::binary);
3577 writeU16(os, TOCLIENT_MOVE_PLAYER);
3578 writeV3F1000(os, player->getPosition());
3579 writeF1000(os, player->getPitch());
3580 writeF1000(os, player->getYaw());
3583 v3f pos = player->getPosition();
3584 f32 pitch = player->getPitch();
3585 f32 yaw = player->getYaw();
3586 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3587 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3594 std::string s = os.str();
3595 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3597 m_con.Send(player->peer_id, 0, data, true);
3600 s32 Server::playSound(const SimpleSoundSpec &spec,
3601 const ServerSoundParams ¶ms)
3603 // Find out initial position of sound
3604 bool pos_exists = false;
3605 v3f pos = params.getPos(m_env, &pos_exists);
3606 // If position is not found while it should be, cancel sound
3607 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3609 // Filter destination clients
3610 std::set<RemoteClient*> dst_clients;
3611 if(params.to_player != "")
3613 Player *player = m_env->getPlayer(params.to_player.c_str());
3615 infostream<<"Server::playSound: Player \""<<params.to_player
3616 <<"\" not found"<<std::endl;
3619 if(player->peer_id == PEER_ID_INEXISTENT){
3620 infostream<<"Server::playSound: Player \""<<params.to_player
3621 <<"\" not connected"<<std::endl;
3624 RemoteClient *client = getClient(player->peer_id);
3625 dst_clients.insert(client);
3629 for(core::map<u16, RemoteClient*>::Iterator
3630 i = m_clients.getIterator(); i.atEnd() == false; i++)
3632 RemoteClient *client = i.getNode()->getValue();
3633 Player *player = m_env->getPlayer(client->peer_id);
3637 if(player->getPosition().getDistanceFrom(pos) >
3638 params.max_hear_distance)
3641 dst_clients.insert(client);
3644 if(dst_clients.size() == 0)
3647 s32 id = m_next_sound_id++;
3648 // The sound will exist as a reference in m_playing_sounds
3649 m_playing_sounds[id] = ServerPlayingSound();
3650 ServerPlayingSound &psound = m_playing_sounds[id];
3651 psound.params = params;
3652 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3653 i != dst_clients.end(); i++)
3654 psound.clients.insert((*i)->peer_id);
3656 std::ostringstream os(std::ios_base::binary);
3657 writeU16(os, TOCLIENT_PLAY_SOUND);
3659 os<<serializeString(spec.name);
3660 writeF1000(os, spec.gain * params.gain);
3661 writeU8(os, params.type);
3662 writeV3F1000(os, pos);
3663 writeU16(os, params.object);
3664 writeU8(os, params.loop);
3666 std::string s = os.str();
3667 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3669 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3670 i != dst_clients.end(); i++){
3672 m_con.Send((*i)->peer_id, 0, data, true);
3676 void Server::stopSound(s32 handle)
3678 // Get sound reference
3679 std::map<s32, ServerPlayingSound>::iterator i =
3680 m_playing_sounds.find(handle);
3681 if(i == m_playing_sounds.end())
3683 ServerPlayingSound &psound = i->second;
3685 std::ostringstream os(std::ios_base::binary);
3686 writeU16(os, TOCLIENT_STOP_SOUND);
3687 writeS32(os, handle);
3689 std::string s = os.str();
3690 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3692 for(std::set<u16>::iterator i = psound.clients.begin();
3693 i != psound.clients.end(); i++){
3695 m_con.Send(*i, 0, data, true);
3697 // Remove sound reference
3698 m_playing_sounds.erase(i);
3701 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3702 core::list<u16> *far_players, float far_d_nodes)
3704 float maxd = far_d_nodes*BS;
3705 v3f p_f = intToFloat(p, BS);
3709 SharedBuffer<u8> reply(replysize);
3710 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3711 writeS16(&reply[2], p.X);
3712 writeS16(&reply[4], p.Y);
3713 writeS16(&reply[6], p.Z);
3715 for(core::map<u16, RemoteClient*>::Iterator
3716 i = m_clients.getIterator();
3717 i.atEnd() == false; i++)
3719 // Get client and check that it is valid
3720 RemoteClient *client = i.getNode()->getValue();
3721 assert(client->peer_id == i.getNode()->getKey());
3722 if(client->serialization_version == SER_FMT_VER_INVALID)
3725 // Don't send if it's the same one
3726 if(client->peer_id == ignore_id)
3732 Player *player = m_env->getPlayer(client->peer_id);
3735 // If player is far away, only set modified blocks not sent
3736 v3f player_pos = player->getPosition();
3737 if(player_pos.getDistanceFrom(p_f) > maxd)
3739 far_players->push_back(client->peer_id);
3746 m_con.Send(client->peer_id, 0, reply, true);
3750 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3751 core::list<u16> *far_players, float far_d_nodes)
3753 float maxd = far_d_nodes*BS;
3754 v3f p_f = intToFloat(p, BS);
3756 for(core::map<u16, RemoteClient*>::Iterator
3757 i = m_clients.getIterator();
3758 i.atEnd() == false; i++)
3760 // Get client and check that it is valid
3761 RemoteClient *client = i.getNode()->getValue();
3762 assert(client->peer_id == i.getNode()->getKey());
3763 if(client->serialization_version == SER_FMT_VER_INVALID)
3766 // Don't send if it's the same one
3767 if(client->peer_id == ignore_id)
3773 Player *player = m_env->getPlayer(client->peer_id);
3776 // If player is far away, only set modified blocks not sent
3777 v3f player_pos = player->getPosition();
3778 if(player_pos.getDistanceFrom(p_f) > maxd)
3780 far_players->push_back(client->peer_id);
3787 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3788 SharedBuffer<u8> reply(replysize);
3789 writeU16(&reply[0], TOCLIENT_ADDNODE);
3790 writeS16(&reply[2], p.X);
3791 writeS16(&reply[4], p.Y);
3792 writeS16(&reply[6], p.Z);
3793 n.serialize(&reply[8], client->serialization_version);
3796 m_con.Send(client->peer_id, 0, reply, true);
3800 void Server::setBlockNotSent(v3s16 p)
3802 for(core::map<u16, RemoteClient*>::Iterator
3803 i = m_clients.getIterator();
3804 i.atEnd()==false; i++)
3806 RemoteClient *client = i.getNode()->getValue();
3807 client->SetBlockNotSent(p);
3811 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3813 DSTACK(__FUNCTION_NAME);
3815 v3s16 p = block->getPos();
3819 bool completely_air = true;
3820 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3821 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3822 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3824 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3826 completely_air = false;
3827 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3832 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3834 infostream<<"[completely air] ";
3835 infostream<<std::endl;
3839 Create a packet with the block in the right format
3842 std::ostringstream os(std::ios_base::binary);
3843 block->serialize(os, ver, false);
3844 std::string s = os.str();
3845 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3847 u32 replysize = 8 + blockdata.getSize();
3848 SharedBuffer<u8> reply(replysize);
3849 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3850 writeS16(&reply[2], p.X);
3851 writeS16(&reply[4], p.Y);
3852 writeS16(&reply[6], p.Z);
3853 memcpy(&reply[8], *blockdata, blockdata.getSize());
3855 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3856 <<": \tpacket size: "<<replysize<<std::endl;*/
3861 m_con.Send(peer_id, 1, reply, true);
3864 void Server::SendBlocks(float dtime)
3866 DSTACK(__FUNCTION_NAME);
3868 JMutexAutoLock envlock(m_env_mutex);
3869 JMutexAutoLock conlock(m_con_mutex);
3871 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3873 core::array<PrioritySortedBlockTransfer> queue;
3875 s32 total_sending = 0;
3878 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3880 for(core::map<u16, RemoteClient*>::Iterator
3881 i = m_clients.getIterator();
3882 i.atEnd() == false; i++)
3884 RemoteClient *client = i.getNode()->getValue();
3885 assert(client->peer_id == i.getNode()->getKey());
3887 // If definitions and textures have not been sent, don't
3888 // send MapBlocks either
3889 if(!client->definitions_sent)
3892 total_sending += client->SendingCount();
3894 if(client->serialization_version == SER_FMT_VER_INVALID)
3897 client->GetNextBlocks(this, dtime, queue);
3902 // Lowest priority number comes first.
3903 // Lowest is most important.
3906 for(u32 i=0; i<queue.size(); i++)
3908 //TODO: Calculate limit dynamically
3909 if(total_sending >= g_settings->getS32
3910 ("max_simultaneous_block_sends_server_total"))
3913 PrioritySortedBlockTransfer q = queue[i];
3915 MapBlock *block = NULL;
3918 block = m_env->getMap().getBlockNoCreate(q.pos);
3920 catch(InvalidPositionException &e)
3925 RemoteClient *client = getClient(q.peer_id);
3927 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3929 client->SentBlock(q.pos);
3935 void Server::fillMediaCache()
3937 DSTACK(__FUNCTION_NAME);
3939 infostream<<"Server: Calculating media file checksums"<<std::endl;
3941 // Collect all media file paths
3942 std::list<std::string> paths;
3943 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3944 i != m_mods.end(); i++){
3945 const ModSpec &mod = *i;
3946 paths.push_back(mod.path + DIR_DELIM + "textures");
3947 paths.push_back(mod.path + DIR_DELIM + "sounds");
3948 paths.push_back(mod.path + DIR_DELIM + "media");
3951 // Collect media file information from paths into cache
3952 for(std::list<std::string>::iterator i = paths.begin();
3953 i != paths.end(); i++)
3955 std::string mediapath = *i;
3956 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3957 for(u32 j=0; j<dirlist.size(); j++){
3958 if(dirlist[j].dir) // Ignode dirs
3960 std::string filename = dirlist[j].name;
3961 // if name contains illegal characters, ignore the file
3962 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3963 errorstream<<"Server: ignoring illegal file name: \""
3964 <<filename<<"\""<<std::endl;
3967 std::string filepath = mediapath + DIR_DELIM + filename;
3969 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3970 if(fis.good() == false){
3971 errorstream<<"Server::fillMediaCache(): Could not open \""
3972 <<filename<<"\" for reading"<<std::endl;
3975 std::ostringstream tmp_os(std::ios_base::binary);
3979 fis.read(buf, 1024);
3980 std::streamsize len = fis.gcount();
3981 tmp_os.write(buf, len);
3990 errorstream<<"Server::fillMediaCache(): Failed to read \""
3991 <<filename<<"\""<<std::endl;
3994 if(tmp_os.str().length() == 0){
3995 errorstream<<"Server::fillMediaCache(): Empty file \""
3996 <<filepath<<"\""<<std::endl;
4001 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4003 unsigned char *digest = sha1.getDigest();
4004 std::string sha1_base64 = base64_encode(digest, 20);
4005 std::string sha1_hex = hex_encode((char*)digest, 20);
4009 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4010 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4015 struct SendableMediaAnnouncement
4018 std::string sha1_digest;
4020 SendableMediaAnnouncement(const std::string name_="",
4021 const std::string sha1_digest_=""):
4023 sha1_digest(sha1_digest_)
4027 void Server::sendMediaAnnouncement(u16 peer_id)
4029 DSTACK(__FUNCTION_NAME);
4031 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4034 core::list<SendableMediaAnnouncement> file_announcements;
4036 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4037 i != m_media.end(); i++){
4039 file_announcements.push_back(
4040 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4044 std::ostringstream os(std::ios_base::binary);
4052 u16 length of sha1_digest
4057 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4058 writeU16(os, file_announcements.size());
4060 for(core::list<SendableMediaAnnouncement>::Iterator
4061 j = file_announcements.begin();
4062 j != file_announcements.end(); j++){
4063 os<<serializeString(j->name);
4064 os<<serializeString(j->sha1_digest);
4068 std::string s = os.str();
4069 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4072 m_con.Send(peer_id, 0, data, true);
4076 struct SendableMedia
4082 SendableMedia(const std::string &name_="", const std::string path_="",
4083 const std::string &data_=""):
4090 void Server::sendRequestedMedia(u16 peer_id,
4091 const core::list<MediaRequest> &tosend)
4093 DSTACK(__FUNCTION_NAME);
4095 verbosestream<<"Server::sendRequestedMedia(): "
4096 <<"Sending files to client"<<std::endl;
4100 // Put 5kB in one bunch (this is not accurate)
4101 u32 bytes_per_bunch = 5000;
4103 core::array< core::list<SendableMedia> > file_bunches;
4104 file_bunches.push_back(core::list<SendableMedia>());
4106 u32 file_size_bunch_total = 0;
4108 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4109 i != tosend.end(); i++)
4111 if(m_media.find(i->name) == m_media.end()){
4112 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4113 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4117 //TODO get path + name
4118 std::string tpath = m_media[(*i).name].path;
4121 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4122 if(fis.good() == false){
4123 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4124 <<tpath<<"\" for reading"<<std::endl;
4127 std::ostringstream tmp_os(std::ios_base::binary);
4131 fis.read(buf, 1024);
4132 std::streamsize len = fis.gcount();
4133 tmp_os.write(buf, len);
4134 file_size_bunch_total += len;
4143 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4144 <<(*i).name<<"\""<<std::endl;
4147 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4148 <<tname<<"\""<<std::endl;*/
4150 file_bunches[file_bunches.size()-1].push_back(
4151 SendableMedia((*i).name, tpath, tmp_os.str()));
4153 // Start next bunch if got enough data
4154 if(file_size_bunch_total >= bytes_per_bunch){
4155 file_bunches.push_back(core::list<SendableMedia>());
4156 file_size_bunch_total = 0;
4161 /* Create and send packets */
4163 u32 num_bunches = file_bunches.size();
4164 for(u32 i=0; i<num_bunches; i++)
4166 std::ostringstream os(std::ios_base::binary);
4170 u16 total number of texture bunches
4171 u16 index of this bunch
4172 u32 number of files in this bunch
4181 writeU16(os, TOCLIENT_MEDIA);
4182 writeU16(os, num_bunches);
4184 writeU32(os, file_bunches[i].size());
4186 for(core::list<SendableMedia>::Iterator
4187 j = file_bunches[i].begin();
4188 j != file_bunches[i].end(); j++){
4189 os<<serializeString(j->name);
4190 os<<serializeLongString(j->data);
4194 std::string s = os.str();
4195 verbosestream<<"Server::sendRequestedMedia(): bunch "
4196 <<i<<"/"<<num_bunches
4197 <<" files="<<file_bunches[i].size()
4198 <<" size=" <<s.size()<<std::endl;
4199 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4201 m_con.Send(peer_id, 0, data, true);
4209 void Server::DiePlayer(Player *player)
4211 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4213 infostream<<"Server::DiePlayer(): Player "
4214 <<player->getName()<<" dies"<<std::endl;
4218 // Trigger scripted stuff
4219 scriptapi_on_dieplayer(m_lua, srp);
4221 // Handle players that are not connected
4222 if(player->peer_id == PEER_ID_INEXISTENT){
4223 RespawnPlayer(player);
4227 SendPlayerHP(player);
4228 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4231 void Server::RespawnPlayer(Player *player)
4233 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4235 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4237 v3f pos = findSpawnPos(m_env->getServerMap());
4238 player->setPosition(pos);
4239 srp->m_last_good_position = pos;
4240 srp->m_last_good_position_age = 0;
4242 SendMovePlayer(player);
4243 SendPlayerHP(player);
4246 void Server::UpdateCrafting(u16 peer_id)
4248 DSTACK(__FUNCTION_NAME);
4250 Player* player = m_env->getPlayer(peer_id);
4253 // Get a preview for crafting
4255 // No crafting in creative mode
4256 if(g_settings->getBool("creative_mode") == false)
4257 getCraftingResult(&player->inventory, preview, false, this);
4259 // Put the new preview in
4260 InventoryList *plist = player->inventory.getList("craftpreview");
4262 assert(plist->getSize() >= 1);
4263 plist->changeItem(0, preview);
4266 RemoteClient* Server::getClient(u16 peer_id)
4268 DSTACK(__FUNCTION_NAME);
4269 //JMutexAutoLock lock(m_con_mutex);
4270 core::map<u16, RemoteClient*>::Node *n;
4271 n = m_clients.find(peer_id);
4272 // A client should exist for all peers
4274 return n->getValue();
4277 std::wstring Server::getStatusString()
4279 std::wostringstream os(std::ios_base::binary);
4282 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4284 os<<L", uptime="<<m_uptime.get();
4285 // Information about clients
4287 for(core::map<u16, RemoteClient*>::Iterator
4288 i = m_clients.getIterator();
4289 i.atEnd() == false; i++)
4291 // Get client and check that it is valid
4292 RemoteClient *client = i.getNode()->getValue();
4293 assert(client->peer_id == i.getNode()->getKey());
4294 if(client->serialization_version == SER_FMT_VER_INVALID)
4297 Player *player = m_env->getPlayer(client->peer_id);
4298 // Get name of player
4299 std::wstring name = L"unknown";
4301 name = narrow_to_wide(player->getName());
4302 // Add name to information string
4306 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4307 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4308 if(g_settings->get("motd") != "")
4309 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4313 u64 Server::getPlayerAuthPrivs(const std::string &name)
4316 return m_authmanager.getPrivs(name);
4318 catch(AuthNotFoundException &e)
4320 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4325 void Server::setPlayerAuthPrivs(const std::string &name, u64 privs)
4328 return m_authmanager.setPrivs(name, privs);
4330 catch(AuthNotFoundException &e)
4332 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4336 u64 Server::getPlayerEffectivePrivs(const std::string &name)
4338 // Local player gets all privileges regardless of
4339 // what's set on their account.
4340 if(m_simple_singleplayer_mode)
4342 if(name == g_settings->get("name"))
4344 return getPlayerAuthPrivs(name);
4347 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4349 // Add player to auth manager
4350 if(m_authmanager.exists(name) == false)
4352 infostream<<"Server: adding player "<<name
4353 <<" to auth manager"<<std::endl;
4354 m_authmanager.add(name);
4355 m_authmanager.setPrivs(name,
4356 stringToPrivs(g_settings->get("default_privs")));
4358 // Change password and save
4359 m_authmanager.setPassword(name, translatePassword(name, password));
4360 m_authmanager.save();
4363 // Saves g_settings to configpath given at initialization
4364 void Server::saveConfig()
4366 if(m_path_config != "")
4367 g_settings->updateConfigFile(m_path_config.c_str());
4370 void Server::notifyPlayer(const char *name, const std::wstring msg)
4372 Player *player = m_env->getPlayer(name);
4375 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4378 void Server::notifyPlayers(const std::wstring msg)
4380 BroadcastChatMessage(msg);
4383 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4387 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4388 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4391 // IGameDef interface
4393 IItemDefManager* Server::getItemDefManager()
4397 INodeDefManager* Server::getNodeDefManager()
4401 ICraftDefManager* Server::getCraftDefManager()
4405 ITextureSource* Server::getTextureSource()
4409 u16 Server::allocateUnknownNodeId(const std::string &name)
4411 return m_nodedef->allocateDummy(name);
4413 ISoundManager* Server::getSoundManager()
4415 return &dummySoundManager;
4417 MtEventManager* Server::getEventManager()
4422 IWritableItemDefManager* Server::getWritableItemDefManager()
4426 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4430 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4435 const ModSpec* Server::getModSpec(const std::string &modname)
4437 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4438 i != m_mods.end(); i++){
4439 const ModSpec &mod = *i;
4440 if(mod.name == modname)
4446 v3f findSpawnPos(ServerMap &map)
4448 //return v3f(50,50,50)*BS;
4453 nodepos = v2s16(0,0);
4458 // Try to find a good place a few times
4459 for(s32 i=0; i<1000; i++)
4462 // We're going to try to throw the player to this position
4463 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4464 -range + (myrand()%(range*2)));
4465 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4466 // Get ground height at point (fallbacks to heightmap function)
4467 s16 groundheight = map.findGroundLevel(nodepos2d);
4468 // Don't go underwater
4469 if(groundheight < WATER_LEVEL)
4471 //infostream<<"-> Underwater"<<std::endl;
4474 // Don't go to high places
4475 if(groundheight > WATER_LEVEL + 4)
4477 //infostream<<"-> Underwater"<<std::endl;
4481 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4482 bool is_good = false;
4484 for(s32 i=0; i<10; i++){
4485 v3s16 blockpos = getNodeBlockPos(nodepos);
4486 map.emergeBlock(blockpos, true);
4487 MapNode n = map.getNodeNoEx(nodepos);
4488 if(n.getContent() == CONTENT_AIR){
4499 // Found a good place
4500 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4506 return intToFloat(nodepos, BS);
4509 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4512 Try to get an existing player
4514 ServerRemotePlayer *player =
4515 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4518 // If player is already connected, cancel
4519 if(player->peer_id != 0)
4521 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4526 player->peer_id = peer_id;
4528 // Re-add player to environment
4529 if(player->m_removed)
4531 player->m_removed = false;
4533 m_env->addActiveObject(player);
4536 // Reset inventory to creative if in creative mode
4537 if(g_settings->getBool("creative_mode"))
4539 // Warning: double code below
4540 // Backup actual inventory
4541 player->inventory_backup = new Inventory(m_itemdef);
4542 *(player->inventory_backup) = player->inventory;
4543 // Set creative inventory
4544 player->resetInventory();
4545 scriptapi_get_creative_inventory(m_lua, player);
4552 If player with the wanted peer_id already exists, cancel.
4554 if(m_env->getPlayer(peer_id) != NULL)
4556 infostream<<"emergePlayer(): Player with wrong name but same"
4557 " peer_id already exists"<<std::endl;
4565 /* Set player position */
4567 infostream<<"Server: Finding spawn place for player \""
4568 <<name<<"\""<<std::endl;
4570 v3f pos = findSpawnPos(m_env->getServerMap());
4572 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4573 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4575 /* Add player to environment */
4576 m_env->addPlayer(player);
4577 m_env->addActiveObject(srp);
4580 scriptapi_on_newplayer(m_lua, srp);
4582 /* Add stuff to inventory */
4583 if(g_settings->getBool("creative_mode"))
4585 // Warning: double code above
4586 // Backup actual inventory
4587 player->inventory_backup = new Inventory(m_itemdef);
4588 *(player->inventory_backup) = player->inventory;
4589 // Set creative inventory
4590 player->resetInventory();
4591 scriptapi_get_creative_inventory(m_lua, player);
4596 } // create new player
4599 void Server::handlePeerChange(PeerChange &c)
4601 JMutexAutoLock envlock(m_env_mutex);
4602 JMutexAutoLock conlock(m_con_mutex);
4604 if(c.type == PEER_ADDED)
4611 core::map<u16, RemoteClient*>::Node *n;
4612 n = m_clients.find(c.peer_id);
4613 // The client shouldn't already exist
4617 RemoteClient *client = new RemoteClient();
4618 client->peer_id = c.peer_id;
4619 m_clients.insert(client->peer_id, client);
4622 else if(c.type == PEER_REMOVED)
4629 core::map<u16, RemoteClient*>::Node *n;
4630 n = m_clients.find(c.peer_id);
4631 // The client should exist
4635 Mark objects to be not known by the client
4637 RemoteClient *client = n->getValue();
4639 for(core::map<u16, bool>::Iterator
4640 i = client->m_known_objects.getIterator();
4641 i.atEnd()==false; i++)
4644 u16 id = i.getNode()->getKey();
4645 ServerActiveObject* obj = m_env->getActiveObject(id);
4647 if(obj && obj->m_known_by_count > 0)
4648 obj->m_known_by_count--;
4652 Clear references to playing sounds
4654 for(std::map<s32, ServerPlayingSound>::iterator
4655 i = m_playing_sounds.begin();
4656 i != m_playing_sounds.end();)
4658 ServerPlayingSound &psound = i->second;
4659 psound.clients.erase(c.peer_id);
4660 if(psound.clients.size() == 0)
4661 m_playing_sounds.erase(i++);
4666 ServerRemotePlayer* player =
4667 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4669 // Collect information about leaving in chat
4670 std::wstring message;
4674 std::wstring name = narrow_to_wide(player->getName());
4677 message += L" left game";
4679 message += L" (timed out)";
4683 // Remove from environment
4685 player->m_removed = true;
4687 // Set player client disconnected
4689 player->peer_id = 0;
4697 std::ostringstream os(std::ios_base::binary);
4698 for(core::map<u16, RemoteClient*>::Iterator
4699 i = m_clients.getIterator();
4700 i.atEnd() == false; i++)
4702 RemoteClient *client = i.getNode()->getValue();
4703 assert(client->peer_id == i.getNode()->getKey());
4704 if(client->serialization_version == SER_FMT_VER_INVALID)
4707 Player *player = m_env->getPlayer(client->peer_id);
4710 // Get name of player
4711 os<<player->getName()<<" ";
4714 actionstream<<player->getName()<<" "
4715 <<(c.timeout?"times out.":"leaves game.")
4716 <<" List of players: "
4717 <<os.str()<<std::endl;
4722 delete m_clients[c.peer_id];
4723 m_clients.remove(c.peer_id);
4725 // Send player info to all remaining clients
4726 //SendPlayerInfos();
4728 // Send leave chat message to all remaining clients
4729 if(message.length() != 0)
4730 BroadcastChatMessage(message);
4739 void Server::handlePeerChanges()
4741 while(m_peer_change_queue.size() > 0)
4743 PeerChange c = m_peer_change_queue.pop_front();
4745 verbosestream<<"Server: Handling peer change: "
4746 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4749 handlePeerChange(c);
4753 u64 Server::getPlayerPrivs(Player *player)
4757 std::string playername = player->getName();
4758 return getPlayerEffectivePrivs(playername);
4761 void dedicated_server_loop(Server &server, bool &kill)
4763 DSTACK(__FUNCTION_NAME);
4765 verbosestream<<"dedicated_server_loop()"<<std::endl;
4767 IntervalLimiter m_profiler_interval;
4771 float steplen = g_settings->getFloat("dedicated_server_step");
4772 // This is kind of a hack but can be done like this
4773 // because server.step() is very light
4775 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4776 sleep_ms((int)(steplen*1000.0));
4778 server.step(steplen);
4780 if(server.getShutdownRequested() || kill)
4782 infostream<<"Dedicated server quitting"<<std::endl;
4789 float profiler_print_interval =
4790 g_settings->getFloat("profiler_print_interval");
4791 if(profiler_print_interval != 0)
4793 if(m_profiler_interval.step(steplen, profiler_print_interval))
4795 infostream<<"Profiler:"<<std::endl;
4796 g_profiler->print(infostream);
4797 g_profiler->clear();