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"
55 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
57 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
59 class MapEditEventIgnorer
62 MapEditEventIgnorer(bool *flag):
71 ~MapEditEventIgnorer()
84 void * ServerThread::Thread()
88 log_register_thread("ServerThread");
90 DSTACK(__FUNCTION_NAME);
92 BEGIN_DEBUG_EXCEPTION_HANDLER
97 //TimeTaker timer("AsyncRunStep() + Receive()");
100 //TimeTaker timer("AsyncRunStep()");
101 m_server->AsyncRunStep();
104 //infostream<<"Running m_server->Receive()"<<std::endl;
107 catch(con::NoIncomingDataException &e)
110 catch(con::PeerNotFoundException &e)
112 infostream<<"Server: PeerNotFoundException"<<std::endl;
114 catch(con::ConnectionBindFailed &e)
116 m_server->setAsyncFatalError(e.what());
120 END_DEBUG_EXCEPTION_HANDLER(errorstream)
125 void * EmergeThread::Thread()
129 log_register_thread("EmergeThread");
131 DSTACK(__FUNCTION_NAME);
133 BEGIN_DEBUG_EXCEPTION_HANDLER
135 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
138 Get block info from queue, emerge them and send them
141 After queue is empty, exit.
145 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
149 SharedPtr<QueuedBlockEmerge> q(qptr);
155 Do not generate over-limit
157 if(blockpos_over_limit(p))
160 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
162 //TimeTaker timer("block emerge");
165 Try to emerge it from somewhere.
167 If it is only wanted as optional, only loading from disk
172 Check if any peer wants it as non-optional. In that case it
175 Also decrement the emerge queue count in clients.
178 bool only_from_disk = true;
181 core::map<u16, u8>::Iterator i;
182 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
184 //u16 peer_id = i.getNode()->getKey();
187 u8 flags = i.getNode()->getValue();
188 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
189 only_from_disk = false;
194 if(enable_mapgen_debug_info)
195 infostream<<"EmergeThread: p="
196 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
197 <<"only_from_disk="<<only_from_disk<<std::endl;
199 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
201 MapBlock *block = NULL;
202 bool got_block = true;
203 core::map<v3s16, MapBlock*> modified_blocks;
206 Try to fetch block from memory or disk.
207 If not found and asked to generate, initialize generator.
210 bool started_generate = false;
211 mapgen::BlockMakeData data;
214 JMutexAutoLock envlock(m_server->m_env_mutex);
216 // Load sector if it isn't loaded
217 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
218 map.loadSectorMeta(p2d);
220 // Attempt to load block
221 block = map.getBlockNoCreateNoEx(p);
222 if(!block || block->isDummy() || !block->isGenerated())
224 if(enable_mapgen_debug_info)
225 infostream<<"EmergeThread: not in memory, "
226 <<"attempting to load from disk"<<std::endl;
228 block = map.loadBlock(p);
231 // If could not load and allowed to generate, start generation
232 // inside this same envlock
233 if(only_from_disk == false &&
234 (block == NULL || block->isGenerated() == false)){
235 if(enable_mapgen_debug_info)
236 infostream<<"EmergeThread: generating"<<std::endl;
237 started_generate = true;
239 map.initBlockMake(&data, p);
244 If generator was initialized, generate now when envlock is free.
249 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
251 TimeTaker t("mapgen::make_block()");
253 mapgen::make_block(&data);
255 if(enable_mapgen_debug_info == false)
256 t.stop(true); // Hide output
260 // Lock environment again to access the map
261 JMutexAutoLock envlock(m_server->m_env_mutex);
263 ScopeProfiler sp(g_profiler, "EmergeThread: after "
264 "mapgen::make_block (envlock)", SPT_AVG);
266 // Blit data back on map, update lighting, add mobs and
267 // whatever this does
268 map.finishBlockMake(&data, modified_blocks);
271 block = map.getBlockNoCreateNoEx(p);
273 // If block doesn't exist, don't try doing anything with it
274 // This happens if the block is not in generation boundaries
279 Do some post-generate stuff
282 v3s16 minp = block->getPos()*MAP_BLOCKSIZE;
283 v3s16 maxp = minp + v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
284 scriptapi_environment_on_generated(m_server->m_lua,
287 if(enable_mapgen_debug_info)
288 infostream<<"EmergeThread: ended up with: "
289 <<analyze_block(block)<<std::endl;
292 Ignore map edit events, they will not need to be
293 sent to anybody because the block hasn't been sent
296 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
298 // Activate objects and stuff
299 m_server->m_env->activateBlock(block, 0);
307 Set sent status of modified blocks on clients
310 // NOTE: Server's clients are also behind the connection mutex
311 JMutexAutoLock lock(m_server->m_con_mutex);
314 Add the originally fetched block to the modified list
318 modified_blocks.insert(p, block);
322 Set the modified blocks unsent for all the clients
325 for(core::map<u16, RemoteClient*>::Iterator
326 i = m_server->m_clients.getIterator();
327 i.atEnd() == false; i++)
329 RemoteClient *client = i.getNode()->getValue();
331 if(modified_blocks.size() > 0)
333 // Remove block from sent history
334 client->SetBlocksNotSent(modified_blocks);
340 END_DEBUG_EXCEPTION_HANDLER(errorstream)
342 log_deregister_thread();
347 void RemoteClient::GetNextBlocks(Server *server, float dtime,
348 core::array<PrioritySortedBlockTransfer> &dest)
350 DSTACK(__FUNCTION_NAME);
353 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
356 m_nothing_to_send_pause_timer -= dtime;
357 m_nearest_unsent_reset_timer += dtime;
359 if(m_nothing_to_send_pause_timer >= 0)
364 // Won't send anything if already sending
365 if(m_blocks_sending.size() >= g_settings->getU16
366 ("max_simultaneous_block_sends_per_client"))
368 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
372 //TimeTaker timer("RemoteClient::GetNextBlocks");
374 Player *player = server->m_env->getPlayer(peer_id);
376 assert(player != NULL);
378 v3f playerpos = player->getPosition();
379 v3f playerspeed = player->getSpeed();
380 v3f playerspeeddir(0,0,0);
381 if(playerspeed.getLength() > 1.0*BS)
382 playerspeeddir = playerspeed / playerspeed.getLength();
383 // Predict to next block
384 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
386 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
388 v3s16 center = getNodeBlockPos(center_nodepos);
390 // Camera position and direction
391 v3f camera_pos = player->getEyePosition();
392 v3f camera_dir = v3f(0,0,1);
393 camera_dir.rotateYZBy(player->getPitch());
394 camera_dir.rotateXZBy(player->getYaw());
396 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
397 <<camera_dir.Z<<")"<<std::endl;*/
400 Get the starting value of the block finder radius.
403 if(m_last_center != center)
405 m_nearest_unsent_d = 0;
406 m_last_center = center;
409 /*infostream<<"m_nearest_unsent_reset_timer="
410 <<m_nearest_unsent_reset_timer<<std::endl;*/
412 // Reset periodically to workaround for some bugs or stuff
413 if(m_nearest_unsent_reset_timer > 20.0)
415 m_nearest_unsent_reset_timer = 0;
416 m_nearest_unsent_d = 0;
417 //infostream<<"Resetting m_nearest_unsent_d for "
418 // <<server->getPlayerName(peer_id)<<std::endl;
421 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
422 s16 d_start = m_nearest_unsent_d;
424 //infostream<<"d_start="<<d_start<<std::endl;
426 u16 max_simul_sends_setting = g_settings->getU16
427 ("max_simultaneous_block_sends_per_client");
428 u16 max_simul_sends_usually = max_simul_sends_setting;
431 Check the time from last addNode/removeNode.
433 Decrease send rate if player is building stuff.
435 m_time_from_building += dtime;
436 if(m_time_from_building < g_settings->getFloat(
437 "full_block_send_enable_min_time_from_building"))
439 max_simul_sends_usually
440 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
444 Number of blocks sending + number of blocks selected for sending
446 u32 num_blocks_selected = m_blocks_sending.size();
449 next time d will be continued from the d from which the nearest
450 unsent block was found this time.
452 This is because not necessarily any of the blocks found this
453 time are actually sent.
455 s32 new_nearest_unsent_d = -1;
457 s16 d_max = g_settings->getS16("max_block_send_distance");
458 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
460 // Don't loop very much at a time
461 s16 max_d_increment_at_time = 2;
462 if(d_max > d_start + max_d_increment_at_time)
463 d_max = d_start + max_d_increment_at_time;
464 /*if(d_max_gen > d_start+2)
465 d_max_gen = d_start+2;*/
467 //infostream<<"Starting from "<<d_start<<std::endl;
469 s32 nearest_emerged_d = -1;
470 s32 nearest_emergefull_d = -1;
471 s32 nearest_sent_d = -1;
472 bool queue_is_full = false;
475 for(d = d_start; d <= d_max; d++)
477 /*errorstream<<"checking d="<<d<<" for "
478 <<server->getPlayerName(peer_id)<<std::endl;*/
479 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
482 If m_nearest_unsent_d was changed by the EmergeThread
483 (it can change it to 0 through SetBlockNotSent),
485 Else update m_nearest_unsent_d
487 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
489 d = m_nearest_unsent_d;
490 last_nearest_unsent_d = m_nearest_unsent_d;
494 Get the border/face dot coordinates of a "d-radiused"
497 core::list<v3s16> list;
498 getFacePositions(list, d);
500 core::list<v3s16>::Iterator li;
501 for(li=list.begin(); li!=list.end(); li++)
503 v3s16 p = *li + center;
507 - Don't allow too many simultaneous transfers
508 - EXCEPT when the blocks are very close
510 Also, don't send blocks that are already flying.
513 // Start with the usual maximum
514 u16 max_simul_dynamic = max_simul_sends_usually;
516 // If block is very close, allow full maximum
517 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
518 max_simul_dynamic = max_simul_sends_setting;
520 // Don't select too many blocks for sending
521 if(num_blocks_selected >= max_simul_dynamic)
523 queue_is_full = true;
524 goto queue_full_break;
527 // Don't send blocks that are currently being transferred
528 if(m_blocks_sending.find(p) != NULL)
534 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
535 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
536 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
537 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
538 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
539 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
542 // If this is true, inexistent block will be made from scratch
543 bool generate = d <= d_max_gen;
546 /*// Limit the generating area vertically to 2/3
547 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
550 // Limit the send area vertically to 1/2
551 if(abs(p.Y - center.Y) > d_max / 2)
557 If block is far away, don't generate it unless it is
563 // Block center y in nodes
564 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
565 // Don't generate if it's very high or very low
566 if(y < -64 || y > 64)
570 v2s16 p2d_nodes_center(
574 // Get ground height in nodes
575 s16 gh = server->m_env->getServerMap().findGroundLevel(
578 // If differs a lot, don't generate
579 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
581 // Actually, don't even send it
587 //infostream<<"d="<<d<<std::endl;
590 Don't generate or send if not in sight
591 FIXME This only works if the client uses a small enough
592 FOV setting. The default of 72 degrees is fine.
595 float camera_fov = (72.0*PI/180) * 4./3.;
596 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
602 Don't send already sent blocks
605 if(m_blocks_sent.find(p) != NULL)
612 Check if map has this block
614 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
616 bool surely_not_found_on_disk = false;
617 bool block_is_invalid = false;
620 // Reset usage timer, this block will be of use in the future.
621 block->resetUsageTimer();
623 // Block is dummy if data doesn't exist.
624 // It means it has been not found from disk and not generated
627 surely_not_found_on_disk = true;
630 // Block is valid if lighting is up-to-date and data exists
631 if(block->isValid() == false)
633 block_is_invalid = true;
636 /*if(block->isFullyGenerated() == false)
638 block_is_invalid = true;
643 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
644 v2s16 chunkpos = map->sector_to_chunk(p2d);
645 if(map->chunkNonVolatile(chunkpos) == false)
646 block_is_invalid = true;
648 if(block->isGenerated() == false)
649 block_is_invalid = true;
652 If block is not close, don't send it unless it is near
655 Block is near ground level if night-time mesh
656 differs from day-time mesh.
660 if(block->dayNightDiffed() == false)
667 If block has been marked to not exist on disk (dummy)
668 and generating new ones is not wanted, skip block.
670 if(generate == false && surely_not_found_on_disk == true)
677 Add inexistent block to emerge queue.
679 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
681 //TODO: Get value from somewhere
682 // Allow only one block in emerge queue
683 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
684 // Allow two blocks in queue per client
685 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
687 // Make it more responsive when needing to generate stuff
688 if(surely_not_found_on_disk)
690 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
692 //infostream<<"Adding block to emerge queue"<<std::endl;
694 // Add it to the emerge queue and trigger the thread
697 if(generate == false)
698 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
700 server->m_emerge_queue.addBlock(peer_id, p, flags);
701 server->m_emergethread.trigger();
703 if(nearest_emerged_d == -1)
704 nearest_emerged_d = d;
706 if(nearest_emergefull_d == -1)
707 nearest_emergefull_d = d;
714 if(nearest_sent_d == -1)
718 Add block to send queue
721 /*errorstream<<"sending from d="<<d<<" to "
722 <<server->getPlayerName(peer_id)<<std::endl;*/
724 PrioritySortedBlockTransfer q((float)d, p, peer_id);
728 num_blocks_selected += 1;
733 //infostream<<"Stopped at "<<d<<std::endl;
735 // If nothing was found for sending and nothing was queued for
736 // emerging, continue next time browsing from here
737 if(nearest_emerged_d != -1){
738 new_nearest_unsent_d = nearest_emerged_d;
739 } else if(nearest_emergefull_d != -1){
740 new_nearest_unsent_d = nearest_emergefull_d;
742 if(d > g_settings->getS16("max_block_send_distance")){
743 new_nearest_unsent_d = 0;
744 m_nothing_to_send_pause_timer = 2.0;
745 /*infostream<<"GetNextBlocks(): d wrapped around for "
746 <<server->getPlayerName(peer_id)
747 <<"; setting to 0 and pausing"<<std::endl;*/
749 if(nearest_sent_d != -1)
750 new_nearest_unsent_d = nearest_sent_d;
752 new_nearest_unsent_d = d;
756 if(new_nearest_unsent_d != -1)
757 m_nearest_unsent_d = new_nearest_unsent_d;
759 /*timer_result = timer.stop(true);
760 if(timer_result != 0)
761 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
764 void RemoteClient::GotBlock(v3s16 p)
766 if(m_blocks_sending.find(p) != NULL)
767 m_blocks_sending.remove(p);
770 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
771 " m_blocks_sending"<<std::endl;*/
772 m_excess_gotblocks++;
774 m_blocks_sent.insert(p, true);
777 void RemoteClient::SentBlock(v3s16 p)
779 if(m_blocks_sending.find(p) == NULL)
780 m_blocks_sending.insert(p, 0.0);
782 infostream<<"RemoteClient::SentBlock(): Sent block"
783 " already in m_blocks_sending"<<std::endl;
786 void RemoteClient::SetBlockNotSent(v3s16 p)
788 m_nearest_unsent_d = 0;
790 if(m_blocks_sending.find(p) != NULL)
791 m_blocks_sending.remove(p);
792 if(m_blocks_sent.find(p) != NULL)
793 m_blocks_sent.remove(p);
796 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
798 m_nearest_unsent_d = 0;
800 for(core::map<v3s16, MapBlock*>::Iterator
801 i = blocks.getIterator();
802 i.atEnd()==false; i++)
804 v3s16 p = i.getNode()->getKey();
806 if(m_blocks_sending.find(p) != NULL)
807 m_blocks_sending.remove(p);
808 if(m_blocks_sent.find(p) != NULL)
809 m_blocks_sent.remove(p);
817 PlayerInfo::PlayerInfo()
823 void PlayerInfo::PrintLine(std::ostream *s)
826 (*s)<<"\""<<name<<"\" ("
827 <<(position.X/10)<<","<<(position.Y/10)
828 <<","<<(position.Z/10)<<") ";
830 (*s)<<" avg_rtt="<<avg_rtt;
839 const std::string &path_world,
840 const std::string &path_config,
841 const SubgameSpec &gamespec,
842 bool simple_singleplayer_mode
844 m_path_world(path_world),
845 m_path_config(path_config),
846 m_gamespec(gamespec),
847 m_simple_singleplayer_mode(simple_singleplayer_mode),
848 m_async_fatal_error(""),
850 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
851 m_authmanager(path_world+DIR_DELIM+"auth.txt"),
852 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
854 m_itemdef(createItemDefManager()),
855 m_nodedef(createNodeDefManager()),
856 m_craftdef(createCraftDefManager()),
857 m_event(new EventManager()),
859 m_emergethread(this),
860 m_time_of_day_send_timer(0),
862 m_shutdown_requested(false),
863 m_ignore_map_edit_events(false),
864 m_ignore_map_edit_events_peer_id(0)
866 m_liquid_transform_timer = 0.0;
867 m_print_info_timer = 0.0;
868 m_objectdata_timer = 0.0;
869 m_emergethread_trigger_timer = 0.0;
870 m_savemap_timer = 0.0;
874 m_step_dtime_mutex.Init();
878 throw ServerError("Supplied empty world path");
880 if(!gamespec.isValid())
881 throw ServerError("Supplied invalid gamespec");
883 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
884 if(m_simple_singleplayer_mode)
885 infostream<<" in simple singleplayer mode"<<std::endl;
887 infostream<<std::endl;
888 infostream<<"- world: "<<m_path_world<<std::endl;
889 infostream<<"- config: "<<m_path_config<<std::endl;
890 infostream<<"- game: "<<m_gamespec.path<<std::endl;
892 // Add world mod search path
893 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
894 // Add addon mod search path
895 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
896 i != m_gamespec.mods_paths.end(); i++)
897 m_modspaths.push_front((*i));
899 // Print out mod search paths
900 for(core::list<std::string>::Iterator i = m_modspaths.begin();
901 i != m_modspaths.end(); i++){
902 std::string modspath = *i;
903 infostream<<"- mods: "<<modspath<<std::endl;
906 // Path to builtin.lua
907 std::string builtinpath = porting::path_share + DIR_DELIM + "builtin"
908 + DIR_DELIM + "builtin.lua";
910 // Create world if it doesn't exist
911 if(!initializeWorld(m_path_world, m_gamespec.id))
912 throw ServerError("Failed to initialize world");
915 JMutexAutoLock envlock(m_env_mutex);
916 JMutexAutoLock conlock(m_con_mutex);
918 // Initialize scripting
920 infostream<<"Server: Initializing Lua"<<std::endl;
921 m_lua = script_init();
924 scriptapi_export(m_lua, this);
925 // Load and run builtin.lua
926 infostream<<"Server: Loading builtin.lua [\""
927 <<builtinpath<<"\"]"<<std::endl;
928 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
930 errorstream<<"Server: Failed to load and run "
931 <<builtinpath<<std::endl;
932 throw ModError("Failed to load and run "+builtinpath);
934 // Find mods in mod search paths
935 m_mods = getMods(m_modspaths);
937 infostream<<"Server: Loading mods: ";
938 for(core::list<ModSpec>::Iterator i = m_mods.begin();
939 i != m_mods.end(); i++){
940 const ModSpec &mod = *i;
941 infostream<<mod.name<<" ";
943 infostream<<std::endl;
944 // Load and run "mod" scripts
945 for(core::list<ModSpec>::Iterator i = m_mods.begin();
946 i != m_mods.end(); i++){
947 const ModSpec &mod = *i;
948 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
949 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
950 <<scriptpath<<"\"]"<<std::endl;
951 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
953 errorstream<<"Server: Failed to load and run "
954 <<scriptpath<<std::endl;
955 throw ModError("Failed to load and run "+scriptpath);
959 // Read Textures and calculate sha1 sums
962 // Apply item aliases in the node definition manager
963 m_nodedef->updateAliases(m_itemdef);
965 // Initialize Environment
967 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
970 // Give environment reference to scripting api
971 scriptapi_add_environment(m_lua, m_env);
973 // Register us to receive map edit events
974 m_env->getMap().addEventReceiver(this);
976 // If file exists, load environment metadata
977 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
979 infostream<<"Server: Loading environment metadata"<<std::endl;
980 m_env->loadMeta(m_path_world);
984 infostream<<"Server: Loading players"<<std::endl;
985 m_env->deSerializePlayers(m_path_world);
988 Add some test ActiveBlockModifiers to environment
990 add_legacy_abms(m_env, m_nodedef);
995 infostream<<"Server destructing"<<std::endl;
998 Send shutdown message
1001 JMutexAutoLock conlock(m_con_mutex);
1003 std::wstring line = L"*** Server shutting down";
1006 Send the message to clients
1008 for(core::map<u16, RemoteClient*>::Iterator
1009 i = m_clients.getIterator();
1010 i.atEnd() == false; i++)
1012 // Get client and check that it is valid
1013 RemoteClient *client = i.getNode()->getValue();
1014 assert(client->peer_id == i.getNode()->getKey());
1015 if(client->serialization_version == SER_FMT_VER_INVALID)
1019 SendChatMessage(client->peer_id, line);
1021 catch(con::PeerNotFoundException &e)
1027 JMutexAutoLock envlock(m_env_mutex);
1032 infostream<<"Server: Saving players"<<std::endl;
1033 m_env->serializePlayers(m_path_world);
1036 Save environment metadata
1038 infostream<<"Server: Saving environment metadata"<<std::endl;
1039 m_env->saveMeta(m_path_world);
1051 JMutexAutoLock clientslock(m_con_mutex);
1053 for(core::map<u16, RemoteClient*>::Iterator
1054 i = m_clients.getIterator();
1055 i.atEnd() == false; i++)
1058 // NOTE: These are removed by env destructor
1060 u16 peer_id = i.getNode()->getKey();
1061 JMutexAutoLock envlock(m_env_mutex);
1062 m_env->removePlayer(peer_id);
1066 delete i.getNode()->getValue();
1070 // Delete things in the reverse order of creation
1077 // Deinitialize scripting
1078 infostream<<"Server: Deinitializing scripting"<<std::endl;
1079 script_deinit(m_lua);
1082 void Server::start(unsigned short port)
1084 DSTACK(__FUNCTION_NAME);
1085 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1087 // Stop thread if already running
1090 // Initialize connection
1091 m_con.SetTimeoutMs(30);
1095 m_thread.setRun(true);
1098 // ASCII art for the win!
1100 <<" .__ __ __ "<<std::endl
1101 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1102 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1103 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1104 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1105 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1106 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1107 actionstream<<"Server for gameid=\""<<m_gamespec.id
1108 <<"\" listening on port "<<port<<"."<<std::endl;
1113 DSTACK(__FUNCTION_NAME);
1115 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1117 // Stop threads (set run=false first so both start stopping)
1118 m_thread.setRun(false);
1119 m_emergethread.setRun(false);
1121 m_emergethread.stop();
1123 infostream<<"Server: Threads stopped"<<std::endl;
1126 void Server::step(float dtime)
1128 DSTACK(__FUNCTION_NAME);
1133 JMutexAutoLock lock(m_step_dtime_mutex);
1134 m_step_dtime += dtime;
1136 // Throw if fatal error occurred in thread
1137 std::string async_err = m_async_fatal_error.get();
1138 if(async_err != ""){
1139 throw ServerError(async_err);
1143 void Server::AsyncRunStep()
1145 DSTACK(__FUNCTION_NAME);
1147 g_profiler->add("Server::AsyncRunStep (num)", 1);
1151 JMutexAutoLock lock1(m_step_dtime_mutex);
1152 dtime = m_step_dtime;
1156 // Send blocks to clients
1163 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1165 //infostream<<"Server steps "<<dtime<<std::endl;
1166 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1169 JMutexAutoLock lock1(m_step_dtime_mutex);
1170 m_step_dtime -= dtime;
1177 m_uptime.set(m_uptime.get() + dtime);
1181 // Process connection's timeouts
1182 JMutexAutoLock lock2(m_con_mutex);
1183 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1184 m_con.RunTimeouts(dtime);
1188 // This has to be called so that the client list gets synced
1189 // with the peer list of the connection
1190 handlePeerChanges();
1194 Update time of day and overall game time
1197 JMutexAutoLock envlock(m_env_mutex);
1199 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1202 Send to clients at constant intervals
1205 m_time_of_day_send_timer -= dtime;
1206 if(m_time_of_day_send_timer < 0.0)
1208 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1210 //JMutexAutoLock envlock(m_env_mutex);
1211 JMutexAutoLock conlock(m_con_mutex);
1213 for(core::map<u16, RemoteClient*>::Iterator
1214 i = m_clients.getIterator();
1215 i.atEnd() == false; i++)
1217 RemoteClient *client = i.getNode()->getValue();
1218 //Player *player = m_env->getPlayer(client->peer_id);
1220 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1221 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1223 m_con.Send(client->peer_id, 0, data, true);
1229 JMutexAutoLock lock(m_env_mutex);
1231 ScopeProfiler sp(g_profiler, "SEnv step");
1232 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1236 const float map_timer_and_unload_dtime = 2.92;
1237 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1239 JMutexAutoLock lock(m_env_mutex);
1240 // Run Map's timers and unload unused data
1241 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1242 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1243 g_settings->getFloat("server_unload_unused_data_timeout"));
1254 JMutexAutoLock lock(m_env_mutex);
1255 JMutexAutoLock lock2(m_con_mutex);
1257 ScopeProfiler sp(g_profiler, "Server: handle players");
1259 //float player_max_speed = BS * 4.0; // Normal speed
1260 float player_max_speed = BS * 20; // Fast speed
1261 float player_max_speed_up = BS * 20;
1263 player_max_speed *= 2.5; // Tolerance
1264 player_max_speed_up *= 2.5;
1266 for(core::map<u16, RemoteClient*>::Iterator
1267 i = m_clients.getIterator();
1268 i.atEnd() == false; i++)
1270 RemoteClient *client = i.getNode()->getValue();
1271 ServerRemotePlayer *player =
1272 static_cast<ServerRemotePlayer*>
1273 (m_env->getPlayer(client->peer_id));
1278 Check player movements
1280 NOTE: Actually the server should handle player physics like the
1281 client does and compare player's position to what is calculated
1282 on our side. This is required when eg. players fly due to an
1285 player->m_last_good_position_age += dtime;
1286 if(player->m_last_good_position_age >= 1.0){
1287 float age = player->m_last_good_position_age;
1288 v3f diff = (player->getPosition() - player->m_last_good_position);
1289 float d_vert = diff.Y;
1291 float d_horiz = diff.getLength();
1292 /*infostream<<player->getName()<<"'s horizontal speed is "
1293 <<(d_horiz/age)<<std::endl;*/
1294 if(d_horiz <= age * player_max_speed &&
1295 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1296 player->m_last_good_position = player->getPosition();
1298 actionstream<<"Player "<<player->getName()
1299 <<" moved too fast; resetting position"
1301 player->setPosition(player->m_last_good_position);
1302 SendMovePlayer(player);
1304 player->m_last_good_position_age = 0;
1308 Handle player HPs (die if hp=0)
1310 if(player->hp == 0 && player->m_hp_not_sent)
1314 Send player inventories and HPs if necessary
1316 if(player->m_inventory_not_sent){
1317 UpdateCrafting(player->peer_id);
1318 SendInventory(player->peer_id);
1320 if(player->m_hp_not_sent){
1321 SendPlayerHP(player);
1327 if(!player->m_is_in_environment){
1328 player->m_removed = false;
1330 m_env->addActiveObject(player);
1335 /* Transform liquids */
1336 m_liquid_transform_timer += dtime;
1337 if(m_liquid_transform_timer >= 1.00)
1339 m_liquid_transform_timer -= 1.00;
1341 JMutexAutoLock lock(m_env_mutex);
1343 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1345 core::map<v3s16, MapBlock*> modified_blocks;
1346 m_env->getMap().transformLiquids(modified_blocks);
1351 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1352 ServerMap &map = ((ServerMap&)m_env->getMap());
1353 map.updateLighting(modified_blocks, lighting_modified_blocks);
1355 // Add blocks modified by lighting to modified_blocks
1356 for(core::map<v3s16, MapBlock*>::Iterator
1357 i = lighting_modified_blocks.getIterator();
1358 i.atEnd() == false; i++)
1360 MapBlock *block = i.getNode()->getValue();
1361 modified_blocks.insert(block->getPos(), block);
1365 Set the modified blocks unsent for all the clients
1368 JMutexAutoLock lock2(m_con_mutex);
1370 for(core::map<u16, RemoteClient*>::Iterator
1371 i = m_clients.getIterator();
1372 i.atEnd() == false; i++)
1374 RemoteClient *client = i.getNode()->getValue();
1376 if(modified_blocks.size() > 0)
1378 // Remove block from sent history
1379 client->SetBlocksNotSent(modified_blocks);
1384 // Periodically print some info
1386 float &counter = m_print_info_timer;
1392 JMutexAutoLock lock2(m_con_mutex);
1394 if(m_clients.size() != 0)
1395 infostream<<"Players:"<<std::endl;
1396 for(core::map<u16, RemoteClient*>::Iterator
1397 i = m_clients.getIterator();
1398 i.atEnd() == false; i++)
1400 //u16 peer_id = i.getNode()->getKey();
1401 RemoteClient *client = i.getNode()->getValue();
1402 Player *player = m_env->getPlayer(client->peer_id);
1405 infostream<<"* "<<player->getName()<<"\t";
1406 client->PrintInfo(infostream);
1411 //if(g_settings->getBool("enable_experimental"))
1415 Check added and deleted active objects
1418 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1419 JMutexAutoLock envlock(m_env_mutex);
1420 JMutexAutoLock conlock(m_con_mutex);
1422 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1424 // Radius inside which objects are active
1425 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1426 radius *= MAP_BLOCKSIZE;
1428 for(core::map<u16, RemoteClient*>::Iterator
1429 i = m_clients.getIterator();
1430 i.atEnd() == false; i++)
1432 RemoteClient *client = i.getNode()->getValue();
1434 // If definitions and textures have not been sent, don't
1435 // send objects either
1436 if(!client->definitions_sent)
1439 Player *player = m_env->getPlayer(client->peer_id);
1442 // This can happen if the client timeouts somehow
1443 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1445 <<" has no associated player"<<std::endl;*/
1448 v3s16 pos = floatToInt(player->getPosition(), BS);
1450 core::map<u16, bool> removed_objects;
1451 core::map<u16, bool> added_objects;
1452 m_env->getRemovedActiveObjects(pos, radius,
1453 client->m_known_objects, removed_objects);
1454 m_env->getAddedActiveObjects(pos, radius,
1455 client->m_known_objects, added_objects);
1457 // Ignore if nothing happened
1458 if(removed_objects.size() == 0 && added_objects.size() == 0)
1460 //infostream<<"active objects: none changed"<<std::endl;
1464 std::string data_buffer;
1468 // Handle removed objects
1469 writeU16((u8*)buf, removed_objects.size());
1470 data_buffer.append(buf, 2);
1471 for(core::map<u16, bool>::Iterator
1472 i = removed_objects.getIterator();
1473 i.atEnd()==false; i++)
1476 u16 id = i.getNode()->getKey();
1477 ServerActiveObject* obj = m_env->getActiveObject(id);
1479 // Add to data buffer for sending
1480 writeU16((u8*)buf, i.getNode()->getKey());
1481 data_buffer.append(buf, 2);
1483 // Remove from known objects
1484 client->m_known_objects.remove(i.getNode()->getKey());
1486 if(obj && obj->m_known_by_count > 0)
1487 obj->m_known_by_count--;
1490 // Handle added objects
1491 writeU16((u8*)buf, added_objects.size());
1492 data_buffer.append(buf, 2);
1493 for(core::map<u16, bool>::Iterator
1494 i = added_objects.getIterator();
1495 i.atEnd()==false; i++)
1498 u16 id = i.getNode()->getKey();
1499 ServerActiveObject* obj = m_env->getActiveObject(id);
1502 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1504 infostream<<"WARNING: "<<__FUNCTION_NAME
1505 <<": NULL object"<<std::endl;
1507 type = obj->getType();
1509 // Add to data buffer for sending
1510 writeU16((u8*)buf, id);
1511 data_buffer.append(buf, 2);
1512 writeU8((u8*)buf, type);
1513 data_buffer.append(buf, 1);
1516 data_buffer.append(serializeLongString(
1517 obj->getClientInitializationData()));
1519 data_buffer.append(serializeLongString(""));
1521 // Add to known objects
1522 client->m_known_objects.insert(i.getNode()->getKey(), false);
1525 obj->m_known_by_count++;
1529 SharedBuffer<u8> reply(2 + data_buffer.size());
1530 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1531 memcpy((char*)&reply[2], data_buffer.c_str(),
1532 data_buffer.size());
1534 m_con.Send(client->peer_id, 0, reply, true);
1536 verbosestream<<"Server: Sent object remove/add: "
1537 <<removed_objects.size()<<" removed, "
1538 <<added_objects.size()<<" added, "
1539 <<"packet size is "<<reply.getSize()<<std::endl;
1544 Collect a list of all the objects known by the clients
1545 and report it back to the environment.
1548 core::map<u16, bool> all_known_objects;
1550 for(core::map<u16, RemoteClient*>::Iterator
1551 i = m_clients.getIterator();
1552 i.atEnd() == false; i++)
1554 RemoteClient *client = i.getNode()->getValue();
1555 // Go through all known objects of client
1556 for(core::map<u16, bool>::Iterator
1557 i = client->m_known_objects.getIterator();
1558 i.atEnd()==false; i++)
1560 u16 id = i.getNode()->getKey();
1561 all_known_objects[id] = true;
1565 m_env->setKnownActiveObjects(whatever);
1571 Send object messages
1574 JMutexAutoLock envlock(m_env_mutex);
1575 JMutexAutoLock conlock(m_con_mutex);
1577 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1580 // Value = data sent by object
1581 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1583 // Get active object messages from environment
1586 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1590 core::list<ActiveObjectMessage>* message_list = NULL;
1591 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1592 n = buffered_messages.find(aom.id);
1595 message_list = new core::list<ActiveObjectMessage>;
1596 buffered_messages.insert(aom.id, message_list);
1600 message_list = n->getValue();
1602 message_list->push_back(aom);
1605 // Route data to every client
1606 for(core::map<u16, RemoteClient*>::Iterator
1607 i = m_clients.getIterator();
1608 i.atEnd()==false; i++)
1610 RemoteClient *client = i.getNode()->getValue();
1611 std::string reliable_data;
1612 std::string unreliable_data;
1613 // Go through all objects in message buffer
1614 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1615 j = buffered_messages.getIterator();
1616 j.atEnd()==false; j++)
1618 // If object is not known by client, skip it
1619 u16 id = j.getNode()->getKey();
1620 if(client->m_known_objects.find(id) == NULL)
1622 // Get message list of object
1623 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1624 // Go through every message
1625 for(core::list<ActiveObjectMessage>::Iterator
1626 k = list->begin(); k != list->end(); k++)
1628 // Compose the full new data with header
1629 ActiveObjectMessage aom = *k;
1630 std::string new_data;
1633 writeU16((u8*)&buf[0], aom.id);
1634 new_data.append(buf, 2);
1636 new_data += serializeString(aom.datastring);
1637 // Add data to buffer
1639 reliable_data += new_data;
1641 unreliable_data += new_data;
1645 reliable_data and unreliable_data are now ready.
1648 if(reliable_data.size() > 0)
1650 SharedBuffer<u8> reply(2 + reliable_data.size());
1651 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1652 memcpy((char*)&reply[2], reliable_data.c_str(),
1653 reliable_data.size());
1655 m_con.Send(client->peer_id, 0, reply, true);
1657 if(unreliable_data.size() > 0)
1659 SharedBuffer<u8> reply(2 + unreliable_data.size());
1660 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1661 memcpy((char*)&reply[2], unreliable_data.c_str(),
1662 unreliable_data.size());
1663 // Send as unreliable
1664 m_con.Send(client->peer_id, 0, reply, false);
1667 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1669 infostream<<"Server: Size of object message data: "
1670 <<"reliable: "<<reliable_data.size()
1671 <<", unreliable: "<<unreliable_data.size()
1676 // Clear buffered_messages
1677 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1678 i = buffered_messages.getIterator();
1679 i.atEnd()==false; i++)
1681 delete i.getNode()->getValue();
1685 } // enable_experimental
1688 Send queued-for-sending map edit events.
1691 // Don't send too many at a time
1694 // Single change sending is disabled if queue size is not small
1695 bool disable_single_change_sending = false;
1696 if(m_unsent_map_edit_queue.size() >= 4)
1697 disable_single_change_sending = true;
1699 int event_count = m_unsent_map_edit_queue.size();
1701 // We'll log the amount of each
1704 while(m_unsent_map_edit_queue.size() != 0)
1706 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1708 // Players far away from the change are stored here.
1709 // Instead of sending the changes, MapBlocks are set not sent
1711 core::list<u16> far_players;
1713 if(event->type == MEET_ADDNODE)
1715 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1716 prof.add("MEET_ADDNODE", 1);
1717 if(disable_single_change_sending)
1718 sendAddNode(event->p, event->n, event->already_known_by_peer,
1721 sendAddNode(event->p, event->n, event->already_known_by_peer,
1724 else if(event->type == MEET_REMOVENODE)
1726 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1727 prof.add("MEET_REMOVENODE", 1);
1728 if(disable_single_change_sending)
1729 sendRemoveNode(event->p, event->already_known_by_peer,
1732 sendRemoveNode(event->p, event->already_known_by_peer,
1735 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1737 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1738 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1739 setBlockNotSent(event->p);
1741 else if(event->type == MEET_OTHER)
1743 infostream<<"Server: MEET_OTHER"<<std::endl;
1744 prof.add("MEET_OTHER", 1);
1745 for(core::map<v3s16, bool>::Iterator
1746 i = event->modified_blocks.getIterator();
1747 i.atEnd()==false; i++)
1749 v3s16 p = i.getNode()->getKey();
1755 prof.add("unknown", 1);
1756 infostream<<"WARNING: Server: Unknown MapEditEvent "
1757 <<((u32)event->type)<<std::endl;
1761 Set blocks not sent to far players
1763 if(far_players.size() > 0)
1765 // Convert list format to that wanted by SetBlocksNotSent
1766 core::map<v3s16, MapBlock*> modified_blocks2;
1767 for(core::map<v3s16, bool>::Iterator
1768 i = event->modified_blocks.getIterator();
1769 i.atEnd()==false; i++)
1771 v3s16 p = i.getNode()->getKey();
1772 modified_blocks2.insert(p,
1773 m_env->getMap().getBlockNoCreateNoEx(p));
1775 // Set blocks not sent
1776 for(core::list<u16>::Iterator
1777 i = far_players.begin();
1778 i != far_players.end(); i++)
1781 RemoteClient *client = getClient(peer_id);
1784 client->SetBlocksNotSent(modified_blocks2);
1790 /*// Don't send too many at a time
1792 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1796 if(event_count >= 5){
1797 infostream<<"Server: MapEditEvents:"<<std::endl;
1798 prof.print(infostream);
1799 } else if(event_count != 0){
1800 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1801 prof.print(verbosestream);
1807 Trigger emergethread (it somehow gets to a non-triggered but
1808 bysy state sometimes)
1811 float &counter = m_emergethread_trigger_timer;
1817 m_emergethread.trigger();
1821 // Save map, players and auth stuff
1823 float &counter = m_savemap_timer;
1825 if(counter >= g_settings->getFloat("server_map_save_interval"))
1828 JMutexAutoLock lock(m_env_mutex);
1830 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1833 if(m_authmanager.isModified())
1834 m_authmanager.save();
1837 if(m_banmanager.isModified())
1838 m_banmanager.save();
1840 // Save changed parts of map
1841 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1844 m_env->serializePlayers(m_path_world);
1846 // Save environment metadata
1847 m_env->saveMeta(m_path_world);
1852 void Server::Receive()
1854 DSTACK(__FUNCTION_NAME);
1855 SharedBuffer<u8> data;
1860 JMutexAutoLock conlock(m_con_mutex);
1861 datasize = m_con.Receive(peer_id, data);
1864 // This has to be called so that the client list gets synced
1865 // with the peer list of the connection
1866 handlePeerChanges();
1868 ProcessData(*data, datasize, peer_id);
1870 catch(con::InvalidIncomingDataException &e)
1872 infostream<<"Server::Receive(): "
1873 "InvalidIncomingDataException: what()="
1874 <<e.what()<<std::endl;
1876 catch(con::PeerNotFoundException &e)
1878 //NOTE: This is not needed anymore
1880 // The peer has been disconnected.
1881 // Find the associated player and remove it.
1883 /*JMutexAutoLock envlock(m_env_mutex);
1885 infostream<<"ServerThread: peer_id="<<peer_id
1886 <<" has apparently closed connection. "
1887 <<"Removing player."<<std::endl;
1889 m_env->removePlayer(peer_id);*/
1893 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1895 DSTACK(__FUNCTION_NAME);
1896 // Environment is locked first.
1897 JMutexAutoLock envlock(m_env_mutex);
1898 JMutexAutoLock conlock(m_con_mutex);
1900 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1903 Address address = m_con.GetPeerAddress(peer_id);
1904 std::string addr_s = address.serializeString();
1906 // drop player if is ip is banned
1907 if(m_banmanager.isIpBanned(addr_s)){
1908 infostream<<"Server: A banned client tried to connect from "
1909 <<addr_s<<"; banned name was "
1910 <<m_banmanager.getBanName(addr_s)<<std::endl;
1911 // This actually doesn't seem to transfer to the client
1912 SendAccessDenied(m_con, peer_id,
1913 L"Your ip is banned. Banned name was "
1914 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1915 m_con.DeletePeer(peer_id);
1919 catch(con::PeerNotFoundException &e)
1921 infostream<<"Server::ProcessData(): Cancelling: peer "
1922 <<peer_id<<" not found"<<std::endl;
1926 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1928 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1936 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1938 if(command == TOSERVER_INIT)
1940 // [0] u16 TOSERVER_INIT
1941 // [2] u8 SER_FMT_VER_HIGHEST
1942 // [3] u8[20] player_name
1943 // [23] u8[28] password <--- can be sent without this, from old versions
1945 if(datasize < 2+1+PLAYERNAME_SIZE)
1948 verbosestream<<"Server: Got TOSERVER_INIT from "
1949 <<peer_id<<std::endl;
1951 // First byte after command is maximum supported
1952 // serialization version
1953 u8 client_max = data[2];
1954 u8 our_max = SER_FMT_VER_HIGHEST;
1955 // Use the highest version supported by both
1956 u8 deployed = core::min_(client_max, our_max);
1957 // If it's lower than the lowest supported, give up.
1958 if(deployed < SER_FMT_VER_LOWEST)
1959 deployed = SER_FMT_VER_INVALID;
1961 //peer->serialization_version = deployed;
1962 getClient(peer_id)->pending_serialization_version = deployed;
1964 if(deployed == SER_FMT_VER_INVALID)
1966 actionstream<<"Server: A mismatched client tried to connect from "
1967 <<addr_s<<std::endl;
1968 infostream<<"Server: Cannot negotiate "
1969 "serialization version with peer "
1970 <<peer_id<<std::endl;
1971 SendAccessDenied(m_con, peer_id, std::wstring(
1972 L"Your client's version is not supported.\n"
1973 L"Server version is ")
1974 + narrow_to_wide(VERSION_STRING) + L"."
1980 Read and check network protocol version
1983 u16 net_proto_version = 0;
1984 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1986 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1989 getClient(peer_id)->net_proto_version = net_proto_version;
1991 if(net_proto_version == 0)
1993 actionstream<<"Server: An old tried to connect from "<<addr_s
1995 SendAccessDenied(m_con, peer_id, std::wstring(
1996 L"Your client's version is not supported.\n"
1997 L"Server version is ")
1998 + narrow_to_wide(VERSION_STRING) + L"."
2003 if(g_settings->getBool("strict_protocol_version_checking"))
2005 if(net_proto_version != PROTOCOL_VERSION)
2007 actionstream<<"Server: A mismatched client tried to connect"
2008 <<" from "<<addr_s<<std::endl;
2009 SendAccessDenied(m_con, peer_id, std::wstring(
2010 L"Your client's version is not supported.\n"
2011 L"Server version is ")
2012 + narrow_to_wide(VERSION_STRING) + L",\n"
2013 + L"server's PROTOCOL_VERSION is "
2014 + narrow_to_wide(itos(PROTOCOL_VERSION))
2015 + L", client's PROTOCOL_VERSION is "
2016 + narrow_to_wide(itos(net_proto_version))
2027 char playername[PLAYERNAME_SIZE];
2028 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2030 playername[i] = data[3+i];
2032 playername[PLAYERNAME_SIZE-1] = 0;
2034 if(playername[0]=='\0')
2036 actionstream<<"Server: Player with an empty name "
2037 <<"tried to connect from "<<addr_s<<std::endl;
2038 SendAccessDenied(m_con, peer_id,
2043 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2045 actionstream<<"Server: Player with an invalid name "
2046 <<"tried to connect from "<<addr_s<<std::endl;
2047 SendAccessDenied(m_con, peer_id,
2048 L"Name contains unallowed characters");
2052 infostream<<"Server: New connection: \""<<playername<<"\" from "
2053 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2056 char password[PASSWORD_SIZE];
2057 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2059 // old version - assume blank password
2064 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2066 password[i] = data[23+i];
2068 password[PASSWORD_SIZE-1] = 0;
2071 // Add player to auth manager
2072 if(m_authmanager.exists(playername) == false)
2074 std::wstring default_password =
2075 narrow_to_wide(g_settings->get("default_password"));
2076 std::string translated_default_password =
2077 translatePassword(playername, default_password);
2079 // If default_password is empty, allow any initial password
2080 if (default_password.length() == 0)
2081 translated_default_password = password;
2083 infostream<<"Server: adding player "<<playername
2084 <<" to auth manager"<<std::endl;
2085 m_authmanager.add(playername);
2086 m_authmanager.setPassword(playername, translated_default_password);
2087 m_authmanager.setPrivs(playername,
2088 stringToPrivs(g_settings->get("default_privs")));
2089 m_authmanager.save();
2092 std::string checkpwd = m_authmanager.getPassword(playername);
2094 /*infostream<<"Server: Client gave password '"<<password
2095 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2097 if(password != checkpwd)
2099 infostream<<"Server: peer_id="<<peer_id
2100 <<": supplied invalid password for "
2101 <<playername<<std::endl;
2102 SendAccessDenied(m_con, peer_id, L"Invalid password");
2106 // Do not allow multiple players in simple singleplayer mode.
2107 // This isn't a perfect way to do it, but will suffice for now.
2108 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2109 infostream<<"Server: Not allowing another client to connect in"
2110 <<" simple singleplayer mode"<<std::endl;
2111 SendAccessDenied(m_con, peer_id,
2112 L"Running in simple singleplayer mode.");
2116 // Enforce user limit.
2117 // Don't enforce for users that have some admin right
2118 if(m_clients.size() >= g_settings->getU16("max_users") &&
2119 (m_authmanager.getPrivs(playername)
2120 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2121 playername != g_settings->get("name"))
2123 actionstream<<"Server: "<<playername<<" tried to join, but there"
2124 <<" are already max_users="
2125 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2126 SendAccessDenied(m_con, peer_id, L"Too many users.");
2131 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2133 // If failed, cancel
2136 errorstream<<"Server: peer_id="<<peer_id
2137 <<": failed to emerge player"<<std::endl;
2142 Answer with a TOCLIENT_INIT
2145 SharedBuffer<u8> reply(2+1+6+8);
2146 writeU16(&reply[0], TOCLIENT_INIT);
2147 writeU8(&reply[2], deployed);
2148 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2149 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2152 m_con.Send(peer_id, 0, reply, true);
2156 Send complete position information
2158 SendMovePlayer(player);
2163 if(command == TOSERVER_INIT2)
2165 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2166 <<peer_id<<std::endl;
2169 getClient(peer_id)->serialization_version
2170 = getClient(peer_id)->pending_serialization_version;
2173 Send some initialization data
2176 infostream<<"Server: Sending content to "
2177 <<getPlayerName(peer_id)<<std::endl;
2179 // Send item definitions
2180 SendItemDef(m_con, peer_id, m_itemdef);
2182 // Send node definitions
2183 SendNodeDef(m_con, peer_id, m_nodedef);
2185 // Send texture announcement
2186 SendTextureAnnouncement(peer_id);
2188 // Send player info to all players
2189 //SendPlayerInfos();
2191 // Send inventory to player
2192 UpdateCrafting(peer_id);
2193 SendInventory(peer_id);
2195 // Send player items to all players
2198 Player *player = m_env->getPlayer(peer_id);
2201 SendPlayerHP(player);
2203 // Show death screen if necessary
2205 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2209 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2210 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2211 m_con.Send(peer_id, 0, data, true);
2214 // Note things in chat if not in simple singleplayer mode
2215 if(!m_simple_singleplayer_mode)
2217 // Send information about server to player in chat
2218 SendChatMessage(peer_id, getStatusString());
2220 // Send information about joining in chat
2222 std::wstring name = L"unknown";
2223 Player *player = m_env->getPlayer(peer_id);
2225 name = narrow_to_wide(player->getName());
2227 std::wstring message;
2230 message += L" joined game";
2231 BroadcastChatMessage(message);
2235 // Warnings about protocol version can be issued here
2236 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2238 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2245 std::ostringstream os(std::ios_base::binary);
2246 for(core::map<u16, RemoteClient*>::Iterator
2247 i = m_clients.getIterator();
2248 i.atEnd() == false; i++)
2250 RemoteClient *client = i.getNode()->getValue();
2251 assert(client->peer_id == i.getNode()->getKey());
2252 if(client->serialization_version == SER_FMT_VER_INVALID)
2255 Player *player = m_env->getPlayer(client->peer_id);
2258 // Get name of player
2259 os<<player->getName()<<" ";
2262 actionstream<<player->getName()<<" joins game. List of players: "
2263 <<os.str()<<std::endl;
2269 if(peer_ser_ver == SER_FMT_VER_INVALID)
2271 infostream<<"Server::ProcessData(): Cancelling: Peer"
2272 " serialization format invalid or not initialized."
2273 " Skipping incoming command="<<command<<std::endl;
2277 Player *player = m_env->getPlayer(peer_id);
2278 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2281 infostream<<"Server::ProcessData(): Cancelling: "
2282 "No player for peer_id="<<peer_id
2286 if(command == TOSERVER_PLAYERPOS)
2288 if(datasize < 2+12+12+4+4)
2292 v3s32 ps = readV3S32(&data[start+2]);
2293 v3s32 ss = readV3S32(&data[start+2+12]);
2294 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2295 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2296 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2297 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2298 pitch = wrapDegrees(pitch);
2299 yaw = wrapDegrees(yaw);
2301 player->setPosition(position);
2302 player->setSpeed(speed);
2303 player->setPitch(pitch);
2304 player->setYaw(yaw);
2306 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2307 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2308 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2310 else if(command == TOSERVER_GOTBLOCKS)
2323 u16 count = data[2];
2324 for(u16 i=0; i<count; i++)
2326 if((s16)datasize < 2+1+(i+1)*6)
2327 throw con::InvalidIncomingDataException
2328 ("GOTBLOCKS length is too short");
2329 v3s16 p = readV3S16(&data[2+1+i*6]);
2330 /*infostream<<"Server: GOTBLOCKS ("
2331 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2332 RemoteClient *client = getClient(peer_id);
2333 client->GotBlock(p);
2336 else if(command == TOSERVER_DELETEDBLOCKS)
2349 u16 count = data[2];
2350 for(u16 i=0; i<count; i++)
2352 if((s16)datasize < 2+1+(i+1)*6)
2353 throw con::InvalidIncomingDataException
2354 ("DELETEDBLOCKS length is too short");
2355 v3s16 p = readV3S16(&data[2+1+i*6]);
2356 /*infostream<<"Server: DELETEDBLOCKS ("
2357 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2358 RemoteClient *client = getClient(peer_id);
2359 client->SetBlockNotSent(p);
2362 else if(command == TOSERVER_CLICK_OBJECT)
2364 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2367 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2369 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2372 else if(command == TOSERVER_GROUND_ACTION)
2374 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2378 else if(command == TOSERVER_RELEASE)
2380 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2383 else if(command == TOSERVER_SIGNTEXT)
2385 infostream<<"Server: SIGNTEXT not supported anymore"
2389 else if(command == TOSERVER_SIGNNODETEXT)
2391 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2399 std::string datastring((char*)&data[2], datasize-2);
2400 std::istringstream is(datastring, std::ios_base::binary);
2403 is.read((char*)buf, 6);
2404 v3s16 p = readV3S16(buf);
2405 is.read((char*)buf, 2);
2406 u16 textlen = readU16(buf);
2408 for(u16 i=0; i<textlen; i++)
2410 is.read((char*)buf, 1);
2411 text += (char)buf[0];
2414 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2418 meta->setText(text);
2420 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2421 <<" at "<<PP(p)<<std::endl;
2423 v3s16 blockpos = getNodeBlockPos(p);
2424 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2427 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2431 setBlockNotSent(blockpos);
2433 else if(command == TOSERVER_INVENTORY_ACTION)
2435 // Strip command and create a stream
2436 std::string datastring((char*)&data[2], datasize-2);
2437 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2438 std::istringstream is(datastring, std::ios_base::binary);
2440 InventoryAction *a = InventoryAction::deSerialize(is);
2443 infostream<<"TOSERVER_INVENTORY_ACTION: "
2444 <<"InventoryAction::deSerialize() returned NULL"
2450 Note: Always set inventory not sent, to repair cases
2451 where the client made a bad prediction.
2455 Handle restrictions and special cases of the move action
2457 if(a->getType() == IACTION_MOVE)
2459 IMoveAction *ma = (IMoveAction*)a;
2461 ma->from_inv.applyCurrentPlayer(player->getName());
2462 ma->to_inv.applyCurrentPlayer(player->getName());
2464 setInventoryModified(ma->from_inv);
2465 setInventoryModified(ma->to_inv);
2467 bool from_inv_is_current_player =
2468 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2469 (ma->from_inv.name == player->getName());
2471 bool to_inv_is_current_player =
2472 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2473 (ma->to_inv.name == player->getName());
2476 Disable moving items out of craftpreview
2478 if(ma->from_list == "craftpreview")
2480 infostream<<"Ignoring IMoveAction from "
2481 <<(ma->from_inv.dump())<<":"<<ma->from_list
2482 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2483 <<" because src is "<<ma->from_list<<std::endl;
2489 Disable moving items into craftresult and craftpreview
2491 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2493 infostream<<"Ignoring IMoveAction from "
2494 <<(ma->from_inv.dump())<<":"<<ma->from_list
2495 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2496 <<" because dst is "<<ma->to_list<<std::endl;
2501 // Disallow moving items in elsewhere than player's inventory
2502 // if not allowed to interact
2503 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2504 && (!from_inv_is_current_player
2505 || !to_inv_is_current_player))
2507 infostream<<"Cannot move outside of player's inventory: "
2508 <<"No interact privilege"<<std::endl;
2513 // If player is not an admin, check for ownership of src and dst
2514 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2516 std::string owner_from = getInventoryOwner(ma->from_inv);
2517 if(owner_from != "" && owner_from != player->getName())
2519 infostream<<"WARNING: "<<player->getName()
2520 <<" tried to access an inventory that"
2521 <<" belongs to "<<owner_from<<std::endl;
2526 std::string owner_to = getInventoryOwner(ma->to_inv);
2527 if(owner_to != "" && owner_to != player->getName())
2529 infostream<<"WARNING: "<<player->getName()
2530 <<" tried to access an inventory that"
2531 <<" belongs to "<<owner_to<<std::endl;
2538 Handle restrictions and special cases of the drop action
2540 else if(a->getType() == IACTION_DROP)
2542 IDropAction *da = (IDropAction*)a;
2544 da->from_inv.applyCurrentPlayer(player->getName());
2546 setInventoryModified(da->from_inv);
2548 // Disallow dropping items if not allowed to interact
2549 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2554 // If player is not an admin, check for ownership
2555 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2557 std::string owner_from = getInventoryOwner(da->from_inv);
2558 if(owner_from != "" && owner_from != player->getName())
2560 infostream<<"WARNING: "<<player->getName()
2561 <<" tried to access an inventory that"
2562 <<" belongs to "<<owner_from<<std::endl;
2569 Handle restrictions and special cases of the craft action
2571 else if(a->getType() == IACTION_CRAFT)
2573 ICraftAction *ca = (ICraftAction*)a;
2575 ca->craft_inv.applyCurrentPlayer(player->getName());
2577 setInventoryModified(ca->craft_inv);
2579 //bool craft_inv_is_current_player =
2580 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2581 // (ca->craft_inv.name == player->getName());
2583 // Disallow crafting if not allowed to interact
2584 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2586 infostream<<"Cannot craft: "
2587 <<"No interact privilege"<<std::endl;
2592 // If player is not an admin, check for ownership of inventory
2593 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2595 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2596 if(owner_craft != "" && owner_craft != player->getName())
2598 infostream<<"WARNING: "<<player->getName()
2599 <<" tried to access an inventory that"
2600 <<" belongs to "<<owner_craft<<std::endl;
2608 a->apply(this, srp, this);
2612 else if(command == TOSERVER_CHAT_MESSAGE)
2620 std::string datastring((char*)&data[2], datasize-2);
2621 std::istringstream is(datastring, std::ios_base::binary);
2624 is.read((char*)buf, 2);
2625 u16 len = readU16(buf);
2627 std::wstring message;
2628 for(u16 i=0; i<len; i++)
2630 is.read((char*)buf, 2);
2631 message += (wchar_t)readU16(buf);
2634 // Get player name of this client
2635 std::wstring name = narrow_to_wide(player->getName());
2638 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2639 wide_to_narrow(message));
2640 // If script ate the message, don't proceed
2644 // Line to send to players
2646 // Whether to send to the player that sent the line
2647 bool send_to_sender = false;
2648 // Whether to send to other players
2649 bool send_to_others = false;
2651 // Local player gets all privileges regardless of
2652 // what's set on their account.
2653 u64 privs = getPlayerPrivs(player);
2656 if(message[0] == L'/')
2658 size_t strip_size = 1;
2659 if (message[1] == L'#') // support old-style commans
2661 message = message.substr(strip_size);
2663 WStrfnd f1(message);
2664 f1.next(L" "); // Skip over /#whatever
2665 std::wstring paramstring = f1.next(L"");
2667 ServerCommandContext *ctx = new ServerCommandContext(
2668 str_split(message, L' '),
2675 std::wstring reply(processServerCommand(ctx));
2676 send_to_sender = ctx->flags & SEND_TO_SENDER;
2677 send_to_others = ctx->flags & SEND_TO_OTHERS;
2679 if (ctx->flags & SEND_NO_PREFIX)
2682 line += L"Server: " + reply;
2689 if(privs & PRIV_SHOUT)
2695 send_to_others = true;
2699 line += L"Server: You are not allowed to shout";
2700 send_to_sender = true;
2707 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2710 Send the message to clients
2712 for(core::map<u16, RemoteClient*>::Iterator
2713 i = m_clients.getIterator();
2714 i.atEnd() == false; i++)
2716 // Get client and check that it is valid
2717 RemoteClient *client = i.getNode()->getValue();
2718 assert(client->peer_id == i.getNode()->getKey());
2719 if(client->serialization_version == SER_FMT_VER_INVALID)
2723 bool sender_selected = (peer_id == client->peer_id);
2724 if(sender_selected == true && send_to_sender == false)
2726 if(sender_selected == false && send_to_others == false)
2729 SendChatMessage(client->peer_id, line);
2733 else if(command == TOSERVER_DAMAGE)
2735 std::string datastring((char*)&data[2], datasize-2);
2736 std::istringstream is(datastring, std::ios_base::binary);
2737 u8 damage = readU8(is);
2739 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2741 if(g_settings->getBool("enable_damage"))
2743 actionstream<<player->getName()<<" damaged by "
2744 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2747 srp->setHP(srp->getHP() - damage);
2749 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2752 if(srp->m_hp_not_sent)
2753 SendPlayerHP(player);
2757 // Force send (to correct the client's predicted HP)
2758 SendPlayerHP(player);
2761 else if(command == TOSERVER_PASSWORD)
2764 [0] u16 TOSERVER_PASSWORD
2765 [2] u8[28] old password
2766 [30] u8[28] new password
2769 if(datasize != 2+PASSWORD_SIZE*2)
2771 /*char password[PASSWORD_SIZE];
2772 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2773 password[i] = data[2+i];
2774 password[PASSWORD_SIZE-1] = 0;*/
2776 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2784 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2786 char c = data[2+PASSWORD_SIZE+i];
2792 infostream<<"Server: Client requests a password change from "
2793 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2795 std::string playername = player->getName();
2797 if(m_authmanager.exists(playername) == false)
2799 infostream<<"Server: playername not found in authmanager"<<std::endl;
2800 // Wrong old password supplied!!
2801 SendChatMessage(peer_id, L"playername not found in authmanager");
2805 std::string checkpwd = m_authmanager.getPassword(playername);
2807 if(oldpwd != checkpwd)
2809 infostream<<"Server: invalid old password"<<std::endl;
2810 // Wrong old password supplied!!
2811 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2815 actionstream<<player->getName()<<" changes password"<<std::endl;
2817 m_authmanager.setPassword(playername, newpwd);
2819 infostream<<"Server: password change successful for "<<playername
2821 SendChatMessage(peer_id, L"Password change successful");
2823 else if(command == TOSERVER_PLAYERITEM)
2828 u16 item = readU16(&data[2]);
2829 srp->setWieldIndex(item);
2830 SendWieldedItem(srp);
2832 else if(command == TOSERVER_RESPAWN)
2837 RespawnPlayer(player);
2839 actionstream<<player->getName()<<" respawns at "
2840 <<PP(player->getPosition()/BS)<<std::endl;
2842 // ActiveObject is added to environment in AsyncRunStep after
2843 // the previous addition has been succesfully removed
2845 else if(command == TOSERVER_REQUEST_TEXTURES) {
2846 std::string datastring((char*)&data[2], datasize-2);
2847 std::istringstream is(datastring, std::ios_base::binary);
2850 core::list<TextureRequest> tosend;
2851 u16 numtextures = readU16(is);
2853 infostream<<"Sending "<<numtextures<<" textures to "
2854 <<getPlayerName(peer_id)<<std::endl;
2855 verbosestream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2857 for(int i = 0; i < numtextures; i++) {
2858 std::string name = deSerializeString(is);
2859 tosend.push_back(TextureRequest(name));
2860 verbosestream<<"TOSERVER_REQUEST_TEXTURES: requested texture "
2864 SendTexturesRequested(peer_id, tosend);
2866 // Now the client should know about everything
2867 // (definitions and textures)
2868 getClient(peer_id)->definitions_sent = true;
2870 else if(command == TOSERVER_INTERACT)
2872 std::string datastring((char*)&data[2], datasize-2);
2873 std::istringstream is(datastring, std::ios_base::binary);
2879 [5] u32 length of the next item
2880 [9] serialized PointedThing
2882 0: start digging (from undersurface) or use
2883 1: stop digging (all parameters ignored)
2884 2: digging completed
2885 3: place block or item (to abovesurface)
2888 u8 action = readU8(is);
2889 u16 item_i = readU16(is);
2890 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2891 PointedThing pointed;
2892 pointed.deSerialize(tmp_is);
2894 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2895 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2899 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2900 <<" tried to interact, but is dead!"<<std::endl;
2904 v3f player_pos = srp->m_last_good_position;
2906 // Update wielded item
2907 if(srp->getWieldIndex() != item_i)
2909 srp->setWieldIndex(item_i);
2910 SendWieldedItem(srp);
2913 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2914 v3s16 p_under = pointed.node_undersurface;
2915 v3s16 p_above = pointed.node_abovesurface;
2917 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2918 ServerActiveObject *pointed_object = NULL;
2919 if(pointed.type == POINTEDTHING_OBJECT)
2921 pointed_object = m_env->getActiveObject(pointed.object_id);
2922 if(pointed_object == NULL)
2924 verbosestream<<"TOSERVER_INTERACT: "
2925 "pointed object is NULL"<<std::endl;
2931 v3f pointed_pos_under = player_pos;
2932 v3f pointed_pos_above = player_pos;
2933 if(pointed.type == POINTEDTHING_NODE)
2935 pointed_pos_under = intToFloat(p_under, BS);
2936 pointed_pos_above = intToFloat(p_above, BS);
2938 else if(pointed.type == POINTEDTHING_OBJECT)
2940 pointed_pos_under = pointed_object->getBasePosition();
2941 pointed_pos_above = pointed_pos_under;
2945 Check that target is reasonably close
2946 (only when digging or placing things)
2948 if(action == 0 || action == 2 || action == 3)
2950 float d = player_pos.getDistanceFrom(pointed_pos_under);
2951 float max_d = BS * 14; // Just some large enough value
2953 actionstream<<"Player "<<player->getName()
2954 <<" tried to access "<<pointed.dump()
2956 <<"d="<<d<<", max_d="<<max_d
2957 <<". ignoring."<<std::endl;
2958 // Re-send block to revert change on client-side
2959 RemoteClient *client = getClient(peer_id);
2960 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2961 client->SetBlockNotSent(blockpos);
2968 Make sure the player is allowed to do it
2970 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2972 infostream<<"Ignoring interaction from player "<<player->getName()
2973 <<" because privileges are "<<getPlayerPrivs(player)
2979 0: start digging or punch object
2983 if(pointed.type == POINTEDTHING_NODE)
2986 NOTE: This can be used in the future to check if
2987 somebody is cheating, by checking the timing.
2989 MapNode n(CONTENT_IGNORE);
2992 n = m_env->getMap().getNode(p_under);
2994 catch(InvalidPositionException &e)
2996 infostream<<"Server: Not punching: Node not found."
2997 <<" Adding block to emerge queue."
2999 m_emerge_queue.addBlock(peer_id,
3000 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3002 if(n.getContent() != CONTENT_IGNORE)
3003 scriptapi_node_on_punch(m_lua, p_under, n, srp);
3005 else if(pointed.type == POINTEDTHING_OBJECT)
3007 // Skip if object has been removed
3008 if(pointed_object->m_removed)
3011 actionstream<<player->getName()<<" punches object "
3012 <<pointed.object_id<<": "
3013 <<pointed_object->getDescription()<<std::endl;
3015 ItemStack punchitem = srp->getWieldedItem();
3016 ToolCapabilities toolcap =
3017 punchitem.getToolCapabilities(m_itemdef);
3018 v3f dir = (pointed_object->getBasePosition() -
3019 (srp->getPosition() + srp->getEyeOffset())
3021 pointed_object->punch(dir, &toolcap, srp,
3022 srp->m_time_from_last_punch);
3023 srp->m_time_from_last_punch = 0;
3031 else if(action == 1)
3036 2: Digging completed
3038 else if(action == 2)
3040 // Only complete digging of nodes
3041 if(pointed.type == POINTEDTHING_NODE)
3043 MapNode n(CONTENT_IGNORE);
3046 n = m_env->getMap().getNode(p_under);
3048 catch(InvalidPositionException &e)
3050 infostream<<"Server: Not finishing digging: Node not found."
3051 <<" Adding block to emerge queue."
3053 m_emerge_queue.addBlock(peer_id,
3054 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3056 if(n.getContent() != CONTENT_IGNORE)
3057 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3062 3: place block or right-click object
3064 else if(action == 3)
3066 ItemStack item = srp->getWieldedItem();
3068 // Reset build time counter
3069 if(pointed.type == POINTEDTHING_NODE &&
3070 item.getDefinition(m_itemdef).type == ITEM_NODE)
3071 getClient(peer_id)->m_time_from_building = 0.0;
3073 if(pointed.type == POINTEDTHING_OBJECT)
3075 // Right click object
3077 // Skip if object has been removed
3078 if(pointed_object->m_removed)
3081 actionstream<<player->getName()<<" right-clicks object "
3082 <<pointed.object_id<<": "
3083 <<pointed_object->getDescription()<<std::endl;
3086 pointed_object->rightClick(srp);
3088 else if(scriptapi_item_on_place(m_lua,
3089 item, srp, pointed))
3091 // Placement was handled in lua
3093 // Apply returned ItemStack
3094 if(g_settings->getBool("creative_mode") == false)
3095 srp->setWieldedItem(item);
3103 else if(action == 4)
3105 ItemStack item = srp->getWieldedItem();
3107 actionstream<<player->getName()<<" uses "<<item.name
3108 <<", pointing at "<<pointed.dump()<<std::endl;
3110 if(scriptapi_item_on_use(m_lua,
3111 item, srp, pointed))
3113 // Apply returned ItemStack
3114 if(g_settings->getBool("creative_mode") == false)
3115 srp->setWieldedItem(item);
3121 Catch invalid actions
3125 infostream<<"WARNING: Server: Invalid action "
3126 <<action<<std::endl;
3129 else if(command == TOSERVER_REMOVED_SOUNDS)
3131 std::string datastring((char*)&data[2], datasize-2);
3132 std::istringstream is(datastring, std::ios_base::binary);
3134 int num = readU16(is);
3135 for(int k=0; k<num; k++){
3136 s32 id = readS32(is);
3137 std::map<s32, ServerPlayingSound>::iterator i =
3138 m_playing_sounds.find(id);
3139 if(i == m_playing_sounds.end())
3141 ServerPlayingSound &psound = i->second;
3142 psound.clients.erase(peer_id);
3143 if(psound.clients.size() == 0)
3144 m_playing_sounds.erase(i++);
3149 infostream<<"Server::ProcessData(): Ignoring "
3150 "unknown command "<<command<<std::endl;
3154 catch(SendFailedException &e)
3156 errorstream<<"Server::ProcessData(): SendFailedException: "
3162 void Server::onMapEditEvent(MapEditEvent *event)
3164 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3165 if(m_ignore_map_edit_events)
3167 MapEditEvent *e = event->clone();
3168 m_unsent_map_edit_queue.push_back(e);
3171 Inventory* Server::getInventory(const InventoryLocation &loc)
3174 case InventoryLocation::UNDEFINED:
3177 case InventoryLocation::CURRENT_PLAYER:
3180 case InventoryLocation::PLAYER:
3182 Player *player = m_env->getPlayer(loc.name.c_str());
3185 return &player->inventory;
3188 case InventoryLocation::NODEMETA:
3190 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3193 return meta->getInventory();
3201 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3204 case InventoryLocation::UNDEFINED:
3207 case InventoryLocation::CURRENT_PLAYER:
3210 case InventoryLocation::PLAYER:
3215 case InventoryLocation::NODEMETA:
3217 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3220 return meta->getOwner();
3228 void Server::setInventoryModified(const InventoryLocation &loc)
3231 case InventoryLocation::UNDEFINED:
3234 case InventoryLocation::PLAYER:
3236 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3237 (m_env->getPlayer(loc.name.c_str()));
3240 srp->m_inventory_not_sent = true;
3243 case InventoryLocation::NODEMETA:
3245 v3s16 blockpos = getNodeBlockPos(loc.p);
3247 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3249 meta->inventoryModified();
3251 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3253 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3255 setBlockNotSent(blockpos);
3263 core::list<PlayerInfo> Server::getPlayerInfo()
3265 DSTACK(__FUNCTION_NAME);
3266 JMutexAutoLock envlock(m_env_mutex);
3267 JMutexAutoLock conlock(m_con_mutex);
3269 core::list<PlayerInfo> list;
3271 core::list<Player*> players = m_env->getPlayers();
3273 core::list<Player*>::Iterator i;
3274 for(i = players.begin();
3275 i != players.end(); i++)
3279 Player *player = *i;
3282 // Copy info from connection to info struct
3283 info.id = player->peer_id;
3284 info.address = m_con.GetPeerAddress(player->peer_id);
3285 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3287 catch(con::PeerNotFoundException &e)
3289 // Set dummy peer info
3291 info.address = Address(0,0,0,0,0);
3295 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3296 info.position = player->getPosition();
3298 list.push_back(info);
3305 void Server::peerAdded(con::Peer *peer)
3307 DSTACK(__FUNCTION_NAME);
3308 verbosestream<<"Server::peerAdded(): peer->id="
3309 <<peer->id<<std::endl;
3312 c.type = PEER_ADDED;
3313 c.peer_id = peer->id;
3315 m_peer_change_queue.push_back(c);
3318 void Server::deletingPeer(con::Peer *peer, bool timeout)
3320 DSTACK(__FUNCTION_NAME);
3321 verbosestream<<"Server::deletingPeer(): peer->id="
3322 <<peer->id<<", timeout="<<timeout<<std::endl;
3325 c.type = PEER_REMOVED;
3326 c.peer_id = peer->id;
3327 c.timeout = timeout;
3328 m_peer_change_queue.push_back(c);
3335 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3337 DSTACK(__FUNCTION_NAME);
3338 std::ostringstream os(std::ios_base::binary);
3340 writeU16(os, TOCLIENT_HP);
3344 std::string s = os.str();
3345 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3347 con.Send(peer_id, 0, data, true);
3350 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3351 const std::wstring &reason)
3353 DSTACK(__FUNCTION_NAME);
3354 std::ostringstream os(std::ios_base::binary);
3356 writeU16(os, TOCLIENT_ACCESS_DENIED);
3357 os<<serializeWideString(reason);
3360 std::string s = os.str();
3361 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3363 con.Send(peer_id, 0, data, true);
3366 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3367 bool set_camera_point_target, v3f camera_point_target)
3369 DSTACK(__FUNCTION_NAME);
3370 std::ostringstream os(std::ios_base::binary);
3372 writeU16(os, TOCLIENT_DEATHSCREEN);
3373 writeU8(os, set_camera_point_target);
3374 writeV3F1000(os, camera_point_target);
3377 std::string s = os.str();
3378 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3380 con.Send(peer_id, 0, data, true);
3383 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3384 IItemDefManager *itemdef)
3386 DSTACK(__FUNCTION_NAME);
3387 std::ostringstream os(std::ios_base::binary);
3391 u32 length of the next item
3392 zlib-compressed serialized ItemDefManager
3394 writeU16(os, TOCLIENT_ITEMDEF);
3395 std::ostringstream tmp_os(std::ios::binary);
3396 itemdef->serialize(tmp_os);
3397 std::ostringstream tmp_os2(std::ios::binary);
3398 compressZlib(tmp_os.str(), tmp_os2);
3399 os<<serializeLongString(tmp_os2.str());
3402 std::string s = os.str();
3403 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3404 <<"): size="<<s.size()<<std::endl;
3405 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3407 con.Send(peer_id, 0, data, true);
3410 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3411 INodeDefManager *nodedef)
3413 DSTACK(__FUNCTION_NAME);
3414 std::ostringstream os(std::ios_base::binary);
3418 u32 length of the next item
3419 zlib-compressed serialized NodeDefManager
3421 writeU16(os, TOCLIENT_NODEDEF);
3422 std::ostringstream tmp_os(std::ios::binary);
3423 nodedef->serialize(tmp_os);
3424 std::ostringstream tmp_os2(std::ios::binary);
3425 compressZlib(tmp_os.str(), tmp_os2);
3426 os<<serializeLongString(tmp_os2.str());
3429 std::string s = os.str();
3430 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3431 <<"): size="<<s.size()<<std::endl;
3432 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3434 con.Send(peer_id, 0, data, true);
3438 Non-static send methods
3441 void Server::SendInventory(u16 peer_id)
3443 DSTACK(__FUNCTION_NAME);
3445 ServerRemotePlayer* player =
3446 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3449 player->m_inventory_not_sent = false;
3455 std::ostringstream os;
3456 //os.imbue(std::locale("C"));
3458 player->inventory.serialize(os);
3460 std::string s = os.str();
3462 SharedBuffer<u8> data(s.size()+2);
3463 writeU16(&data[0], TOCLIENT_INVENTORY);
3464 memcpy(&data[2], s.c_str(), s.size());
3467 m_con.Send(peer_id, 0, data, true);
3470 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3472 DSTACK(__FUNCTION_NAME);
3476 std::ostringstream os(std::ios_base::binary);
3478 writeU16(os, TOCLIENT_PLAYERITEM);
3480 writeU16(os, srp->peer_id);
3481 os<<serializeString(srp->getWieldedItem().getItemString());
3484 std::string s = os.str();
3485 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3487 m_con.SendToAll(0, data, true);
3490 void Server::SendPlayerItems()
3492 DSTACK(__FUNCTION_NAME);
3494 std::ostringstream os(std::ios_base::binary);
3495 core::list<Player *> players = m_env->getPlayers(true);
3497 writeU16(os, TOCLIENT_PLAYERITEM);
3498 writeU16(os, players.size());
3499 core::list<Player *>::Iterator i;
3500 for(i = players.begin(); i != players.end(); ++i)
3503 ServerRemotePlayer *srp =
3504 static_cast<ServerRemotePlayer*>(p);
3505 writeU16(os, p->peer_id);
3506 os<<serializeString(srp->getWieldedItem().getItemString());
3510 std::string s = os.str();
3511 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3513 m_con.SendToAll(0, data, true);
3516 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3518 DSTACK(__FUNCTION_NAME);
3520 std::ostringstream os(std::ios_base::binary);
3524 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3525 os.write((char*)buf, 2);
3528 writeU16(buf, message.size());
3529 os.write((char*)buf, 2);
3532 for(u32 i=0; i<message.size(); i++)
3536 os.write((char*)buf, 2);
3540 std::string s = os.str();
3541 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3543 m_con.Send(peer_id, 0, data, true);
3546 void Server::BroadcastChatMessage(const std::wstring &message)
3548 for(core::map<u16, RemoteClient*>::Iterator
3549 i = m_clients.getIterator();
3550 i.atEnd() == false; i++)
3552 // Get client and check that it is valid
3553 RemoteClient *client = i.getNode()->getValue();
3554 assert(client->peer_id == i.getNode()->getKey());
3555 if(client->serialization_version == SER_FMT_VER_INVALID)
3558 SendChatMessage(client->peer_id, message);
3562 void Server::SendPlayerHP(Player *player)
3564 SendHP(m_con, player->peer_id, player->hp);
3565 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3568 void Server::SendMovePlayer(Player *player)
3570 DSTACK(__FUNCTION_NAME);
3571 std::ostringstream os(std::ios_base::binary);
3573 writeU16(os, TOCLIENT_MOVE_PLAYER);
3574 writeV3F1000(os, player->getPosition());
3575 writeF1000(os, player->getPitch());
3576 writeF1000(os, player->getYaw());
3579 v3f pos = player->getPosition();
3580 f32 pitch = player->getPitch();
3581 f32 yaw = player->getYaw();
3582 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3583 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3590 std::string s = os.str();
3591 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3593 m_con.Send(player->peer_id, 0, data, true);
3596 s32 Server::playSound(const SimpleSoundSpec &spec,
3597 const ServerSoundParams ¶ms)
3599 // Find out initial position of sound
3600 bool pos_exists = false;
3601 v3f pos = params.getPos(m_env, &pos_exists);
3602 // If position is not found while it should be, cancel sound
3603 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3605 // Filter destination clients
3606 std::set<RemoteClient*> dst_clients;
3607 if(params.to_player != "")
3609 Player *player = m_env->getPlayer(params.to_player.c_str());
3611 infostream<<"Server::playSound: Player \""<<params.to_player
3612 <<"\" not found"<<std::endl;
3615 if(player->peer_id == PEER_ID_INEXISTENT){
3616 infostream<<"Server::playSound: Player \""<<params.to_player
3617 <<"\" not connected"<<std::endl;
3620 RemoteClient *client = getClient(player->peer_id);
3621 dst_clients.insert(client);
3625 for(core::map<u16, RemoteClient*>::Iterator
3626 i = m_clients.getIterator(); i.atEnd() == false; i++)
3628 RemoteClient *client = i.getNode()->getValue();
3629 Player *player = m_env->getPlayer(client->peer_id);
3633 if(player->getPosition().getDistanceFrom(pos) >
3634 params.max_hear_distance)
3637 dst_clients.insert(client);
3640 if(dst_clients.size() == 0)
3643 s32 id = m_next_sound_id++;
3644 // The sound will exist as a reference in m_playing_sounds
3645 m_playing_sounds[id] = ServerPlayingSound();
3646 ServerPlayingSound &psound = m_playing_sounds[id];
3647 psound.params = params;
3648 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3649 i != dst_clients.end(); i++)
3650 psound.clients.insert((*i)->peer_id);
3652 std::ostringstream os(std::ios_base::binary);
3653 writeU16(os, TOCLIENT_PLAY_SOUND);
3655 os<<serializeString(spec.name);
3656 writeF1000(os, spec.gain * params.gain);
3657 writeU8(os, params.type);
3658 writeV3F1000(os, pos);
3659 writeU16(os, params.object);
3660 writeU8(os, params.loop);
3662 std::string s = os.str();
3663 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3665 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3666 i != dst_clients.end(); i++){
3668 m_con.Send((*i)->peer_id, 0, data, true);
3672 void Server::stopSound(s32 handle)
3674 // Get sound reference
3675 std::map<s32, ServerPlayingSound>::iterator i =
3676 m_playing_sounds.find(handle);
3677 if(i == m_playing_sounds.end())
3679 ServerPlayingSound &psound = i->second;
3681 std::ostringstream os(std::ios_base::binary);
3682 writeU16(os, TOCLIENT_STOP_SOUND);
3683 writeS32(os, handle);
3685 std::string s = os.str();
3686 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3688 for(std::set<u16>::iterator i = psound.clients.begin();
3689 i != psound.clients.end(); i++){
3691 m_con.Send(*i, 0, data, true);
3693 // Remove sound reference
3694 m_playing_sounds.erase(i);
3697 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3698 core::list<u16> *far_players, float far_d_nodes)
3700 float maxd = far_d_nodes*BS;
3701 v3f p_f = intToFloat(p, BS);
3705 SharedBuffer<u8> reply(replysize);
3706 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3707 writeS16(&reply[2], p.X);
3708 writeS16(&reply[4], p.Y);
3709 writeS16(&reply[6], p.Z);
3711 for(core::map<u16, RemoteClient*>::Iterator
3712 i = m_clients.getIterator();
3713 i.atEnd() == false; i++)
3715 // Get client and check that it is valid
3716 RemoteClient *client = i.getNode()->getValue();
3717 assert(client->peer_id == i.getNode()->getKey());
3718 if(client->serialization_version == SER_FMT_VER_INVALID)
3721 // Don't send if it's the same one
3722 if(client->peer_id == ignore_id)
3728 Player *player = m_env->getPlayer(client->peer_id);
3731 // If player is far away, only set modified blocks not sent
3732 v3f player_pos = player->getPosition();
3733 if(player_pos.getDistanceFrom(p_f) > maxd)
3735 far_players->push_back(client->peer_id);
3742 m_con.Send(client->peer_id, 0, reply, true);
3746 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3747 core::list<u16> *far_players, float far_d_nodes)
3749 float maxd = far_d_nodes*BS;
3750 v3f p_f = intToFloat(p, BS);
3752 for(core::map<u16, RemoteClient*>::Iterator
3753 i = m_clients.getIterator();
3754 i.atEnd() == false; i++)
3756 // Get client and check that it is valid
3757 RemoteClient *client = i.getNode()->getValue();
3758 assert(client->peer_id == i.getNode()->getKey());
3759 if(client->serialization_version == SER_FMT_VER_INVALID)
3762 // Don't send if it's the same one
3763 if(client->peer_id == ignore_id)
3769 Player *player = m_env->getPlayer(client->peer_id);
3772 // If player is far away, only set modified blocks not sent
3773 v3f player_pos = player->getPosition();
3774 if(player_pos.getDistanceFrom(p_f) > maxd)
3776 far_players->push_back(client->peer_id);
3783 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3784 SharedBuffer<u8> reply(replysize);
3785 writeU16(&reply[0], TOCLIENT_ADDNODE);
3786 writeS16(&reply[2], p.X);
3787 writeS16(&reply[4], p.Y);
3788 writeS16(&reply[6], p.Z);
3789 n.serialize(&reply[8], client->serialization_version);
3792 m_con.Send(client->peer_id, 0, reply, true);
3796 void Server::setBlockNotSent(v3s16 p)
3798 for(core::map<u16, RemoteClient*>::Iterator
3799 i = m_clients.getIterator();
3800 i.atEnd()==false; i++)
3802 RemoteClient *client = i.getNode()->getValue();
3803 client->SetBlockNotSent(p);
3807 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3809 DSTACK(__FUNCTION_NAME);
3811 v3s16 p = block->getPos();
3815 bool completely_air = true;
3816 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3817 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3818 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3820 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3822 completely_air = false;
3823 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3828 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3830 infostream<<"[completely air] ";
3831 infostream<<std::endl;
3835 Create a packet with the block in the right format
3838 std::ostringstream os(std::ios_base::binary);
3839 block->serialize(os, ver, false);
3840 std::string s = os.str();
3841 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3843 u32 replysize = 8 + blockdata.getSize();
3844 SharedBuffer<u8> reply(replysize);
3845 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3846 writeS16(&reply[2], p.X);
3847 writeS16(&reply[4], p.Y);
3848 writeS16(&reply[6], p.Z);
3849 memcpy(&reply[8], *blockdata, blockdata.getSize());
3851 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3852 <<": \tpacket size: "<<replysize<<std::endl;*/
3857 m_con.Send(peer_id, 1, reply, true);
3860 void Server::SendBlocks(float dtime)
3862 DSTACK(__FUNCTION_NAME);
3864 JMutexAutoLock envlock(m_env_mutex);
3865 JMutexAutoLock conlock(m_con_mutex);
3867 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3869 core::array<PrioritySortedBlockTransfer> queue;
3871 s32 total_sending = 0;
3874 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3876 for(core::map<u16, RemoteClient*>::Iterator
3877 i = m_clients.getIterator();
3878 i.atEnd() == false; i++)
3880 RemoteClient *client = i.getNode()->getValue();
3881 assert(client->peer_id == i.getNode()->getKey());
3883 // If definitions and textures have not been sent, don't
3884 // send MapBlocks either
3885 if(!client->definitions_sent)
3888 total_sending += client->SendingCount();
3890 if(client->serialization_version == SER_FMT_VER_INVALID)
3893 client->GetNextBlocks(this, dtime, queue);
3898 // Lowest priority number comes first.
3899 // Lowest is most important.
3902 for(u32 i=0; i<queue.size(); i++)
3904 //TODO: Calculate limit dynamically
3905 if(total_sending >= g_settings->getS32
3906 ("max_simultaneous_block_sends_server_total"))
3909 PrioritySortedBlockTransfer q = queue[i];
3911 MapBlock *block = NULL;
3914 block = m_env->getMap().getBlockNoCreate(q.pos);
3916 catch(InvalidPositionException &e)
3921 RemoteClient *client = getClient(q.peer_id);
3923 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3925 client->SentBlock(q.pos);
3931 void Server::PrepareTextures()
3933 DSTACK(__FUNCTION_NAME);
3935 infostream<<"Server: Calculating texture checksums"<<std::endl;
3937 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3938 i != m_mods.end(); i++){
3939 const ModSpec &mod = *i;
3940 std::string texturepath = mod.path + DIR_DELIM + "textures";
3941 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3942 for(u32 j=0; j<dirlist.size(); j++){
3943 if(dirlist[j].dir) // Ignode dirs
3945 std::string tname = dirlist[j].name;
3946 // if name contains illegal characters, ignore the texture
3947 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3948 errorstream<<"Server: ignoring illegal texture name: \""
3949 <<tname<<"\""<<std::endl;
3952 std::string tpath = texturepath + DIR_DELIM + tname;
3954 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3955 if(fis.good() == false){
3956 errorstream<<"Server::PrepareTextures(): Could not open \""
3957 <<tname<<"\" for reading"<<std::endl;
3960 std::ostringstream tmp_os(std::ios_base::binary);
3964 fis.read(buf, 1024);
3965 std::streamsize len = fis.gcount();
3966 tmp_os.write(buf, len);
3975 errorstream<<"Server::PrepareTextures(): Failed to read \""
3976 <<tname<<"\""<<std::endl;
3979 if(tmp_os.str().length() == 0){
3980 errorstream<<"Server::PrepareTextures(): Empty file \""
3981 <<tpath<<"\""<<std::endl;
3986 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3988 unsigned char *digest = sha1.getDigest();
3989 std::string digest_string = base64_encode(digest, 20);
3994 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3995 verbosestream<<"Server: sha1 for "<<tname<<"\tis "<<std::endl;
4000 struct SendableTextureAnnouncement
4003 std::string sha1_digest;
4005 SendableTextureAnnouncement(const std::string name_="",
4006 const std::string sha1_digest_=""):
4008 sha1_digest(sha1_digest_)
4013 void Server::SendTextureAnnouncement(u16 peer_id){
4014 DSTACK(__FUNCTION_NAME);
4016 verbosestream<<"Server: Announcing textures to id("<<peer_id<<")"
4019 core::list<SendableTextureAnnouncement> texture_announcements;
4021 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
4024 texture_announcements.push_back(
4025 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
4028 //send announcements
4032 u32 number of textures
4036 u16 length of digest string
4040 std::ostringstream os(std::ios_base::binary);
4042 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
4043 writeU16(os, texture_announcements.size());
4045 for(core::list<SendableTextureAnnouncement>::Iterator
4046 j = texture_announcements.begin();
4047 j != texture_announcements.end(); j++){
4048 os<<serializeString(j->name);
4049 os<<serializeString(j->sha1_digest);
4053 std::string s = os.str();
4054 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4057 m_con.Send(peer_id, 0, data, true);
4061 struct SendableTexture
4067 SendableTexture(const std::string &name_="", const std::string path_="",
4068 const std::string &data_=""):
4075 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
4076 DSTACK(__FUNCTION_NAME);
4078 verbosestream<<"Server::SendTexturesRequested(): "
4079 <<"Sending textures to client"<<std::endl;
4083 // Put 5kB in one bunch (this is not accurate)
4084 u32 bytes_per_bunch = 5000;
4086 core::array< core::list<SendableTexture> > texture_bunches;
4087 texture_bunches.push_back(core::list<SendableTexture>());
4089 u32 texture_size_bunch_total = 0;
4091 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
4092 if(m_Textures.find(i->name) == m_Textures.end()){
4093 errorstream<<"Server::SendTexturesRequested(): Client asked for "
4094 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
4098 //TODO get path + name
4099 std::string tpath = m_Textures[(*i).name].path;
4102 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4103 if(fis.good() == false){
4104 errorstream<<"Server::SendTexturesRequested(): Could not open \""
4105 <<tpath<<"\" for reading"<<std::endl;
4108 std::ostringstream tmp_os(std::ios_base::binary);
4112 fis.read(buf, 1024);
4113 std::streamsize len = fis.gcount();
4114 tmp_os.write(buf, len);
4115 texture_size_bunch_total += len;
4124 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
4125 <<(*i).name<<"\""<<std::endl;
4128 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
4129 <<tname<<"\""<<std::endl;*/
4131 texture_bunches[texture_bunches.size()-1].push_back(
4132 SendableTexture((*i).name, tpath, tmp_os.str()));
4134 // Start next bunch if got enough data
4135 if(texture_size_bunch_total >= bytes_per_bunch){
4136 texture_bunches.push_back(core::list<SendableTexture>());
4137 texture_size_bunch_total = 0;
4142 /* Create and send packets */
4144 u32 num_bunches = texture_bunches.size();
4145 for(u32 i=0; i<num_bunches; i++)
4149 u16 total number of texture bunches
4150 u16 index of this bunch
4151 u32 number of textures in this bunch
4159 std::ostringstream os(std::ios_base::binary);
4161 writeU16(os, TOCLIENT_TEXTURES);
4162 writeU16(os, num_bunches);
4164 writeU32(os, texture_bunches[i].size());
4166 for(core::list<SendableTexture>::Iterator
4167 j = texture_bunches[i].begin();
4168 j != texture_bunches[i].end(); j++){
4169 os<<serializeString(j->name);
4170 os<<serializeLongString(j->data);
4174 std::string s = os.str();
4175 verbosestream<<"Server::SendTexturesRequested(): bunch "
4176 <<i<<"/"<<num_bunches
4177 <<" textures="<<texture_bunches[i].size()
4178 <<" size=" <<s.size()<<std::endl;
4179 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4181 m_con.Send(peer_id, 0, data, true);
4191 void Server::DiePlayer(Player *player)
4193 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4195 infostream<<"Server::DiePlayer(): Player "
4196 <<player->getName()<<" dies"<<std::endl;
4200 // Trigger scripted stuff
4201 scriptapi_on_dieplayer(m_lua, srp);
4203 // Handle players that are not connected
4204 if(player->peer_id == PEER_ID_INEXISTENT){
4205 RespawnPlayer(player);
4209 SendPlayerHP(player);
4210 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4213 void Server::RespawnPlayer(Player *player)
4215 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4217 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4219 v3f pos = findSpawnPos(m_env->getServerMap());
4220 player->setPosition(pos);
4221 srp->m_last_good_position = pos;
4222 srp->m_last_good_position_age = 0;
4224 SendMovePlayer(player);
4225 SendPlayerHP(player);
4228 void Server::UpdateCrafting(u16 peer_id)
4230 DSTACK(__FUNCTION_NAME);
4232 Player* player = m_env->getPlayer(peer_id);
4235 // Get a preview for crafting
4237 // No crafting in creative mode
4238 if(g_settings->getBool("creative_mode") == false)
4239 getCraftingResult(&player->inventory, preview, false, this);
4241 // Put the new preview in
4242 InventoryList *plist = player->inventory.getList("craftpreview");
4244 assert(plist->getSize() >= 1);
4245 plist->changeItem(0, preview);
4248 RemoteClient* Server::getClient(u16 peer_id)
4250 DSTACK(__FUNCTION_NAME);
4251 //JMutexAutoLock lock(m_con_mutex);
4252 core::map<u16, RemoteClient*>::Node *n;
4253 n = m_clients.find(peer_id);
4254 // A client should exist for all peers
4256 return n->getValue();
4259 std::wstring Server::getStatusString()
4261 std::wostringstream os(std::ios_base::binary);
4264 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4266 os<<L", uptime="<<m_uptime.get();
4267 // Information about clients
4269 for(core::map<u16, RemoteClient*>::Iterator
4270 i = m_clients.getIterator();
4271 i.atEnd() == false; i++)
4273 // Get client and check that it is valid
4274 RemoteClient *client = i.getNode()->getValue();
4275 assert(client->peer_id == i.getNode()->getKey());
4276 if(client->serialization_version == SER_FMT_VER_INVALID)
4279 Player *player = m_env->getPlayer(client->peer_id);
4280 // Get name of player
4281 std::wstring name = L"unknown";
4283 name = narrow_to_wide(player->getName());
4284 // Add name to information string
4288 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4289 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4290 if(g_settings->get("motd") != "")
4291 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4295 u64 Server::getPlayerAuthPrivs(const std::string &name)
4298 return m_authmanager.getPrivs(name);
4300 catch(AuthNotFoundException &e)
4302 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4307 void Server::setPlayerAuthPrivs(const std::string &name, u64 privs)
4310 return m_authmanager.setPrivs(name, privs);
4312 catch(AuthNotFoundException &e)
4314 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4318 u64 Server::getPlayerEffectivePrivs(const std::string &name)
4320 // Local player gets all privileges regardless of
4321 // what's set on their account.
4322 if(m_simple_singleplayer_mode)
4324 if(name == g_settings->get("name"))
4326 return getPlayerAuthPrivs(name);
4329 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4331 // Add player to auth manager
4332 if(m_authmanager.exists(name) == false)
4334 infostream<<"Server: adding player "<<name
4335 <<" to auth manager"<<std::endl;
4336 m_authmanager.add(name);
4337 m_authmanager.setPrivs(name,
4338 stringToPrivs(g_settings->get("default_privs")));
4340 // Change password and save
4341 m_authmanager.setPassword(name, translatePassword(name, password));
4342 m_authmanager.save();
4345 // Saves g_settings to configpath given at initialization
4346 void Server::saveConfig()
4348 if(m_path_config != "")
4349 g_settings->updateConfigFile(m_path_config.c_str());
4352 void Server::notifyPlayer(const char *name, const std::wstring msg)
4354 Player *player = m_env->getPlayer(name);
4357 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4360 void Server::notifyPlayers(const std::wstring msg)
4362 BroadcastChatMessage(msg);
4365 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4369 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4370 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4373 // IGameDef interface
4375 IItemDefManager* Server::getItemDefManager()
4379 INodeDefManager* Server::getNodeDefManager()
4383 ICraftDefManager* Server::getCraftDefManager()
4387 ITextureSource* Server::getTextureSource()
4391 u16 Server::allocateUnknownNodeId(const std::string &name)
4393 return m_nodedef->allocateDummy(name);
4395 ISoundManager* Server::getSoundManager()
4397 return &dummySoundManager;
4399 MtEventManager* Server::getEventManager()
4404 IWritableItemDefManager* Server::getWritableItemDefManager()
4408 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4412 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4417 const ModSpec* Server::getModSpec(const std::string &modname)
4419 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4420 i != m_mods.end(); i++){
4421 const ModSpec &mod = *i;
4422 if(mod.name == modname)
4428 v3f findSpawnPos(ServerMap &map)
4430 //return v3f(50,50,50)*BS;
4435 nodepos = v2s16(0,0);
4440 // Try to find a good place a few times
4441 for(s32 i=0; i<1000; i++)
4444 // We're going to try to throw the player to this position
4445 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4446 -range + (myrand()%(range*2)));
4447 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4448 // Get ground height at point (fallbacks to heightmap function)
4449 s16 groundheight = map.findGroundLevel(nodepos2d);
4450 // Don't go underwater
4451 if(groundheight < WATER_LEVEL)
4453 //infostream<<"-> Underwater"<<std::endl;
4456 // Don't go to high places
4457 if(groundheight > WATER_LEVEL + 4)
4459 //infostream<<"-> Underwater"<<std::endl;
4463 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4464 bool is_good = false;
4466 for(s32 i=0; i<10; i++){
4467 v3s16 blockpos = getNodeBlockPos(nodepos);
4468 map.emergeBlock(blockpos, true);
4469 MapNode n = map.getNodeNoEx(nodepos);
4470 if(n.getContent() == CONTENT_AIR){
4481 // Found a good place
4482 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4488 return intToFloat(nodepos, BS);
4491 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4494 Try to get an existing player
4496 ServerRemotePlayer *player =
4497 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4500 // If player is already connected, cancel
4501 if(player->peer_id != 0)
4503 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4508 player->peer_id = peer_id;
4510 // Re-add player to environment
4511 if(player->m_removed)
4513 player->m_removed = false;
4515 m_env->addActiveObject(player);
4518 // Reset inventory to creative if in creative mode
4519 if(g_settings->getBool("creative_mode"))
4521 // Warning: double code below
4522 // Backup actual inventory
4523 player->inventory_backup = new Inventory(m_itemdef);
4524 *(player->inventory_backup) = player->inventory;
4525 // Set creative inventory
4526 player->resetInventory();
4527 scriptapi_get_creative_inventory(m_lua, player);
4534 If player with the wanted peer_id already exists, cancel.
4536 if(m_env->getPlayer(peer_id) != NULL)
4538 infostream<<"emergePlayer(): Player with wrong name but same"
4539 " peer_id already exists"<<std::endl;
4547 /* Set player position */
4549 infostream<<"Server: Finding spawn place for player \""
4550 <<name<<"\""<<std::endl;
4552 v3f pos = findSpawnPos(m_env->getServerMap());
4554 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4555 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4557 /* Add player to environment */
4558 m_env->addPlayer(player);
4559 m_env->addActiveObject(srp);
4562 scriptapi_on_newplayer(m_lua, srp);
4564 /* Add stuff to inventory */
4565 if(g_settings->getBool("creative_mode"))
4567 // Warning: double code above
4568 // Backup actual inventory
4569 player->inventory_backup = new Inventory(m_itemdef);
4570 *(player->inventory_backup) = player->inventory;
4571 // Set creative inventory
4572 player->resetInventory();
4573 scriptapi_get_creative_inventory(m_lua, player);
4578 } // create new player
4581 void Server::handlePeerChange(PeerChange &c)
4583 JMutexAutoLock envlock(m_env_mutex);
4584 JMutexAutoLock conlock(m_con_mutex);
4586 if(c.type == PEER_ADDED)
4593 core::map<u16, RemoteClient*>::Node *n;
4594 n = m_clients.find(c.peer_id);
4595 // The client shouldn't already exist
4599 RemoteClient *client = new RemoteClient();
4600 client->peer_id = c.peer_id;
4601 m_clients.insert(client->peer_id, client);
4604 else if(c.type == PEER_REMOVED)
4611 core::map<u16, RemoteClient*>::Node *n;
4612 n = m_clients.find(c.peer_id);
4613 // The client should exist
4617 Mark objects to be not known by the client
4619 RemoteClient *client = n->getValue();
4621 for(core::map<u16, bool>::Iterator
4622 i = client->m_known_objects.getIterator();
4623 i.atEnd()==false; i++)
4626 u16 id = i.getNode()->getKey();
4627 ServerActiveObject* obj = m_env->getActiveObject(id);
4629 if(obj && obj->m_known_by_count > 0)
4630 obj->m_known_by_count--;
4634 Clear references to playing sounds
4636 for(std::map<s32, ServerPlayingSound>::iterator
4637 i = m_playing_sounds.begin();
4638 i != m_playing_sounds.end();)
4640 ServerPlayingSound &psound = i->second;
4641 psound.clients.erase(c.peer_id);
4642 if(psound.clients.size() == 0)
4643 m_playing_sounds.erase(i++);
4648 ServerRemotePlayer* player =
4649 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4651 // Collect information about leaving in chat
4652 std::wstring message;
4656 std::wstring name = narrow_to_wide(player->getName());
4659 message += L" left game";
4661 message += L" (timed out)";
4665 // Remove from environment
4667 player->m_removed = true;
4669 // Set player client disconnected
4671 player->peer_id = 0;
4679 std::ostringstream os(std::ios_base::binary);
4680 for(core::map<u16, RemoteClient*>::Iterator
4681 i = m_clients.getIterator();
4682 i.atEnd() == false; i++)
4684 RemoteClient *client = i.getNode()->getValue();
4685 assert(client->peer_id == i.getNode()->getKey());
4686 if(client->serialization_version == SER_FMT_VER_INVALID)
4689 Player *player = m_env->getPlayer(client->peer_id);
4692 // Get name of player
4693 os<<player->getName()<<" ";
4696 actionstream<<player->getName()<<" "
4697 <<(c.timeout?"times out.":"leaves game.")
4698 <<" List of players: "
4699 <<os.str()<<std::endl;
4704 delete m_clients[c.peer_id];
4705 m_clients.remove(c.peer_id);
4707 // Send player info to all remaining clients
4708 //SendPlayerInfos();
4710 // Send leave chat message to all remaining clients
4711 if(message.length() != 0)
4712 BroadcastChatMessage(message);
4721 void Server::handlePeerChanges()
4723 while(m_peer_change_queue.size() > 0)
4725 PeerChange c = m_peer_change_queue.pop_front();
4727 verbosestream<<"Server: Handling peer change: "
4728 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4731 handlePeerChange(c);
4735 u64 Server::getPlayerPrivs(Player *player)
4739 std::string playername = player->getName();
4740 return getPlayerEffectivePrivs(playername);
4743 void dedicated_server_loop(Server &server, bool &kill)
4745 DSTACK(__FUNCTION_NAME);
4747 verbosestream<<"dedicated_server_loop()"<<std::endl;
4749 IntervalLimiter m_profiler_interval;
4753 float steplen = g_settings->getFloat("dedicated_server_step");
4754 // This is kind of a hack but can be done like this
4755 // because server.step() is very light
4757 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4758 sleep_ms((int)(steplen*1000.0));
4760 server.step(steplen);
4762 if(server.getShutdownRequested() || kill)
4764 infostream<<"Dedicated server quitting"<<std::endl;
4771 float profiler_print_interval =
4772 g_settings->getFloat("profiler_print_interval");
4773 if(profiler_print_interval != 0)
4775 if(m_profiler_interval.step(steplen, profiler_print_interval))
4777 infostream<<"Profiler:"<<std::endl;
4778 g_profiler->print(infostream);
4779 g_profiler->clear();