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 = data.blockpos_min*MAP_BLOCKSIZE;
284 v3s16 maxp = data.blockpos_max*MAP_BLOCKSIZE +
285 v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
286 scriptapi_environment_on_generated(m_server->m_lua,
287 minp, maxp, mapgen::get_blockseed(data.seed, minp));
289 if(enable_mapgen_debug_info)
290 infostream<<"EmergeThread: ended up with: "
291 <<analyze_block(block)<<std::endl;
294 Ignore map edit events, they will not need to be
295 sent to anybody because the block hasn't been sent
298 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
300 // Activate objects and stuff
301 m_server->m_env->activateBlock(block, 0);
309 Set sent status of modified blocks on clients
312 // NOTE: Server's clients are also behind the connection mutex
313 JMutexAutoLock lock(m_server->m_con_mutex);
316 Add the originally fetched block to the modified list
320 modified_blocks.insert(p, block);
324 Set the modified blocks unsent for all the clients
327 for(core::map<u16, RemoteClient*>::Iterator
328 i = m_server->m_clients.getIterator();
329 i.atEnd() == false; i++)
331 RemoteClient *client = i.getNode()->getValue();
333 if(modified_blocks.size() > 0)
335 // Remove block from sent history
336 client->SetBlocksNotSent(modified_blocks);
342 END_DEBUG_EXCEPTION_HANDLER(errorstream)
344 log_deregister_thread();
349 void RemoteClient::GetNextBlocks(Server *server, float dtime,
350 core::array<PrioritySortedBlockTransfer> &dest)
352 DSTACK(__FUNCTION_NAME);
355 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
358 m_nothing_to_send_pause_timer -= dtime;
359 m_nearest_unsent_reset_timer += dtime;
361 if(m_nothing_to_send_pause_timer >= 0)
366 // Won't send anything if already sending
367 if(m_blocks_sending.size() >= g_settings->getU16
368 ("max_simultaneous_block_sends_per_client"))
370 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
374 //TimeTaker timer("RemoteClient::GetNextBlocks");
376 Player *player = server->m_env->getPlayer(peer_id);
378 assert(player != NULL);
380 v3f playerpos = player->getPosition();
381 v3f playerspeed = player->getSpeed();
382 v3f playerspeeddir(0,0,0);
383 if(playerspeed.getLength() > 1.0*BS)
384 playerspeeddir = playerspeed / playerspeed.getLength();
385 // Predict to next block
386 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
388 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
390 v3s16 center = getNodeBlockPos(center_nodepos);
392 // Camera position and direction
393 v3f camera_pos = player->getEyePosition();
394 v3f camera_dir = v3f(0,0,1);
395 camera_dir.rotateYZBy(player->getPitch());
396 camera_dir.rotateXZBy(player->getYaw());
398 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
399 <<camera_dir.Z<<")"<<std::endl;*/
402 Get the starting value of the block finder radius.
405 if(m_last_center != center)
407 m_nearest_unsent_d = 0;
408 m_last_center = center;
411 /*infostream<<"m_nearest_unsent_reset_timer="
412 <<m_nearest_unsent_reset_timer<<std::endl;*/
414 // Reset periodically to workaround for some bugs or stuff
415 if(m_nearest_unsent_reset_timer > 20.0)
417 m_nearest_unsent_reset_timer = 0;
418 m_nearest_unsent_d = 0;
419 //infostream<<"Resetting m_nearest_unsent_d for "
420 // <<server->getPlayerName(peer_id)<<std::endl;
423 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
424 s16 d_start = m_nearest_unsent_d;
426 //infostream<<"d_start="<<d_start<<std::endl;
428 u16 max_simul_sends_setting = g_settings->getU16
429 ("max_simultaneous_block_sends_per_client");
430 u16 max_simul_sends_usually = max_simul_sends_setting;
433 Check the time from last addNode/removeNode.
435 Decrease send rate if player is building stuff.
437 m_time_from_building += dtime;
438 if(m_time_from_building < g_settings->getFloat(
439 "full_block_send_enable_min_time_from_building"))
441 max_simul_sends_usually
442 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
446 Number of blocks sending + number of blocks selected for sending
448 u32 num_blocks_selected = m_blocks_sending.size();
451 next time d will be continued from the d from which the nearest
452 unsent block was found this time.
454 This is because not necessarily any of the blocks found this
455 time are actually sent.
457 s32 new_nearest_unsent_d = -1;
459 s16 d_max = g_settings->getS16("max_block_send_distance");
460 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
462 // Don't loop very much at a time
463 s16 max_d_increment_at_time = 2;
464 if(d_max > d_start + max_d_increment_at_time)
465 d_max = d_start + max_d_increment_at_time;
466 /*if(d_max_gen > d_start+2)
467 d_max_gen = d_start+2;*/
469 //infostream<<"Starting from "<<d_start<<std::endl;
471 s32 nearest_emerged_d = -1;
472 s32 nearest_emergefull_d = -1;
473 s32 nearest_sent_d = -1;
474 bool queue_is_full = false;
477 for(d = d_start; d <= d_max; d++)
479 /*errorstream<<"checking d="<<d<<" for "
480 <<server->getPlayerName(peer_id)<<std::endl;*/
481 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
484 If m_nearest_unsent_d was changed by the EmergeThread
485 (it can change it to 0 through SetBlockNotSent),
487 Else update m_nearest_unsent_d
489 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
491 d = m_nearest_unsent_d;
492 last_nearest_unsent_d = m_nearest_unsent_d;
496 Get the border/face dot coordinates of a "d-radiused"
499 core::list<v3s16> list;
500 getFacePositions(list, d);
502 core::list<v3s16>::Iterator li;
503 for(li=list.begin(); li!=list.end(); li++)
505 v3s16 p = *li + center;
509 - Don't allow too many simultaneous transfers
510 - EXCEPT when the blocks are very close
512 Also, don't send blocks that are already flying.
515 // Start with the usual maximum
516 u16 max_simul_dynamic = max_simul_sends_usually;
518 // If block is very close, allow full maximum
519 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
520 max_simul_dynamic = max_simul_sends_setting;
522 // Don't select too many blocks for sending
523 if(num_blocks_selected >= max_simul_dynamic)
525 queue_is_full = true;
526 goto queue_full_break;
529 // Don't send blocks that are currently being transferred
530 if(m_blocks_sending.find(p) != NULL)
536 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
537 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
538 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
539 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
540 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
541 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
544 // If this is true, inexistent block will be made from scratch
545 bool generate = d <= d_max_gen;
548 /*// Limit the generating area vertically to 2/3
549 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
552 // Limit the send area vertically to 1/2
553 if(abs(p.Y - center.Y) > d_max / 2)
559 If block is far away, don't generate it unless it is
565 // Block center y in nodes
566 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
567 // Don't generate if it's very high or very low
568 if(y < -64 || y > 64)
572 v2s16 p2d_nodes_center(
576 // Get ground height in nodes
577 s16 gh = server->m_env->getServerMap().findGroundLevel(
580 // If differs a lot, don't generate
581 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
583 // Actually, don't even send it
589 //infostream<<"d="<<d<<std::endl;
592 Don't generate or send if not in sight
593 FIXME This only works if the client uses a small enough
594 FOV setting. The default of 72 degrees is fine.
597 float camera_fov = (72.0*PI/180) * 4./3.;
598 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
604 Don't send already sent blocks
607 if(m_blocks_sent.find(p) != NULL)
614 Check if map has this block
616 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
618 bool surely_not_found_on_disk = false;
619 bool block_is_invalid = false;
622 // Reset usage timer, this block will be of use in the future.
623 block->resetUsageTimer();
625 // Block is dummy if data doesn't exist.
626 // It means it has been not found from disk and not generated
629 surely_not_found_on_disk = true;
632 // Block is valid if lighting is up-to-date and data exists
633 if(block->isValid() == false)
635 block_is_invalid = true;
638 /*if(block->isFullyGenerated() == false)
640 block_is_invalid = true;
645 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
646 v2s16 chunkpos = map->sector_to_chunk(p2d);
647 if(map->chunkNonVolatile(chunkpos) == false)
648 block_is_invalid = true;
650 if(block->isGenerated() == false)
651 block_is_invalid = true;
654 If block is not close, don't send it unless it is near
657 Block is near ground level if night-time mesh
658 differs from day-time mesh.
662 if(block->dayNightDiffed() == false)
669 If block has been marked to not exist on disk (dummy)
670 and generating new ones is not wanted, skip block.
672 if(generate == false && surely_not_found_on_disk == true)
679 Add inexistent block to emerge queue.
681 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
683 //TODO: Get value from somewhere
684 // Allow only one block in emerge queue
685 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
686 // Allow two blocks in queue per client
687 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
689 // Make it more responsive when needing to generate stuff
690 if(surely_not_found_on_disk)
692 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
694 //infostream<<"Adding block to emerge queue"<<std::endl;
696 // Add it to the emerge queue and trigger the thread
699 if(generate == false)
700 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
702 server->m_emerge_queue.addBlock(peer_id, p, flags);
703 server->m_emergethread.trigger();
705 if(nearest_emerged_d == -1)
706 nearest_emerged_d = d;
708 if(nearest_emergefull_d == -1)
709 nearest_emergefull_d = d;
716 if(nearest_sent_d == -1)
720 Add block to send queue
723 /*errorstream<<"sending from d="<<d<<" to "
724 <<server->getPlayerName(peer_id)<<std::endl;*/
726 PrioritySortedBlockTransfer q((float)d, p, peer_id);
730 num_blocks_selected += 1;
735 //infostream<<"Stopped at "<<d<<std::endl;
737 // If nothing was found for sending and nothing was queued for
738 // emerging, continue next time browsing from here
739 if(nearest_emerged_d != -1){
740 new_nearest_unsent_d = nearest_emerged_d;
741 } else if(nearest_emergefull_d != -1){
742 new_nearest_unsent_d = nearest_emergefull_d;
744 if(d > g_settings->getS16("max_block_send_distance")){
745 new_nearest_unsent_d = 0;
746 m_nothing_to_send_pause_timer = 2.0;
747 /*infostream<<"GetNextBlocks(): d wrapped around for "
748 <<server->getPlayerName(peer_id)
749 <<"; setting to 0 and pausing"<<std::endl;*/
751 if(nearest_sent_d != -1)
752 new_nearest_unsent_d = nearest_sent_d;
754 new_nearest_unsent_d = d;
758 if(new_nearest_unsent_d != -1)
759 m_nearest_unsent_d = new_nearest_unsent_d;
761 /*timer_result = timer.stop(true);
762 if(timer_result != 0)
763 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
766 void RemoteClient::GotBlock(v3s16 p)
768 if(m_blocks_sending.find(p) != NULL)
769 m_blocks_sending.remove(p);
772 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
773 " m_blocks_sending"<<std::endl;*/
774 m_excess_gotblocks++;
776 m_blocks_sent.insert(p, true);
779 void RemoteClient::SentBlock(v3s16 p)
781 if(m_blocks_sending.find(p) == NULL)
782 m_blocks_sending.insert(p, 0.0);
784 infostream<<"RemoteClient::SentBlock(): Sent block"
785 " already in m_blocks_sending"<<std::endl;
788 void RemoteClient::SetBlockNotSent(v3s16 p)
790 m_nearest_unsent_d = 0;
792 if(m_blocks_sending.find(p) != NULL)
793 m_blocks_sending.remove(p);
794 if(m_blocks_sent.find(p) != NULL)
795 m_blocks_sent.remove(p);
798 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
800 m_nearest_unsent_d = 0;
802 for(core::map<v3s16, MapBlock*>::Iterator
803 i = blocks.getIterator();
804 i.atEnd()==false; i++)
806 v3s16 p = i.getNode()->getKey();
808 if(m_blocks_sending.find(p) != NULL)
809 m_blocks_sending.remove(p);
810 if(m_blocks_sent.find(p) != NULL)
811 m_blocks_sent.remove(p);
819 PlayerInfo::PlayerInfo()
825 void PlayerInfo::PrintLine(std::ostream *s)
828 (*s)<<"\""<<name<<"\" ("
829 <<(position.X/10)<<","<<(position.Y/10)
830 <<","<<(position.Z/10)<<") ";
832 (*s)<<" avg_rtt="<<avg_rtt;
841 const std::string &path_world,
842 const std::string &path_config,
843 const SubgameSpec &gamespec,
844 bool simple_singleplayer_mode
846 m_path_world(path_world),
847 m_path_config(path_config),
848 m_gamespec(gamespec),
849 m_simple_singleplayer_mode(simple_singleplayer_mode),
850 m_async_fatal_error(""),
852 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
853 m_authmanager(path_world+DIR_DELIM+"auth.txt"),
854 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
856 m_itemdef(createItemDefManager()),
857 m_nodedef(createNodeDefManager()),
858 m_craftdef(createCraftDefManager()),
859 m_event(new EventManager()),
861 m_emergethread(this),
862 m_time_of_day_send_timer(0),
864 m_shutdown_requested(false),
865 m_ignore_map_edit_events(false),
866 m_ignore_map_edit_events_peer_id(0)
868 m_liquid_transform_timer = 0.0;
869 m_print_info_timer = 0.0;
870 m_objectdata_timer = 0.0;
871 m_emergethread_trigger_timer = 0.0;
872 m_savemap_timer = 0.0;
876 m_step_dtime_mutex.Init();
880 throw ServerError("Supplied empty world path");
882 if(!gamespec.isValid())
883 throw ServerError("Supplied invalid gamespec");
885 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
886 if(m_simple_singleplayer_mode)
887 infostream<<" in simple singleplayer mode"<<std::endl;
889 infostream<<std::endl;
890 infostream<<"- world: "<<m_path_world<<std::endl;
891 infostream<<"- config: "<<m_path_config<<std::endl;
892 infostream<<"- game: "<<m_gamespec.path<<std::endl;
894 // Add world mod search path
895 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
896 // Add addon mod search path
897 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
898 i != m_gamespec.mods_paths.end(); i++)
899 m_modspaths.push_front((*i));
901 // Print out mod search paths
902 for(core::list<std::string>::Iterator i = m_modspaths.begin();
903 i != m_modspaths.end(); i++){
904 std::string modspath = *i;
905 infostream<<"- mods: "<<modspath<<std::endl;
908 // Path to builtin.lua
909 std::string builtinpath = porting::path_share + DIR_DELIM + "builtin"
910 + DIR_DELIM + "builtin.lua";
912 // Create world if it doesn't exist
913 if(!initializeWorld(m_path_world, m_gamespec.id))
914 throw ServerError("Failed to initialize world");
917 JMutexAutoLock envlock(m_env_mutex);
918 JMutexAutoLock conlock(m_con_mutex);
920 // Initialize scripting
922 infostream<<"Server: Initializing Lua"<<std::endl;
923 m_lua = script_init();
926 scriptapi_export(m_lua, this);
927 // Load and run builtin.lua
928 infostream<<"Server: Loading builtin.lua [\""
929 <<builtinpath<<"\"]"<<std::endl;
930 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
932 errorstream<<"Server: Failed to load and run "
933 <<builtinpath<<std::endl;
934 throw ModError("Failed to load and run "+builtinpath);
936 // Find mods in mod search paths
937 m_mods = getMods(m_modspaths);
939 infostream<<"Server: Loading mods: ";
940 for(core::list<ModSpec>::Iterator i = m_mods.begin();
941 i != m_mods.end(); i++){
942 const ModSpec &mod = *i;
943 infostream<<mod.name<<" ";
945 infostream<<std::endl;
946 // Load and run "mod" scripts
947 for(core::list<ModSpec>::Iterator i = m_mods.begin();
948 i != m_mods.end(); i++){
949 const ModSpec &mod = *i;
950 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
951 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
952 <<scriptpath<<"\"]"<<std::endl;
953 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
955 errorstream<<"Server: Failed to load and run "
956 <<scriptpath<<std::endl;
957 throw ModError("Failed to load and run "+scriptpath);
961 // Read Textures and calculate sha1 sums
964 // Apply item aliases in the node definition manager
965 m_nodedef->updateAliases(m_itemdef);
967 // Initialize Environment
969 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
972 // Give environment reference to scripting api
973 scriptapi_add_environment(m_lua, m_env);
975 // Register us to receive map edit events
976 m_env->getMap().addEventReceiver(this);
978 // If file exists, load environment metadata
979 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
981 infostream<<"Server: Loading environment metadata"<<std::endl;
982 m_env->loadMeta(m_path_world);
986 infostream<<"Server: Loading players"<<std::endl;
987 m_env->deSerializePlayers(m_path_world);
990 Add some test ActiveBlockModifiers to environment
992 add_legacy_abms(m_env, m_nodedef);
997 infostream<<"Server destructing"<<std::endl;
1000 Send shutdown message
1003 JMutexAutoLock conlock(m_con_mutex);
1005 std::wstring line = L"*** Server shutting down";
1008 Send the message to clients
1010 for(core::map<u16, RemoteClient*>::Iterator
1011 i = m_clients.getIterator();
1012 i.atEnd() == false; i++)
1014 // Get client and check that it is valid
1015 RemoteClient *client = i.getNode()->getValue();
1016 assert(client->peer_id == i.getNode()->getKey());
1017 if(client->serialization_version == SER_FMT_VER_INVALID)
1021 SendChatMessage(client->peer_id, line);
1023 catch(con::PeerNotFoundException &e)
1029 JMutexAutoLock envlock(m_env_mutex);
1034 infostream<<"Server: Saving players"<<std::endl;
1035 m_env->serializePlayers(m_path_world);
1038 Save environment metadata
1040 infostream<<"Server: Saving environment metadata"<<std::endl;
1041 m_env->saveMeta(m_path_world);
1053 JMutexAutoLock clientslock(m_con_mutex);
1055 for(core::map<u16, RemoteClient*>::Iterator
1056 i = m_clients.getIterator();
1057 i.atEnd() == false; i++)
1060 // NOTE: These are removed by env destructor
1062 u16 peer_id = i.getNode()->getKey();
1063 JMutexAutoLock envlock(m_env_mutex);
1064 m_env->removePlayer(peer_id);
1068 delete i.getNode()->getValue();
1072 // Delete things in the reverse order of creation
1079 // Deinitialize scripting
1080 infostream<<"Server: Deinitializing scripting"<<std::endl;
1081 script_deinit(m_lua);
1084 void Server::start(unsigned short port)
1086 DSTACK(__FUNCTION_NAME);
1087 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1089 // Stop thread if already running
1092 // Initialize connection
1093 m_con.SetTimeoutMs(30);
1097 m_thread.setRun(true);
1100 // ASCII art for the win!
1102 <<" .__ __ __ "<<std::endl
1103 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1104 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1105 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1106 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1107 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1108 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1109 actionstream<<"Server for gameid=\""<<m_gamespec.id
1110 <<"\" listening on port "<<port<<"."<<std::endl;
1115 DSTACK(__FUNCTION_NAME);
1117 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1119 // Stop threads (set run=false first so both start stopping)
1120 m_thread.setRun(false);
1121 m_emergethread.setRun(false);
1123 m_emergethread.stop();
1125 infostream<<"Server: Threads stopped"<<std::endl;
1128 void Server::step(float dtime)
1130 DSTACK(__FUNCTION_NAME);
1135 JMutexAutoLock lock(m_step_dtime_mutex);
1136 m_step_dtime += dtime;
1138 // Throw if fatal error occurred in thread
1139 std::string async_err = m_async_fatal_error.get();
1140 if(async_err != ""){
1141 throw ServerError(async_err);
1145 void Server::AsyncRunStep()
1147 DSTACK(__FUNCTION_NAME);
1149 g_profiler->add("Server::AsyncRunStep (num)", 1);
1153 JMutexAutoLock lock1(m_step_dtime_mutex);
1154 dtime = m_step_dtime;
1158 // Send blocks to clients
1165 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1167 //infostream<<"Server steps "<<dtime<<std::endl;
1168 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1171 JMutexAutoLock lock1(m_step_dtime_mutex);
1172 m_step_dtime -= dtime;
1179 m_uptime.set(m_uptime.get() + dtime);
1183 // Process connection's timeouts
1184 JMutexAutoLock lock2(m_con_mutex);
1185 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1186 m_con.RunTimeouts(dtime);
1190 // This has to be called so that the client list gets synced
1191 // with the peer list of the connection
1192 handlePeerChanges();
1196 Update time of day and overall game time
1199 JMutexAutoLock envlock(m_env_mutex);
1201 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1204 Send to clients at constant intervals
1207 m_time_of_day_send_timer -= dtime;
1208 if(m_time_of_day_send_timer < 0.0)
1210 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1212 //JMutexAutoLock envlock(m_env_mutex);
1213 JMutexAutoLock conlock(m_con_mutex);
1215 for(core::map<u16, RemoteClient*>::Iterator
1216 i = m_clients.getIterator();
1217 i.atEnd() == false; i++)
1219 RemoteClient *client = i.getNode()->getValue();
1220 //Player *player = m_env->getPlayer(client->peer_id);
1222 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1223 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1225 m_con.Send(client->peer_id, 0, data, true);
1231 JMutexAutoLock lock(m_env_mutex);
1233 ScopeProfiler sp(g_profiler, "SEnv step");
1234 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1238 const float map_timer_and_unload_dtime = 2.92;
1239 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1241 JMutexAutoLock lock(m_env_mutex);
1242 // Run Map's timers and unload unused data
1243 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1244 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1245 g_settings->getFloat("server_unload_unused_data_timeout"));
1256 JMutexAutoLock lock(m_env_mutex);
1257 JMutexAutoLock lock2(m_con_mutex);
1259 ScopeProfiler sp(g_profiler, "Server: handle players");
1261 //float player_max_speed = BS * 4.0; // Normal speed
1262 float player_max_speed = BS * 20; // Fast speed
1263 float player_max_speed_up = BS * 20;
1265 player_max_speed *= 2.5; // Tolerance
1266 player_max_speed_up *= 2.5;
1268 for(core::map<u16, RemoteClient*>::Iterator
1269 i = m_clients.getIterator();
1270 i.atEnd() == false; i++)
1272 RemoteClient *client = i.getNode()->getValue();
1273 ServerRemotePlayer *player =
1274 static_cast<ServerRemotePlayer*>
1275 (m_env->getPlayer(client->peer_id));
1280 Check player movements
1282 NOTE: Actually the server should handle player physics like the
1283 client does and compare player's position to what is calculated
1284 on our side. This is required when eg. players fly due to an
1287 player->m_last_good_position_age += dtime;
1288 if(player->m_last_good_position_age >= 1.0){
1289 float age = player->m_last_good_position_age;
1290 v3f diff = (player->getPosition() - player->m_last_good_position);
1291 float d_vert = diff.Y;
1293 float d_horiz = diff.getLength();
1294 /*infostream<<player->getName()<<"'s horizontal speed is "
1295 <<(d_horiz/age)<<std::endl;*/
1296 if(d_horiz <= age * player_max_speed &&
1297 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1298 player->m_last_good_position = player->getPosition();
1300 actionstream<<"Player "<<player->getName()
1301 <<" moved too fast; resetting position"
1303 player->setPosition(player->m_last_good_position);
1304 SendMovePlayer(player);
1306 player->m_last_good_position_age = 0;
1310 Handle player HPs (die if hp=0)
1312 if(player->hp == 0 && player->m_hp_not_sent)
1316 Send player inventories and HPs if necessary
1318 if(player->m_inventory_not_sent){
1319 UpdateCrafting(player->peer_id);
1320 SendInventory(player->peer_id);
1322 if(player->m_hp_not_sent){
1323 SendPlayerHP(player);
1329 if(!player->m_is_in_environment){
1330 player->m_removed = false;
1332 m_env->addActiveObject(player);
1337 /* Transform liquids */
1338 m_liquid_transform_timer += dtime;
1339 if(m_liquid_transform_timer >= 1.00)
1341 m_liquid_transform_timer -= 1.00;
1343 JMutexAutoLock lock(m_env_mutex);
1345 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1347 core::map<v3s16, MapBlock*> modified_blocks;
1348 m_env->getMap().transformLiquids(modified_blocks);
1353 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1354 ServerMap &map = ((ServerMap&)m_env->getMap());
1355 map.updateLighting(modified_blocks, lighting_modified_blocks);
1357 // Add blocks modified by lighting to modified_blocks
1358 for(core::map<v3s16, MapBlock*>::Iterator
1359 i = lighting_modified_blocks.getIterator();
1360 i.atEnd() == false; i++)
1362 MapBlock *block = i.getNode()->getValue();
1363 modified_blocks.insert(block->getPos(), block);
1367 Set the modified blocks unsent for all the clients
1370 JMutexAutoLock lock2(m_con_mutex);
1372 for(core::map<u16, RemoteClient*>::Iterator
1373 i = m_clients.getIterator();
1374 i.atEnd() == false; i++)
1376 RemoteClient *client = i.getNode()->getValue();
1378 if(modified_blocks.size() > 0)
1380 // Remove block from sent history
1381 client->SetBlocksNotSent(modified_blocks);
1386 // Periodically print some info
1388 float &counter = m_print_info_timer;
1394 JMutexAutoLock lock2(m_con_mutex);
1396 if(m_clients.size() != 0)
1397 infostream<<"Players:"<<std::endl;
1398 for(core::map<u16, RemoteClient*>::Iterator
1399 i = m_clients.getIterator();
1400 i.atEnd() == false; i++)
1402 //u16 peer_id = i.getNode()->getKey();
1403 RemoteClient *client = i.getNode()->getValue();
1404 Player *player = m_env->getPlayer(client->peer_id);
1407 infostream<<"* "<<player->getName()<<"\t";
1408 client->PrintInfo(infostream);
1413 //if(g_settings->getBool("enable_experimental"))
1417 Check added and deleted active objects
1420 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1421 JMutexAutoLock envlock(m_env_mutex);
1422 JMutexAutoLock conlock(m_con_mutex);
1424 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1426 // Radius inside which objects are active
1427 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1428 radius *= MAP_BLOCKSIZE;
1430 for(core::map<u16, RemoteClient*>::Iterator
1431 i = m_clients.getIterator();
1432 i.atEnd() == false; i++)
1434 RemoteClient *client = i.getNode()->getValue();
1436 // If definitions and textures have not been sent, don't
1437 // send objects either
1438 if(!client->definitions_sent)
1441 Player *player = m_env->getPlayer(client->peer_id);
1444 // This can happen if the client timeouts somehow
1445 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1447 <<" has no associated player"<<std::endl;*/
1450 v3s16 pos = floatToInt(player->getPosition(), BS);
1452 core::map<u16, bool> removed_objects;
1453 core::map<u16, bool> added_objects;
1454 m_env->getRemovedActiveObjects(pos, radius,
1455 client->m_known_objects, removed_objects);
1456 m_env->getAddedActiveObjects(pos, radius,
1457 client->m_known_objects, added_objects);
1459 // Ignore if nothing happened
1460 if(removed_objects.size() == 0 && added_objects.size() == 0)
1462 //infostream<<"active objects: none changed"<<std::endl;
1466 std::string data_buffer;
1470 // Handle removed objects
1471 writeU16((u8*)buf, removed_objects.size());
1472 data_buffer.append(buf, 2);
1473 for(core::map<u16, bool>::Iterator
1474 i = removed_objects.getIterator();
1475 i.atEnd()==false; i++)
1478 u16 id = i.getNode()->getKey();
1479 ServerActiveObject* obj = m_env->getActiveObject(id);
1481 // Add to data buffer for sending
1482 writeU16((u8*)buf, i.getNode()->getKey());
1483 data_buffer.append(buf, 2);
1485 // Remove from known objects
1486 client->m_known_objects.remove(i.getNode()->getKey());
1488 if(obj && obj->m_known_by_count > 0)
1489 obj->m_known_by_count--;
1492 // Handle added objects
1493 writeU16((u8*)buf, added_objects.size());
1494 data_buffer.append(buf, 2);
1495 for(core::map<u16, bool>::Iterator
1496 i = added_objects.getIterator();
1497 i.atEnd()==false; i++)
1500 u16 id = i.getNode()->getKey();
1501 ServerActiveObject* obj = m_env->getActiveObject(id);
1504 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1506 infostream<<"WARNING: "<<__FUNCTION_NAME
1507 <<": NULL object"<<std::endl;
1509 type = obj->getType();
1511 // Add to data buffer for sending
1512 writeU16((u8*)buf, id);
1513 data_buffer.append(buf, 2);
1514 writeU8((u8*)buf, type);
1515 data_buffer.append(buf, 1);
1518 data_buffer.append(serializeLongString(
1519 obj->getClientInitializationData()));
1521 data_buffer.append(serializeLongString(""));
1523 // Add to known objects
1524 client->m_known_objects.insert(i.getNode()->getKey(), false);
1527 obj->m_known_by_count++;
1531 SharedBuffer<u8> reply(2 + data_buffer.size());
1532 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1533 memcpy((char*)&reply[2], data_buffer.c_str(),
1534 data_buffer.size());
1536 m_con.Send(client->peer_id, 0, reply, true);
1538 verbosestream<<"Server: Sent object remove/add: "
1539 <<removed_objects.size()<<" removed, "
1540 <<added_objects.size()<<" added, "
1541 <<"packet size is "<<reply.getSize()<<std::endl;
1546 Collect a list of all the objects known by the clients
1547 and report it back to the environment.
1550 core::map<u16, bool> all_known_objects;
1552 for(core::map<u16, RemoteClient*>::Iterator
1553 i = m_clients.getIterator();
1554 i.atEnd() == false; i++)
1556 RemoteClient *client = i.getNode()->getValue();
1557 // Go through all known objects of client
1558 for(core::map<u16, bool>::Iterator
1559 i = client->m_known_objects.getIterator();
1560 i.atEnd()==false; i++)
1562 u16 id = i.getNode()->getKey();
1563 all_known_objects[id] = true;
1567 m_env->setKnownActiveObjects(whatever);
1573 Send object messages
1576 JMutexAutoLock envlock(m_env_mutex);
1577 JMutexAutoLock conlock(m_con_mutex);
1579 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1582 // Value = data sent by object
1583 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1585 // Get active object messages from environment
1588 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1592 core::list<ActiveObjectMessage>* message_list = NULL;
1593 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1594 n = buffered_messages.find(aom.id);
1597 message_list = new core::list<ActiveObjectMessage>;
1598 buffered_messages.insert(aom.id, message_list);
1602 message_list = n->getValue();
1604 message_list->push_back(aom);
1607 // Route data to every client
1608 for(core::map<u16, RemoteClient*>::Iterator
1609 i = m_clients.getIterator();
1610 i.atEnd()==false; i++)
1612 RemoteClient *client = i.getNode()->getValue();
1613 std::string reliable_data;
1614 std::string unreliable_data;
1615 // Go through all objects in message buffer
1616 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1617 j = buffered_messages.getIterator();
1618 j.atEnd()==false; j++)
1620 // If object is not known by client, skip it
1621 u16 id = j.getNode()->getKey();
1622 if(client->m_known_objects.find(id) == NULL)
1624 // Get message list of object
1625 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1626 // Go through every message
1627 for(core::list<ActiveObjectMessage>::Iterator
1628 k = list->begin(); k != list->end(); k++)
1630 // Compose the full new data with header
1631 ActiveObjectMessage aom = *k;
1632 std::string new_data;
1635 writeU16((u8*)&buf[0], aom.id);
1636 new_data.append(buf, 2);
1638 new_data += serializeString(aom.datastring);
1639 // Add data to buffer
1641 reliable_data += new_data;
1643 unreliable_data += new_data;
1647 reliable_data and unreliable_data are now ready.
1650 if(reliable_data.size() > 0)
1652 SharedBuffer<u8> reply(2 + reliable_data.size());
1653 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1654 memcpy((char*)&reply[2], reliable_data.c_str(),
1655 reliable_data.size());
1657 m_con.Send(client->peer_id, 0, reply, true);
1659 if(unreliable_data.size() > 0)
1661 SharedBuffer<u8> reply(2 + unreliable_data.size());
1662 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1663 memcpy((char*)&reply[2], unreliable_data.c_str(),
1664 unreliable_data.size());
1665 // Send as unreliable
1666 m_con.Send(client->peer_id, 0, reply, false);
1669 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1671 infostream<<"Server: Size of object message data: "
1672 <<"reliable: "<<reliable_data.size()
1673 <<", unreliable: "<<unreliable_data.size()
1678 // Clear buffered_messages
1679 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1680 i = buffered_messages.getIterator();
1681 i.atEnd()==false; i++)
1683 delete i.getNode()->getValue();
1687 } // enable_experimental
1690 Send queued-for-sending map edit events.
1693 // We will be accessing the environment and the connection
1694 JMutexAutoLock lock(m_env_mutex);
1695 JMutexAutoLock conlock(m_con_mutex);
1697 // Don't send too many at a time
1700 // Single change sending is disabled if queue size is not small
1701 bool disable_single_change_sending = false;
1702 if(m_unsent_map_edit_queue.size() >= 4)
1703 disable_single_change_sending = true;
1705 int event_count = m_unsent_map_edit_queue.size();
1707 // We'll log the amount of each
1710 while(m_unsent_map_edit_queue.size() != 0)
1712 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1714 // Players far away from the change are stored here.
1715 // Instead of sending the changes, MapBlocks are set not sent
1717 core::list<u16> far_players;
1719 if(event->type == MEET_ADDNODE)
1721 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1722 prof.add("MEET_ADDNODE", 1);
1723 if(disable_single_change_sending)
1724 sendAddNode(event->p, event->n, event->already_known_by_peer,
1727 sendAddNode(event->p, event->n, event->already_known_by_peer,
1730 else if(event->type == MEET_REMOVENODE)
1732 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1733 prof.add("MEET_REMOVENODE", 1);
1734 if(disable_single_change_sending)
1735 sendRemoveNode(event->p, event->already_known_by_peer,
1738 sendRemoveNode(event->p, event->already_known_by_peer,
1741 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1743 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1744 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1745 setBlockNotSent(event->p);
1747 else if(event->type == MEET_OTHER)
1749 infostream<<"Server: MEET_OTHER"<<std::endl;
1750 prof.add("MEET_OTHER", 1);
1751 for(core::map<v3s16, bool>::Iterator
1752 i = event->modified_blocks.getIterator();
1753 i.atEnd()==false; i++)
1755 v3s16 p = i.getNode()->getKey();
1761 prof.add("unknown", 1);
1762 infostream<<"WARNING: Server: Unknown MapEditEvent "
1763 <<((u32)event->type)<<std::endl;
1767 Set blocks not sent to far players
1769 if(far_players.size() > 0)
1771 // Convert list format to that wanted by SetBlocksNotSent
1772 core::map<v3s16, MapBlock*> modified_blocks2;
1773 for(core::map<v3s16, bool>::Iterator
1774 i = event->modified_blocks.getIterator();
1775 i.atEnd()==false; i++)
1777 v3s16 p = i.getNode()->getKey();
1778 modified_blocks2.insert(p,
1779 m_env->getMap().getBlockNoCreateNoEx(p));
1781 // Set blocks not sent
1782 for(core::list<u16>::Iterator
1783 i = far_players.begin();
1784 i != far_players.end(); i++)
1787 RemoteClient *client = getClient(peer_id);
1790 client->SetBlocksNotSent(modified_blocks2);
1796 /*// Don't send too many at a time
1798 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1802 if(event_count >= 5){
1803 infostream<<"Server: MapEditEvents:"<<std::endl;
1804 prof.print(infostream);
1805 } else if(event_count != 0){
1806 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1807 prof.print(verbosestream);
1813 Trigger emergethread (it somehow gets to a non-triggered but
1814 bysy state sometimes)
1817 float &counter = m_emergethread_trigger_timer;
1823 m_emergethread.trigger();
1827 // Save map, players and auth stuff
1829 float &counter = m_savemap_timer;
1831 if(counter >= g_settings->getFloat("server_map_save_interval"))
1834 JMutexAutoLock lock(m_env_mutex);
1836 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1839 if(m_authmanager.isModified())
1840 m_authmanager.save();
1843 if(m_banmanager.isModified())
1844 m_banmanager.save();
1846 // Save changed parts of map
1847 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1850 m_env->serializePlayers(m_path_world);
1852 // Save environment metadata
1853 m_env->saveMeta(m_path_world);
1858 void Server::Receive()
1860 DSTACK(__FUNCTION_NAME);
1861 SharedBuffer<u8> data;
1866 JMutexAutoLock conlock(m_con_mutex);
1867 datasize = m_con.Receive(peer_id, data);
1870 // This has to be called so that the client list gets synced
1871 // with the peer list of the connection
1872 handlePeerChanges();
1874 ProcessData(*data, datasize, peer_id);
1876 catch(con::InvalidIncomingDataException &e)
1878 infostream<<"Server::Receive(): "
1879 "InvalidIncomingDataException: what()="
1880 <<e.what()<<std::endl;
1882 catch(con::PeerNotFoundException &e)
1884 //NOTE: This is not needed anymore
1886 // The peer has been disconnected.
1887 // Find the associated player and remove it.
1889 /*JMutexAutoLock envlock(m_env_mutex);
1891 infostream<<"ServerThread: peer_id="<<peer_id
1892 <<" has apparently closed connection. "
1893 <<"Removing player."<<std::endl;
1895 m_env->removePlayer(peer_id);*/
1899 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1901 DSTACK(__FUNCTION_NAME);
1902 // Environment is locked first.
1903 JMutexAutoLock envlock(m_env_mutex);
1904 JMutexAutoLock conlock(m_con_mutex);
1906 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1909 Address address = m_con.GetPeerAddress(peer_id);
1910 std::string addr_s = address.serializeString();
1912 // drop player if is ip is banned
1913 if(m_banmanager.isIpBanned(addr_s)){
1914 infostream<<"Server: A banned client tried to connect from "
1915 <<addr_s<<"; banned name was "
1916 <<m_banmanager.getBanName(addr_s)<<std::endl;
1917 // This actually doesn't seem to transfer to the client
1918 SendAccessDenied(m_con, peer_id,
1919 L"Your ip is banned. Banned name was "
1920 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1921 m_con.DeletePeer(peer_id);
1925 catch(con::PeerNotFoundException &e)
1927 infostream<<"Server::ProcessData(): Cancelling: peer "
1928 <<peer_id<<" not found"<<std::endl;
1932 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1934 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1942 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1944 if(command == TOSERVER_INIT)
1946 // [0] u16 TOSERVER_INIT
1947 // [2] u8 SER_FMT_VER_HIGHEST
1948 // [3] u8[20] player_name
1949 // [23] u8[28] password <--- can be sent without this, from old versions
1951 if(datasize < 2+1+PLAYERNAME_SIZE)
1954 verbosestream<<"Server: Got TOSERVER_INIT from "
1955 <<peer_id<<std::endl;
1957 // First byte after command is maximum supported
1958 // serialization version
1959 u8 client_max = data[2];
1960 u8 our_max = SER_FMT_VER_HIGHEST;
1961 // Use the highest version supported by both
1962 u8 deployed = core::min_(client_max, our_max);
1963 // If it's lower than the lowest supported, give up.
1964 if(deployed < SER_FMT_VER_LOWEST)
1965 deployed = SER_FMT_VER_INVALID;
1967 //peer->serialization_version = deployed;
1968 getClient(peer_id)->pending_serialization_version = deployed;
1970 if(deployed == SER_FMT_VER_INVALID)
1972 actionstream<<"Server: A mismatched client tried to connect from "
1973 <<addr_s<<std::endl;
1974 infostream<<"Server: Cannot negotiate "
1975 "serialization version with peer "
1976 <<peer_id<<std::endl;
1977 SendAccessDenied(m_con, peer_id, std::wstring(
1978 L"Your client's version is not supported.\n"
1979 L"Server version is ")
1980 + narrow_to_wide(VERSION_STRING) + L"."
1986 Read and check network protocol version
1989 u16 net_proto_version = 0;
1990 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1992 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1995 getClient(peer_id)->net_proto_version = net_proto_version;
1997 if(net_proto_version == 0)
1999 actionstream<<"Server: An old tried to connect from "<<addr_s
2001 SendAccessDenied(m_con, peer_id, std::wstring(
2002 L"Your client's version is not supported.\n"
2003 L"Server version is ")
2004 + narrow_to_wide(VERSION_STRING) + L"."
2009 if(g_settings->getBool("strict_protocol_version_checking"))
2011 if(net_proto_version != PROTOCOL_VERSION)
2013 actionstream<<"Server: A mismatched client tried to connect"
2014 <<" from "<<addr_s<<std::endl;
2015 SendAccessDenied(m_con, peer_id, std::wstring(
2016 L"Your client's version is not supported.\n"
2017 L"Server version is ")
2018 + narrow_to_wide(VERSION_STRING) + L",\n"
2019 + L"server's PROTOCOL_VERSION is "
2020 + narrow_to_wide(itos(PROTOCOL_VERSION))
2021 + L", client's PROTOCOL_VERSION is "
2022 + narrow_to_wide(itos(net_proto_version))
2033 char playername[PLAYERNAME_SIZE];
2034 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2036 playername[i] = data[3+i];
2038 playername[PLAYERNAME_SIZE-1] = 0;
2040 if(playername[0]=='\0')
2042 actionstream<<"Server: Player with an empty name "
2043 <<"tried to connect from "<<addr_s<<std::endl;
2044 SendAccessDenied(m_con, peer_id,
2049 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2051 actionstream<<"Server: Player with an invalid name "
2052 <<"tried to connect from "<<addr_s<<std::endl;
2053 SendAccessDenied(m_con, peer_id,
2054 L"Name contains unallowed characters");
2058 infostream<<"Server: New connection: \""<<playername<<"\" from "
2059 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2062 char password[PASSWORD_SIZE];
2063 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2065 // old version - assume blank password
2070 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2072 password[i] = data[23+i];
2074 password[PASSWORD_SIZE-1] = 0;
2077 // Add player to auth manager
2078 if(m_authmanager.exists(playername) == false)
2080 std::wstring default_password =
2081 narrow_to_wide(g_settings->get("default_password"));
2082 std::string translated_default_password =
2083 translatePassword(playername, default_password);
2085 // If default_password is empty, allow any initial password
2086 if (default_password.length() == 0)
2087 translated_default_password = password;
2089 infostream<<"Server: adding player "<<playername
2090 <<" to auth manager"<<std::endl;
2091 m_authmanager.add(playername);
2092 m_authmanager.setPassword(playername, translated_default_password);
2093 m_authmanager.setPrivs(playername,
2094 stringToPrivs(g_settings->get("default_privs")));
2095 m_authmanager.save();
2098 std::string checkpwd = m_authmanager.getPassword(playername);
2100 /*infostream<<"Server: Client gave password '"<<password
2101 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2103 if(password != checkpwd)
2105 infostream<<"Server: peer_id="<<peer_id
2106 <<": supplied invalid password for "
2107 <<playername<<std::endl;
2108 SendAccessDenied(m_con, peer_id, L"Invalid password");
2112 // Do not allow multiple players in simple singleplayer mode.
2113 // This isn't a perfect way to do it, but will suffice for now.
2114 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2115 infostream<<"Server: Not allowing another client to connect in"
2116 <<" simple singleplayer mode"<<std::endl;
2117 SendAccessDenied(m_con, peer_id,
2118 L"Running in simple singleplayer mode.");
2122 // Enforce user limit.
2123 // Don't enforce for users that have some admin right
2124 if(m_clients.size() >= g_settings->getU16("max_users") &&
2125 (m_authmanager.getPrivs(playername)
2126 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2127 playername != g_settings->get("name"))
2129 actionstream<<"Server: "<<playername<<" tried to join, but there"
2130 <<" are already max_users="
2131 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2132 SendAccessDenied(m_con, peer_id, L"Too many users.");
2137 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2139 // If failed, cancel
2142 errorstream<<"Server: peer_id="<<peer_id
2143 <<": failed to emerge player"<<std::endl;
2148 Answer with a TOCLIENT_INIT
2151 SharedBuffer<u8> reply(2+1+6+8);
2152 writeU16(&reply[0], TOCLIENT_INIT);
2153 writeU8(&reply[2], deployed);
2154 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2155 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2158 m_con.Send(peer_id, 0, reply, true);
2162 Send complete position information
2164 SendMovePlayer(player);
2169 if(command == TOSERVER_INIT2)
2171 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2172 <<peer_id<<std::endl;
2175 getClient(peer_id)->serialization_version
2176 = getClient(peer_id)->pending_serialization_version;
2179 Send some initialization data
2182 infostream<<"Server: Sending content to "
2183 <<getPlayerName(peer_id)<<std::endl;
2185 // Send item definitions
2186 SendItemDef(m_con, peer_id, m_itemdef);
2188 // Send node definitions
2189 SendNodeDef(m_con, peer_id, m_nodedef);
2191 // Send texture announcement
2192 sendMediaAnnouncement(peer_id);
2194 // Send player info to all players
2195 //SendPlayerInfos();
2197 // Send inventory to player
2198 UpdateCrafting(peer_id);
2199 SendInventory(peer_id);
2201 // Send player items to all players
2204 Player *player = m_env->getPlayer(peer_id);
2207 SendPlayerHP(player);
2209 // Show death screen if necessary
2211 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2215 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2216 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2217 m_con.Send(peer_id, 0, data, true);
2220 // Note things in chat if not in simple singleplayer mode
2221 if(!m_simple_singleplayer_mode)
2223 // Send information about server to player in chat
2224 SendChatMessage(peer_id, getStatusString());
2226 // Send information about joining in chat
2228 std::wstring name = L"unknown";
2229 Player *player = m_env->getPlayer(peer_id);
2231 name = narrow_to_wide(player->getName());
2233 std::wstring message;
2236 message += L" joined game";
2237 BroadcastChatMessage(message);
2241 // Warnings about protocol version can be issued here
2242 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2244 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2251 std::ostringstream os(std::ios_base::binary);
2252 for(core::map<u16, RemoteClient*>::Iterator
2253 i = m_clients.getIterator();
2254 i.atEnd() == false; i++)
2256 RemoteClient *client = i.getNode()->getValue();
2257 assert(client->peer_id == i.getNode()->getKey());
2258 if(client->serialization_version == SER_FMT_VER_INVALID)
2261 Player *player = m_env->getPlayer(client->peer_id);
2264 // Get name of player
2265 os<<player->getName()<<" ";
2268 actionstream<<player->getName()<<" joins game. List of players: "
2269 <<os.str()<<std::endl;
2275 if(peer_ser_ver == SER_FMT_VER_INVALID)
2277 infostream<<"Server::ProcessData(): Cancelling: Peer"
2278 " serialization format invalid or not initialized."
2279 " Skipping incoming command="<<command<<std::endl;
2283 Player *player = m_env->getPlayer(peer_id);
2284 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2287 infostream<<"Server::ProcessData(): Cancelling: "
2288 "No player for peer_id="<<peer_id
2292 if(command == TOSERVER_PLAYERPOS)
2294 if(datasize < 2+12+12+4+4)
2298 v3s32 ps = readV3S32(&data[start+2]);
2299 v3s32 ss = readV3S32(&data[start+2+12]);
2300 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2301 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2302 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2303 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2304 pitch = wrapDegrees(pitch);
2305 yaw = wrapDegrees(yaw);
2307 player->setPosition(position);
2308 player->setSpeed(speed);
2309 player->setPitch(pitch);
2310 player->setYaw(yaw);
2312 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2313 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2314 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2316 else if(command == TOSERVER_GOTBLOCKS)
2329 u16 count = data[2];
2330 for(u16 i=0; i<count; i++)
2332 if((s16)datasize < 2+1+(i+1)*6)
2333 throw con::InvalidIncomingDataException
2334 ("GOTBLOCKS length is too short");
2335 v3s16 p = readV3S16(&data[2+1+i*6]);
2336 /*infostream<<"Server: GOTBLOCKS ("
2337 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2338 RemoteClient *client = getClient(peer_id);
2339 client->GotBlock(p);
2342 else if(command == TOSERVER_DELETEDBLOCKS)
2355 u16 count = data[2];
2356 for(u16 i=0; i<count; i++)
2358 if((s16)datasize < 2+1+(i+1)*6)
2359 throw con::InvalidIncomingDataException
2360 ("DELETEDBLOCKS length is too short");
2361 v3s16 p = readV3S16(&data[2+1+i*6]);
2362 /*infostream<<"Server: DELETEDBLOCKS ("
2363 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2364 RemoteClient *client = getClient(peer_id);
2365 client->SetBlockNotSent(p);
2368 else if(command == TOSERVER_CLICK_OBJECT)
2370 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2373 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2375 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2378 else if(command == TOSERVER_GROUND_ACTION)
2380 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2384 else if(command == TOSERVER_RELEASE)
2386 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2389 else if(command == TOSERVER_SIGNTEXT)
2391 infostream<<"Server: SIGNTEXT not supported anymore"
2395 else if(command == TOSERVER_SIGNNODETEXT)
2397 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2405 std::string datastring((char*)&data[2], datasize-2);
2406 std::istringstream is(datastring, std::ios_base::binary);
2409 is.read((char*)buf, 6);
2410 v3s16 p = readV3S16(buf);
2411 is.read((char*)buf, 2);
2412 u16 textlen = readU16(buf);
2414 for(u16 i=0; i<textlen; i++)
2416 is.read((char*)buf, 1);
2417 text += (char)buf[0];
2420 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2424 meta->setText(text);
2426 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2427 <<" at "<<PP(p)<<std::endl;
2429 v3s16 blockpos = getNodeBlockPos(p);
2430 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2433 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2437 setBlockNotSent(blockpos);
2439 else if(command == TOSERVER_INVENTORY_ACTION)
2441 // Strip command and create a stream
2442 std::string datastring((char*)&data[2], datasize-2);
2443 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2444 std::istringstream is(datastring, std::ios_base::binary);
2446 InventoryAction *a = InventoryAction::deSerialize(is);
2449 infostream<<"TOSERVER_INVENTORY_ACTION: "
2450 <<"InventoryAction::deSerialize() returned NULL"
2456 Note: Always set inventory not sent, to repair cases
2457 where the client made a bad prediction.
2461 Handle restrictions and special cases of the move action
2463 if(a->getType() == IACTION_MOVE)
2465 IMoveAction *ma = (IMoveAction*)a;
2467 ma->from_inv.applyCurrentPlayer(player->getName());
2468 ma->to_inv.applyCurrentPlayer(player->getName());
2470 setInventoryModified(ma->from_inv);
2471 setInventoryModified(ma->to_inv);
2473 bool from_inv_is_current_player =
2474 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2475 (ma->from_inv.name == player->getName());
2477 bool to_inv_is_current_player =
2478 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2479 (ma->to_inv.name == player->getName());
2482 Disable moving items out of craftpreview
2484 if(ma->from_list == "craftpreview")
2486 infostream<<"Ignoring IMoveAction from "
2487 <<(ma->from_inv.dump())<<":"<<ma->from_list
2488 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2489 <<" because src is "<<ma->from_list<<std::endl;
2495 Disable moving items into craftresult and craftpreview
2497 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2499 infostream<<"Ignoring IMoveAction from "
2500 <<(ma->from_inv.dump())<<":"<<ma->from_list
2501 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2502 <<" because dst is "<<ma->to_list<<std::endl;
2507 // Disallow moving items in elsewhere than player's inventory
2508 // if not allowed to interact
2509 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2510 && (!from_inv_is_current_player
2511 || !to_inv_is_current_player))
2513 infostream<<"Cannot move outside of player's inventory: "
2514 <<"No interact privilege"<<std::endl;
2519 // If player is not an admin, check for ownership of src and dst
2520 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2522 std::string owner_from = getInventoryOwner(ma->from_inv);
2523 if(owner_from != "" && owner_from != player->getName())
2525 infostream<<"WARNING: "<<player->getName()
2526 <<" tried to access an inventory that"
2527 <<" belongs to "<<owner_from<<std::endl;
2532 std::string owner_to = getInventoryOwner(ma->to_inv);
2533 if(owner_to != "" && owner_to != player->getName())
2535 infostream<<"WARNING: "<<player->getName()
2536 <<" tried to access an inventory that"
2537 <<" belongs to "<<owner_to<<std::endl;
2544 Handle restrictions and special cases of the drop action
2546 else if(a->getType() == IACTION_DROP)
2548 IDropAction *da = (IDropAction*)a;
2550 da->from_inv.applyCurrentPlayer(player->getName());
2552 setInventoryModified(da->from_inv);
2554 // Disallow dropping items if not allowed to interact
2555 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2560 // If player is not an admin, check for ownership
2561 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2563 std::string owner_from = getInventoryOwner(da->from_inv);
2564 if(owner_from != "" && owner_from != player->getName())
2566 infostream<<"WARNING: "<<player->getName()
2567 <<" tried to access an inventory that"
2568 <<" belongs to "<<owner_from<<std::endl;
2575 Handle restrictions and special cases of the craft action
2577 else if(a->getType() == IACTION_CRAFT)
2579 ICraftAction *ca = (ICraftAction*)a;
2581 ca->craft_inv.applyCurrentPlayer(player->getName());
2583 setInventoryModified(ca->craft_inv);
2585 //bool craft_inv_is_current_player =
2586 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2587 // (ca->craft_inv.name == player->getName());
2589 // Disallow crafting if not allowed to interact
2590 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2592 infostream<<"Cannot craft: "
2593 <<"No interact privilege"<<std::endl;
2598 // If player is not an admin, check for ownership of inventory
2599 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2601 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2602 if(owner_craft != "" && owner_craft != player->getName())
2604 infostream<<"WARNING: "<<player->getName()
2605 <<" tried to access an inventory that"
2606 <<" belongs to "<<owner_craft<<std::endl;
2614 a->apply(this, srp, this);
2618 else if(command == TOSERVER_CHAT_MESSAGE)
2626 std::string datastring((char*)&data[2], datasize-2);
2627 std::istringstream is(datastring, std::ios_base::binary);
2630 is.read((char*)buf, 2);
2631 u16 len = readU16(buf);
2633 std::wstring message;
2634 for(u16 i=0; i<len; i++)
2636 is.read((char*)buf, 2);
2637 message += (wchar_t)readU16(buf);
2640 // Get player name of this client
2641 std::wstring name = narrow_to_wide(player->getName());
2644 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2645 wide_to_narrow(message));
2646 // If script ate the message, don't proceed
2650 // Line to send to players
2652 // Whether to send to the player that sent the line
2653 bool send_to_sender = false;
2654 // Whether to send to other players
2655 bool send_to_others = false;
2657 // Local player gets all privileges regardless of
2658 // what's set on their account.
2659 u64 privs = getPlayerPrivs(player);
2662 if(message[0] == L'/')
2664 size_t strip_size = 1;
2665 if (message[1] == L'#') // support old-style commans
2667 message = message.substr(strip_size);
2669 WStrfnd f1(message);
2670 f1.next(L" "); // Skip over /#whatever
2671 std::wstring paramstring = f1.next(L"");
2673 ServerCommandContext *ctx = new ServerCommandContext(
2674 str_split(message, L' '),
2681 std::wstring reply(processServerCommand(ctx));
2682 send_to_sender = ctx->flags & SEND_TO_SENDER;
2683 send_to_others = ctx->flags & SEND_TO_OTHERS;
2685 if (ctx->flags & SEND_NO_PREFIX)
2688 line += L"Server: " + reply;
2695 if(privs & PRIV_SHOUT)
2701 send_to_others = true;
2705 line += L"Server: You are not allowed to shout";
2706 send_to_sender = true;
2713 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2716 Send the message to clients
2718 for(core::map<u16, RemoteClient*>::Iterator
2719 i = m_clients.getIterator();
2720 i.atEnd() == false; i++)
2722 // Get client and check that it is valid
2723 RemoteClient *client = i.getNode()->getValue();
2724 assert(client->peer_id == i.getNode()->getKey());
2725 if(client->serialization_version == SER_FMT_VER_INVALID)
2729 bool sender_selected = (peer_id == client->peer_id);
2730 if(sender_selected == true && send_to_sender == false)
2732 if(sender_selected == false && send_to_others == false)
2735 SendChatMessage(client->peer_id, line);
2739 else if(command == TOSERVER_DAMAGE)
2741 std::string datastring((char*)&data[2], datasize-2);
2742 std::istringstream is(datastring, std::ios_base::binary);
2743 u8 damage = readU8(is);
2745 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2747 if(g_settings->getBool("enable_damage"))
2749 actionstream<<player->getName()<<" damaged by "
2750 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2753 srp->setHP(srp->getHP() - damage);
2755 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2758 if(srp->m_hp_not_sent)
2759 SendPlayerHP(player);
2763 // Force send (to correct the client's predicted HP)
2764 SendPlayerHP(player);
2767 else if(command == TOSERVER_PASSWORD)
2770 [0] u16 TOSERVER_PASSWORD
2771 [2] u8[28] old password
2772 [30] u8[28] new password
2775 if(datasize != 2+PASSWORD_SIZE*2)
2777 /*char password[PASSWORD_SIZE];
2778 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2779 password[i] = data[2+i];
2780 password[PASSWORD_SIZE-1] = 0;*/
2782 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2790 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2792 char c = data[2+PASSWORD_SIZE+i];
2798 infostream<<"Server: Client requests a password change from "
2799 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2801 std::string playername = player->getName();
2803 if(m_authmanager.exists(playername) == false)
2805 infostream<<"Server: playername not found in authmanager"<<std::endl;
2806 // Wrong old password supplied!!
2807 SendChatMessage(peer_id, L"playername not found in authmanager");
2811 std::string checkpwd = m_authmanager.getPassword(playername);
2813 if(oldpwd != checkpwd)
2815 infostream<<"Server: invalid old password"<<std::endl;
2816 // Wrong old password supplied!!
2817 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2821 actionstream<<player->getName()<<" changes password"<<std::endl;
2823 m_authmanager.setPassword(playername, newpwd);
2825 infostream<<"Server: password change successful for "<<playername
2827 SendChatMessage(peer_id, L"Password change successful");
2829 else if(command == TOSERVER_PLAYERITEM)
2834 u16 item = readU16(&data[2]);
2835 srp->setWieldIndex(item);
2836 SendWieldedItem(srp);
2838 else if(command == TOSERVER_RESPAWN)
2843 RespawnPlayer(player);
2845 actionstream<<player->getName()<<" respawns at "
2846 <<PP(player->getPosition()/BS)<<std::endl;
2848 // ActiveObject is added to environment in AsyncRunStep after
2849 // the previous addition has been succesfully removed
2851 else if(command == TOSERVER_REQUEST_MEDIA) {
2852 std::string datastring((char*)&data[2], datasize-2);
2853 std::istringstream is(datastring, std::ios_base::binary);
2855 core::list<MediaRequest> tosend;
2856 u16 numfiles = readU16(is);
2858 infostream<<"Sending "<<numfiles<<" files to "
2859 <<getPlayerName(peer_id)<<std::endl;
2860 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2862 for(int i = 0; i < numfiles; i++) {
2863 std::string name = deSerializeString(is);
2864 tosend.push_back(MediaRequest(name));
2865 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2869 sendRequestedMedia(peer_id, tosend);
2871 // Now the client should know about everything
2872 // (definitions and files)
2873 getClient(peer_id)->definitions_sent = true;
2875 else if(command == TOSERVER_INTERACT)
2877 std::string datastring((char*)&data[2], datasize-2);
2878 std::istringstream is(datastring, std::ios_base::binary);
2884 [5] u32 length of the next item
2885 [9] serialized PointedThing
2887 0: start digging (from undersurface) or use
2888 1: stop digging (all parameters ignored)
2889 2: digging completed
2890 3: place block or item (to abovesurface)
2893 u8 action = readU8(is);
2894 u16 item_i = readU16(is);
2895 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2896 PointedThing pointed;
2897 pointed.deSerialize(tmp_is);
2899 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2900 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2904 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2905 <<" tried to interact, but is dead!"<<std::endl;
2909 v3f player_pos = srp->m_last_good_position;
2911 // Update wielded item
2912 if(srp->getWieldIndex() != item_i)
2914 srp->setWieldIndex(item_i);
2915 SendWieldedItem(srp);
2918 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2919 v3s16 p_under = pointed.node_undersurface;
2920 v3s16 p_above = pointed.node_abovesurface;
2922 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2923 ServerActiveObject *pointed_object = NULL;
2924 if(pointed.type == POINTEDTHING_OBJECT)
2926 pointed_object = m_env->getActiveObject(pointed.object_id);
2927 if(pointed_object == NULL)
2929 verbosestream<<"TOSERVER_INTERACT: "
2930 "pointed object is NULL"<<std::endl;
2936 v3f pointed_pos_under = player_pos;
2937 v3f pointed_pos_above = player_pos;
2938 if(pointed.type == POINTEDTHING_NODE)
2940 pointed_pos_under = intToFloat(p_under, BS);
2941 pointed_pos_above = intToFloat(p_above, BS);
2943 else if(pointed.type == POINTEDTHING_OBJECT)
2945 pointed_pos_under = pointed_object->getBasePosition();
2946 pointed_pos_above = pointed_pos_under;
2950 Check that target is reasonably close
2951 (only when digging or placing things)
2953 if(action == 0 || action == 2 || action == 3)
2955 float d = player_pos.getDistanceFrom(pointed_pos_under);
2956 float max_d = BS * 14; // Just some large enough value
2958 actionstream<<"Player "<<player->getName()
2959 <<" tried to access "<<pointed.dump()
2961 <<"d="<<d<<", max_d="<<max_d
2962 <<". ignoring."<<std::endl;
2963 // Re-send block to revert change on client-side
2964 RemoteClient *client = getClient(peer_id);
2965 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2966 client->SetBlockNotSent(blockpos);
2973 Make sure the player is allowed to do it
2975 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2977 infostream<<"Ignoring interaction from player "<<player->getName()
2978 <<" because privileges are "<<getPlayerPrivs(player)
2984 0: start digging or punch object
2988 if(pointed.type == POINTEDTHING_NODE)
2991 NOTE: This can be used in the future to check if
2992 somebody is cheating, by checking the timing.
2994 MapNode n(CONTENT_IGNORE);
2997 n = m_env->getMap().getNode(p_under);
2999 catch(InvalidPositionException &e)
3001 infostream<<"Server: Not punching: Node not found."
3002 <<" Adding block to emerge queue."
3004 m_emerge_queue.addBlock(peer_id,
3005 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3007 if(n.getContent() != CONTENT_IGNORE)
3008 scriptapi_node_on_punch(m_lua, p_under, n, srp);
3010 else if(pointed.type == POINTEDTHING_OBJECT)
3012 // Skip if object has been removed
3013 if(pointed_object->m_removed)
3016 actionstream<<player->getName()<<" punches object "
3017 <<pointed.object_id<<": "
3018 <<pointed_object->getDescription()<<std::endl;
3020 ItemStack punchitem = srp->getWieldedItem();
3021 ToolCapabilities toolcap =
3022 punchitem.getToolCapabilities(m_itemdef);
3023 v3f dir = (pointed_object->getBasePosition() -
3024 (srp->getPosition() + srp->getEyeOffset())
3026 pointed_object->punch(dir, &toolcap, srp,
3027 srp->m_time_from_last_punch);
3028 srp->m_time_from_last_punch = 0;
3036 else if(action == 1)
3041 2: Digging completed
3043 else if(action == 2)
3045 // Only complete digging of nodes
3046 if(pointed.type == POINTEDTHING_NODE)
3048 MapNode n(CONTENT_IGNORE);
3051 n = m_env->getMap().getNode(p_under);
3053 catch(InvalidPositionException &e)
3055 infostream<<"Server: Not finishing digging: Node not found."
3056 <<" Adding block to emerge queue."
3058 m_emerge_queue.addBlock(peer_id,
3059 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3061 if(n.getContent() != CONTENT_IGNORE)
3062 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3067 3: place block or right-click object
3069 else if(action == 3)
3071 ItemStack item = srp->getWieldedItem();
3073 // Reset build time counter
3074 if(pointed.type == POINTEDTHING_NODE &&
3075 item.getDefinition(m_itemdef).type == ITEM_NODE)
3076 getClient(peer_id)->m_time_from_building = 0.0;
3078 if(pointed.type == POINTEDTHING_OBJECT)
3080 // Right click object
3082 // Skip if object has been removed
3083 if(pointed_object->m_removed)
3086 actionstream<<player->getName()<<" right-clicks object "
3087 <<pointed.object_id<<": "
3088 <<pointed_object->getDescription()<<std::endl;
3091 pointed_object->rightClick(srp);
3093 else if(scriptapi_item_on_place(m_lua,
3094 item, srp, pointed))
3096 // Placement was handled in lua
3098 // Apply returned ItemStack
3099 if(g_settings->getBool("creative_mode") == false)
3100 srp->setWieldedItem(item);
3108 else if(action == 4)
3110 ItemStack item = srp->getWieldedItem();
3112 actionstream<<player->getName()<<" uses "<<item.name
3113 <<", pointing at "<<pointed.dump()<<std::endl;
3115 if(scriptapi_item_on_use(m_lua,
3116 item, srp, pointed))
3118 // Apply returned ItemStack
3119 if(g_settings->getBool("creative_mode") == false)
3120 srp->setWieldedItem(item);
3126 Catch invalid actions
3130 infostream<<"WARNING: Server: Invalid action "
3131 <<action<<std::endl;
3134 else if(command == TOSERVER_REMOVED_SOUNDS)
3136 std::string datastring((char*)&data[2], datasize-2);
3137 std::istringstream is(datastring, std::ios_base::binary);
3139 int num = readU16(is);
3140 for(int k=0; k<num; k++){
3141 s32 id = readS32(is);
3142 std::map<s32, ServerPlayingSound>::iterator i =
3143 m_playing_sounds.find(id);
3144 if(i == m_playing_sounds.end())
3146 ServerPlayingSound &psound = i->second;
3147 psound.clients.erase(peer_id);
3148 if(psound.clients.size() == 0)
3149 m_playing_sounds.erase(i++);
3154 infostream<<"Server::ProcessData(): Ignoring "
3155 "unknown command "<<command<<std::endl;
3159 catch(SendFailedException &e)
3161 errorstream<<"Server::ProcessData(): SendFailedException: "
3167 void Server::onMapEditEvent(MapEditEvent *event)
3169 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3170 if(m_ignore_map_edit_events)
3172 MapEditEvent *e = event->clone();
3173 m_unsent_map_edit_queue.push_back(e);
3176 Inventory* Server::getInventory(const InventoryLocation &loc)
3179 case InventoryLocation::UNDEFINED:
3182 case InventoryLocation::CURRENT_PLAYER:
3185 case InventoryLocation::PLAYER:
3187 Player *player = m_env->getPlayer(loc.name.c_str());
3190 return &player->inventory;
3193 case InventoryLocation::NODEMETA:
3195 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3198 return meta->getInventory();
3206 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3209 case InventoryLocation::UNDEFINED:
3212 case InventoryLocation::CURRENT_PLAYER:
3215 case InventoryLocation::PLAYER:
3220 case InventoryLocation::NODEMETA:
3222 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3225 return meta->getOwner();
3233 void Server::setInventoryModified(const InventoryLocation &loc)
3236 case InventoryLocation::UNDEFINED:
3239 case InventoryLocation::PLAYER:
3241 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3242 (m_env->getPlayer(loc.name.c_str()));
3245 srp->m_inventory_not_sent = true;
3248 case InventoryLocation::NODEMETA:
3250 v3s16 blockpos = getNodeBlockPos(loc.p);
3252 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3254 meta->inventoryModified();
3256 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3258 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3260 setBlockNotSent(blockpos);
3268 core::list<PlayerInfo> Server::getPlayerInfo()
3270 DSTACK(__FUNCTION_NAME);
3271 JMutexAutoLock envlock(m_env_mutex);
3272 JMutexAutoLock conlock(m_con_mutex);
3274 core::list<PlayerInfo> list;
3276 core::list<Player*> players = m_env->getPlayers();
3278 core::list<Player*>::Iterator i;
3279 for(i = players.begin();
3280 i != players.end(); i++)
3284 Player *player = *i;
3287 // Copy info from connection to info struct
3288 info.id = player->peer_id;
3289 info.address = m_con.GetPeerAddress(player->peer_id);
3290 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3292 catch(con::PeerNotFoundException &e)
3294 // Set dummy peer info
3296 info.address = Address(0,0,0,0,0);
3300 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3301 info.position = player->getPosition();
3303 list.push_back(info);
3310 void Server::peerAdded(con::Peer *peer)
3312 DSTACK(__FUNCTION_NAME);
3313 verbosestream<<"Server::peerAdded(): peer->id="
3314 <<peer->id<<std::endl;
3317 c.type = PEER_ADDED;
3318 c.peer_id = peer->id;
3320 m_peer_change_queue.push_back(c);
3323 void Server::deletingPeer(con::Peer *peer, bool timeout)
3325 DSTACK(__FUNCTION_NAME);
3326 verbosestream<<"Server::deletingPeer(): peer->id="
3327 <<peer->id<<", timeout="<<timeout<<std::endl;
3330 c.type = PEER_REMOVED;
3331 c.peer_id = peer->id;
3332 c.timeout = timeout;
3333 m_peer_change_queue.push_back(c);
3340 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3342 DSTACK(__FUNCTION_NAME);
3343 std::ostringstream os(std::ios_base::binary);
3345 writeU16(os, TOCLIENT_HP);
3349 std::string s = os.str();
3350 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3352 con.Send(peer_id, 0, data, true);
3355 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3356 const std::wstring &reason)
3358 DSTACK(__FUNCTION_NAME);
3359 std::ostringstream os(std::ios_base::binary);
3361 writeU16(os, TOCLIENT_ACCESS_DENIED);
3362 os<<serializeWideString(reason);
3365 std::string s = os.str();
3366 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3368 con.Send(peer_id, 0, data, true);
3371 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3372 bool set_camera_point_target, v3f camera_point_target)
3374 DSTACK(__FUNCTION_NAME);
3375 std::ostringstream os(std::ios_base::binary);
3377 writeU16(os, TOCLIENT_DEATHSCREEN);
3378 writeU8(os, set_camera_point_target);
3379 writeV3F1000(os, camera_point_target);
3382 std::string s = os.str();
3383 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3385 con.Send(peer_id, 0, data, true);
3388 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3389 IItemDefManager *itemdef)
3391 DSTACK(__FUNCTION_NAME);
3392 std::ostringstream os(std::ios_base::binary);
3396 u32 length of the next item
3397 zlib-compressed serialized ItemDefManager
3399 writeU16(os, TOCLIENT_ITEMDEF);
3400 std::ostringstream tmp_os(std::ios::binary);
3401 itemdef->serialize(tmp_os);
3402 std::ostringstream tmp_os2(std::ios::binary);
3403 compressZlib(tmp_os.str(), tmp_os2);
3404 os<<serializeLongString(tmp_os2.str());
3407 std::string s = os.str();
3408 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3409 <<"): size="<<s.size()<<std::endl;
3410 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3412 con.Send(peer_id, 0, data, true);
3415 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3416 INodeDefManager *nodedef)
3418 DSTACK(__FUNCTION_NAME);
3419 std::ostringstream os(std::ios_base::binary);
3423 u32 length of the next item
3424 zlib-compressed serialized NodeDefManager
3426 writeU16(os, TOCLIENT_NODEDEF);
3427 std::ostringstream tmp_os(std::ios::binary);
3428 nodedef->serialize(tmp_os);
3429 std::ostringstream tmp_os2(std::ios::binary);
3430 compressZlib(tmp_os.str(), tmp_os2);
3431 os<<serializeLongString(tmp_os2.str());
3434 std::string s = os.str();
3435 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3436 <<"): size="<<s.size()<<std::endl;
3437 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3439 con.Send(peer_id, 0, data, true);
3443 Non-static send methods
3446 void Server::SendInventory(u16 peer_id)
3448 DSTACK(__FUNCTION_NAME);
3450 ServerRemotePlayer* player =
3451 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3454 player->m_inventory_not_sent = false;
3460 std::ostringstream os;
3461 //os.imbue(std::locale("C"));
3463 player->inventory.serialize(os);
3465 std::string s = os.str();
3467 SharedBuffer<u8> data(s.size()+2);
3468 writeU16(&data[0], TOCLIENT_INVENTORY);
3469 memcpy(&data[2], s.c_str(), s.size());
3472 m_con.Send(peer_id, 0, data, true);
3475 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3477 DSTACK(__FUNCTION_NAME);
3481 std::ostringstream os(std::ios_base::binary);
3483 writeU16(os, TOCLIENT_PLAYERITEM);
3485 writeU16(os, srp->peer_id);
3486 os<<serializeString(srp->getWieldedItem().getItemString());
3489 std::string s = os.str();
3490 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3492 m_con.SendToAll(0, data, true);
3495 void Server::SendPlayerItems()
3497 DSTACK(__FUNCTION_NAME);
3499 std::ostringstream os(std::ios_base::binary);
3500 core::list<Player *> players = m_env->getPlayers(true);
3502 writeU16(os, TOCLIENT_PLAYERITEM);
3503 writeU16(os, players.size());
3504 core::list<Player *>::Iterator i;
3505 for(i = players.begin(); i != players.end(); ++i)
3508 ServerRemotePlayer *srp =
3509 static_cast<ServerRemotePlayer*>(p);
3510 writeU16(os, p->peer_id);
3511 os<<serializeString(srp->getWieldedItem().getItemString());
3515 std::string s = os.str();
3516 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3518 m_con.SendToAll(0, data, true);
3521 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3523 DSTACK(__FUNCTION_NAME);
3525 std::ostringstream os(std::ios_base::binary);
3529 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3530 os.write((char*)buf, 2);
3533 writeU16(buf, message.size());
3534 os.write((char*)buf, 2);
3537 for(u32 i=0; i<message.size(); i++)
3541 os.write((char*)buf, 2);
3545 std::string s = os.str();
3546 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3548 m_con.Send(peer_id, 0, data, true);
3551 void Server::BroadcastChatMessage(const std::wstring &message)
3553 for(core::map<u16, RemoteClient*>::Iterator
3554 i = m_clients.getIterator();
3555 i.atEnd() == false; i++)
3557 // Get client and check that it is valid
3558 RemoteClient *client = i.getNode()->getValue();
3559 assert(client->peer_id == i.getNode()->getKey());
3560 if(client->serialization_version == SER_FMT_VER_INVALID)
3563 SendChatMessage(client->peer_id, message);
3567 void Server::SendPlayerHP(Player *player)
3569 SendHP(m_con, player->peer_id, player->hp);
3570 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3573 void Server::SendMovePlayer(Player *player)
3575 DSTACK(__FUNCTION_NAME);
3576 std::ostringstream os(std::ios_base::binary);
3578 writeU16(os, TOCLIENT_MOVE_PLAYER);
3579 writeV3F1000(os, player->getPosition());
3580 writeF1000(os, player->getPitch());
3581 writeF1000(os, player->getYaw());
3584 v3f pos = player->getPosition();
3585 f32 pitch = player->getPitch();
3586 f32 yaw = player->getYaw();
3587 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3588 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3595 std::string s = os.str();
3596 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3598 m_con.Send(player->peer_id, 0, data, true);
3601 s32 Server::playSound(const SimpleSoundSpec &spec,
3602 const ServerSoundParams ¶ms)
3604 // Find out initial position of sound
3605 bool pos_exists = false;
3606 v3f pos = params.getPos(m_env, &pos_exists);
3607 // If position is not found while it should be, cancel sound
3608 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3610 // Filter destination clients
3611 std::set<RemoteClient*> dst_clients;
3612 if(params.to_player != "")
3614 Player *player = m_env->getPlayer(params.to_player.c_str());
3616 infostream<<"Server::playSound: Player \""<<params.to_player
3617 <<"\" not found"<<std::endl;
3620 if(player->peer_id == PEER_ID_INEXISTENT){
3621 infostream<<"Server::playSound: Player \""<<params.to_player
3622 <<"\" not connected"<<std::endl;
3625 RemoteClient *client = getClient(player->peer_id);
3626 dst_clients.insert(client);
3630 for(core::map<u16, RemoteClient*>::Iterator
3631 i = m_clients.getIterator(); i.atEnd() == false; i++)
3633 RemoteClient *client = i.getNode()->getValue();
3634 Player *player = m_env->getPlayer(client->peer_id);
3638 if(player->getPosition().getDistanceFrom(pos) >
3639 params.max_hear_distance)
3642 dst_clients.insert(client);
3645 if(dst_clients.size() == 0)
3648 s32 id = m_next_sound_id++;
3649 // The sound will exist as a reference in m_playing_sounds
3650 m_playing_sounds[id] = ServerPlayingSound();
3651 ServerPlayingSound &psound = m_playing_sounds[id];
3652 psound.params = params;
3653 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3654 i != dst_clients.end(); i++)
3655 psound.clients.insert((*i)->peer_id);
3657 std::ostringstream os(std::ios_base::binary);
3658 writeU16(os, TOCLIENT_PLAY_SOUND);
3660 os<<serializeString(spec.name);
3661 writeF1000(os, spec.gain * params.gain);
3662 writeU8(os, params.type);
3663 writeV3F1000(os, pos);
3664 writeU16(os, params.object);
3665 writeU8(os, params.loop);
3667 std::string s = os.str();
3668 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3670 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3671 i != dst_clients.end(); i++){
3673 m_con.Send((*i)->peer_id, 0, data, true);
3677 void Server::stopSound(s32 handle)
3679 // Get sound reference
3680 std::map<s32, ServerPlayingSound>::iterator i =
3681 m_playing_sounds.find(handle);
3682 if(i == m_playing_sounds.end())
3684 ServerPlayingSound &psound = i->second;
3686 std::ostringstream os(std::ios_base::binary);
3687 writeU16(os, TOCLIENT_STOP_SOUND);
3688 writeS32(os, handle);
3690 std::string s = os.str();
3691 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3693 for(std::set<u16>::iterator i = psound.clients.begin();
3694 i != psound.clients.end(); i++){
3696 m_con.Send(*i, 0, data, true);
3698 // Remove sound reference
3699 m_playing_sounds.erase(i);
3702 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3703 core::list<u16> *far_players, float far_d_nodes)
3705 float maxd = far_d_nodes*BS;
3706 v3f p_f = intToFloat(p, BS);
3710 SharedBuffer<u8> reply(replysize);
3711 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3712 writeS16(&reply[2], p.X);
3713 writeS16(&reply[4], p.Y);
3714 writeS16(&reply[6], p.Z);
3716 for(core::map<u16, RemoteClient*>::Iterator
3717 i = m_clients.getIterator();
3718 i.atEnd() == false; i++)
3720 // Get client and check that it is valid
3721 RemoteClient *client = i.getNode()->getValue();
3722 assert(client->peer_id == i.getNode()->getKey());
3723 if(client->serialization_version == SER_FMT_VER_INVALID)
3726 // Don't send if it's the same one
3727 if(client->peer_id == ignore_id)
3733 Player *player = m_env->getPlayer(client->peer_id);
3736 // If player is far away, only set modified blocks not sent
3737 v3f player_pos = player->getPosition();
3738 if(player_pos.getDistanceFrom(p_f) > maxd)
3740 far_players->push_back(client->peer_id);
3747 m_con.Send(client->peer_id, 0, reply, true);
3751 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3752 core::list<u16> *far_players, float far_d_nodes)
3754 float maxd = far_d_nodes*BS;
3755 v3f p_f = intToFloat(p, BS);
3757 for(core::map<u16, RemoteClient*>::Iterator
3758 i = m_clients.getIterator();
3759 i.atEnd() == false; i++)
3761 // Get client and check that it is valid
3762 RemoteClient *client = i.getNode()->getValue();
3763 assert(client->peer_id == i.getNode()->getKey());
3764 if(client->serialization_version == SER_FMT_VER_INVALID)
3767 // Don't send if it's the same one
3768 if(client->peer_id == ignore_id)
3774 Player *player = m_env->getPlayer(client->peer_id);
3777 // If player is far away, only set modified blocks not sent
3778 v3f player_pos = player->getPosition();
3779 if(player_pos.getDistanceFrom(p_f) > maxd)
3781 far_players->push_back(client->peer_id);
3788 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3789 SharedBuffer<u8> reply(replysize);
3790 writeU16(&reply[0], TOCLIENT_ADDNODE);
3791 writeS16(&reply[2], p.X);
3792 writeS16(&reply[4], p.Y);
3793 writeS16(&reply[6], p.Z);
3794 n.serialize(&reply[8], client->serialization_version);
3797 m_con.Send(client->peer_id, 0, reply, true);
3801 void Server::setBlockNotSent(v3s16 p)
3803 for(core::map<u16, RemoteClient*>::Iterator
3804 i = m_clients.getIterator();
3805 i.atEnd()==false; i++)
3807 RemoteClient *client = i.getNode()->getValue();
3808 client->SetBlockNotSent(p);
3812 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3814 DSTACK(__FUNCTION_NAME);
3816 v3s16 p = block->getPos();
3820 bool completely_air = true;
3821 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3822 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3823 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3825 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3827 completely_air = false;
3828 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3833 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3835 infostream<<"[completely air] ";
3836 infostream<<std::endl;
3840 Create a packet with the block in the right format
3843 std::ostringstream os(std::ios_base::binary);
3844 block->serialize(os, ver, false);
3845 std::string s = os.str();
3846 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3848 u32 replysize = 8 + blockdata.getSize();
3849 SharedBuffer<u8> reply(replysize);
3850 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3851 writeS16(&reply[2], p.X);
3852 writeS16(&reply[4], p.Y);
3853 writeS16(&reply[6], p.Z);
3854 memcpy(&reply[8], *blockdata, blockdata.getSize());
3856 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3857 <<": \tpacket size: "<<replysize<<std::endl;*/
3862 m_con.Send(peer_id, 1, reply, true);
3865 void Server::SendBlocks(float dtime)
3867 DSTACK(__FUNCTION_NAME);
3869 JMutexAutoLock envlock(m_env_mutex);
3870 JMutexAutoLock conlock(m_con_mutex);
3872 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3874 core::array<PrioritySortedBlockTransfer> queue;
3876 s32 total_sending = 0;
3879 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3881 for(core::map<u16, RemoteClient*>::Iterator
3882 i = m_clients.getIterator();
3883 i.atEnd() == false; i++)
3885 RemoteClient *client = i.getNode()->getValue();
3886 assert(client->peer_id == i.getNode()->getKey());
3888 // If definitions and textures have not been sent, don't
3889 // send MapBlocks either
3890 if(!client->definitions_sent)
3893 total_sending += client->SendingCount();
3895 if(client->serialization_version == SER_FMT_VER_INVALID)
3898 client->GetNextBlocks(this, dtime, queue);
3903 // Lowest priority number comes first.
3904 // Lowest is most important.
3907 for(u32 i=0; i<queue.size(); i++)
3909 //TODO: Calculate limit dynamically
3910 if(total_sending >= g_settings->getS32
3911 ("max_simultaneous_block_sends_server_total"))
3914 PrioritySortedBlockTransfer q = queue[i];
3916 MapBlock *block = NULL;
3919 block = m_env->getMap().getBlockNoCreate(q.pos);
3921 catch(InvalidPositionException &e)
3926 RemoteClient *client = getClient(q.peer_id);
3928 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3930 client->SentBlock(q.pos);
3936 void Server::fillMediaCache()
3938 DSTACK(__FUNCTION_NAME);
3940 infostream<<"Server: Calculating media file checksums"<<std::endl;
3942 // Collect all media file paths
3943 std::list<std::string> paths;
3944 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3945 i != m_mods.end(); i++){
3946 const ModSpec &mod = *i;
3947 paths.push_back(mod.path + DIR_DELIM + "textures");
3948 paths.push_back(mod.path + DIR_DELIM + "sounds");
3949 paths.push_back(mod.path + DIR_DELIM + "media");
3952 // Collect media file information from paths into cache
3953 for(std::list<std::string>::iterator i = paths.begin();
3954 i != paths.end(); i++)
3956 std::string mediapath = *i;
3957 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3958 for(u32 j=0; j<dirlist.size(); j++){
3959 if(dirlist[j].dir) // Ignode dirs
3961 std::string filename = dirlist[j].name;
3962 // if name contains illegal characters, ignore the file
3963 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3964 errorstream<<"Server: ignoring illegal file name: \""
3965 <<filename<<"\""<<std::endl;
3968 std::string filepath = mediapath + DIR_DELIM + filename;
3970 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3971 if(fis.good() == false){
3972 errorstream<<"Server::fillMediaCache(): Could not open \""
3973 <<filename<<"\" for reading"<<std::endl;
3976 std::ostringstream tmp_os(std::ios_base::binary);
3980 fis.read(buf, 1024);
3981 std::streamsize len = fis.gcount();
3982 tmp_os.write(buf, len);
3991 errorstream<<"Server::fillMediaCache(): Failed to read \""
3992 <<filename<<"\""<<std::endl;
3995 if(tmp_os.str().length() == 0){
3996 errorstream<<"Server::fillMediaCache(): Empty file \""
3997 <<filepath<<"\""<<std::endl;
4002 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4004 unsigned char *digest = sha1.getDigest();
4005 std::string sha1_base64 = base64_encode(digest, 20);
4006 std::string sha1_hex = hex_encode((char*)digest, 20);
4010 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4011 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4016 struct SendableMediaAnnouncement
4019 std::string sha1_digest;
4021 SendableMediaAnnouncement(const std::string name_="",
4022 const std::string sha1_digest_=""):
4024 sha1_digest(sha1_digest_)
4028 void Server::sendMediaAnnouncement(u16 peer_id)
4030 DSTACK(__FUNCTION_NAME);
4032 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4035 core::list<SendableMediaAnnouncement> file_announcements;
4037 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4038 i != m_media.end(); i++){
4040 file_announcements.push_back(
4041 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4045 std::ostringstream os(std::ios_base::binary);
4053 u16 length of sha1_digest
4058 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4059 writeU16(os, file_announcements.size());
4061 for(core::list<SendableMediaAnnouncement>::Iterator
4062 j = file_announcements.begin();
4063 j != file_announcements.end(); j++){
4064 os<<serializeString(j->name);
4065 os<<serializeString(j->sha1_digest);
4069 std::string s = os.str();
4070 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4073 m_con.Send(peer_id, 0, data, true);
4077 struct SendableMedia
4083 SendableMedia(const std::string &name_="", const std::string path_="",
4084 const std::string &data_=""):
4091 void Server::sendRequestedMedia(u16 peer_id,
4092 const core::list<MediaRequest> &tosend)
4094 DSTACK(__FUNCTION_NAME);
4096 verbosestream<<"Server::sendRequestedMedia(): "
4097 <<"Sending files to client"<<std::endl;
4101 // Put 5kB in one bunch (this is not accurate)
4102 u32 bytes_per_bunch = 5000;
4104 core::array< core::list<SendableMedia> > file_bunches;
4105 file_bunches.push_back(core::list<SendableMedia>());
4107 u32 file_size_bunch_total = 0;
4109 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4110 i != tosend.end(); i++)
4112 if(m_media.find(i->name) == m_media.end()){
4113 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4114 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4118 //TODO get path + name
4119 std::string tpath = m_media[(*i).name].path;
4122 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4123 if(fis.good() == false){
4124 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4125 <<tpath<<"\" for reading"<<std::endl;
4128 std::ostringstream tmp_os(std::ios_base::binary);
4132 fis.read(buf, 1024);
4133 std::streamsize len = fis.gcount();
4134 tmp_os.write(buf, len);
4135 file_size_bunch_total += len;
4144 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4145 <<(*i).name<<"\""<<std::endl;
4148 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4149 <<tname<<"\""<<std::endl;*/
4151 file_bunches[file_bunches.size()-1].push_back(
4152 SendableMedia((*i).name, tpath, tmp_os.str()));
4154 // Start next bunch if got enough data
4155 if(file_size_bunch_total >= bytes_per_bunch){
4156 file_bunches.push_back(core::list<SendableMedia>());
4157 file_size_bunch_total = 0;
4162 /* Create and send packets */
4164 u32 num_bunches = file_bunches.size();
4165 for(u32 i=0; i<num_bunches; i++)
4167 std::ostringstream os(std::ios_base::binary);
4171 u16 total number of texture bunches
4172 u16 index of this bunch
4173 u32 number of files in this bunch
4182 writeU16(os, TOCLIENT_MEDIA);
4183 writeU16(os, num_bunches);
4185 writeU32(os, file_bunches[i].size());
4187 for(core::list<SendableMedia>::Iterator
4188 j = file_bunches[i].begin();
4189 j != file_bunches[i].end(); j++){
4190 os<<serializeString(j->name);
4191 os<<serializeLongString(j->data);
4195 std::string s = os.str();
4196 verbosestream<<"Server::sendRequestedMedia(): bunch "
4197 <<i<<"/"<<num_bunches
4198 <<" files="<<file_bunches[i].size()
4199 <<" size=" <<s.size()<<std::endl;
4200 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4202 m_con.Send(peer_id, 0, data, true);
4210 void Server::DiePlayer(Player *player)
4212 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4214 infostream<<"Server::DiePlayer(): Player "
4215 <<player->getName()<<" dies"<<std::endl;
4219 // Trigger scripted stuff
4220 scriptapi_on_dieplayer(m_lua, srp);
4222 // Handle players that are not connected
4223 if(player->peer_id == PEER_ID_INEXISTENT){
4224 RespawnPlayer(player);
4228 SendPlayerHP(player);
4229 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4232 void Server::RespawnPlayer(Player *player)
4234 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4236 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4238 v3f pos = findSpawnPos(m_env->getServerMap());
4239 player->setPosition(pos);
4240 srp->m_last_good_position = pos;
4241 srp->m_last_good_position_age = 0;
4243 SendMovePlayer(player);
4244 SendPlayerHP(player);
4247 void Server::UpdateCrafting(u16 peer_id)
4249 DSTACK(__FUNCTION_NAME);
4251 Player* player = m_env->getPlayer(peer_id);
4254 // Get a preview for crafting
4256 // No crafting in creative mode
4257 if(g_settings->getBool("creative_mode") == false)
4258 getCraftingResult(&player->inventory, preview, false, this);
4260 // Put the new preview in
4261 InventoryList *plist = player->inventory.getList("craftpreview");
4263 assert(plist->getSize() >= 1);
4264 plist->changeItem(0, preview);
4267 RemoteClient* Server::getClient(u16 peer_id)
4269 DSTACK(__FUNCTION_NAME);
4270 //JMutexAutoLock lock(m_con_mutex);
4271 core::map<u16, RemoteClient*>::Node *n;
4272 n = m_clients.find(peer_id);
4273 // A client should exist for all peers
4275 return n->getValue();
4278 std::wstring Server::getStatusString()
4280 std::wostringstream os(std::ios_base::binary);
4283 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4285 os<<L", uptime="<<m_uptime.get();
4286 // Information about clients
4288 for(core::map<u16, RemoteClient*>::Iterator
4289 i = m_clients.getIterator();
4290 i.atEnd() == false; i++)
4292 // Get client and check that it is valid
4293 RemoteClient *client = i.getNode()->getValue();
4294 assert(client->peer_id == i.getNode()->getKey());
4295 if(client->serialization_version == SER_FMT_VER_INVALID)
4298 Player *player = m_env->getPlayer(client->peer_id);
4299 // Get name of player
4300 std::wstring name = L"unknown";
4302 name = narrow_to_wide(player->getName());
4303 // Add name to information string
4307 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4308 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4309 if(g_settings->get("motd") != "")
4310 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4314 u64 Server::getPlayerAuthPrivs(const std::string &name)
4317 return m_authmanager.getPrivs(name);
4319 catch(AuthNotFoundException &e)
4321 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4326 void Server::setPlayerAuthPrivs(const std::string &name, u64 privs)
4329 return m_authmanager.setPrivs(name, privs);
4331 catch(AuthNotFoundException &e)
4333 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4337 u64 Server::getPlayerEffectivePrivs(const std::string &name)
4339 // Local player gets all privileges regardless of
4340 // what's set on their account.
4341 if(m_simple_singleplayer_mode)
4343 if(name == g_settings->get("name"))
4345 return getPlayerAuthPrivs(name);
4348 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4350 // Add player to auth manager
4351 if(m_authmanager.exists(name) == false)
4353 infostream<<"Server: adding player "<<name
4354 <<" to auth manager"<<std::endl;
4355 m_authmanager.add(name);
4356 m_authmanager.setPrivs(name,
4357 stringToPrivs(g_settings->get("default_privs")));
4359 // Change password and save
4360 m_authmanager.setPassword(name, translatePassword(name, password));
4361 m_authmanager.save();
4364 // Saves g_settings to configpath given at initialization
4365 void Server::saveConfig()
4367 if(m_path_config != "")
4368 g_settings->updateConfigFile(m_path_config.c_str());
4371 void Server::notifyPlayer(const char *name, const std::wstring msg)
4373 Player *player = m_env->getPlayer(name);
4376 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4379 void Server::notifyPlayers(const std::wstring msg)
4381 BroadcastChatMessage(msg);
4384 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4388 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4389 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4392 // IGameDef interface
4394 IItemDefManager* Server::getItemDefManager()
4398 INodeDefManager* Server::getNodeDefManager()
4402 ICraftDefManager* Server::getCraftDefManager()
4406 ITextureSource* Server::getTextureSource()
4410 u16 Server::allocateUnknownNodeId(const std::string &name)
4412 return m_nodedef->allocateDummy(name);
4414 ISoundManager* Server::getSoundManager()
4416 return &dummySoundManager;
4418 MtEventManager* Server::getEventManager()
4423 IWritableItemDefManager* Server::getWritableItemDefManager()
4427 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4431 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4436 const ModSpec* Server::getModSpec(const std::string &modname)
4438 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4439 i != m_mods.end(); i++){
4440 const ModSpec &mod = *i;
4441 if(mod.name == modname)
4447 v3f findSpawnPos(ServerMap &map)
4449 //return v3f(50,50,50)*BS;
4454 nodepos = v2s16(0,0);
4459 // Try to find a good place a few times
4460 for(s32 i=0; i<1000; i++)
4463 // We're going to try to throw the player to this position
4464 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4465 -range + (myrand()%(range*2)));
4466 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4467 // Get ground height at point (fallbacks to heightmap function)
4468 s16 groundheight = map.findGroundLevel(nodepos2d);
4469 // Don't go underwater
4470 if(groundheight < WATER_LEVEL)
4472 //infostream<<"-> Underwater"<<std::endl;
4475 // Don't go to high places
4476 if(groundheight > WATER_LEVEL + 4)
4478 //infostream<<"-> Underwater"<<std::endl;
4482 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4483 bool is_good = false;
4485 for(s32 i=0; i<10; i++){
4486 v3s16 blockpos = getNodeBlockPos(nodepos);
4487 map.emergeBlock(blockpos, true);
4488 MapNode n = map.getNodeNoEx(nodepos);
4489 if(n.getContent() == CONTENT_AIR){
4500 // Found a good place
4501 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4507 return intToFloat(nodepos, BS);
4510 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4513 Try to get an existing player
4515 ServerRemotePlayer *player =
4516 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4519 // If player is already connected, cancel
4520 if(player->peer_id != 0)
4522 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4527 player->peer_id = peer_id;
4529 // Re-add player to environment
4530 if(player->m_removed)
4532 player->m_removed = false;
4534 m_env->addActiveObject(player);
4537 // Reset inventory to creative if in creative mode
4538 if(g_settings->getBool("creative_mode"))
4540 // Warning: double code below
4541 // Backup actual inventory
4542 player->inventory_backup = new Inventory(m_itemdef);
4543 *(player->inventory_backup) = player->inventory;
4544 // Set creative inventory
4545 player->resetInventory();
4546 scriptapi_get_creative_inventory(m_lua, player);
4553 If player with the wanted peer_id already exists, cancel.
4555 if(m_env->getPlayer(peer_id) != NULL)
4557 infostream<<"emergePlayer(): Player with wrong name but same"
4558 " peer_id already exists"<<std::endl;
4566 /* Set player position */
4568 infostream<<"Server: Finding spawn place for player \""
4569 <<name<<"\""<<std::endl;
4571 v3f pos = findSpawnPos(m_env->getServerMap());
4573 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4574 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4576 /* Add player to environment */
4577 m_env->addPlayer(player);
4578 m_env->addActiveObject(srp);
4581 scriptapi_on_newplayer(m_lua, srp);
4583 /* Add stuff to inventory */
4584 if(g_settings->getBool("creative_mode"))
4586 // Warning: double code above
4587 // Backup actual inventory
4588 player->inventory_backup = new Inventory(m_itemdef);
4589 *(player->inventory_backup) = player->inventory;
4590 // Set creative inventory
4591 player->resetInventory();
4592 scriptapi_get_creative_inventory(m_lua, player);
4597 } // create new player
4600 void Server::handlePeerChange(PeerChange &c)
4602 JMutexAutoLock envlock(m_env_mutex);
4603 JMutexAutoLock conlock(m_con_mutex);
4605 if(c.type == PEER_ADDED)
4612 core::map<u16, RemoteClient*>::Node *n;
4613 n = m_clients.find(c.peer_id);
4614 // The client shouldn't already exist
4618 RemoteClient *client = new RemoteClient();
4619 client->peer_id = c.peer_id;
4620 m_clients.insert(client->peer_id, client);
4623 else if(c.type == PEER_REMOVED)
4630 core::map<u16, RemoteClient*>::Node *n;
4631 n = m_clients.find(c.peer_id);
4632 // The client should exist
4636 Mark objects to be not known by the client
4638 RemoteClient *client = n->getValue();
4640 for(core::map<u16, bool>::Iterator
4641 i = client->m_known_objects.getIterator();
4642 i.atEnd()==false; i++)
4645 u16 id = i.getNode()->getKey();
4646 ServerActiveObject* obj = m_env->getActiveObject(id);
4648 if(obj && obj->m_known_by_count > 0)
4649 obj->m_known_by_count--;
4653 Clear references to playing sounds
4655 for(std::map<s32, ServerPlayingSound>::iterator
4656 i = m_playing_sounds.begin();
4657 i != m_playing_sounds.end();)
4659 ServerPlayingSound &psound = i->second;
4660 psound.clients.erase(c.peer_id);
4661 if(psound.clients.size() == 0)
4662 m_playing_sounds.erase(i++);
4667 ServerRemotePlayer* player =
4668 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4670 // Collect information about leaving in chat
4671 std::wstring message;
4675 std::wstring name = narrow_to_wide(player->getName());
4678 message += L" left game";
4680 message += L" (timed out)";
4684 // Remove from environment
4686 player->m_removed = true;
4688 // Set player client disconnected
4690 player->peer_id = 0;
4698 std::ostringstream os(std::ios_base::binary);
4699 for(core::map<u16, RemoteClient*>::Iterator
4700 i = m_clients.getIterator();
4701 i.atEnd() == false; i++)
4703 RemoteClient *client = i.getNode()->getValue();
4704 assert(client->peer_id == i.getNode()->getKey());
4705 if(client->serialization_version == SER_FMT_VER_INVALID)
4708 Player *player = m_env->getPlayer(client->peer_id);
4711 // Get name of player
4712 os<<player->getName()<<" ";
4715 actionstream<<player->getName()<<" "
4716 <<(c.timeout?"times out.":"leaves game.")
4717 <<" List of players: "
4718 <<os.str()<<std::endl;
4723 delete m_clients[c.peer_id];
4724 m_clients.remove(c.peer_id);
4726 // Send player info to all remaining clients
4727 //SendPlayerInfos();
4729 // Send leave chat message to all remaining clients
4730 if(message.length() != 0)
4731 BroadcastChatMessage(message);
4740 void Server::handlePeerChanges()
4742 while(m_peer_change_queue.size() > 0)
4744 PeerChange c = m_peer_change_queue.pop_front();
4746 verbosestream<<"Server: Handling peer change: "
4747 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4750 handlePeerChange(c);
4754 u64 Server::getPlayerPrivs(Player *player)
4758 std::string playername = player->getName();
4759 return getPlayerEffectivePrivs(playername);
4762 void dedicated_server_loop(Server &server, bool &kill)
4764 DSTACK(__FUNCTION_NAME);
4766 verbosestream<<"dedicated_server_loop()"<<std::endl;
4768 IntervalLimiter m_profiler_interval;
4772 float steplen = g_settings->getFloat("dedicated_server_step");
4773 // This is kind of a hack but can be done like this
4774 // because server.step() is very light
4776 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4777 sleep_ms((int)(steplen*1000.0));
4779 server.step(steplen);
4781 if(server.getShutdownRequested() || kill)
4783 infostream<<"Dedicated server quitting"<<std::endl;
4790 float profiler_print_interval =
4791 g_settings->getFloat("profiler_print_interval");
4792 if(profiler_print_interval != 0)
4794 if(m_profiler_interval.step(steplen, profiler_print_interval))
4796 infostream<<"Profiler:"<<std::endl;
4797 g_profiler->print(infostream);
4798 g_profiler->clear();