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
54 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
56 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
58 class MapEditEventIgnorer
61 MapEditEventIgnorer(bool *flag):
70 ~MapEditEventIgnorer()
83 void * ServerThread::Thread()
87 log_register_thread("ServerThread");
89 DSTACK(__FUNCTION_NAME);
91 BEGIN_DEBUG_EXCEPTION_HANDLER
96 //TimeTaker timer("AsyncRunStep() + Receive()");
99 //TimeTaker timer("AsyncRunStep()");
100 m_server->AsyncRunStep();
103 //infostream<<"Running m_server->Receive()"<<std::endl;
106 catch(con::NoIncomingDataException &e)
109 catch(con::PeerNotFoundException &e)
111 infostream<<"Server: PeerNotFoundException"<<std::endl;
113 catch(con::ConnectionBindFailed &e)
115 m_server->setAsyncFatalError(e.what());
119 END_DEBUG_EXCEPTION_HANDLER(errorstream)
124 void * EmergeThread::Thread()
128 log_register_thread("EmergeThread");
130 DSTACK(__FUNCTION_NAME);
132 BEGIN_DEBUG_EXCEPTION_HANDLER
134 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
137 Get block info from queue, emerge them and send them
140 After queue is empty, exit.
144 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
148 SharedPtr<QueuedBlockEmerge> q(qptr);
154 Do not generate over-limit
156 if(blockpos_over_limit(p))
159 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
161 //TimeTaker timer("block emerge");
164 Try to emerge it from somewhere.
166 If it is only wanted as optional, only loading from disk
171 Check if any peer wants it as non-optional. In that case it
174 Also decrement the emerge queue count in clients.
177 bool only_from_disk = true;
180 core::map<u16, u8>::Iterator i;
181 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
183 //u16 peer_id = i.getNode()->getKey();
186 u8 flags = i.getNode()->getValue();
187 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
188 only_from_disk = false;
193 if(enable_mapgen_debug_info)
194 infostream<<"EmergeThread: p="
195 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
196 <<"only_from_disk="<<only_from_disk<<std::endl;
198 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
200 MapBlock *block = NULL;
201 bool got_block = true;
202 core::map<v3s16, MapBlock*> modified_blocks;
205 Try to fetch block from memory or disk.
206 If not found and asked to generate, initialize generator.
209 bool started_generate = false;
210 mapgen::BlockMakeData data;
213 JMutexAutoLock envlock(m_server->m_env_mutex);
215 // Load sector if it isn't loaded
216 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
217 map.loadSectorMeta(p2d);
219 // Attempt to load block
220 block = map.getBlockNoCreateNoEx(p);
221 if(!block || block->isDummy() || !block->isGenerated())
223 if(enable_mapgen_debug_info)
224 infostream<<"EmergeThread: not in memory, "
225 <<"attempting to load from disk"<<std::endl;
227 block = map.loadBlock(p);
230 // If could not load and allowed to generate, start generation
231 // inside this same envlock
232 if(only_from_disk == false &&
233 (block == NULL || block->isGenerated() == false)){
234 if(enable_mapgen_debug_info)
235 infostream<<"EmergeThread: generating"<<std::endl;
236 started_generate = true;
238 map.initBlockMake(&data, p);
243 If generator was initialized, generate now when envlock is free.
248 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
250 TimeTaker t("mapgen::make_block()");
252 mapgen::make_block(&data);
254 if(enable_mapgen_debug_info == false)
255 t.stop(true); // Hide output
259 // Lock environment again to access the map
260 JMutexAutoLock envlock(m_server->m_env_mutex);
262 ScopeProfiler sp(g_profiler, "EmergeThread: after "
263 "mapgen::make_block (envlock)", SPT_AVG);
265 // Blit data back on map, update lighting, add mobs and
266 // whatever this does
267 map.finishBlockMake(&data, modified_blocks);
270 block = map.getBlockNoCreateNoEx(p);
272 // If block doesn't exist, don't try doing anything with it
273 // This happens if the block is not in generation boundaries
278 Do some post-generate stuff
281 v3s16 minp = block->getPos()*MAP_BLOCKSIZE;
282 v3s16 maxp = minp + v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
283 scriptapi_environment_on_generated(m_server->m_lua,
286 if(enable_mapgen_debug_info)
287 infostream<<"EmergeThread: ended up with: "
288 <<analyze_block(block)<<std::endl;
291 Ignore map edit events, they will not need to be
292 sent to anybody because the block hasn't been sent
295 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
297 // Activate objects and stuff
298 m_server->m_env->activateBlock(block, 0);
306 Set sent status of modified blocks on clients
309 // NOTE: Server's clients are also behind the connection mutex
310 JMutexAutoLock lock(m_server->m_con_mutex);
313 Add the originally fetched block to the modified list
317 modified_blocks.insert(p, block);
321 Set the modified blocks unsent for all the clients
324 for(core::map<u16, RemoteClient*>::Iterator
325 i = m_server->m_clients.getIterator();
326 i.atEnd() == false; i++)
328 RemoteClient *client = i.getNode()->getValue();
330 if(modified_blocks.size() > 0)
332 // Remove block from sent history
333 client->SetBlocksNotSent(modified_blocks);
339 END_DEBUG_EXCEPTION_HANDLER(errorstream)
341 log_deregister_thread();
346 void RemoteClient::GetNextBlocks(Server *server, float dtime,
347 core::array<PrioritySortedBlockTransfer> &dest)
349 DSTACK(__FUNCTION_NAME);
352 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
355 m_nothing_to_send_pause_timer -= dtime;
356 m_nearest_unsent_reset_timer += dtime;
358 if(m_nothing_to_send_pause_timer >= 0)
363 // Won't send anything if already sending
364 if(m_blocks_sending.size() >= g_settings->getU16
365 ("max_simultaneous_block_sends_per_client"))
367 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
371 //TimeTaker timer("RemoteClient::GetNextBlocks");
373 Player *player = server->m_env->getPlayer(peer_id);
375 assert(player != NULL);
377 v3f playerpos = player->getPosition();
378 v3f playerspeed = player->getSpeed();
379 v3f playerspeeddir(0,0,0);
380 if(playerspeed.getLength() > 1.0*BS)
381 playerspeeddir = playerspeed / playerspeed.getLength();
382 // Predict to next block
383 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
385 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
387 v3s16 center = getNodeBlockPos(center_nodepos);
389 // Camera position and direction
390 v3f camera_pos = player->getEyePosition();
391 v3f camera_dir = v3f(0,0,1);
392 camera_dir.rotateYZBy(player->getPitch());
393 camera_dir.rotateXZBy(player->getYaw());
395 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
396 <<camera_dir.Z<<")"<<std::endl;*/
399 Get the starting value of the block finder radius.
402 if(m_last_center != center)
404 m_nearest_unsent_d = 0;
405 m_last_center = center;
408 /*infostream<<"m_nearest_unsent_reset_timer="
409 <<m_nearest_unsent_reset_timer<<std::endl;*/
411 // Reset periodically to workaround for some bugs or stuff
412 if(m_nearest_unsent_reset_timer > 20.0)
414 m_nearest_unsent_reset_timer = 0;
415 m_nearest_unsent_d = 0;
416 //infostream<<"Resetting m_nearest_unsent_d for "
417 // <<server->getPlayerName(peer_id)<<std::endl;
420 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
421 s16 d_start = m_nearest_unsent_d;
423 //infostream<<"d_start="<<d_start<<std::endl;
425 u16 max_simul_sends_setting = g_settings->getU16
426 ("max_simultaneous_block_sends_per_client");
427 u16 max_simul_sends_usually = max_simul_sends_setting;
430 Check the time from last addNode/removeNode.
432 Decrease send rate if player is building stuff.
434 m_time_from_building += dtime;
435 if(m_time_from_building < g_settings->getFloat(
436 "full_block_send_enable_min_time_from_building"))
438 max_simul_sends_usually
439 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
443 Number of blocks sending + number of blocks selected for sending
445 u32 num_blocks_selected = m_blocks_sending.size();
448 next time d will be continued from the d from which the nearest
449 unsent block was found this time.
451 This is because not necessarily any of the blocks found this
452 time are actually sent.
454 s32 new_nearest_unsent_d = -1;
456 s16 d_max = g_settings->getS16("max_block_send_distance");
457 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
459 // Don't loop very much at a time
460 s16 max_d_increment_at_time = 2;
461 if(d_max > d_start + max_d_increment_at_time)
462 d_max = d_start + max_d_increment_at_time;
463 /*if(d_max_gen > d_start+2)
464 d_max_gen = d_start+2;*/
466 //infostream<<"Starting from "<<d_start<<std::endl;
468 s32 nearest_emerged_d = -1;
469 s32 nearest_emergefull_d = -1;
470 s32 nearest_sent_d = -1;
471 bool queue_is_full = false;
474 for(d = d_start; d <= d_max; d++)
476 /*errorstream<<"checking d="<<d<<" for "
477 <<server->getPlayerName(peer_id)<<std::endl;*/
478 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
481 If m_nearest_unsent_d was changed by the EmergeThread
482 (it can change it to 0 through SetBlockNotSent),
484 Else update m_nearest_unsent_d
486 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
488 d = m_nearest_unsent_d;
489 last_nearest_unsent_d = m_nearest_unsent_d;
493 Get the border/face dot coordinates of a "d-radiused"
496 core::list<v3s16> list;
497 getFacePositions(list, d);
499 core::list<v3s16>::Iterator li;
500 for(li=list.begin(); li!=list.end(); li++)
502 v3s16 p = *li + center;
506 - Don't allow too many simultaneous transfers
507 - EXCEPT when the blocks are very close
509 Also, don't send blocks that are already flying.
512 // Start with the usual maximum
513 u16 max_simul_dynamic = max_simul_sends_usually;
515 // If block is very close, allow full maximum
516 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
517 max_simul_dynamic = max_simul_sends_setting;
519 // Don't select too many blocks for sending
520 if(num_blocks_selected >= max_simul_dynamic)
522 queue_is_full = true;
523 goto queue_full_break;
526 // Don't send blocks that are currently being transferred
527 if(m_blocks_sending.find(p) != NULL)
533 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
534 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
535 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
536 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
537 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
538 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
541 // If this is true, inexistent block will be made from scratch
542 bool generate = d <= d_max_gen;
545 /*// Limit the generating area vertically to 2/3
546 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
549 // Limit the send area vertically to 1/2
550 if(abs(p.Y - center.Y) > d_max / 2)
556 If block is far away, don't generate it unless it is
562 // Block center y in nodes
563 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
564 // Don't generate if it's very high or very low
565 if(y < -64 || y > 64)
569 v2s16 p2d_nodes_center(
573 // Get ground height in nodes
574 s16 gh = server->m_env->getServerMap().findGroundLevel(
577 // If differs a lot, don't generate
578 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
580 // Actually, don't even send it
586 //infostream<<"d="<<d<<std::endl;
589 Don't generate or send if not in sight
590 FIXME This only works if the client uses a small enough
591 FOV setting. The default of 72 degrees is fine.
594 float camera_fov = (72.0*PI/180) * 4./3.;
595 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
601 Don't send already sent blocks
604 if(m_blocks_sent.find(p) != NULL)
611 Check if map has this block
613 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
615 bool surely_not_found_on_disk = false;
616 bool block_is_invalid = false;
619 // Reset usage timer, this block will be of use in the future.
620 block->resetUsageTimer();
622 // Block is dummy if data doesn't exist.
623 // It means it has been not found from disk and not generated
626 surely_not_found_on_disk = true;
629 // Block is valid if lighting is up-to-date and data exists
630 if(block->isValid() == false)
632 block_is_invalid = true;
635 /*if(block->isFullyGenerated() == false)
637 block_is_invalid = true;
642 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
643 v2s16 chunkpos = map->sector_to_chunk(p2d);
644 if(map->chunkNonVolatile(chunkpos) == false)
645 block_is_invalid = true;
647 if(block->isGenerated() == false)
648 block_is_invalid = true;
651 If block is not close, don't send it unless it is near
654 Block is near ground level if night-time mesh
655 differs from day-time mesh.
659 if(block->dayNightDiffed() == false)
666 If block has been marked to not exist on disk (dummy)
667 and generating new ones is not wanted, skip block.
669 if(generate == false && surely_not_found_on_disk == true)
676 Add inexistent block to emerge queue.
678 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
680 //TODO: Get value from somewhere
681 // Allow only one block in emerge queue
682 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
683 // Allow two blocks in queue per client
684 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
686 // Make it more responsive when needing to generate stuff
687 if(surely_not_found_on_disk)
689 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
691 //infostream<<"Adding block to emerge queue"<<std::endl;
693 // Add it to the emerge queue and trigger the thread
696 if(generate == false)
697 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
699 server->m_emerge_queue.addBlock(peer_id, p, flags);
700 server->m_emergethread.trigger();
702 if(nearest_emerged_d == -1)
703 nearest_emerged_d = d;
705 if(nearest_emergefull_d == -1)
706 nearest_emergefull_d = d;
713 if(nearest_sent_d == -1)
717 Add block to send queue
720 /*errorstream<<"sending from d="<<d<<" to "
721 <<server->getPlayerName(peer_id)<<std::endl;*/
723 PrioritySortedBlockTransfer q((float)d, p, peer_id);
727 num_blocks_selected += 1;
732 //infostream<<"Stopped at "<<d<<std::endl;
734 // If nothing was found for sending and nothing was queued for
735 // emerging, continue next time browsing from here
736 if(nearest_emerged_d != -1){
737 new_nearest_unsent_d = nearest_emerged_d;
738 } else if(nearest_emergefull_d != -1){
739 new_nearest_unsent_d = nearest_emergefull_d;
741 if(d > g_settings->getS16("max_block_send_distance")){
742 new_nearest_unsent_d = 0;
743 m_nothing_to_send_pause_timer = 2.0;
744 /*infostream<<"GetNextBlocks(): d wrapped around for "
745 <<server->getPlayerName(peer_id)
746 <<"; setting to 0 and pausing"<<std::endl;*/
748 if(nearest_sent_d != -1)
749 new_nearest_unsent_d = nearest_sent_d;
751 new_nearest_unsent_d = d;
755 if(new_nearest_unsent_d != -1)
756 m_nearest_unsent_d = new_nearest_unsent_d;
758 /*timer_result = timer.stop(true);
759 if(timer_result != 0)
760 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
763 void RemoteClient::GotBlock(v3s16 p)
765 if(m_blocks_sending.find(p) != NULL)
766 m_blocks_sending.remove(p);
769 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
770 " m_blocks_sending"<<std::endl;*/
771 m_excess_gotblocks++;
773 m_blocks_sent.insert(p, true);
776 void RemoteClient::SentBlock(v3s16 p)
778 if(m_blocks_sending.find(p) == NULL)
779 m_blocks_sending.insert(p, 0.0);
781 infostream<<"RemoteClient::SentBlock(): Sent block"
782 " already in m_blocks_sending"<<std::endl;
785 void RemoteClient::SetBlockNotSent(v3s16 p)
787 m_nearest_unsent_d = 0;
789 if(m_blocks_sending.find(p) != NULL)
790 m_blocks_sending.remove(p);
791 if(m_blocks_sent.find(p) != NULL)
792 m_blocks_sent.remove(p);
795 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
797 m_nearest_unsent_d = 0;
799 for(core::map<v3s16, MapBlock*>::Iterator
800 i = blocks.getIterator();
801 i.atEnd()==false; i++)
803 v3s16 p = i.getNode()->getKey();
805 if(m_blocks_sending.find(p) != NULL)
806 m_blocks_sending.remove(p);
807 if(m_blocks_sent.find(p) != NULL)
808 m_blocks_sent.remove(p);
816 PlayerInfo::PlayerInfo()
822 void PlayerInfo::PrintLine(std::ostream *s)
825 (*s)<<"\""<<name<<"\" ("
826 <<(position.X/10)<<","<<(position.Y/10)
827 <<","<<(position.Z/10)<<") ";
829 (*s)<<" avg_rtt="<<avg_rtt;
838 const std::string &path_world,
839 const std::string &path_config,
840 const SubgameSpec &gamespec,
841 bool simple_singleplayer_mode
843 m_path_world(path_world),
844 m_path_config(path_config),
845 m_gamespec(gamespec),
846 m_simple_singleplayer_mode(simple_singleplayer_mode),
847 m_async_fatal_error(""),
849 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
850 m_authmanager(path_world+DIR_DELIM+"auth.txt"),
851 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
853 m_itemdef(createItemDefManager()),
854 m_nodedef(createNodeDefManager()),
855 m_craftdef(createCraftDefManager()),
857 m_emergethread(this),
858 m_time_of_day_send_timer(0),
860 m_shutdown_requested(false),
861 m_ignore_map_edit_events(false),
862 m_ignore_map_edit_events_peer_id(0)
864 m_liquid_transform_timer = 0.0;
865 m_print_info_timer = 0.0;
866 m_objectdata_timer = 0.0;
867 m_emergethread_trigger_timer = 0.0;
868 m_savemap_timer = 0.0;
872 m_step_dtime_mutex.Init();
876 throw ServerError("Supplied empty world path");
878 if(!gamespec.isValid())
879 throw ServerError("Supplied invalid gamespec");
881 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
882 if(m_simple_singleplayer_mode)
883 infostream<<" in simple singleplayer mode"<<std::endl;
885 infostream<<std::endl;
886 infostream<<"- world: "<<m_path_world<<std::endl;
887 infostream<<"- config: "<<m_path_config<<std::endl;
888 infostream<<"- game: "<<m_gamespec.path<<std::endl;
890 // Add world mod search path
891 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
892 // Add addon mod search path
893 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
894 i != m_gamespec.mods_paths.end(); i++)
895 m_modspaths.push_front((*i));
897 // Print out mod search paths
898 for(core::list<std::string>::Iterator i = m_modspaths.begin();
899 i != m_modspaths.end(); i++){
900 std::string modspath = *i;
901 infostream<<"- mods: "<<modspath<<std::endl;
904 // Path to builtin.lua
905 std::string builtinpath = porting::path_share + DIR_DELIM + "builtin"
906 + DIR_DELIM + "builtin.lua";
908 // Create world if it doesn't exist
909 if(!initializeWorld(m_path_world, m_gamespec.id))
910 throw ServerError("Failed to initialize world");
913 JMutexAutoLock envlock(m_env_mutex);
914 JMutexAutoLock conlock(m_con_mutex);
916 // Initialize scripting
918 infostream<<"Server: Initializing Lua"<<std::endl;
919 m_lua = script_init();
922 scriptapi_export(m_lua, this);
923 // Load and run builtin.lua
924 infostream<<"Server: Loading builtin.lua [\""
925 <<builtinpath<<"\"]"<<std::endl;
926 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
928 errorstream<<"Server: Failed to load and run "
929 <<builtinpath<<std::endl;
930 throw ModError("Failed to load and run "+builtinpath);
932 // Find mods in mod search paths
933 m_mods = getMods(m_modspaths);
935 infostream<<"Server: Loading mods: ";
936 for(core::list<ModSpec>::Iterator i = m_mods.begin();
937 i != m_mods.end(); i++){
938 const ModSpec &mod = *i;
939 infostream<<mod.name<<" ";
941 infostream<<std::endl;
942 // Load and run "mod" scripts
943 for(core::list<ModSpec>::Iterator i = m_mods.begin();
944 i != m_mods.end(); i++){
945 const ModSpec &mod = *i;
946 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
947 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
948 <<scriptpath<<"\"]"<<std::endl;
949 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
951 errorstream<<"Server: Failed to load and run "
952 <<scriptpath<<std::endl;
953 throw ModError("Failed to load and run "+scriptpath);
957 // Read Textures and calculate sha1 sums
960 // Apply item aliases in the node definition manager
961 m_nodedef->updateAliases(m_itemdef);
963 // Initialize Environment
965 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
968 // Give environment reference to scripting api
969 scriptapi_add_environment(m_lua, m_env);
971 // Register us to receive map edit events
972 m_env->getMap().addEventReceiver(this);
974 // If file exists, load environment metadata
975 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
977 infostream<<"Server: Loading environment metadata"<<std::endl;
978 m_env->loadMeta(m_path_world);
982 infostream<<"Server: Loading players"<<std::endl;
983 m_env->deSerializePlayers(m_path_world);
986 Add some test ActiveBlockModifiers to environment
988 add_legacy_abms(m_env, m_nodedef);
993 infostream<<"Server destructing"<<std::endl;
996 Send shutdown message
999 JMutexAutoLock conlock(m_con_mutex);
1001 std::wstring line = L"*** Server shutting down";
1004 Send the message to clients
1006 for(core::map<u16, RemoteClient*>::Iterator
1007 i = m_clients.getIterator();
1008 i.atEnd() == false; i++)
1010 // Get client and check that it is valid
1011 RemoteClient *client = i.getNode()->getValue();
1012 assert(client->peer_id == i.getNode()->getKey());
1013 if(client->serialization_version == SER_FMT_VER_INVALID)
1017 SendChatMessage(client->peer_id, line);
1019 catch(con::PeerNotFoundException &e)
1025 JMutexAutoLock envlock(m_env_mutex);
1030 infostream<<"Server: Saving players"<<std::endl;
1031 m_env->serializePlayers(m_path_world);
1034 Save environment metadata
1036 infostream<<"Server: Saving environment metadata"<<std::endl;
1037 m_env->saveMeta(m_path_world);
1049 JMutexAutoLock clientslock(m_con_mutex);
1051 for(core::map<u16, RemoteClient*>::Iterator
1052 i = m_clients.getIterator();
1053 i.atEnd() == false; i++)
1056 // NOTE: These are removed by env destructor
1058 u16 peer_id = i.getNode()->getKey();
1059 JMutexAutoLock envlock(m_env_mutex);
1060 m_env->removePlayer(peer_id);
1064 delete i.getNode()->getValue();
1068 // Delete Environment
1075 // Deinitialize scripting
1076 infostream<<"Server: Deinitializing scripting"<<std::endl;
1077 script_deinit(m_lua);
1080 void Server::start(unsigned short port)
1082 DSTACK(__FUNCTION_NAME);
1083 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1085 // Stop thread if already running
1088 // Initialize connection
1089 m_con.SetTimeoutMs(30);
1093 m_thread.setRun(true);
1096 // ASCII art for the win!
1098 <<" .__ __ __ "<<std::endl
1099 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1100 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1101 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1102 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1103 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1104 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1105 actionstream<<"Server for gameid=\""<<m_gamespec.id
1106 <<"\" listening on port "<<port<<"."<<std::endl;
1111 DSTACK(__FUNCTION_NAME);
1113 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1115 // Stop threads (set run=false first so both start stopping)
1116 m_thread.setRun(false);
1117 m_emergethread.setRun(false);
1119 m_emergethread.stop();
1121 infostream<<"Server: Threads stopped"<<std::endl;
1124 void Server::step(float dtime)
1126 DSTACK(__FUNCTION_NAME);
1131 JMutexAutoLock lock(m_step_dtime_mutex);
1132 m_step_dtime += dtime;
1134 // Throw if fatal error occurred in thread
1135 std::string async_err = m_async_fatal_error.get();
1136 if(async_err != ""){
1137 throw ServerError(async_err);
1141 void Server::AsyncRunStep()
1143 DSTACK(__FUNCTION_NAME);
1145 g_profiler->add("Server::AsyncRunStep (num)", 1);
1149 JMutexAutoLock lock1(m_step_dtime_mutex);
1150 dtime = m_step_dtime;
1154 // Send blocks to clients
1161 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1163 //infostream<<"Server steps "<<dtime<<std::endl;
1164 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1167 JMutexAutoLock lock1(m_step_dtime_mutex);
1168 m_step_dtime -= dtime;
1175 m_uptime.set(m_uptime.get() + dtime);
1179 // Process connection's timeouts
1180 JMutexAutoLock lock2(m_con_mutex);
1181 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1182 m_con.RunTimeouts(dtime);
1186 // This has to be called so that the client list gets synced
1187 // with the peer list of the connection
1188 handlePeerChanges();
1192 Update time of day and overall game time
1195 JMutexAutoLock envlock(m_env_mutex);
1197 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1200 Send to clients at constant intervals
1203 m_time_of_day_send_timer -= dtime;
1204 if(m_time_of_day_send_timer < 0.0)
1206 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1208 //JMutexAutoLock envlock(m_env_mutex);
1209 JMutexAutoLock conlock(m_con_mutex);
1211 for(core::map<u16, RemoteClient*>::Iterator
1212 i = m_clients.getIterator();
1213 i.atEnd() == false; i++)
1215 RemoteClient *client = i.getNode()->getValue();
1216 //Player *player = m_env->getPlayer(client->peer_id);
1218 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1219 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1221 m_con.Send(client->peer_id, 0, data, true);
1227 JMutexAutoLock lock(m_env_mutex);
1229 ScopeProfiler sp(g_profiler, "SEnv step");
1230 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1234 const float map_timer_and_unload_dtime = 2.92;
1235 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1237 JMutexAutoLock lock(m_env_mutex);
1238 // Run Map's timers and unload unused data
1239 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1240 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1241 g_settings->getFloat("server_unload_unused_data_timeout"));
1252 JMutexAutoLock lock(m_env_mutex);
1253 JMutexAutoLock lock2(m_con_mutex);
1255 ScopeProfiler sp(g_profiler, "Server: handle players");
1257 //float player_max_speed = BS * 4.0; // Normal speed
1258 float player_max_speed = BS * 20; // Fast speed
1259 float player_max_speed_up = BS * 20;
1261 player_max_speed *= 2.5; // Tolerance
1262 player_max_speed_up *= 2.5;
1264 for(core::map<u16, RemoteClient*>::Iterator
1265 i = m_clients.getIterator();
1266 i.atEnd() == false; i++)
1268 RemoteClient *client = i.getNode()->getValue();
1269 ServerRemotePlayer *player =
1270 static_cast<ServerRemotePlayer*>
1271 (m_env->getPlayer(client->peer_id));
1276 Check player movements
1278 NOTE: Actually the server should handle player physics like the
1279 client does and compare player's position to what is calculated
1280 on our side. This is required when eg. players fly due to an
1283 player->m_last_good_position_age += dtime;
1284 if(player->m_last_good_position_age >= 1.0){
1285 float age = player->m_last_good_position_age;
1286 v3f diff = (player->getPosition() - player->m_last_good_position);
1287 float d_vert = diff.Y;
1289 float d_horiz = diff.getLength();
1290 /*infostream<<player->getName()<<"'s horizontal speed is "
1291 <<(d_horiz/age)<<std::endl;*/
1292 if(d_horiz <= age * player_max_speed &&
1293 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1294 player->m_last_good_position = player->getPosition();
1296 actionstream<<"Player "<<player->getName()
1297 <<" moved too fast; resetting position"
1299 player->setPosition(player->m_last_good_position);
1300 SendMovePlayer(player);
1302 player->m_last_good_position_age = 0;
1306 Handle player HPs (die if hp=0)
1308 if(player->hp == 0 && player->m_hp_not_sent)
1312 Send player inventories and HPs if necessary
1314 if(player->m_inventory_not_sent){
1315 UpdateCrafting(player->peer_id);
1316 SendInventory(player->peer_id);
1318 if(player->m_hp_not_sent){
1319 SendPlayerHP(player);
1325 if(!player->m_is_in_environment){
1326 player->m_removed = false;
1328 m_env->addActiveObject(player);
1333 /* Transform liquids */
1334 m_liquid_transform_timer += dtime;
1335 if(m_liquid_transform_timer >= 1.00)
1337 m_liquid_transform_timer -= 1.00;
1339 JMutexAutoLock lock(m_env_mutex);
1341 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1343 core::map<v3s16, MapBlock*> modified_blocks;
1344 m_env->getMap().transformLiquids(modified_blocks);
1349 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1350 ServerMap &map = ((ServerMap&)m_env->getMap());
1351 map.updateLighting(modified_blocks, lighting_modified_blocks);
1353 // Add blocks modified by lighting to modified_blocks
1354 for(core::map<v3s16, MapBlock*>::Iterator
1355 i = lighting_modified_blocks.getIterator();
1356 i.atEnd() == false; i++)
1358 MapBlock *block = i.getNode()->getValue();
1359 modified_blocks.insert(block->getPos(), block);
1363 Set the modified blocks unsent for all the clients
1366 JMutexAutoLock lock2(m_con_mutex);
1368 for(core::map<u16, RemoteClient*>::Iterator
1369 i = m_clients.getIterator();
1370 i.atEnd() == false; i++)
1372 RemoteClient *client = i.getNode()->getValue();
1374 if(modified_blocks.size() > 0)
1376 // Remove block from sent history
1377 client->SetBlocksNotSent(modified_blocks);
1382 // Periodically print some info
1384 float &counter = m_print_info_timer;
1390 JMutexAutoLock lock2(m_con_mutex);
1392 if(m_clients.size() != 0)
1393 infostream<<"Players:"<<std::endl;
1394 for(core::map<u16, RemoteClient*>::Iterator
1395 i = m_clients.getIterator();
1396 i.atEnd() == false; i++)
1398 //u16 peer_id = i.getNode()->getKey();
1399 RemoteClient *client = i.getNode()->getValue();
1400 Player *player = m_env->getPlayer(client->peer_id);
1403 infostream<<"* "<<player->getName()<<"\t";
1404 client->PrintInfo(infostream);
1409 //if(g_settings->getBool("enable_experimental"))
1413 Check added and deleted active objects
1416 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1417 JMutexAutoLock envlock(m_env_mutex);
1418 JMutexAutoLock conlock(m_con_mutex);
1420 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1422 // Radius inside which objects are active
1423 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1424 radius *= MAP_BLOCKSIZE;
1426 for(core::map<u16, RemoteClient*>::Iterator
1427 i = m_clients.getIterator();
1428 i.atEnd() == false; i++)
1430 RemoteClient *client = i.getNode()->getValue();
1432 // If definitions and textures have not been sent, don't
1433 // send objects either
1434 if(!client->definitions_sent)
1437 Player *player = m_env->getPlayer(client->peer_id);
1440 // This can happen if the client timeouts somehow
1441 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1443 <<" has no associated player"<<std::endl;*/
1446 v3s16 pos = floatToInt(player->getPosition(), BS);
1448 core::map<u16, bool> removed_objects;
1449 core::map<u16, bool> added_objects;
1450 m_env->getRemovedActiveObjects(pos, radius,
1451 client->m_known_objects, removed_objects);
1452 m_env->getAddedActiveObjects(pos, radius,
1453 client->m_known_objects, added_objects);
1455 // Ignore if nothing happened
1456 if(removed_objects.size() == 0 && added_objects.size() == 0)
1458 //infostream<<"active objects: none changed"<<std::endl;
1462 std::string data_buffer;
1466 // Handle removed objects
1467 writeU16((u8*)buf, removed_objects.size());
1468 data_buffer.append(buf, 2);
1469 for(core::map<u16, bool>::Iterator
1470 i = removed_objects.getIterator();
1471 i.atEnd()==false; i++)
1474 u16 id = i.getNode()->getKey();
1475 ServerActiveObject* obj = m_env->getActiveObject(id);
1477 // Add to data buffer for sending
1478 writeU16((u8*)buf, i.getNode()->getKey());
1479 data_buffer.append(buf, 2);
1481 // Remove from known objects
1482 client->m_known_objects.remove(i.getNode()->getKey());
1484 if(obj && obj->m_known_by_count > 0)
1485 obj->m_known_by_count--;
1488 // Handle added objects
1489 writeU16((u8*)buf, added_objects.size());
1490 data_buffer.append(buf, 2);
1491 for(core::map<u16, bool>::Iterator
1492 i = added_objects.getIterator();
1493 i.atEnd()==false; i++)
1496 u16 id = i.getNode()->getKey();
1497 ServerActiveObject* obj = m_env->getActiveObject(id);
1500 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1502 infostream<<"WARNING: "<<__FUNCTION_NAME
1503 <<": NULL object"<<std::endl;
1505 type = obj->getType();
1507 // Add to data buffer for sending
1508 writeU16((u8*)buf, id);
1509 data_buffer.append(buf, 2);
1510 writeU8((u8*)buf, type);
1511 data_buffer.append(buf, 1);
1514 data_buffer.append(serializeLongString(
1515 obj->getClientInitializationData()));
1517 data_buffer.append(serializeLongString(""));
1519 // Add to known objects
1520 client->m_known_objects.insert(i.getNode()->getKey(), false);
1523 obj->m_known_by_count++;
1527 SharedBuffer<u8> reply(2 + data_buffer.size());
1528 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1529 memcpy((char*)&reply[2], data_buffer.c_str(),
1530 data_buffer.size());
1532 m_con.Send(client->peer_id, 0, reply, true);
1534 verbosestream<<"Server: Sent object remove/add: "
1535 <<removed_objects.size()<<" removed, "
1536 <<added_objects.size()<<" added, "
1537 <<"packet size is "<<reply.getSize()<<std::endl;
1542 Collect a list of all the objects known by the clients
1543 and report it back to the environment.
1546 core::map<u16, bool> all_known_objects;
1548 for(core::map<u16, RemoteClient*>::Iterator
1549 i = m_clients.getIterator();
1550 i.atEnd() == false; i++)
1552 RemoteClient *client = i.getNode()->getValue();
1553 // Go through all known objects of client
1554 for(core::map<u16, bool>::Iterator
1555 i = client->m_known_objects.getIterator();
1556 i.atEnd()==false; i++)
1558 u16 id = i.getNode()->getKey();
1559 all_known_objects[id] = true;
1563 m_env->setKnownActiveObjects(whatever);
1569 Send object messages
1572 JMutexAutoLock envlock(m_env_mutex);
1573 JMutexAutoLock conlock(m_con_mutex);
1575 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1578 // Value = data sent by object
1579 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1581 // Get active object messages from environment
1584 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1588 core::list<ActiveObjectMessage>* message_list = NULL;
1589 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1590 n = buffered_messages.find(aom.id);
1593 message_list = new core::list<ActiveObjectMessage>;
1594 buffered_messages.insert(aom.id, message_list);
1598 message_list = n->getValue();
1600 message_list->push_back(aom);
1603 // Route data to every client
1604 for(core::map<u16, RemoteClient*>::Iterator
1605 i = m_clients.getIterator();
1606 i.atEnd()==false; i++)
1608 RemoteClient *client = i.getNode()->getValue();
1609 std::string reliable_data;
1610 std::string unreliable_data;
1611 // Go through all objects in message buffer
1612 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1613 j = buffered_messages.getIterator();
1614 j.atEnd()==false; j++)
1616 // If object is not known by client, skip it
1617 u16 id = j.getNode()->getKey();
1618 if(client->m_known_objects.find(id) == NULL)
1620 // Get message list of object
1621 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1622 // Go through every message
1623 for(core::list<ActiveObjectMessage>::Iterator
1624 k = list->begin(); k != list->end(); k++)
1626 // Compose the full new data with header
1627 ActiveObjectMessage aom = *k;
1628 std::string new_data;
1631 writeU16((u8*)&buf[0], aom.id);
1632 new_data.append(buf, 2);
1634 new_data += serializeString(aom.datastring);
1635 // Add data to buffer
1637 reliable_data += new_data;
1639 unreliable_data += new_data;
1643 reliable_data and unreliable_data are now ready.
1646 if(reliable_data.size() > 0)
1648 SharedBuffer<u8> reply(2 + reliable_data.size());
1649 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1650 memcpy((char*)&reply[2], reliable_data.c_str(),
1651 reliable_data.size());
1653 m_con.Send(client->peer_id, 0, reply, true);
1655 if(unreliable_data.size() > 0)
1657 SharedBuffer<u8> reply(2 + unreliable_data.size());
1658 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1659 memcpy((char*)&reply[2], unreliable_data.c_str(),
1660 unreliable_data.size());
1661 // Send as unreliable
1662 m_con.Send(client->peer_id, 0, reply, false);
1665 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1667 infostream<<"Server: Size of object message data: "
1668 <<"reliable: "<<reliable_data.size()
1669 <<", unreliable: "<<unreliable_data.size()
1674 // Clear buffered_messages
1675 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1676 i = buffered_messages.getIterator();
1677 i.atEnd()==false; i++)
1679 delete i.getNode()->getValue();
1683 } // enable_experimental
1686 Send queued-for-sending map edit events.
1689 // Don't send too many at a time
1692 // Single change sending is disabled if queue size is not small
1693 bool disable_single_change_sending = false;
1694 if(m_unsent_map_edit_queue.size() >= 4)
1695 disable_single_change_sending = true;
1697 int event_count = m_unsent_map_edit_queue.size();
1699 // We'll log the amount of each
1702 while(m_unsent_map_edit_queue.size() != 0)
1704 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1706 // Players far away from the change are stored here.
1707 // Instead of sending the changes, MapBlocks are set not sent
1709 core::list<u16> far_players;
1711 if(event->type == MEET_ADDNODE)
1713 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1714 prof.add("MEET_ADDNODE", 1);
1715 if(disable_single_change_sending)
1716 sendAddNode(event->p, event->n, event->already_known_by_peer,
1719 sendAddNode(event->p, event->n, event->already_known_by_peer,
1722 else if(event->type == MEET_REMOVENODE)
1724 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1725 prof.add("MEET_REMOVENODE", 1);
1726 if(disable_single_change_sending)
1727 sendRemoveNode(event->p, event->already_known_by_peer,
1730 sendRemoveNode(event->p, event->already_known_by_peer,
1733 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1735 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1736 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1737 setBlockNotSent(event->p);
1739 else if(event->type == MEET_OTHER)
1741 infostream<<"Server: MEET_OTHER"<<std::endl;
1742 prof.add("MEET_OTHER", 1);
1743 for(core::map<v3s16, bool>::Iterator
1744 i = event->modified_blocks.getIterator();
1745 i.atEnd()==false; i++)
1747 v3s16 p = i.getNode()->getKey();
1753 prof.add("unknown", 1);
1754 infostream<<"WARNING: Server: Unknown MapEditEvent "
1755 <<((u32)event->type)<<std::endl;
1759 Set blocks not sent to far players
1761 if(far_players.size() > 0)
1763 // Convert list format to that wanted by SetBlocksNotSent
1764 core::map<v3s16, MapBlock*> modified_blocks2;
1765 for(core::map<v3s16, bool>::Iterator
1766 i = event->modified_blocks.getIterator();
1767 i.atEnd()==false; i++)
1769 v3s16 p = i.getNode()->getKey();
1770 modified_blocks2.insert(p,
1771 m_env->getMap().getBlockNoCreateNoEx(p));
1773 // Set blocks not sent
1774 for(core::list<u16>::Iterator
1775 i = far_players.begin();
1776 i != far_players.end(); i++)
1779 RemoteClient *client = getClient(peer_id);
1782 client->SetBlocksNotSent(modified_blocks2);
1788 /*// Don't send too many at a time
1790 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1794 if(event_count >= 5){
1795 infostream<<"Server: MapEditEvents:"<<std::endl;
1796 prof.print(infostream);
1797 } else if(event_count != 0){
1798 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1799 prof.print(verbosestream);
1805 Trigger emergethread (it somehow gets to a non-triggered but
1806 bysy state sometimes)
1809 float &counter = m_emergethread_trigger_timer;
1815 m_emergethread.trigger();
1819 // Save map, players and auth stuff
1821 float &counter = m_savemap_timer;
1823 if(counter >= g_settings->getFloat("server_map_save_interval"))
1826 JMutexAutoLock lock(m_env_mutex);
1828 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1831 if(m_authmanager.isModified())
1832 m_authmanager.save();
1835 if(m_banmanager.isModified())
1836 m_banmanager.save();
1838 // Save changed parts of map
1839 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1842 m_env->serializePlayers(m_path_world);
1844 // Save environment metadata
1845 m_env->saveMeta(m_path_world);
1850 void Server::Receive()
1852 DSTACK(__FUNCTION_NAME);
1853 SharedBuffer<u8> data;
1858 JMutexAutoLock conlock(m_con_mutex);
1859 datasize = m_con.Receive(peer_id, data);
1862 // This has to be called so that the client list gets synced
1863 // with the peer list of the connection
1864 handlePeerChanges();
1866 ProcessData(*data, datasize, peer_id);
1868 catch(con::InvalidIncomingDataException &e)
1870 infostream<<"Server::Receive(): "
1871 "InvalidIncomingDataException: what()="
1872 <<e.what()<<std::endl;
1874 catch(con::PeerNotFoundException &e)
1876 //NOTE: This is not needed anymore
1878 // The peer has been disconnected.
1879 // Find the associated player and remove it.
1881 /*JMutexAutoLock envlock(m_env_mutex);
1883 infostream<<"ServerThread: peer_id="<<peer_id
1884 <<" has apparently closed connection. "
1885 <<"Removing player."<<std::endl;
1887 m_env->removePlayer(peer_id);*/
1891 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1893 DSTACK(__FUNCTION_NAME);
1894 // Environment is locked first.
1895 JMutexAutoLock envlock(m_env_mutex);
1896 JMutexAutoLock conlock(m_con_mutex);
1898 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1901 Address address = m_con.GetPeerAddress(peer_id);
1902 std::string addr_s = address.serializeString();
1904 // drop player if is ip is banned
1905 if(m_banmanager.isIpBanned(addr_s)){
1906 infostream<<"Server: A banned client tried to connect from "
1907 <<addr_s<<"; banned name was "
1908 <<m_banmanager.getBanName(addr_s)<<std::endl;
1909 // This actually doesn't seem to transfer to the client
1910 SendAccessDenied(m_con, peer_id,
1911 L"Your ip is banned. Banned name was "
1912 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1913 m_con.DeletePeer(peer_id);
1917 catch(con::PeerNotFoundException &e)
1919 infostream<<"Server::ProcessData(): Cancelling: peer "
1920 <<peer_id<<" not found"<<std::endl;
1924 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1926 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1934 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1936 if(command == TOSERVER_INIT)
1938 // [0] u16 TOSERVER_INIT
1939 // [2] u8 SER_FMT_VER_HIGHEST
1940 // [3] u8[20] player_name
1941 // [23] u8[28] password <--- can be sent without this, from old versions
1943 if(datasize < 2+1+PLAYERNAME_SIZE)
1946 verbosestream<<"Server: Got TOSERVER_INIT from "
1947 <<peer_id<<std::endl;
1949 // First byte after command is maximum supported
1950 // serialization version
1951 u8 client_max = data[2];
1952 u8 our_max = SER_FMT_VER_HIGHEST;
1953 // Use the highest version supported by both
1954 u8 deployed = core::min_(client_max, our_max);
1955 // If it's lower than the lowest supported, give up.
1956 if(deployed < SER_FMT_VER_LOWEST)
1957 deployed = SER_FMT_VER_INVALID;
1959 //peer->serialization_version = deployed;
1960 getClient(peer_id)->pending_serialization_version = deployed;
1962 if(deployed == SER_FMT_VER_INVALID)
1964 actionstream<<"Server: A mismatched client tried to connect from "
1965 <<addr_s<<std::endl;
1966 infostream<<"Server: Cannot negotiate "
1967 "serialization version with peer "
1968 <<peer_id<<std::endl;
1969 SendAccessDenied(m_con, peer_id, std::wstring(
1970 L"Your client's version is not supported.\n"
1971 L"Server version is ")
1972 + narrow_to_wide(VERSION_STRING) + L"."
1978 Read and check network protocol version
1981 u16 net_proto_version = 0;
1982 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1984 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1987 getClient(peer_id)->net_proto_version = net_proto_version;
1989 if(net_proto_version == 0)
1991 actionstream<<"Server: An old tried to connect from "<<addr_s
1993 SendAccessDenied(m_con, peer_id, std::wstring(
1994 L"Your client's version is not supported.\n"
1995 L"Server version is ")
1996 + narrow_to_wide(VERSION_STRING) + L"."
2001 if(g_settings->getBool("strict_protocol_version_checking"))
2003 if(net_proto_version != PROTOCOL_VERSION)
2005 actionstream<<"Server: A mismatched client tried to connect"
2006 <<" from "<<addr_s<<std::endl;
2007 SendAccessDenied(m_con, peer_id, std::wstring(
2008 L"Your client's version is not supported.\n"
2009 L"Server version is ")
2010 + narrow_to_wide(VERSION_STRING) + L",\n"
2011 + L"server's PROTOCOL_VERSION is "
2012 + narrow_to_wide(itos(PROTOCOL_VERSION))
2013 + L", client's PROTOCOL_VERSION is "
2014 + narrow_to_wide(itos(net_proto_version))
2025 char playername[PLAYERNAME_SIZE];
2026 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2028 playername[i] = data[3+i];
2030 playername[PLAYERNAME_SIZE-1] = 0;
2032 if(playername[0]=='\0')
2034 actionstream<<"Server: Player with an empty name "
2035 <<"tried to connect from "<<addr_s<<std::endl;
2036 SendAccessDenied(m_con, peer_id,
2041 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2043 actionstream<<"Server: Player with an invalid name "
2044 <<"tried to connect from "<<addr_s<<std::endl;
2045 SendAccessDenied(m_con, peer_id,
2046 L"Name contains unallowed characters");
2050 infostream<<"Server: New connection: \""<<playername<<"\" from "
2051 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2054 char password[PASSWORD_SIZE];
2055 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2057 // old version - assume blank password
2062 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2064 password[i] = data[23+i];
2066 password[PASSWORD_SIZE-1] = 0;
2069 // Add player to auth manager
2070 if(m_authmanager.exists(playername) == false)
2072 std::wstring default_password =
2073 narrow_to_wide(g_settings->get("default_password"));
2074 std::string translated_default_password =
2075 translatePassword(playername, default_password);
2077 // If default_password is empty, allow any initial password
2078 if (default_password.length() == 0)
2079 translated_default_password = password;
2081 infostream<<"Server: adding player "<<playername
2082 <<" to auth manager"<<std::endl;
2083 m_authmanager.add(playername);
2084 m_authmanager.setPassword(playername, translated_default_password);
2085 m_authmanager.setPrivs(playername,
2086 stringToPrivs(g_settings->get("default_privs")));
2087 m_authmanager.save();
2090 std::string checkpwd = m_authmanager.getPassword(playername);
2092 /*infostream<<"Server: Client gave password '"<<password
2093 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2095 if(password != checkpwd)
2097 infostream<<"Server: peer_id="<<peer_id
2098 <<": supplied invalid password for "
2099 <<playername<<std::endl;
2100 SendAccessDenied(m_con, peer_id, L"Invalid password");
2104 // Do not allow multiple players in simple singleplayer mode.
2105 // This isn't a perfect way to do it, but will suffice for now.
2106 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2107 infostream<<"Server: Not allowing another client to connect in"
2108 <<" simple singleplayer mode"<<std::endl;
2109 SendAccessDenied(m_con, peer_id,
2110 L"Running in simple singleplayer mode.");
2114 // Enforce user limit.
2115 // Don't enforce for users that have some admin right
2116 if(m_clients.size() >= g_settings->getU16("max_users") &&
2117 (m_authmanager.getPrivs(playername)
2118 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2119 playername != g_settings->get("name"))
2121 actionstream<<"Server: "<<playername<<" tried to join, but there"
2122 <<" are already max_users="
2123 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2124 SendAccessDenied(m_con, peer_id, L"Too many users.");
2129 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2131 // If failed, cancel
2134 errorstream<<"Server: peer_id="<<peer_id
2135 <<": failed to emerge player"<<std::endl;
2140 Answer with a TOCLIENT_INIT
2143 SharedBuffer<u8> reply(2+1+6+8);
2144 writeU16(&reply[0], TOCLIENT_INIT);
2145 writeU8(&reply[2], deployed);
2146 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2147 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2150 m_con.Send(peer_id, 0, reply, true);
2154 Send complete position information
2156 SendMovePlayer(player);
2161 if(command == TOSERVER_INIT2)
2163 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2164 <<peer_id<<std::endl;
2167 getClient(peer_id)->serialization_version
2168 = getClient(peer_id)->pending_serialization_version;
2171 Send some initialization data
2174 infostream<<"Server: Sending content to "
2175 <<getPlayerName(peer_id)<<std::endl;
2177 // Send item definitions
2178 SendItemDef(m_con, peer_id, m_itemdef);
2180 // Send node definitions
2181 SendNodeDef(m_con, peer_id, m_nodedef);
2183 // Send texture announcement
2184 SendTextureAnnouncement(peer_id);
2186 // Send player info to all players
2187 //SendPlayerInfos();
2189 // Send inventory to player
2190 UpdateCrafting(peer_id);
2191 SendInventory(peer_id);
2193 // Send player items to all players
2196 Player *player = m_env->getPlayer(peer_id);
2199 SendPlayerHP(player);
2201 // Show death screen if necessary
2203 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2207 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2208 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2209 m_con.Send(peer_id, 0, data, true);
2212 // Note things in chat if not in simple singleplayer mode
2213 if(!m_simple_singleplayer_mode)
2215 // Send information about server to player in chat
2216 SendChatMessage(peer_id, getStatusString());
2218 // Send information about joining in chat
2220 std::wstring name = L"unknown";
2221 Player *player = m_env->getPlayer(peer_id);
2223 name = narrow_to_wide(player->getName());
2225 std::wstring message;
2228 message += L" joined game";
2229 BroadcastChatMessage(message);
2233 // Warnings about protocol version can be issued here
2234 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2236 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2243 std::ostringstream os(std::ios_base::binary);
2244 for(core::map<u16, RemoteClient*>::Iterator
2245 i = m_clients.getIterator();
2246 i.atEnd() == false; i++)
2248 RemoteClient *client = i.getNode()->getValue();
2249 assert(client->peer_id == i.getNode()->getKey());
2250 if(client->serialization_version == SER_FMT_VER_INVALID)
2253 Player *player = m_env->getPlayer(client->peer_id);
2256 // Get name of player
2257 os<<player->getName()<<" ";
2260 actionstream<<player->getName()<<" joins game. List of players: "
2261 <<os.str()<<std::endl;
2267 if(peer_ser_ver == SER_FMT_VER_INVALID)
2269 infostream<<"Server::ProcessData(): Cancelling: Peer"
2270 " serialization format invalid or not initialized."
2271 " Skipping incoming command="<<command<<std::endl;
2275 Player *player = m_env->getPlayer(peer_id);
2276 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2279 infostream<<"Server::ProcessData(): Cancelling: "
2280 "No player for peer_id="<<peer_id
2284 if(command == TOSERVER_PLAYERPOS)
2286 if(datasize < 2+12+12+4+4)
2290 v3s32 ps = readV3S32(&data[start+2]);
2291 v3s32 ss = readV3S32(&data[start+2+12]);
2292 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2293 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2294 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2295 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2296 pitch = wrapDegrees(pitch);
2297 yaw = wrapDegrees(yaw);
2299 player->setPosition(position);
2300 player->setSpeed(speed);
2301 player->setPitch(pitch);
2302 player->setYaw(yaw);
2304 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2305 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2306 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2308 else if(command == TOSERVER_GOTBLOCKS)
2321 u16 count = data[2];
2322 for(u16 i=0; i<count; i++)
2324 if((s16)datasize < 2+1+(i+1)*6)
2325 throw con::InvalidIncomingDataException
2326 ("GOTBLOCKS length is too short");
2327 v3s16 p = readV3S16(&data[2+1+i*6]);
2328 /*infostream<<"Server: GOTBLOCKS ("
2329 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2330 RemoteClient *client = getClient(peer_id);
2331 client->GotBlock(p);
2334 else if(command == TOSERVER_DELETEDBLOCKS)
2347 u16 count = data[2];
2348 for(u16 i=0; i<count; i++)
2350 if((s16)datasize < 2+1+(i+1)*6)
2351 throw con::InvalidIncomingDataException
2352 ("DELETEDBLOCKS length is too short");
2353 v3s16 p = readV3S16(&data[2+1+i*6]);
2354 /*infostream<<"Server: DELETEDBLOCKS ("
2355 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2356 RemoteClient *client = getClient(peer_id);
2357 client->SetBlockNotSent(p);
2360 else if(command == TOSERVER_CLICK_OBJECT)
2362 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2365 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2367 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2370 else if(command == TOSERVER_GROUND_ACTION)
2372 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2376 else if(command == TOSERVER_RELEASE)
2378 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2381 else if(command == TOSERVER_SIGNTEXT)
2383 infostream<<"Server: SIGNTEXT not supported anymore"
2387 else if(command == TOSERVER_SIGNNODETEXT)
2389 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2397 std::string datastring((char*)&data[2], datasize-2);
2398 std::istringstream is(datastring, std::ios_base::binary);
2401 is.read((char*)buf, 6);
2402 v3s16 p = readV3S16(buf);
2403 is.read((char*)buf, 2);
2404 u16 textlen = readU16(buf);
2406 for(u16 i=0; i<textlen; i++)
2408 is.read((char*)buf, 1);
2409 text += (char)buf[0];
2412 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2416 meta->setText(text);
2418 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2419 <<" at "<<PP(p)<<std::endl;
2421 v3s16 blockpos = getNodeBlockPos(p);
2422 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2425 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2429 setBlockNotSent(blockpos);
2431 else if(command == TOSERVER_INVENTORY_ACTION)
2433 // Strip command and create a stream
2434 std::string datastring((char*)&data[2], datasize-2);
2435 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2436 std::istringstream is(datastring, std::ios_base::binary);
2438 InventoryAction *a = InventoryAction::deSerialize(is);
2441 infostream<<"TOSERVER_INVENTORY_ACTION: "
2442 <<"InventoryAction::deSerialize() returned NULL"
2448 Note: Always set inventory not sent, to repair cases
2449 where the client made a bad prediction.
2453 Handle restrictions and special cases of the move action
2455 if(a->getType() == IACTION_MOVE)
2457 IMoveAction *ma = (IMoveAction*)a;
2459 ma->from_inv.applyCurrentPlayer(player->getName());
2460 ma->to_inv.applyCurrentPlayer(player->getName());
2462 setInventoryModified(ma->from_inv);
2463 setInventoryModified(ma->to_inv);
2465 bool from_inv_is_current_player =
2466 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2467 (ma->from_inv.name == player->getName());
2469 bool to_inv_is_current_player =
2470 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2471 (ma->to_inv.name == player->getName());
2474 Disable moving items out of craftpreview
2476 if(ma->from_list == "craftpreview")
2478 infostream<<"Ignoring IMoveAction from "
2479 <<(ma->from_inv.dump())<<":"<<ma->from_list
2480 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2481 <<" because src is "<<ma->from_list<<std::endl;
2487 Disable moving items into craftresult and craftpreview
2489 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2491 infostream<<"Ignoring IMoveAction from "
2492 <<(ma->from_inv.dump())<<":"<<ma->from_list
2493 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2494 <<" because dst is "<<ma->to_list<<std::endl;
2499 // Disallow moving items in elsewhere than player's inventory
2500 // if not allowed to interact
2501 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2502 && (!from_inv_is_current_player
2503 || !to_inv_is_current_player))
2505 infostream<<"Cannot move outside of player's inventory: "
2506 <<"No interact privilege"<<std::endl;
2511 // If player is not an admin, check for ownership of src and dst
2512 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2514 std::string owner_from = getInventoryOwner(ma->from_inv);
2515 if(owner_from != "" && owner_from != player->getName())
2517 infostream<<"WARNING: "<<player->getName()
2518 <<" tried to access an inventory that"
2519 <<" belongs to "<<owner_from<<std::endl;
2524 std::string owner_to = getInventoryOwner(ma->to_inv);
2525 if(owner_to != "" && owner_to != player->getName())
2527 infostream<<"WARNING: "<<player->getName()
2528 <<" tried to access an inventory that"
2529 <<" belongs to "<<owner_to<<std::endl;
2536 Handle restrictions and special cases of the drop action
2538 else if(a->getType() == IACTION_DROP)
2540 IDropAction *da = (IDropAction*)a;
2542 da->from_inv.applyCurrentPlayer(player->getName());
2544 setInventoryModified(da->from_inv);
2546 // Disallow dropping items if not allowed to interact
2547 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2552 // If player is not an admin, check for ownership
2553 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2555 std::string owner_from = getInventoryOwner(da->from_inv);
2556 if(owner_from != "" && owner_from != player->getName())
2558 infostream<<"WARNING: "<<player->getName()
2559 <<" tried to access an inventory that"
2560 <<" belongs to "<<owner_from<<std::endl;
2567 Handle restrictions and special cases of the craft action
2569 else if(a->getType() == IACTION_CRAFT)
2571 ICraftAction *ca = (ICraftAction*)a;
2573 ca->craft_inv.applyCurrentPlayer(player->getName());
2575 setInventoryModified(ca->craft_inv);
2577 //bool craft_inv_is_current_player =
2578 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2579 // (ca->craft_inv.name == player->getName());
2581 // Disallow crafting if not allowed to interact
2582 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2584 infostream<<"Cannot craft: "
2585 <<"No interact privilege"<<std::endl;
2590 // If player is not an admin, check for ownership of inventory
2591 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2593 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2594 if(owner_craft != "" && owner_craft != player->getName())
2596 infostream<<"WARNING: "<<player->getName()
2597 <<" tried to access an inventory that"
2598 <<" belongs to "<<owner_craft<<std::endl;
2606 a->apply(this, srp, this);
2610 else if(command == TOSERVER_CHAT_MESSAGE)
2618 std::string datastring((char*)&data[2], datasize-2);
2619 std::istringstream is(datastring, std::ios_base::binary);
2622 is.read((char*)buf, 2);
2623 u16 len = readU16(buf);
2625 std::wstring message;
2626 for(u16 i=0; i<len; i++)
2628 is.read((char*)buf, 2);
2629 message += (wchar_t)readU16(buf);
2632 // Get player name of this client
2633 std::wstring name = narrow_to_wide(player->getName());
2636 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2637 wide_to_narrow(message));
2638 // If script ate the message, don't proceed
2642 // Line to send to players
2644 // Whether to send to the player that sent the line
2645 bool send_to_sender = false;
2646 // Whether to send to other players
2647 bool send_to_others = false;
2649 // Local player gets all privileges regardless of
2650 // what's set on their account.
2651 u64 privs = getPlayerPrivs(player);
2654 if(message[0] == L'/')
2656 size_t strip_size = 1;
2657 if (message[1] == L'#') // support old-style commans
2659 message = message.substr(strip_size);
2661 WStrfnd f1(message);
2662 f1.next(L" "); // Skip over /#whatever
2663 std::wstring paramstring = f1.next(L"");
2665 ServerCommandContext *ctx = new ServerCommandContext(
2666 str_split(message, L' '),
2673 std::wstring reply(processServerCommand(ctx));
2674 send_to_sender = ctx->flags & SEND_TO_SENDER;
2675 send_to_others = ctx->flags & SEND_TO_OTHERS;
2677 if (ctx->flags & SEND_NO_PREFIX)
2680 line += L"Server: " + reply;
2687 if(privs & PRIV_SHOUT)
2693 send_to_others = true;
2697 line += L"Server: You are not allowed to shout";
2698 send_to_sender = true;
2705 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2708 Send the message to clients
2710 for(core::map<u16, RemoteClient*>::Iterator
2711 i = m_clients.getIterator();
2712 i.atEnd() == false; i++)
2714 // Get client and check that it is valid
2715 RemoteClient *client = i.getNode()->getValue();
2716 assert(client->peer_id == i.getNode()->getKey());
2717 if(client->serialization_version == SER_FMT_VER_INVALID)
2721 bool sender_selected = (peer_id == client->peer_id);
2722 if(sender_selected == true && send_to_sender == false)
2724 if(sender_selected == false && send_to_others == false)
2727 SendChatMessage(client->peer_id, line);
2731 else if(command == TOSERVER_DAMAGE)
2733 std::string datastring((char*)&data[2], datasize-2);
2734 std::istringstream is(datastring, std::ios_base::binary);
2735 u8 damage = readU8(is);
2737 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2739 if(g_settings->getBool("enable_damage"))
2741 actionstream<<player->getName()<<" damaged by "
2742 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2745 srp->setHP(srp->getHP() - damage);
2747 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2750 if(srp->m_hp_not_sent)
2751 SendPlayerHP(player);
2755 // Force send (to correct the client's predicted HP)
2756 SendPlayerHP(player);
2759 else if(command == TOSERVER_PASSWORD)
2762 [0] u16 TOSERVER_PASSWORD
2763 [2] u8[28] old password
2764 [30] u8[28] new password
2767 if(datasize != 2+PASSWORD_SIZE*2)
2769 /*char password[PASSWORD_SIZE];
2770 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2771 password[i] = data[2+i];
2772 password[PASSWORD_SIZE-1] = 0;*/
2774 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2782 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2784 char c = data[2+PASSWORD_SIZE+i];
2790 infostream<<"Server: Client requests a password change from "
2791 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2793 std::string playername = player->getName();
2795 if(m_authmanager.exists(playername) == false)
2797 infostream<<"Server: playername not found in authmanager"<<std::endl;
2798 // Wrong old password supplied!!
2799 SendChatMessage(peer_id, L"playername not found in authmanager");
2803 std::string checkpwd = m_authmanager.getPassword(playername);
2805 if(oldpwd != checkpwd)
2807 infostream<<"Server: invalid old password"<<std::endl;
2808 // Wrong old password supplied!!
2809 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2813 actionstream<<player->getName()<<" changes password"<<std::endl;
2815 m_authmanager.setPassword(playername, newpwd);
2817 infostream<<"Server: password change successful for "<<playername
2819 SendChatMessage(peer_id, L"Password change successful");
2821 else if(command == TOSERVER_PLAYERITEM)
2826 u16 item = readU16(&data[2]);
2827 srp->setWieldIndex(item);
2828 SendWieldedItem(srp);
2830 else if(command == TOSERVER_RESPAWN)
2835 RespawnPlayer(player);
2837 actionstream<<player->getName()<<" respawns at "
2838 <<PP(player->getPosition()/BS)<<std::endl;
2840 // ActiveObject is added to environment in AsyncRunStep after
2841 // the previous addition has been succesfully removed
2843 else if(command == TOSERVER_REQUEST_TEXTURES) {
2844 std::string datastring((char*)&data[2], datasize-2);
2845 std::istringstream is(datastring, std::ios_base::binary);
2848 core::list<TextureRequest> tosend;
2849 u16 numtextures = readU16(is);
2851 infostream<<"Sending "<<numtextures<<" textures to "
2852 <<getPlayerName(peer_id)<<std::endl;
2853 verbosestream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2855 for(int i = 0; i < numtextures; i++) {
2856 std::string name = deSerializeString(is);
2857 tosend.push_back(TextureRequest(name));
2858 verbosestream<<"TOSERVER_REQUEST_TEXTURES: requested texture "
2862 SendTexturesRequested(peer_id, tosend);
2864 // Now the client should know about everything
2865 // (definitions and textures)
2866 getClient(peer_id)->definitions_sent = true;
2868 else if(command == TOSERVER_INTERACT)
2870 std::string datastring((char*)&data[2], datasize-2);
2871 std::istringstream is(datastring, std::ios_base::binary);
2877 [5] u32 length of the next item
2878 [9] serialized PointedThing
2880 0: start digging (from undersurface) or use
2881 1: stop digging (all parameters ignored)
2882 2: digging completed
2883 3: place block or item (to abovesurface)
2886 u8 action = readU8(is);
2887 u16 item_i = readU16(is);
2888 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2889 PointedThing pointed;
2890 pointed.deSerialize(tmp_is);
2892 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2893 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2897 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2898 <<" tried to interact, but is dead!"<<std::endl;
2902 v3f player_pos = srp->m_last_good_position;
2904 // Update wielded item
2905 if(srp->getWieldIndex() != item_i)
2907 srp->setWieldIndex(item_i);
2908 SendWieldedItem(srp);
2911 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2912 v3s16 p_under = pointed.node_undersurface;
2913 v3s16 p_above = pointed.node_abovesurface;
2915 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2916 ServerActiveObject *pointed_object = NULL;
2917 if(pointed.type == POINTEDTHING_OBJECT)
2919 pointed_object = m_env->getActiveObject(pointed.object_id);
2920 if(pointed_object == NULL)
2922 verbosestream<<"TOSERVER_INTERACT: "
2923 "pointed object is NULL"<<std::endl;
2929 v3f pointed_pos_under = player_pos;
2930 v3f pointed_pos_above = player_pos;
2931 if(pointed.type == POINTEDTHING_NODE)
2933 pointed_pos_under = intToFloat(p_under, BS);
2934 pointed_pos_above = intToFloat(p_above, BS);
2936 else if(pointed.type == POINTEDTHING_OBJECT)
2938 pointed_pos_under = pointed_object->getBasePosition();
2939 pointed_pos_above = pointed_pos_under;
2943 Check that target is reasonably close
2944 (only when digging or placing things)
2946 if(action == 0 || action == 2 || action == 3)
2948 float d = player_pos.getDistanceFrom(pointed_pos_under);
2949 float max_d = BS * 14; // Just some large enough value
2951 actionstream<<"Player "<<player->getName()
2952 <<" tried to access "<<pointed.dump()
2954 <<"d="<<d<<", max_d="<<max_d
2955 <<". ignoring."<<std::endl;
2956 // Re-send block to revert change on client-side
2957 RemoteClient *client = getClient(peer_id);
2958 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2959 client->SetBlockNotSent(blockpos);
2966 Make sure the player is allowed to do it
2968 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2970 infostream<<"Ignoring interaction from player "<<player->getName()
2971 <<" because privileges are "<<getPlayerPrivs(player)
2977 0: start digging or punch object
2981 if(pointed.type == POINTEDTHING_NODE)
2984 NOTE: This can be used in the future to check if
2985 somebody is cheating, by checking the timing.
2987 MapNode n(CONTENT_IGNORE);
2990 n = m_env->getMap().getNode(p_under);
2992 catch(InvalidPositionException &e)
2994 infostream<<"Server: Not punching: Node not found."
2995 <<" Adding block to emerge queue."
2997 m_emerge_queue.addBlock(peer_id,
2998 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3000 if(n.getContent() != CONTENT_IGNORE)
3001 scriptapi_node_on_punch(m_lua, p_under, n, srp);
3003 else if(pointed.type == POINTEDTHING_OBJECT)
3005 // Skip if object has been removed
3006 if(pointed_object->m_removed)
3009 actionstream<<player->getName()<<" punches object "
3010 <<pointed.object_id<<": "
3011 <<pointed_object->getDescription()<<std::endl;
3013 ItemStack punchitem = srp->getWieldedItem();
3014 ToolCapabilities toolcap =
3015 punchitem.getToolCapabilities(m_itemdef);
3016 v3f dir = (pointed_object->getBasePosition() -
3017 (srp->getPosition() + srp->getEyeOffset())
3019 pointed_object->punch(dir, &toolcap, srp,
3020 srp->m_time_from_last_punch);
3021 srp->m_time_from_last_punch = 0;
3029 else if(action == 1)
3034 2: Digging completed
3036 else if(action == 2)
3038 // Only complete digging of nodes
3039 if(pointed.type == POINTEDTHING_NODE)
3041 MapNode n(CONTENT_IGNORE);
3044 n = m_env->getMap().getNode(p_under);
3046 catch(InvalidPositionException &e)
3048 infostream<<"Server: Not finishing digging: Node not found."
3049 <<" Adding block to emerge queue."
3051 m_emerge_queue.addBlock(peer_id,
3052 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3054 if(n.getContent() != CONTENT_IGNORE)
3055 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3060 3: place block or right-click object
3062 else if(action == 3)
3064 ItemStack item = srp->getWieldedItem();
3066 // Reset build time counter
3067 if(pointed.type == POINTEDTHING_NODE &&
3068 item.getDefinition(m_itemdef).type == ITEM_NODE)
3069 getClient(peer_id)->m_time_from_building = 0.0;
3071 if(pointed.type == POINTEDTHING_OBJECT)
3073 // Right click object
3075 // Skip if object has been removed
3076 if(pointed_object->m_removed)
3079 actionstream<<player->getName()<<" right-clicks object "
3080 <<pointed.object_id<<": "
3081 <<pointed_object->getDescription()<<std::endl;
3084 pointed_object->rightClick(srp);
3086 else if(scriptapi_item_on_place(m_lua,
3087 item, srp, pointed))
3089 // Placement was handled in lua
3091 // Apply returned ItemStack
3092 if(g_settings->getBool("creative_mode") == false)
3093 srp->setWieldedItem(item);
3101 else if(action == 4)
3103 ItemStack item = srp->getWieldedItem();
3105 actionstream<<player->getName()<<" uses "<<item.name
3106 <<", pointing at "<<pointed.dump()<<std::endl;
3108 if(scriptapi_item_on_use(m_lua,
3109 item, srp, pointed))
3111 // Apply returned ItemStack
3112 if(g_settings->getBool("creative_mode") == false)
3113 srp->setWieldedItem(item);
3119 Catch invalid actions
3123 infostream<<"WARNING: Server: Invalid action "
3124 <<action<<std::endl;
3129 infostream<<"Server::ProcessData(): Ignoring "
3130 "unknown command "<<command<<std::endl;
3134 catch(SendFailedException &e)
3136 errorstream<<"Server::ProcessData(): SendFailedException: "
3142 void Server::onMapEditEvent(MapEditEvent *event)
3144 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3145 if(m_ignore_map_edit_events)
3147 MapEditEvent *e = event->clone();
3148 m_unsent_map_edit_queue.push_back(e);
3151 Inventory* Server::getInventory(const InventoryLocation &loc)
3154 case InventoryLocation::UNDEFINED:
3157 case InventoryLocation::CURRENT_PLAYER:
3160 case InventoryLocation::PLAYER:
3162 Player *player = m_env->getPlayer(loc.name.c_str());
3165 return &player->inventory;
3168 case InventoryLocation::NODEMETA:
3170 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3173 return meta->getInventory();
3181 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3184 case InventoryLocation::UNDEFINED:
3187 case InventoryLocation::CURRENT_PLAYER:
3190 case InventoryLocation::PLAYER:
3195 case InventoryLocation::NODEMETA:
3197 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3200 return meta->getOwner();
3208 void Server::setInventoryModified(const InventoryLocation &loc)
3211 case InventoryLocation::UNDEFINED:
3214 case InventoryLocation::PLAYER:
3216 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3217 (m_env->getPlayer(loc.name.c_str()));
3220 srp->m_inventory_not_sent = true;
3223 case InventoryLocation::NODEMETA:
3225 v3s16 blockpos = getNodeBlockPos(loc.p);
3227 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3229 meta->inventoryModified();
3231 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3233 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3235 setBlockNotSent(blockpos);
3243 core::list<PlayerInfo> Server::getPlayerInfo()
3245 DSTACK(__FUNCTION_NAME);
3246 JMutexAutoLock envlock(m_env_mutex);
3247 JMutexAutoLock conlock(m_con_mutex);
3249 core::list<PlayerInfo> list;
3251 core::list<Player*> players = m_env->getPlayers();
3253 core::list<Player*>::Iterator i;
3254 for(i = players.begin();
3255 i != players.end(); i++)
3259 Player *player = *i;
3262 // Copy info from connection to info struct
3263 info.id = player->peer_id;
3264 info.address = m_con.GetPeerAddress(player->peer_id);
3265 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3267 catch(con::PeerNotFoundException &e)
3269 // Set dummy peer info
3271 info.address = Address(0,0,0,0,0);
3275 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3276 info.position = player->getPosition();
3278 list.push_back(info);
3285 void Server::peerAdded(con::Peer *peer)
3287 DSTACK(__FUNCTION_NAME);
3288 verbosestream<<"Server::peerAdded(): peer->id="
3289 <<peer->id<<std::endl;
3292 c.type = PEER_ADDED;
3293 c.peer_id = peer->id;
3295 m_peer_change_queue.push_back(c);
3298 void Server::deletingPeer(con::Peer *peer, bool timeout)
3300 DSTACK(__FUNCTION_NAME);
3301 verbosestream<<"Server::deletingPeer(): peer->id="
3302 <<peer->id<<", timeout="<<timeout<<std::endl;
3305 c.type = PEER_REMOVED;
3306 c.peer_id = peer->id;
3307 c.timeout = timeout;
3308 m_peer_change_queue.push_back(c);
3315 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3317 DSTACK(__FUNCTION_NAME);
3318 std::ostringstream os(std::ios_base::binary);
3320 writeU16(os, TOCLIENT_HP);
3324 std::string s = os.str();
3325 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3327 con.Send(peer_id, 0, data, true);
3330 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3331 const std::wstring &reason)
3333 DSTACK(__FUNCTION_NAME);
3334 std::ostringstream os(std::ios_base::binary);
3336 writeU16(os, TOCLIENT_ACCESS_DENIED);
3337 os<<serializeWideString(reason);
3340 std::string s = os.str();
3341 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3343 con.Send(peer_id, 0, data, true);
3346 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3347 bool set_camera_point_target, v3f camera_point_target)
3349 DSTACK(__FUNCTION_NAME);
3350 std::ostringstream os(std::ios_base::binary);
3352 writeU16(os, TOCLIENT_DEATHSCREEN);
3353 writeU8(os, set_camera_point_target);
3354 writeV3F1000(os, camera_point_target);
3357 std::string s = os.str();
3358 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3360 con.Send(peer_id, 0, data, true);
3363 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3364 IItemDefManager *itemdef)
3366 DSTACK(__FUNCTION_NAME);
3367 std::ostringstream os(std::ios_base::binary);
3371 u32 length of the next item
3372 zlib-compressed serialized ItemDefManager
3374 writeU16(os, TOCLIENT_ITEMDEF);
3375 std::ostringstream tmp_os(std::ios::binary);
3376 itemdef->serialize(tmp_os);
3377 std::ostringstream tmp_os2(std::ios::binary);
3378 compressZlib(tmp_os.str(), tmp_os2);
3379 os<<serializeLongString(tmp_os2.str());
3382 std::string s = os.str();
3383 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3384 <<"): size="<<s.size()<<std::endl;
3385 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3387 con.Send(peer_id, 0, data, true);
3390 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3391 INodeDefManager *nodedef)
3393 DSTACK(__FUNCTION_NAME);
3394 std::ostringstream os(std::ios_base::binary);
3398 u32 length of the next item
3399 zlib-compressed serialized NodeDefManager
3401 writeU16(os, TOCLIENT_NODEDEF);
3402 std::ostringstream tmp_os(std::ios::binary);
3403 nodedef->serialize(tmp_os);
3404 std::ostringstream tmp_os2(std::ios::binary);
3405 compressZlib(tmp_os.str(), tmp_os2);
3406 os<<serializeLongString(tmp_os2.str());
3409 std::string s = os.str();
3410 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3411 <<"): size="<<s.size()<<std::endl;
3412 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3414 con.Send(peer_id, 0, data, true);
3418 Non-static send methods
3421 void Server::SendInventory(u16 peer_id)
3423 DSTACK(__FUNCTION_NAME);
3425 ServerRemotePlayer* player =
3426 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3429 player->m_inventory_not_sent = false;
3435 std::ostringstream os;
3436 //os.imbue(std::locale("C"));
3438 player->inventory.serialize(os);
3440 std::string s = os.str();
3442 SharedBuffer<u8> data(s.size()+2);
3443 writeU16(&data[0], TOCLIENT_INVENTORY);
3444 memcpy(&data[2], s.c_str(), s.size());
3447 m_con.Send(peer_id, 0, data, true);
3450 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3452 DSTACK(__FUNCTION_NAME);
3456 std::ostringstream os(std::ios_base::binary);
3458 writeU16(os, TOCLIENT_PLAYERITEM);
3460 writeU16(os, srp->peer_id);
3461 os<<serializeString(srp->getWieldedItem().getItemString());
3464 std::string s = os.str();
3465 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3467 m_con.SendToAll(0, data, true);
3470 void Server::SendPlayerItems()
3472 DSTACK(__FUNCTION_NAME);
3474 std::ostringstream os(std::ios_base::binary);
3475 core::list<Player *> players = m_env->getPlayers(true);
3477 writeU16(os, TOCLIENT_PLAYERITEM);
3478 writeU16(os, players.size());
3479 core::list<Player *>::Iterator i;
3480 for(i = players.begin(); i != players.end(); ++i)
3483 ServerRemotePlayer *srp =
3484 static_cast<ServerRemotePlayer*>(p);
3485 writeU16(os, p->peer_id);
3486 os<<serializeString(srp->getWieldedItem().getItemString());
3490 std::string s = os.str();
3491 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3493 m_con.SendToAll(0, data, true);
3496 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3498 DSTACK(__FUNCTION_NAME);
3500 std::ostringstream os(std::ios_base::binary);
3504 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3505 os.write((char*)buf, 2);
3508 writeU16(buf, message.size());
3509 os.write((char*)buf, 2);
3512 for(u32 i=0; i<message.size(); i++)
3516 os.write((char*)buf, 2);
3520 std::string s = os.str();
3521 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3523 m_con.Send(peer_id, 0, data, true);
3526 void Server::BroadcastChatMessage(const std::wstring &message)
3528 for(core::map<u16, RemoteClient*>::Iterator
3529 i = m_clients.getIterator();
3530 i.atEnd() == false; i++)
3532 // Get client and check that it is valid
3533 RemoteClient *client = i.getNode()->getValue();
3534 assert(client->peer_id == i.getNode()->getKey());
3535 if(client->serialization_version == SER_FMT_VER_INVALID)
3538 SendChatMessage(client->peer_id, message);
3542 void Server::SendPlayerHP(Player *player)
3544 SendHP(m_con, player->peer_id, player->hp);
3545 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3548 void Server::SendMovePlayer(Player *player)
3550 DSTACK(__FUNCTION_NAME);
3551 std::ostringstream os(std::ios_base::binary);
3553 writeU16(os, TOCLIENT_MOVE_PLAYER);
3554 writeV3F1000(os, player->getPosition());
3555 writeF1000(os, player->getPitch());
3556 writeF1000(os, player->getYaw());
3559 v3f pos = player->getPosition();
3560 f32 pitch = player->getPitch();
3561 f32 yaw = player->getYaw();
3562 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3563 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3570 std::string s = os.str();
3571 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3573 m_con.Send(player->peer_id, 0, data, true);
3576 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3577 core::list<u16> *far_players, float far_d_nodes)
3579 float maxd = far_d_nodes*BS;
3580 v3f p_f = intToFloat(p, BS);
3584 SharedBuffer<u8> reply(replysize);
3585 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3586 writeS16(&reply[2], p.X);
3587 writeS16(&reply[4], p.Y);
3588 writeS16(&reply[6], p.Z);
3590 for(core::map<u16, RemoteClient*>::Iterator
3591 i = m_clients.getIterator();
3592 i.atEnd() == false; i++)
3594 // Get client and check that it is valid
3595 RemoteClient *client = i.getNode()->getValue();
3596 assert(client->peer_id == i.getNode()->getKey());
3597 if(client->serialization_version == SER_FMT_VER_INVALID)
3600 // Don't send if it's the same one
3601 if(client->peer_id == ignore_id)
3607 Player *player = m_env->getPlayer(client->peer_id);
3610 // If player is far away, only set modified blocks not sent
3611 v3f player_pos = player->getPosition();
3612 if(player_pos.getDistanceFrom(p_f) > maxd)
3614 far_players->push_back(client->peer_id);
3621 m_con.Send(client->peer_id, 0, reply, true);
3625 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3626 core::list<u16> *far_players, float far_d_nodes)
3628 float maxd = far_d_nodes*BS;
3629 v3f p_f = intToFloat(p, BS);
3631 for(core::map<u16, RemoteClient*>::Iterator
3632 i = m_clients.getIterator();
3633 i.atEnd() == false; i++)
3635 // Get client and check that it is valid
3636 RemoteClient *client = i.getNode()->getValue();
3637 assert(client->peer_id == i.getNode()->getKey());
3638 if(client->serialization_version == SER_FMT_VER_INVALID)
3641 // Don't send if it's the same one
3642 if(client->peer_id == ignore_id)
3648 Player *player = m_env->getPlayer(client->peer_id);
3651 // If player is far away, only set modified blocks not sent
3652 v3f player_pos = player->getPosition();
3653 if(player_pos.getDistanceFrom(p_f) > maxd)
3655 far_players->push_back(client->peer_id);
3662 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3663 SharedBuffer<u8> reply(replysize);
3664 writeU16(&reply[0], TOCLIENT_ADDNODE);
3665 writeS16(&reply[2], p.X);
3666 writeS16(&reply[4], p.Y);
3667 writeS16(&reply[6], p.Z);
3668 n.serialize(&reply[8], client->serialization_version);
3671 m_con.Send(client->peer_id, 0, reply, true);
3675 void Server::setBlockNotSent(v3s16 p)
3677 for(core::map<u16, RemoteClient*>::Iterator
3678 i = m_clients.getIterator();
3679 i.atEnd()==false; i++)
3681 RemoteClient *client = i.getNode()->getValue();
3682 client->SetBlockNotSent(p);
3686 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3688 DSTACK(__FUNCTION_NAME);
3690 v3s16 p = block->getPos();
3694 bool completely_air = true;
3695 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3696 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3697 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3699 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3701 completely_air = false;
3702 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3707 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3709 infostream<<"[completely air] ";
3710 infostream<<std::endl;
3714 Create a packet with the block in the right format
3717 std::ostringstream os(std::ios_base::binary);
3718 block->serialize(os, ver, false);
3719 std::string s = os.str();
3720 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3722 u32 replysize = 8 + blockdata.getSize();
3723 SharedBuffer<u8> reply(replysize);
3724 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3725 writeS16(&reply[2], p.X);
3726 writeS16(&reply[4], p.Y);
3727 writeS16(&reply[6], p.Z);
3728 memcpy(&reply[8], *blockdata, blockdata.getSize());
3730 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3731 <<": \tpacket size: "<<replysize<<std::endl;*/
3736 m_con.Send(peer_id, 1, reply, true);
3739 void Server::SendBlocks(float dtime)
3741 DSTACK(__FUNCTION_NAME);
3743 JMutexAutoLock envlock(m_env_mutex);
3744 JMutexAutoLock conlock(m_con_mutex);
3746 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3748 core::array<PrioritySortedBlockTransfer> queue;
3750 s32 total_sending = 0;
3753 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3755 for(core::map<u16, RemoteClient*>::Iterator
3756 i = m_clients.getIterator();
3757 i.atEnd() == false; i++)
3759 RemoteClient *client = i.getNode()->getValue();
3760 assert(client->peer_id == i.getNode()->getKey());
3762 // If definitions and textures have not been sent, don't
3763 // send MapBlocks either
3764 if(!client->definitions_sent)
3767 total_sending += client->SendingCount();
3769 if(client->serialization_version == SER_FMT_VER_INVALID)
3772 client->GetNextBlocks(this, dtime, queue);
3777 // Lowest priority number comes first.
3778 // Lowest is most important.
3781 for(u32 i=0; i<queue.size(); i++)
3783 //TODO: Calculate limit dynamically
3784 if(total_sending >= g_settings->getS32
3785 ("max_simultaneous_block_sends_server_total"))
3788 PrioritySortedBlockTransfer q = queue[i];
3790 MapBlock *block = NULL;
3793 block = m_env->getMap().getBlockNoCreate(q.pos);
3795 catch(InvalidPositionException &e)
3800 RemoteClient *client = getClient(q.peer_id);
3802 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3804 client->SentBlock(q.pos);
3810 void Server::PrepareTextures()
3812 DSTACK(__FUNCTION_NAME);
3814 infostream<<"Server: Calculating texture checksums"<<std::endl;
3816 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3817 i != m_mods.end(); i++){
3818 const ModSpec &mod = *i;
3819 std::string texturepath = mod.path + DIR_DELIM + "textures";
3820 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3821 for(u32 j=0; j<dirlist.size(); j++){
3822 if(dirlist[j].dir) // Ignode dirs
3824 std::string tname = dirlist[j].name;
3825 // if name contains illegal characters, ignore the texture
3826 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3827 errorstream<<"Server: ignoring illegal texture name: \""
3828 <<tname<<"\""<<std::endl;
3831 std::string tpath = texturepath + DIR_DELIM + tname;
3833 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3834 if(fis.good() == false){
3835 errorstream<<"Server::PrepareTextures(): Could not open \""
3836 <<tname<<"\" for reading"<<std::endl;
3839 std::ostringstream tmp_os(std::ios_base::binary);
3843 fis.read(buf, 1024);
3844 std::streamsize len = fis.gcount();
3845 tmp_os.write(buf, len);
3854 errorstream<<"Server::PrepareTextures(): Failed to read \""
3855 <<tname<<"\""<<std::endl;
3858 if(tmp_os.str().length() == 0){
3859 errorstream<<"Server::PrepareTextures(): Empty file \""
3860 <<tpath<<"\""<<std::endl;
3865 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3867 unsigned char *digest = sha1.getDigest();
3868 std::string digest_string = base64_encode(digest, 20);
3873 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3874 verbosestream<<"Server: sha1 for "<<tname<<"\tis "<<std::endl;
3879 struct SendableTextureAnnouncement
3882 std::string sha1_digest;
3884 SendableTextureAnnouncement(const std::string name_="",
3885 const std::string sha1_digest_=""):
3887 sha1_digest(sha1_digest_)
3892 void Server::SendTextureAnnouncement(u16 peer_id){
3893 DSTACK(__FUNCTION_NAME);
3895 verbosestream<<"Server: Announcing textures to id("<<peer_id<<")"
3898 core::list<SendableTextureAnnouncement> texture_announcements;
3900 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3903 texture_announcements.push_back(
3904 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3907 //send announcements
3911 u32 number of textures
3915 u16 length of digest string
3919 std::ostringstream os(std::ios_base::binary);
3921 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3922 writeU16(os, texture_announcements.size());
3924 for(core::list<SendableTextureAnnouncement>::Iterator
3925 j = texture_announcements.begin();
3926 j != texture_announcements.end(); j++){
3927 os<<serializeString(j->name);
3928 os<<serializeString(j->sha1_digest);
3932 std::string s = os.str();
3933 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3936 m_con.Send(peer_id, 0, data, true);
3940 struct SendableTexture
3946 SendableTexture(const std::string &name_="", const std::string path_="",
3947 const std::string &data_=""):
3954 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3955 DSTACK(__FUNCTION_NAME);
3957 verbosestream<<"Server::SendTexturesRequested(): "
3958 <<"Sending textures to client"<<std::endl;
3962 // Put 5kB in one bunch (this is not accurate)
3963 u32 bytes_per_bunch = 5000;
3965 core::array< core::list<SendableTexture> > texture_bunches;
3966 texture_bunches.push_back(core::list<SendableTexture>());
3968 u32 texture_size_bunch_total = 0;
3970 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3971 if(m_Textures.find(i->name) == m_Textures.end()){
3972 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3973 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3977 //TODO get path + name
3978 std::string tpath = m_Textures[(*i).name].path;
3981 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3982 if(fis.good() == false){
3983 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3984 <<tpath<<"\" for reading"<<std::endl;
3987 std::ostringstream tmp_os(std::ios_base::binary);
3991 fis.read(buf, 1024);
3992 std::streamsize len = fis.gcount();
3993 tmp_os.write(buf, len);
3994 texture_size_bunch_total += len;
4003 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
4004 <<(*i).name<<"\""<<std::endl;
4007 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
4008 <<tname<<"\""<<std::endl;*/
4010 texture_bunches[texture_bunches.size()-1].push_back(
4011 SendableTexture((*i).name, tpath, tmp_os.str()));
4013 // Start next bunch if got enough data
4014 if(texture_size_bunch_total >= bytes_per_bunch){
4015 texture_bunches.push_back(core::list<SendableTexture>());
4016 texture_size_bunch_total = 0;
4021 /* Create and send packets */
4023 u32 num_bunches = texture_bunches.size();
4024 for(u32 i=0; i<num_bunches; i++)
4028 u16 total number of texture bunches
4029 u16 index of this bunch
4030 u32 number of textures in this bunch
4038 std::ostringstream os(std::ios_base::binary);
4040 writeU16(os, TOCLIENT_TEXTURES);
4041 writeU16(os, num_bunches);
4043 writeU32(os, texture_bunches[i].size());
4045 for(core::list<SendableTexture>::Iterator
4046 j = texture_bunches[i].begin();
4047 j != texture_bunches[i].end(); j++){
4048 os<<serializeString(j->name);
4049 os<<serializeLongString(j->data);
4053 std::string s = os.str();
4054 verbosestream<<"Server::SendTexturesRequested(): bunch "
4055 <<i<<"/"<<num_bunches
4056 <<" textures="<<texture_bunches[i].size()
4057 <<" size=" <<s.size()<<std::endl;
4058 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4060 m_con.Send(peer_id, 0, data, true);
4070 void Server::DiePlayer(Player *player)
4072 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4074 infostream<<"Server::DiePlayer(): Player "
4075 <<player->getName()<<" dies"<<std::endl;
4079 // Trigger scripted stuff
4080 scriptapi_on_dieplayer(m_lua, srp);
4082 // Handle players that are not connected
4083 if(player->peer_id == PEER_ID_INEXISTENT){
4084 RespawnPlayer(player);
4088 SendPlayerHP(player);
4089 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4092 void Server::RespawnPlayer(Player *player)
4094 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4096 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4098 v3f pos = findSpawnPos(m_env->getServerMap());
4099 player->setPosition(pos);
4100 srp->m_last_good_position = pos;
4101 srp->m_last_good_position_age = 0;
4103 SendMovePlayer(player);
4104 SendPlayerHP(player);
4107 void Server::UpdateCrafting(u16 peer_id)
4109 DSTACK(__FUNCTION_NAME);
4111 Player* player = m_env->getPlayer(peer_id);
4114 // Get a preview for crafting
4116 // No crafting in creative mode
4117 if(g_settings->getBool("creative_mode") == false)
4118 getCraftingResult(&player->inventory, preview, false, this);
4120 // Put the new preview in
4121 InventoryList *plist = player->inventory.getList("craftpreview");
4123 assert(plist->getSize() >= 1);
4124 plist->changeItem(0, preview);
4127 RemoteClient* Server::getClient(u16 peer_id)
4129 DSTACK(__FUNCTION_NAME);
4130 //JMutexAutoLock lock(m_con_mutex);
4131 core::map<u16, RemoteClient*>::Node *n;
4132 n = m_clients.find(peer_id);
4133 // A client should exist for all peers
4135 return n->getValue();
4138 std::wstring Server::getStatusString()
4140 std::wostringstream os(std::ios_base::binary);
4143 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4145 os<<L", uptime="<<m_uptime.get();
4146 // Information about clients
4148 for(core::map<u16, RemoteClient*>::Iterator
4149 i = m_clients.getIterator();
4150 i.atEnd() == false; i++)
4152 // Get client and check that it is valid
4153 RemoteClient *client = i.getNode()->getValue();
4154 assert(client->peer_id == i.getNode()->getKey());
4155 if(client->serialization_version == SER_FMT_VER_INVALID)
4158 Player *player = m_env->getPlayer(client->peer_id);
4159 // Get name of player
4160 std::wstring name = L"unknown";
4162 name = narrow_to_wide(player->getName());
4163 // Add name to information string
4167 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4168 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4169 if(g_settings->get("motd") != "")
4170 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4174 u64 Server::getPlayerAuthPrivs(const std::string &name)
4177 return m_authmanager.getPrivs(name);
4179 catch(AuthNotFoundException &e)
4181 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4186 void Server::setPlayerAuthPrivs(const std::string &name, u64 privs)
4189 return m_authmanager.setPrivs(name, privs);
4191 catch(AuthNotFoundException &e)
4193 dstream<<"WARNING: Auth not found for "<<name<<std::endl;
4197 u64 Server::getPlayerEffectivePrivs(const std::string &name)
4199 // Local player gets all privileges regardless of
4200 // what's set on their account.
4201 if(m_simple_singleplayer_mode)
4203 if(name == g_settings->get("name"))
4205 return getPlayerAuthPrivs(name);
4208 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4210 // Add player to auth manager
4211 if(m_authmanager.exists(name) == false)
4213 infostream<<"Server: adding player "<<name
4214 <<" to auth manager"<<std::endl;
4215 m_authmanager.add(name);
4216 m_authmanager.setPrivs(name,
4217 stringToPrivs(g_settings->get("default_privs")));
4219 // Change password and save
4220 m_authmanager.setPassword(name, translatePassword(name, password));
4221 m_authmanager.save();
4224 // Saves g_settings to configpath given at initialization
4225 void Server::saveConfig()
4227 if(m_path_config != "")
4228 g_settings->updateConfigFile(m_path_config.c_str());
4231 void Server::notifyPlayer(const char *name, const std::wstring msg)
4233 Player *player = m_env->getPlayer(name);
4236 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4239 void Server::notifyPlayers(const std::wstring msg)
4241 BroadcastChatMessage(msg);
4244 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4248 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4249 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4252 // IGameDef interface
4254 IItemDefManager* Server::getItemDefManager()
4258 INodeDefManager* Server::getNodeDefManager()
4262 ICraftDefManager* Server::getCraftDefManager()
4266 ITextureSource* Server::getTextureSource()
4270 u16 Server::allocateUnknownNodeId(const std::string &name)
4272 return m_nodedef->allocateDummy(name);
4274 ISoundManager* Server::getSoundManager()
4276 return &dummySoundManager;
4279 IWritableItemDefManager* Server::getWritableItemDefManager()
4283 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4287 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4292 const ModSpec* Server::getModSpec(const std::string &modname)
4294 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4295 i != m_mods.end(); i++){
4296 const ModSpec &mod = *i;
4297 if(mod.name == modname)
4303 v3f findSpawnPos(ServerMap &map)
4305 //return v3f(50,50,50)*BS;
4310 nodepos = v2s16(0,0);
4315 // Try to find a good place a few times
4316 for(s32 i=0; i<1000; i++)
4319 // We're going to try to throw the player to this position
4320 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4321 -range + (myrand()%(range*2)));
4322 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4323 // Get ground height at point (fallbacks to heightmap function)
4324 s16 groundheight = map.findGroundLevel(nodepos2d);
4325 // Don't go underwater
4326 if(groundheight < WATER_LEVEL)
4328 //infostream<<"-> Underwater"<<std::endl;
4331 // Don't go to high places
4332 if(groundheight > WATER_LEVEL + 4)
4334 //infostream<<"-> Underwater"<<std::endl;
4338 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4339 bool is_good = false;
4341 for(s32 i=0; i<10; i++){
4342 v3s16 blockpos = getNodeBlockPos(nodepos);
4343 map.emergeBlock(blockpos, true);
4344 MapNode n = map.getNodeNoEx(nodepos);
4345 if(n.getContent() == CONTENT_AIR){
4356 // Found a good place
4357 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4363 return intToFloat(nodepos, BS);
4366 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4369 Try to get an existing player
4371 ServerRemotePlayer *player =
4372 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4375 // If player is already connected, cancel
4376 if(player->peer_id != 0)
4378 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4383 player->peer_id = peer_id;
4385 // Re-add player to environment
4386 if(player->m_removed)
4388 player->m_removed = false;
4390 m_env->addActiveObject(player);
4393 // Reset inventory to creative if in creative mode
4394 if(g_settings->getBool("creative_mode"))
4396 // Warning: double code below
4397 // Backup actual inventory
4398 player->inventory_backup = new Inventory(m_itemdef);
4399 *(player->inventory_backup) = player->inventory;
4400 // Set creative inventory
4401 player->resetInventory();
4402 scriptapi_get_creative_inventory(m_lua, player);
4409 If player with the wanted peer_id already exists, cancel.
4411 if(m_env->getPlayer(peer_id) != NULL)
4413 infostream<<"emergePlayer(): Player with wrong name but same"
4414 " peer_id already exists"<<std::endl;
4422 /* Set player position */
4424 infostream<<"Server: Finding spawn place for player \""
4425 <<name<<"\""<<std::endl;
4427 v3f pos = findSpawnPos(m_env->getServerMap());
4429 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4430 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4432 /* Add player to environment */
4433 m_env->addPlayer(player);
4434 m_env->addActiveObject(srp);
4437 scriptapi_on_newplayer(m_lua, srp);
4439 /* Add stuff to inventory */
4440 if(g_settings->getBool("creative_mode"))
4442 // Warning: double code above
4443 // Backup actual inventory
4444 player->inventory_backup = new Inventory(m_itemdef);
4445 *(player->inventory_backup) = player->inventory;
4446 // Set creative inventory
4447 player->resetInventory();
4448 scriptapi_get_creative_inventory(m_lua, player);
4453 } // create new player
4456 void Server::handlePeerChange(PeerChange &c)
4458 JMutexAutoLock envlock(m_env_mutex);
4459 JMutexAutoLock conlock(m_con_mutex);
4461 if(c.type == PEER_ADDED)
4468 core::map<u16, RemoteClient*>::Node *n;
4469 n = m_clients.find(c.peer_id);
4470 // The client shouldn't already exist
4474 RemoteClient *client = new RemoteClient();
4475 client->peer_id = c.peer_id;
4476 m_clients.insert(client->peer_id, client);
4479 else if(c.type == PEER_REMOVED)
4486 core::map<u16, RemoteClient*>::Node *n;
4487 n = m_clients.find(c.peer_id);
4488 // The client should exist
4492 Mark objects to be not known by the client
4494 RemoteClient *client = n->getValue();
4496 for(core::map<u16, bool>::Iterator
4497 i = client->m_known_objects.getIterator();
4498 i.atEnd()==false; i++)
4501 u16 id = i.getNode()->getKey();
4502 ServerActiveObject* obj = m_env->getActiveObject(id);
4504 if(obj && obj->m_known_by_count > 0)
4505 obj->m_known_by_count--;
4508 ServerRemotePlayer* player =
4509 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4511 // Collect information about leaving in chat
4512 std::wstring message;
4516 std::wstring name = narrow_to_wide(player->getName());
4519 message += L" left game";
4521 message += L" (timed out)";
4525 // Remove from environment
4527 player->m_removed = true;
4529 // Set player client disconnected
4531 player->peer_id = 0;
4539 std::ostringstream os(std::ios_base::binary);
4540 for(core::map<u16, RemoteClient*>::Iterator
4541 i = m_clients.getIterator();
4542 i.atEnd() == false; i++)
4544 RemoteClient *client = i.getNode()->getValue();
4545 assert(client->peer_id == i.getNode()->getKey());
4546 if(client->serialization_version == SER_FMT_VER_INVALID)
4549 Player *player = m_env->getPlayer(client->peer_id);
4552 // Get name of player
4553 os<<player->getName()<<" ";
4556 actionstream<<player->getName()<<" "
4557 <<(c.timeout?"times out.":"leaves game.")
4558 <<" List of players: "
4559 <<os.str()<<std::endl;
4564 delete m_clients[c.peer_id];
4565 m_clients.remove(c.peer_id);
4567 // Send player info to all remaining clients
4568 //SendPlayerInfos();
4570 // Send leave chat message to all remaining clients
4571 if(message.length() != 0)
4572 BroadcastChatMessage(message);
4581 void Server::handlePeerChanges()
4583 while(m_peer_change_queue.size() > 0)
4585 PeerChange c = m_peer_change_queue.pop_front();
4587 verbosestream<<"Server: Handling peer change: "
4588 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4591 handlePeerChange(c);
4595 u64 Server::getPlayerPrivs(Player *player)
4599 std::string playername = player->getName();
4600 return getPlayerEffectivePrivs(playername);
4603 void dedicated_server_loop(Server &server, bool &kill)
4605 DSTACK(__FUNCTION_NAME);
4607 verbosestream<<"dedicated_server_loop()"<<std::endl;
4609 IntervalLimiter m_profiler_interval;
4613 float steplen = g_settings->getFloat("dedicated_server_step");
4614 // This is kind of a hack but can be done like this
4615 // because server.step() is very light
4617 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4618 sleep_ms((int)(steplen*1000.0));
4620 server.step(steplen);
4622 if(server.getShutdownRequested() || kill)
4624 infostream<<"Dedicated server quitting"<<std::endl;
4631 float profiler_print_interval =
4632 g_settings->getFloat("profiler_print_interval");
4633 if(profiler_print_interval != 0)
4635 if(m_profiler_interval.step(steplen, profiler_print_interval))
4637 infostream<<"Profiler:"<<std::endl;
4638 g_profiler->print(infostream);
4639 g_profiler->clear();