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"
53 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
55 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
57 class MapEditEventIgnorer
60 MapEditEventIgnorer(bool *flag):
69 ~MapEditEventIgnorer()
82 void * ServerThread::Thread()
86 log_register_thread("ServerThread");
88 DSTACK(__FUNCTION_NAME);
90 BEGIN_DEBUG_EXCEPTION_HANDLER
95 //TimeTaker timer("AsyncRunStep() + Receive()");
98 //TimeTaker timer("AsyncRunStep()");
99 m_server->AsyncRunStep();
102 //infostream<<"Running m_server->Receive()"<<std::endl;
105 catch(con::NoIncomingDataException &e)
108 catch(con::PeerNotFoundException &e)
110 infostream<<"Server: PeerNotFoundException"<<std::endl;
114 END_DEBUG_EXCEPTION_HANDLER(errorstream)
119 void * EmergeThread::Thread()
123 log_register_thread("EmergeThread");
125 DSTACK(__FUNCTION_NAME);
127 BEGIN_DEBUG_EXCEPTION_HANDLER
129 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
132 Get block info from queue, emerge them and send them
135 After queue is empty, exit.
139 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
143 SharedPtr<QueuedBlockEmerge> q(qptr);
149 Do not generate over-limit
151 if(blockpos_over_limit(p))
154 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
156 //TimeTaker timer("block emerge");
159 Try to emerge it from somewhere.
161 If it is only wanted as optional, only loading from disk
166 Check if any peer wants it as non-optional. In that case it
169 Also decrement the emerge queue count in clients.
172 bool only_from_disk = true;
175 core::map<u16, u8>::Iterator i;
176 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
178 //u16 peer_id = i.getNode()->getKey();
181 u8 flags = i.getNode()->getValue();
182 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
183 only_from_disk = false;
188 if(enable_mapgen_debug_info)
189 infostream<<"EmergeThread: p="
190 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
191 <<"only_from_disk="<<only_from_disk<<std::endl;
193 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
195 MapBlock *block = NULL;
196 bool got_block = true;
197 core::map<v3s16, MapBlock*> modified_blocks;
200 Try to fetch block from memory or disk.
201 If not found and asked to generate, initialize generator.
204 bool started_generate = false;
205 mapgen::BlockMakeData data;
208 JMutexAutoLock envlock(m_server->m_env_mutex);
210 // Load sector if it isn't loaded
211 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
212 map.loadSectorMeta(p2d);
214 // Attempt to load block
215 block = map.getBlockNoCreateNoEx(p);
216 if(!block || block->isDummy() || !block->isGenerated())
218 if(enable_mapgen_debug_info)
219 infostream<<"EmergeThread: not in memory, "
220 <<"attempting to load from disk"<<std::endl;
222 block = map.loadBlock(p);
225 // If could not load and allowed to generate, start generation
226 // inside this same envlock
227 if(only_from_disk == false &&
228 (block == NULL || block->isGenerated() == false)){
229 if(enable_mapgen_debug_info)
230 infostream<<"EmergeThread: generating"<<std::endl;
231 started_generate = true;
233 map.initBlockMake(&data, p);
238 If generator was initialized, generate now when envlock is free.
243 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
245 TimeTaker t("mapgen::make_block()");
247 mapgen::make_block(&data);
249 if(enable_mapgen_debug_info == false)
250 t.stop(true); // Hide output
254 // Lock environment again to access the map
255 JMutexAutoLock envlock(m_server->m_env_mutex);
257 ScopeProfiler sp(g_profiler, "EmergeThread: after "
258 "mapgen::make_block (envlock)", SPT_AVG);
260 // Blit data back on map, update lighting, add mobs and
261 // whatever this does
262 map.finishBlockMake(&data, modified_blocks);
265 block = map.getBlockNoCreateNoEx(p);
267 // If block doesn't exist, don't try doing anything with it
268 // This happens if the block is not in generation boundaries
273 Do some post-generate stuff
276 v3s16 minp = block->getPos()*MAP_BLOCKSIZE;
277 v3s16 maxp = minp + v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
278 scriptapi_environment_on_generated(m_server->m_lua,
281 if(enable_mapgen_debug_info)
282 infostream<<"EmergeThread: ended up with: "
283 <<analyze_block(block)<<std::endl;
286 Ignore map edit events, they will not need to be
287 sent to anybody because the block hasn't been sent
290 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
292 // Activate objects and stuff
293 m_server->m_env->activateBlock(block, 0);
301 Set sent status of modified blocks on clients
304 // NOTE: Server's clients are also behind the connection mutex
305 JMutexAutoLock lock(m_server->m_con_mutex);
308 Add the originally fetched block to the modified list
312 modified_blocks.insert(p, block);
316 Set the modified blocks unsent for all the clients
319 for(core::map<u16, RemoteClient*>::Iterator
320 i = m_server->m_clients.getIterator();
321 i.atEnd() == false; i++)
323 RemoteClient *client = i.getNode()->getValue();
325 if(modified_blocks.size() > 0)
327 // Remove block from sent history
328 client->SetBlocksNotSent(modified_blocks);
334 END_DEBUG_EXCEPTION_HANDLER(errorstream)
336 log_deregister_thread();
341 void RemoteClient::GetNextBlocks(Server *server, float dtime,
342 core::array<PrioritySortedBlockTransfer> &dest)
344 DSTACK(__FUNCTION_NAME);
347 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
350 m_nothing_to_send_pause_timer -= dtime;
351 m_nearest_unsent_reset_timer += dtime;
353 if(m_nothing_to_send_pause_timer >= 0)
358 // Won't send anything if already sending
359 if(m_blocks_sending.size() >= g_settings->getU16
360 ("max_simultaneous_block_sends_per_client"))
362 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
366 //TimeTaker timer("RemoteClient::GetNextBlocks");
368 Player *player = server->m_env->getPlayer(peer_id);
370 assert(player != NULL);
372 v3f playerpos = player->getPosition();
373 v3f playerspeed = player->getSpeed();
374 v3f playerspeeddir(0,0,0);
375 if(playerspeed.getLength() > 1.0*BS)
376 playerspeeddir = playerspeed / playerspeed.getLength();
377 // Predict to next block
378 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
380 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
382 v3s16 center = getNodeBlockPos(center_nodepos);
384 // Camera position and direction
385 v3f camera_pos = player->getEyePosition();
386 v3f camera_dir = v3f(0,0,1);
387 camera_dir.rotateYZBy(player->getPitch());
388 camera_dir.rotateXZBy(player->getYaw());
390 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
391 <<camera_dir.Z<<")"<<std::endl;*/
394 Get the starting value of the block finder radius.
397 if(m_last_center != center)
399 m_nearest_unsent_d = 0;
400 m_last_center = center;
403 /*infostream<<"m_nearest_unsent_reset_timer="
404 <<m_nearest_unsent_reset_timer<<std::endl;*/
406 // Reset periodically to workaround for some bugs or stuff
407 if(m_nearest_unsent_reset_timer > 20.0)
409 m_nearest_unsent_reset_timer = 0;
410 m_nearest_unsent_d = 0;
411 //infostream<<"Resetting m_nearest_unsent_d for "
412 // <<server->getPlayerName(peer_id)<<std::endl;
415 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
416 s16 d_start = m_nearest_unsent_d;
418 //infostream<<"d_start="<<d_start<<std::endl;
420 u16 max_simul_sends_setting = g_settings->getU16
421 ("max_simultaneous_block_sends_per_client");
422 u16 max_simul_sends_usually = max_simul_sends_setting;
425 Check the time from last addNode/removeNode.
427 Decrease send rate if player is building stuff.
429 m_time_from_building += dtime;
430 if(m_time_from_building < g_settings->getFloat(
431 "full_block_send_enable_min_time_from_building"))
433 max_simul_sends_usually
434 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
438 Number of blocks sending + number of blocks selected for sending
440 u32 num_blocks_selected = m_blocks_sending.size();
443 next time d will be continued from the d from which the nearest
444 unsent block was found this time.
446 This is because not necessarily any of the blocks found this
447 time are actually sent.
449 s32 new_nearest_unsent_d = -1;
451 s16 d_max = g_settings->getS16("max_block_send_distance");
452 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
454 // Don't loop very much at a time
455 s16 max_d_increment_at_time = 2;
456 if(d_max > d_start + max_d_increment_at_time)
457 d_max = d_start + max_d_increment_at_time;
458 /*if(d_max_gen > d_start+2)
459 d_max_gen = d_start+2;*/
461 //infostream<<"Starting from "<<d_start<<std::endl;
463 s32 nearest_emerged_d = -1;
464 s32 nearest_emergefull_d = -1;
465 s32 nearest_sent_d = -1;
466 bool queue_is_full = false;
469 for(d = d_start; d <= d_max; d++)
471 /*errorstream<<"checking d="<<d<<" for "
472 <<server->getPlayerName(peer_id)<<std::endl;*/
473 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
476 If m_nearest_unsent_d was changed by the EmergeThread
477 (it can change it to 0 through SetBlockNotSent),
479 Else update m_nearest_unsent_d
481 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
483 d = m_nearest_unsent_d;
484 last_nearest_unsent_d = m_nearest_unsent_d;
488 Get the border/face dot coordinates of a "d-radiused"
491 core::list<v3s16> list;
492 getFacePositions(list, d);
494 core::list<v3s16>::Iterator li;
495 for(li=list.begin(); li!=list.end(); li++)
497 v3s16 p = *li + center;
501 - Don't allow too many simultaneous transfers
502 - EXCEPT when the blocks are very close
504 Also, don't send blocks that are already flying.
507 // Start with the usual maximum
508 u16 max_simul_dynamic = max_simul_sends_usually;
510 // If block is very close, allow full maximum
511 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
512 max_simul_dynamic = max_simul_sends_setting;
514 // Don't select too many blocks for sending
515 if(num_blocks_selected >= max_simul_dynamic)
517 queue_is_full = true;
518 goto queue_full_break;
521 // Don't send blocks that are currently being transferred
522 if(m_blocks_sending.find(p) != NULL)
528 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
529 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
530 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
531 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
532 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
533 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
536 // If this is true, inexistent block will be made from scratch
537 bool generate = d <= d_max_gen;
540 /*// Limit the generating area vertically to 2/3
541 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
544 // Limit the send area vertically to 1/2
545 if(abs(p.Y - center.Y) > d_max / 2)
551 If block is far away, don't generate it unless it is
557 // Block center y in nodes
558 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
559 // Don't generate if it's very high or very low
560 if(y < -64 || y > 64)
564 v2s16 p2d_nodes_center(
568 // Get ground height in nodes
569 s16 gh = server->m_env->getServerMap().findGroundLevel(
572 // If differs a lot, don't generate
573 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
575 // Actually, don't even send it
581 //infostream<<"d="<<d<<std::endl;
584 Don't generate or send if not in sight
585 FIXME This only works if the client uses a small enough
586 FOV setting. The default of 72 degrees is fine.
589 float camera_fov = (72.0*PI/180) * 4./3.;
590 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
596 Don't send already sent blocks
599 if(m_blocks_sent.find(p) != NULL)
606 Check if map has this block
608 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
610 bool surely_not_found_on_disk = false;
611 bool block_is_invalid = false;
614 // Reset usage timer, this block will be of use in the future.
615 block->resetUsageTimer();
617 // Block is dummy if data doesn't exist.
618 // It means it has been not found from disk and not generated
621 surely_not_found_on_disk = true;
624 // Block is valid if lighting is up-to-date and data exists
625 if(block->isValid() == false)
627 block_is_invalid = true;
630 /*if(block->isFullyGenerated() == false)
632 block_is_invalid = true;
637 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
638 v2s16 chunkpos = map->sector_to_chunk(p2d);
639 if(map->chunkNonVolatile(chunkpos) == false)
640 block_is_invalid = true;
642 if(block->isGenerated() == false)
643 block_is_invalid = true;
646 If block is not close, don't send it unless it is near
649 Block is near ground level if night-time mesh
650 differs from day-time mesh.
654 if(block->dayNightDiffed() == false)
661 If block has been marked to not exist on disk (dummy)
662 and generating new ones is not wanted, skip block.
664 if(generate == false && surely_not_found_on_disk == true)
671 Add inexistent block to emerge queue.
673 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
675 //TODO: Get value from somewhere
676 // Allow only one block in emerge queue
677 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
678 // Allow two blocks in queue per client
679 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
681 // Make it more responsive when needing to generate stuff
682 if(surely_not_found_on_disk)
684 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
686 //infostream<<"Adding block to emerge queue"<<std::endl;
688 // Add it to the emerge queue and trigger the thread
691 if(generate == false)
692 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
694 server->m_emerge_queue.addBlock(peer_id, p, flags);
695 server->m_emergethread.trigger();
697 if(nearest_emerged_d == -1)
698 nearest_emerged_d = d;
700 if(nearest_emergefull_d == -1)
701 nearest_emergefull_d = d;
708 if(nearest_sent_d == -1)
712 Add block to send queue
715 /*errorstream<<"sending from d="<<d<<" to "
716 <<server->getPlayerName(peer_id)<<std::endl;*/
718 PrioritySortedBlockTransfer q((float)d, p, peer_id);
722 num_blocks_selected += 1;
727 //infostream<<"Stopped at "<<d<<std::endl;
729 // If nothing was found for sending and nothing was queued for
730 // emerging, continue next time browsing from here
731 if(nearest_emerged_d != -1){
732 new_nearest_unsent_d = nearest_emerged_d;
733 } else if(nearest_emergefull_d != -1){
734 new_nearest_unsent_d = nearest_emergefull_d;
736 if(d > g_settings->getS16("max_block_send_distance")){
737 new_nearest_unsent_d = 0;
738 m_nothing_to_send_pause_timer = 2.0;
739 /*infostream<<"GetNextBlocks(): d wrapped around for "
740 <<server->getPlayerName(peer_id)
741 <<"; setting to 0 and pausing"<<std::endl;*/
743 if(nearest_sent_d != -1)
744 new_nearest_unsent_d = nearest_sent_d;
746 new_nearest_unsent_d = d;
750 if(new_nearest_unsent_d != -1)
751 m_nearest_unsent_d = new_nearest_unsent_d;
753 /*timer_result = timer.stop(true);
754 if(timer_result != 0)
755 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
758 void RemoteClient::GotBlock(v3s16 p)
760 if(m_blocks_sending.find(p) != NULL)
761 m_blocks_sending.remove(p);
764 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
765 " m_blocks_sending"<<std::endl;*/
766 m_excess_gotblocks++;
768 m_blocks_sent.insert(p, true);
771 void RemoteClient::SentBlock(v3s16 p)
773 if(m_blocks_sending.find(p) == NULL)
774 m_blocks_sending.insert(p, 0.0);
776 infostream<<"RemoteClient::SentBlock(): Sent block"
777 " already in m_blocks_sending"<<std::endl;
780 void RemoteClient::SetBlockNotSent(v3s16 p)
782 m_nearest_unsent_d = 0;
784 if(m_blocks_sending.find(p) != NULL)
785 m_blocks_sending.remove(p);
786 if(m_blocks_sent.find(p) != NULL)
787 m_blocks_sent.remove(p);
790 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
792 m_nearest_unsent_d = 0;
794 for(core::map<v3s16, MapBlock*>::Iterator
795 i = blocks.getIterator();
796 i.atEnd()==false; i++)
798 v3s16 p = i.getNode()->getKey();
800 if(m_blocks_sending.find(p) != NULL)
801 m_blocks_sending.remove(p);
802 if(m_blocks_sent.find(p) != NULL)
803 m_blocks_sent.remove(p);
811 PlayerInfo::PlayerInfo()
817 void PlayerInfo::PrintLine(std::ostream *s)
820 (*s)<<"\""<<name<<"\" ("
821 <<(position.X/10)<<","<<(position.Y/10)
822 <<","<<(position.Z/10)<<") ";
824 (*s)<<" avg_rtt="<<avg_rtt;
833 const std::string &path_world,
834 const std::string &path_config,
835 const SubgameSpec &gamespec
837 m_path_world(path_world),
838 m_path_config(path_config),
839 m_gamespec(gamespec),
841 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
842 m_authmanager(path_world+DIR_DELIM+"auth.txt"),
843 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
845 m_itemdef(createItemDefManager()),
846 m_nodedef(createNodeDefManager()),
847 m_craftdef(createCraftDefManager()),
849 m_emergethread(this),
851 m_time_of_day_send_timer(0),
853 m_shutdown_requested(false),
854 m_ignore_map_edit_events(false),
855 m_ignore_map_edit_events_peer_id(0)
857 m_liquid_transform_timer = 0.0;
858 m_print_info_timer = 0.0;
859 m_objectdata_timer = 0.0;
860 m_emergethread_trigger_timer = 0.0;
861 m_savemap_timer = 0.0;
865 m_step_dtime_mutex.Init();
868 if(!gamespec.isValid())
869 throw ServerError("Supplied invalid gamespec");
871 // Figure out some paths
873 m_path_share = porting::path_share + DIR_DELIM + "server";
875 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\""<<std::endl;
876 infostream<<"- world: "<<m_path_world<<std::endl;
877 infostream<<"- config: "<<m_path_config<<std::endl;
878 infostream<<"- game: "<<m_gamespec.path<<std::endl;
879 for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
880 i != m_gamespec.addon_paths.end(); i++)
881 infostream<<"- addons: "<<(*i)<<std::endl;
883 // Path to builtin.lua
884 std::string builtinpath = m_path_share + DIR_DELIM + "builtin.lua";
886 // Add default global mod search path
887 m_modspaths.push_front(m_gamespec.path + DIR_DELIM "mods");
888 // Add world mod search path
889 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
890 // Add addon mod search path
891 for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
892 i != m_gamespec.addon_paths.end(); i++)
893 m_modspaths.push_front((*i) + DIR_DELIM + "mods");
895 // Print out mod search paths
896 for(core::list<std::string>::Iterator i = m_modspaths.begin();
897 i != m_modspaths.end(); i++){
898 std::string modspath = *i;
899 infostream<<"- mods: "<<modspath<<std::endl;
902 // Create world.mt if does not already exist
903 std::string worldmt_path = m_path_world + DIR_DELIM + "world.mt";
904 if(!fs::PathExists(worldmt_path)){
905 infostream<<"Creating world.mt ("<<worldmt_path<<")"<<std::endl;
906 fs::CreateAllDirs(m_path_world);
907 std::ofstream of(worldmt_path.c_str(), std::ios::binary);
908 of<<"gameid = "<<m_gamespec.id<<"\n";
912 JMutexAutoLock envlock(m_env_mutex);
913 JMutexAutoLock conlock(m_con_mutex);
915 // Initialize scripting
917 infostream<<"Server: Initializing Lua"<<std::endl;
918 m_lua = script_init();
921 scriptapi_export(m_lua, this);
922 // Load and run builtin.lua
923 infostream<<"Server: Loading builtin.lua [\""
924 <<builtinpath<<"\"]"<<std::endl;
925 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
927 errorstream<<"Server: Failed to load and run "
928 <<builtinpath<<std::endl;
929 throw ModError("Failed to load and run "+builtinpath);
931 // Find mods in mod search paths
932 m_mods = getMods(m_modspaths);
934 infostream<<"Server: Loading mods: ";
935 for(core::list<ModSpec>::Iterator i = m_mods.begin();
936 i != m_mods.end(); i++){
937 const ModSpec &mod = *i;
938 infostream<<mod.name<<" ";
940 infostream<<std::endl;
941 // Load and run "mod" scripts
942 for(core::list<ModSpec>::Iterator i = m_mods.begin();
943 i != m_mods.end(); i++){
944 const ModSpec &mod = *i;
945 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
946 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
947 <<scriptpath<<"\"]"<<std::endl;
948 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
950 errorstream<<"Server: Failed to load and run "
951 <<scriptpath<<std::endl;
952 throw ModError("Failed to load and run "+scriptpath);
956 // Read Textures and calculate sha1 sums
959 // Apply item aliases in the node definition manager
960 m_nodedef->updateAliases(m_itemdef);
962 // Initialize Environment
964 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
967 // Give environment reference to scripting api
968 scriptapi_add_environment(m_lua, m_env);
970 // Register us to receive map edit events
971 m_env->getMap().addEventReceiver(this);
973 // If file exists, load environment metadata
974 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
976 infostream<<"Server: Loading environment metadata"<<std::endl;
977 m_env->loadMeta(m_path_world);
981 infostream<<"Server: Loading players"<<std::endl;
982 m_env->deSerializePlayers(m_path_world);
985 Add some test ActiveBlockModifiers to environment
987 add_legacy_abms(m_env, m_nodedef);
992 infostream<<"Server destructing"<<std::endl;
995 Send shutdown message
998 JMutexAutoLock conlock(m_con_mutex);
1000 std::wstring line = L"*** Server shutting down";
1003 Send the message to clients
1005 for(core::map<u16, RemoteClient*>::Iterator
1006 i = m_clients.getIterator();
1007 i.atEnd() == false; i++)
1009 // Get client and check that it is valid
1010 RemoteClient *client = i.getNode()->getValue();
1011 assert(client->peer_id == i.getNode()->getKey());
1012 if(client->serialization_version == SER_FMT_VER_INVALID)
1016 SendChatMessage(client->peer_id, line);
1018 catch(con::PeerNotFoundException &e)
1024 JMutexAutoLock envlock(m_env_mutex);
1029 infostream<<"Server: Saving players"<<std::endl;
1030 m_env->serializePlayers(m_path_world);
1033 Save environment metadata
1035 infostream<<"Server: Saving environment metadata"<<std::endl;
1036 m_env->saveMeta(m_path_world);
1048 JMutexAutoLock clientslock(m_con_mutex);
1050 for(core::map<u16, RemoteClient*>::Iterator
1051 i = m_clients.getIterator();
1052 i.atEnd() == false; i++)
1055 // NOTE: These are removed by env destructor
1057 u16 peer_id = i.getNode()->getKey();
1058 JMutexAutoLock envlock(m_env_mutex);
1059 m_env->removePlayer(peer_id);
1063 delete i.getNode()->getValue();
1067 // Delete Environment
1074 // Deinitialize scripting
1075 infostream<<"Server: Deinitializing scripting"<<std::endl;
1076 script_deinit(m_lua);
1079 void Server::start(unsigned short port)
1081 DSTACK(__FUNCTION_NAME);
1082 // Stop thread if already running
1085 // Initialize connection
1086 m_con.SetTimeoutMs(30);
1090 m_thread.setRun(true);
1093 // ASCII art for the win!
1095 <<" .__ __ __ "<<std::endl
1096 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1097 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1098 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1099 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1100 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1101 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1102 actionstream<<"Server for gameid=\""<<m_gamespec.id
1103 <<"\" listening on port "<<port<<"."<<std::endl;
1108 DSTACK(__FUNCTION_NAME);
1110 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1112 // Stop threads (set run=false first so both start stopping)
1113 m_thread.setRun(false);
1114 m_emergethread.setRun(false);
1116 m_emergethread.stop();
1118 infostream<<"Server: Threads stopped"<<std::endl;
1121 void Server::step(float dtime)
1123 DSTACK(__FUNCTION_NAME);
1128 JMutexAutoLock lock(m_step_dtime_mutex);
1129 m_step_dtime += dtime;
1133 void Server::AsyncRunStep()
1135 DSTACK(__FUNCTION_NAME);
1137 g_profiler->add("Server::AsyncRunStep (num)", 1);
1141 JMutexAutoLock lock1(m_step_dtime_mutex);
1142 dtime = m_step_dtime;
1146 // Send blocks to clients
1153 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1155 //infostream<<"Server steps "<<dtime<<std::endl;
1156 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1159 JMutexAutoLock lock1(m_step_dtime_mutex);
1160 m_step_dtime -= dtime;
1167 m_uptime.set(m_uptime.get() + dtime);
1171 // Process connection's timeouts
1172 JMutexAutoLock lock2(m_con_mutex);
1173 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1174 m_con.RunTimeouts(dtime);
1178 // This has to be called so that the client list gets synced
1179 // with the peer list of the connection
1180 handlePeerChanges();
1184 Update m_time_of_day and overall game time
1187 JMutexAutoLock envlock(m_env_mutex);
1189 m_time_counter += dtime;
1190 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1191 u32 units = (u32)(m_time_counter*speed);
1192 m_time_counter -= (f32)units / speed;
1194 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1196 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1199 Send to clients at constant intervals
1202 m_time_of_day_send_timer -= dtime;
1203 if(m_time_of_day_send_timer < 0.0)
1205 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1207 //JMutexAutoLock envlock(m_env_mutex);
1208 JMutexAutoLock conlock(m_con_mutex);
1210 for(core::map<u16, RemoteClient*>::Iterator
1211 i = m_clients.getIterator();
1212 i.atEnd() == false; i++)
1214 RemoteClient *client = i.getNode()->getValue();
1215 //Player *player = m_env->getPlayer(client->peer_id);
1217 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1218 m_env->getTimeOfDay());
1220 m_con.Send(client->peer_id, 0, data, true);
1226 JMutexAutoLock lock(m_env_mutex);
1228 ScopeProfiler sp(g_profiler, "SEnv step");
1229 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1233 const float map_timer_and_unload_dtime = 2.92;
1234 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1236 JMutexAutoLock lock(m_env_mutex);
1237 // Run Map's timers and unload unused data
1238 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1239 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1240 g_settings->getFloat("server_unload_unused_data_timeout"));
1251 JMutexAutoLock lock(m_env_mutex);
1252 JMutexAutoLock lock2(m_con_mutex);
1254 ScopeProfiler sp(g_profiler, "Server: handle players");
1256 //float player_max_speed = BS * 4.0; // Normal speed
1257 float player_max_speed = BS * 20; // Fast speed
1258 float player_max_speed_up = BS * 20;
1260 player_max_speed *= 2.5; // Tolerance
1261 player_max_speed_up *= 2.5;
1263 for(core::map<u16, RemoteClient*>::Iterator
1264 i = m_clients.getIterator();
1265 i.atEnd() == false; i++)
1267 RemoteClient *client = i.getNode()->getValue();
1268 ServerRemotePlayer *player =
1269 static_cast<ServerRemotePlayer*>
1270 (m_env->getPlayer(client->peer_id));
1275 Check player movements
1277 NOTE: Actually the server should handle player physics like the
1278 client does and compare player's position to what is calculated
1279 on our side. This is required when eg. players fly due to an
1282 player->m_last_good_position_age += dtime;
1283 if(player->m_last_good_position_age >= 1.0){
1284 float age = player->m_last_good_position_age;
1285 v3f diff = (player->getPosition() - player->m_last_good_position);
1286 float d_vert = diff.Y;
1288 float d_horiz = diff.getLength();
1289 /*infostream<<player->getName()<<"'s horizontal speed is "
1290 <<(d_horiz/age)<<std::endl;*/
1291 if(d_horiz <= age * player_max_speed &&
1292 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1293 player->m_last_good_position = player->getPosition();
1295 actionstream<<"Player "<<player->getName()
1296 <<" moved too fast; resetting position"
1298 player->setPosition(player->m_last_good_position);
1299 SendMovePlayer(player);
1301 player->m_last_good_position_age = 0;
1305 Handle player HPs (die if hp=0)
1307 if(player->hp == 0 && player->m_hp_not_sent)
1311 Send player inventories and HPs if necessary
1313 if(player->m_inventory_not_sent){
1314 UpdateCrafting(player->peer_id);
1315 SendInventory(player->peer_id);
1317 if(player->m_hp_not_sent){
1318 SendPlayerHP(player);
1324 if(!player->m_is_in_environment){
1325 player->m_removed = false;
1327 m_env->addActiveObject(player);
1332 /* Transform liquids */
1333 m_liquid_transform_timer += dtime;
1334 if(m_liquid_transform_timer >= 1.00)
1336 m_liquid_transform_timer -= 1.00;
1338 JMutexAutoLock lock(m_env_mutex);
1340 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1342 core::map<v3s16, MapBlock*> modified_blocks;
1343 m_env->getMap().transformLiquids(modified_blocks);
1348 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1349 ServerMap &map = ((ServerMap&)m_env->getMap());
1350 map.updateLighting(modified_blocks, lighting_modified_blocks);
1352 // Add blocks modified by lighting to modified_blocks
1353 for(core::map<v3s16, MapBlock*>::Iterator
1354 i = lighting_modified_blocks.getIterator();
1355 i.atEnd() == false; i++)
1357 MapBlock *block = i.getNode()->getValue();
1358 modified_blocks.insert(block->getPos(), block);
1362 Set the modified blocks unsent for all the clients
1365 JMutexAutoLock lock2(m_con_mutex);
1367 for(core::map<u16, RemoteClient*>::Iterator
1368 i = m_clients.getIterator();
1369 i.atEnd() == false; i++)
1371 RemoteClient *client = i.getNode()->getValue();
1373 if(modified_blocks.size() > 0)
1375 // Remove block from sent history
1376 client->SetBlocksNotSent(modified_blocks);
1381 // Periodically print some info
1383 float &counter = m_print_info_timer;
1389 JMutexAutoLock lock2(m_con_mutex);
1391 if(m_clients.size() != 0)
1392 infostream<<"Players:"<<std::endl;
1393 for(core::map<u16, RemoteClient*>::Iterator
1394 i = m_clients.getIterator();
1395 i.atEnd() == false; i++)
1397 //u16 peer_id = i.getNode()->getKey();
1398 RemoteClient *client = i.getNode()->getValue();
1399 Player *player = m_env->getPlayer(client->peer_id);
1402 infostream<<"* "<<player->getName()<<"\t";
1403 client->PrintInfo(infostream);
1408 //if(g_settings->getBool("enable_experimental"))
1412 Check added and deleted active objects
1415 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1416 JMutexAutoLock envlock(m_env_mutex);
1417 JMutexAutoLock conlock(m_con_mutex);
1419 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1421 // Radius inside which objects are active
1422 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1423 radius *= MAP_BLOCKSIZE;
1425 for(core::map<u16, RemoteClient*>::Iterator
1426 i = m_clients.getIterator();
1427 i.atEnd() == false; i++)
1429 RemoteClient *client = i.getNode()->getValue();
1431 // If definitions and textures have not been sent, don't
1432 // send objects either
1433 if(!client->definitions_sent)
1436 Player *player = m_env->getPlayer(client->peer_id);
1439 // This can happen if the client timeouts somehow
1440 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1442 <<" has no associated player"<<std::endl;*/
1445 v3s16 pos = floatToInt(player->getPosition(), BS);
1447 core::map<u16, bool> removed_objects;
1448 core::map<u16, bool> added_objects;
1449 m_env->getRemovedActiveObjects(pos, radius,
1450 client->m_known_objects, removed_objects);
1451 m_env->getAddedActiveObjects(pos, radius,
1452 client->m_known_objects, added_objects);
1454 // Ignore if nothing happened
1455 if(removed_objects.size() == 0 && added_objects.size() == 0)
1457 //infostream<<"active objects: none changed"<<std::endl;
1461 std::string data_buffer;
1465 // Handle removed objects
1466 writeU16((u8*)buf, removed_objects.size());
1467 data_buffer.append(buf, 2);
1468 for(core::map<u16, bool>::Iterator
1469 i = removed_objects.getIterator();
1470 i.atEnd()==false; i++)
1473 u16 id = i.getNode()->getKey();
1474 ServerActiveObject* obj = m_env->getActiveObject(id);
1476 // Add to data buffer for sending
1477 writeU16((u8*)buf, i.getNode()->getKey());
1478 data_buffer.append(buf, 2);
1480 // Remove from known objects
1481 client->m_known_objects.remove(i.getNode()->getKey());
1483 if(obj && obj->m_known_by_count > 0)
1484 obj->m_known_by_count--;
1487 // Handle added objects
1488 writeU16((u8*)buf, added_objects.size());
1489 data_buffer.append(buf, 2);
1490 for(core::map<u16, bool>::Iterator
1491 i = added_objects.getIterator();
1492 i.atEnd()==false; i++)
1495 u16 id = i.getNode()->getKey();
1496 ServerActiveObject* obj = m_env->getActiveObject(id);
1499 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1501 infostream<<"WARNING: "<<__FUNCTION_NAME
1502 <<": NULL object"<<std::endl;
1504 type = obj->getType();
1506 // Add to data buffer for sending
1507 writeU16((u8*)buf, id);
1508 data_buffer.append(buf, 2);
1509 writeU8((u8*)buf, type);
1510 data_buffer.append(buf, 1);
1513 data_buffer.append(serializeLongString(
1514 obj->getClientInitializationData()));
1516 data_buffer.append(serializeLongString(""));
1518 // Add to known objects
1519 client->m_known_objects.insert(i.getNode()->getKey(), false);
1522 obj->m_known_by_count++;
1526 SharedBuffer<u8> reply(2 + data_buffer.size());
1527 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1528 memcpy((char*)&reply[2], data_buffer.c_str(),
1529 data_buffer.size());
1531 m_con.Send(client->peer_id, 0, reply, true);
1533 verbosestream<<"Server: Sent object remove/add: "
1534 <<removed_objects.size()<<" removed, "
1535 <<added_objects.size()<<" added, "
1536 <<"packet size is "<<reply.getSize()<<std::endl;
1541 Collect a list of all the objects known by the clients
1542 and report it back to the environment.
1545 core::map<u16, bool> all_known_objects;
1547 for(core::map<u16, RemoteClient*>::Iterator
1548 i = m_clients.getIterator();
1549 i.atEnd() == false; i++)
1551 RemoteClient *client = i.getNode()->getValue();
1552 // Go through all known objects of client
1553 for(core::map<u16, bool>::Iterator
1554 i = client->m_known_objects.getIterator();
1555 i.atEnd()==false; i++)
1557 u16 id = i.getNode()->getKey();
1558 all_known_objects[id] = true;
1562 m_env->setKnownActiveObjects(whatever);
1568 Send object messages
1571 JMutexAutoLock envlock(m_env_mutex);
1572 JMutexAutoLock conlock(m_con_mutex);
1574 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1577 // Value = data sent by object
1578 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1580 // Get active object messages from environment
1583 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1587 core::list<ActiveObjectMessage>* message_list = NULL;
1588 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1589 n = buffered_messages.find(aom.id);
1592 message_list = new core::list<ActiveObjectMessage>;
1593 buffered_messages.insert(aom.id, message_list);
1597 message_list = n->getValue();
1599 message_list->push_back(aom);
1602 // Route data to every client
1603 for(core::map<u16, RemoteClient*>::Iterator
1604 i = m_clients.getIterator();
1605 i.atEnd()==false; i++)
1607 RemoteClient *client = i.getNode()->getValue();
1608 std::string reliable_data;
1609 std::string unreliable_data;
1610 // Go through all objects in message buffer
1611 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1612 j = buffered_messages.getIterator();
1613 j.atEnd()==false; j++)
1615 // If object is not known by client, skip it
1616 u16 id = j.getNode()->getKey();
1617 if(client->m_known_objects.find(id) == NULL)
1619 // Get message list of object
1620 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1621 // Go through every message
1622 for(core::list<ActiveObjectMessage>::Iterator
1623 k = list->begin(); k != list->end(); k++)
1625 // Compose the full new data with header
1626 ActiveObjectMessage aom = *k;
1627 std::string new_data;
1630 writeU16((u8*)&buf[0], aom.id);
1631 new_data.append(buf, 2);
1633 new_data += serializeString(aom.datastring);
1634 // Add data to buffer
1636 reliable_data += new_data;
1638 unreliable_data += new_data;
1642 reliable_data and unreliable_data are now ready.
1645 if(reliable_data.size() > 0)
1647 SharedBuffer<u8> reply(2 + reliable_data.size());
1648 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1649 memcpy((char*)&reply[2], reliable_data.c_str(),
1650 reliable_data.size());
1652 m_con.Send(client->peer_id, 0, reply, true);
1654 if(unreliable_data.size() > 0)
1656 SharedBuffer<u8> reply(2 + unreliable_data.size());
1657 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1658 memcpy((char*)&reply[2], unreliable_data.c_str(),
1659 unreliable_data.size());
1660 // Send as unreliable
1661 m_con.Send(client->peer_id, 0, reply, false);
1664 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1666 infostream<<"Server: Size of object message data: "
1667 <<"reliable: "<<reliable_data.size()
1668 <<", unreliable: "<<unreliable_data.size()
1673 // Clear buffered_messages
1674 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1675 i = buffered_messages.getIterator();
1676 i.atEnd()==false; i++)
1678 delete i.getNode()->getValue();
1682 } // enable_experimental
1685 Send queued-for-sending map edit events.
1688 // Don't send too many at a time
1691 // Single change sending is disabled if queue size is not small
1692 bool disable_single_change_sending = false;
1693 if(m_unsent_map_edit_queue.size() >= 4)
1694 disable_single_change_sending = true;
1696 int event_count = m_unsent_map_edit_queue.size();
1698 // We'll log the amount of each
1701 while(m_unsent_map_edit_queue.size() != 0)
1703 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1705 // Players far away from the change are stored here.
1706 // Instead of sending the changes, MapBlocks are set not sent
1708 core::list<u16> far_players;
1710 if(event->type == MEET_ADDNODE)
1712 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1713 prof.add("MEET_ADDNODE", 1);
1714 if(disable_single_change_sending)
1715 sendAddNode(event->p, event->n, event->already_known_by_peer,
1718 sendAddNode(event->p, event->n, event->already_known_by_peer,
1721 else if(event->type == MEET_REMOVENODE)
1723 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1724 prof.add("MEET_REMOVENODE", 1);
1725 if(disable_single_change_sending)
1726 sendRemoveNode(event->p, event->already_known_by_peer,
1729 sendRemoveNode(event->p, event->already_known_by_peer,
1732 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1734 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1735 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1736 setBlockNotSent(event->p);
1738 else if(event->type == MEET_OTHER)
1740 infostream<<"Server: MEET_OTHER"<<std::endl;
1741 prof.add("MEET_OTHER", 1);
1742 for(core::map<v3s16, bool>::Iterator
1743 i = event->modified_blocks.getIterator();
1744 i.atEnd()==false; i++)
1746 v3s16 p = i.getNode()->getKey();
1752 prof.add("unknown", 1);
1753 infostream<<"WARNING: Server: Unknown MapEditEvent "
1754 <<((u32)event->type)<<std::endl;
1758 Set blocks not sent to far players
1760 if(far_players.size() > 0)
1762 // Convert list format to that wanted by SetBlocksNotSent
1763 core::map<v3s16, MapBlock*> modified_blocks2;
1764 for(core::map<v3s16, bool>::Iterator
1765 i = event->modified_blocks.getIterator();
1766 i.atEnd()==false; i++)
1768 v3s16 p = i.getNode()->getKey();
1769 modified_blocks2.insert(p,
1770 m_env->getMap().getBlockNoCreateNoEx(p));
1772 // Set blocks not sent
1773 for(core::list<u16>::Iterator
1774 i = far_players.begin();
1775 i != far_players.end(); i++)
1778 RemoteClient *client = getClient(peer_id);
1781 client->SetBlocksNotSent(modified_blocks2);
1787 /*// Don't send too many at a time
1789 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1793 if(event_count >= 5){
1794 infostream<<"Server: MapEditEvents:"<<std::endl;
1795 prof.print(infostream);
1796 } else if(event_count != 0){
1797 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1798 prof.print(verbosestream);
1804 Trigger emergethread (it somehow gets to a non-triggered but
1805 bysy state sometimes)
1808 float &counter = m_emergethread_trigger_timer;
1814 m_emergethread.trigger();
1818 // Save map, players and auth stuff
1820 float &counter = m_savemap_timer;
1822 if(counter >= g_settings->getFloat("server_map_save_interval"))
1825 JMutexAutoLock lock(m_env_mutex);
1827 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1830 if(m_authmanager.isModified())
1831 m_authmanager.save();
1834 if(m_banmanager.isModified())
1835 m_banmanager.save();
1837 // Save changed parts of map
1838 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1841 m_env->serializePlayers(m_path_world);
1843 // Save environment metadata
1844 m_env->saveMeta(m_path_world);
1849 void Server::Receive()
1851 DSTACK(__FUNCTION_NAME);
1852 SharedBuffer<u8> data;
1857 JMutexAutoLock conlock(m_con_mutex);
1858 datasize = m_con.Receive(peer_id, data);
1861 // This has to be called so that the client list gets synced
1862 // with the peer list of the connection
1863 handlePeerChanges();
1865 ProcessData(*data, datasize, peer_id);
1867 catch(con::InvalidIncomingDataException &e)
1869 infostream<<"Server::Receive(): "
1870 "InvalidIncomingDataException: what()="
1871 <<e.what()<<std::endl;
1873 catch(con::PeerNotFoundException &e)
1875 //NOTE: This is not needed anymore
1877 // The peer has been disconnected.
1878 // Find the associated player and remove it.
1880 /*JMutexAutoLock envlock(m_env_mutex);
1882 infostream<<"ServerThread: peer_id="<<peer_id
1883 <<" has apparently closed connection. "
1884 <<"Removing player."<<std::endl;
1886 m_env->removePlayer(peer_id);*/
1890 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1892 DSTACK(__FUNCTION_NAME);
1893 // Environment is locked first.
1894 JMutexAutoLock envlock(m_env_mutex);
1895 JMutexAutoLock conlock(m_con_mutex);
1897 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1900 Address address = m_con.GetPeerAddress(peer_id);
1902 // drop player if is ip is banned
1903 if(m_banmanager.isIpBanned(address.serializeString())){
1904 SendAccessDenied(m_con, peer_id,
1905 L"Your ip is banned. Banned name was "
1906 +narrow_to_wide(m_banmanager.getBanName(
1907 address.serializeString())));
1908 m_con.DeletePeer(peer_id);
1912 catch(con::PeerNotFoundException &e)
1914 infostream<<"Server::ProcessData(): Cancelling: peer "
1915 <<peer_id<<" not found"<<std::endl;
1919 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1921 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1929 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1931 if(command == TOSERVER_INIT)
1933 // [0] u16 TOSERVER_INIT
1934 // [2] u8 SER_FMT_VER_HIGHEST
1935 // [3] u8[20] player_name
1936 // [23] u8[28] password <--- can be sent without this, from old versions
1938 if(datasize < 2+1+PLAYERNAME_SIZE)
1941 verbosestream<<"Server: Got TOSERVER_INIT from "
1942 <<peer_id<<std::endl;
1944 // First byte after command is maximum supported
1945 // serialization version
1946 u8 client_max = data[2];
1947 u8 our_max = SER_FMT_VER_HIGHEST;
1948 // Use the highest version supported by both
1949 u8 deployed = core::min_(client_max, our_max);
1950 // If it's lower than the lowest supported, give up.
1951 if(deployed < SER_FMT_VER_LOWEST)
1952 deployed = SER_FMT_VER_INVALID;
1954 //peer->serialization_version = deployed;
1955 getClient(peer_id)->pending_serialization_version = deployed;
1957 if(deployed == SER_FMT_VER_INVALID)
1959 actionstream<<"Server: A mismatched client tried to connect from "
1960 <<addr_s<<std::endl;
1961 infostream<<"Server: Cannot negotiate "
1962 "serialization version with peer "
1963 <<peer_id<<std::endl;
1964 SendAccessDenied(m_con, peer_id, std::wstring(
1965 L"Your client's version is not supported.\n"
1966 L"Server version is ")
1967 + narrow_to_wide(VERSION_STRING) + L"."
1973 Read and check network protocol version
1976 u16 net_proto_version = 0;
1977 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1979 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1982 getClient(peer_id)->net_proto_version = net_proto_version;
1984 if(net_proto_version == 0)
1986 actionstream<<"Server: An old tried to connect from "<<addr_s
1988 SendAccessDenied(m_con, peer_id, std::wstring(
1989 L"Your client's version is not supported.\n"
1990 L"Server version is ")
1991 + narrow_to_wide(VERSION_STRING) + L"."
1996 if(g_settings->getBool("strict_protocol_version_checking"))
1998 if(net_proto_version != PROTOCOL_VERSION)
2000 actionstream<<"Server: A mismatched client tried to connect"
2001 <<" from "<<addr_s<<std::endl;
2002 SendAccessDenied(m_con, peer_id, std::wstring(
2003 L"Your client's version is not supported.\n"
2004 L"Server version is ")
2005 + narrow_to_wide(VERSION_STRING) + L",\n"
2006 + L"server's PROTOCOL_VERSION is "
2007 + narrow_to_wide(itos(PROTOCOL_VERSION))
2008 + L", client's PROTOCOL_VERSION is "
2009 + narrow_to_wide(itos(net_proto_version))
2020 char playername[PLAYERNAME_SIZE];
2021 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2023 playername[i] = data[3+i];
2025 playername[PLAYERNAME_SIZE-1] = 0;
2027 if(playername[0]=='\0')
2029 actionstream<<"Server: Player with an empty name "
2030 <<"tried to connect from "<<addr_s<<std::endl;
2031 SendAccessDenied(m_con, peer_id,
2036 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2038 actionstream<<"Server: Player with an invalid name "
2039 <<"tried to connect from "<<addr_s<<std::endl;
2040 SendAccessDenied(m_con, peer_id,
2041 L"Name contains unallowed characters");
2045 infostream<<"Server: New connection: \""<<playername<<"\" from "
2046 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2049 char password[PASSWORD_SIZE];
2050 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2052 // old version - assume blank password
2057 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2059 password[i] = data[23+i];
2061 password[PASSWORD_SIZE-1] = 0;
2064 // Add player to auth manager
2065 if(m_authmanager.exists(playername) == false)
2067 std::wstring default_password =
2068 narrow_to_wide(g_settings->get("default_password"));
2069 std::string translated_default_password =
2070 translatePassword(playername, default_password);
2072 // If default_password is empty, allow any initial password
2073 if (default_password.length() == 0)
2074 translated_default_password = password;
2076 infostream<<"Server: adding player "<<playername
2077 <<" to auth manager"<<std::endl;
2078 m_authmanager.add(playername);
2079 m_authmanager.setPassword(playername, translated_default_password);
2080 m_authmanager.setPrivs(playername,
2081 stringToPrivs(g_settings->get("default_privs")));
2082 m_authmanager.save();
2085 std::string checkpwd = m_authmanager.getPassword(playername);
2087 /*infostream<<"Server: Client gave password '"<<password
2088 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2090 if(password != checkpwd)
2092 infostream<<"Server: peer_id="<<peer_id
2093 <<": supplied invalid password for "
2094 <<playername<<std::endl;
2095 SendAccessDenied(m_con, peer_id, L"Invalid password");
2099 // Enforce user limit.
2100 // Don't enforce for users that have some admin right
2101 if(m_clients.size() >= g_settings->getU16("max_users") &&
2102 (m_authmanager.getPrivs(playername)
2103 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2104 playername != g_settings->get("name"))
2106 actionstream<<"Server: "<<playername<<" tried to join, but there"
2107 <<" are already max_users="
2108 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2109 SendAccessDenied(m_con, peer_id, L"Too many users.");
2114 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2116 // If failed, cancel
2119 errorstream<<"Server: peer_id="<<peer_id
2120 <<": failed to emerge player"<<std::endl;
2125 Answer with a TOCLIENT_INIT
2128 SharedBuffer<u8> reply(2+1+6+8);
2129 writeU16(&reply[0], TOCLIENT_INIT);
2130 writeU8(&reply[2], deployed);
2131 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2132 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2135 m_con.Send(peer_id, 0, reply, true);
2139 Send complete position information
2141 SendMovePlayer(player);
2146 if(command == TOSERVER_INIT2)
2148 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2149 <<peer_id<<std::endl;
2152 getClient(peer_id)->serialization_version
2153 = getClient(peer_id)->pending_serialization_version;
2156 Send some initialization data
2159 infostream<<"Server: Sending content to "
2160 <<getPlayerName(peer_id)<<std::endl;
2162 // Send item definitions
2163 SendItemDef(m_con, peer_id, m_itemdef);
2165 // Send node definitions
2166 SendNodeDef(m_con, peer_id, m_nodedef);
2168 // Send texture announcement
2169 SendTextureAnnouncement(peer_id);
2171 // Send player info to all players
2172 //SendPlayerInfos();
2174 // Send inventory to player
2175 UpdateCrafting(peer_id);
2176 SendInventory(peer_id);
2178 // Send player items to all players
2181 Player *player = m_env->getPlayer(peer_id);
2184 SendPlayerHP(player);
2186 // Show death screen if necessary
2188 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2192 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2193 m_env->getTimeOfDay());
2194 m_con.Send(peer_id, 0, data, true);
2197 // Send information about server to player in chat
2198 SendChatMessage(peer_id, getStatusString());
2200 // Send information about joining in chat
2202 std::wstring name = L"unknown";
2203 Player *player = m_env->getPlayer(peer_id);
2205 name = narrow_to_wide(player->getName());
2207 std::wstring message;
2210 message += L" joined game";
2211 BroadcastChatMessage(message);
2214 // Warnings about protocol version can be issued here
2215 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2217 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2224 std::ostringstream os(std::ios_base::binary);
2225 for(core::map<u16, RemoteClient*>::Iterator
2226 i = m_clients.getIterator();
2227 i.atEnd() == false; i++)
2229 RemoteClient *client = i.getNode()->getValue();
2230 assert(client->peer_id == i.getNode()->getKey());
2231 if(client->serialization_version == SER_FMT_VER_INVALID)
2234 Player *player = m_env->getPlayer(client->peer_id);
2237 // Get name of player
2238 os<<player->getName()<<" ";
2241 actionstream<<player->getName()<<" joins game. List of players: "
2242 <<os.str()<<std::endl;
2248 if(peer_ser_ver == SER_FMT_VER_INVALID)
2250 infostream<<"Server::ProcessData(): Cancelling: Peer"
2251 " serialization format invalid or not initialized."
2252 " Skipping incoming command="<<command<<std::endl;
2256 Player *player = m_env->getPlayer(peer_id);
2257 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2260 infostream<<"Server::ProcessData(): Cancelling: "
2261 "No player for peer_id="<<peer_id
2265 if(command == TOSERVER_PLAYERPOS)
2267 if(datasize < 2+12+12+4+4)
2271 v3s32 ps = readV3S32(&data[start+2]);
2272 v3s32 ss = readV3S32(&data[start+2+12]);
2273 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2274 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2275 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2276 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2277 pitch = wrapDegrees(pitch);
2278 yaw = wrapDegrees(yaw);
2280 player->setPosition(position);
2281 player->setSpeed(speed);
2282 player->setPitch(pitch);
2283 player->setYaw(yaw);
2285 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2286 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2287 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2289 else if(command == TOSERVER_GOTBLOCKS)
2302 u16 count = data[2];
2303 for(u16 i=0; i<count; i++)
2305 if((s16)datasize < 2+1+(i+1)*6)
2306 throw con::InvalidIncomingDataException
2307 ("GOTBLOCKS length is too short");
2308 v3s16 p = readV3S16(&data[2+1+i*6]);
2309 /*infostream<<"Server: GOTBLOCKS ("
2310 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2311 RemoteClient *client = getClient(peer_id);
2312 client->GotBlock(p);
2315 else if(command == TOSERVER_DELETEDBLOCKS)
2328 u16 count = data[2];
2329 for(u16 i=0; i<count; i++)
2331 if((s16)datasize < 2+1+(i+1)*6)
2332 throw con::InvalidIncomingDataException
2333 ("DELETEDBLOCKS length is too short");
2334 v3s16 p = readV3S16(&data[2+1+i*6]);
2335 /*infostream<<"Server: DELETEDBLOCKS ("
2336 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2337 RemoteClient *client = getClient(peer_id);
2338 client->SetBlockNotSent(p);
2341 else if(command == TOSERVER_CLICK_OBJECT)
2343 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2346 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2348 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2351 else if(command == TOSERVER_GROUND_ACTION)
2353 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2357 else if(command == TOSERVER_RELEASE)
2359 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2362 else if(command == TOSERVER_SIGNTEXT)
2364 infostream<<"Server: SIGNTEXT not supported anymore"
2368 else if(command == TOSERVER_SIGNNODETEXT)
2370 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2378 std::string datastring((char*)&data[2], datasize-2);
2379 std::istringstream is(datastring, std::ios_base::binary);
2382 is.read((char*)buf, 6);
2383 v3s16 p = readV3S16(buf);
2384 is.read((char*)buf, 2);
2385 u16 textlen = readU16(buf);
2387 for(u16 i=0; i<textlen; i++)
2389 is.read((char*)buf, 1);
2390 text += (char)buf[0];
2393 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2397 meta->setText(text);
2399 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2400 <<" at "<<PP(p)<<std::endl;
2402 v3s16 blockpos = getNodeBlockPos(p);
2403 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2406 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2410 setBlockNotSent(blockpos);
2412 else if(command == TOSERVER_INVENTORY_ACTION)
2414 // Strip command and create a stream
2415 std::string datastring((char*)&data[2], datasize-2);
2416 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2417 std::istringstream is(datastring, std::ios_base::binary);
2419 InventoryAction *a = InventoryAction::deSerialize(is);
2422 infostream<<"TOSERVER_INVENTORY_ACTION: "
2423 <<"InventoryAction::deSerialize() returned NULL"
2429 Note: Always set inventory not sent, to repair cases
2430 where the client made a bad prediction.
2434 Handle restrictions and special cases of the move action
2436 if(a->getType() == IACTION_MOVE)
2438 IMoveAction *ma = (IMoveAction*)a;
2440 ma->from_inv.applyCurrentPlayer(player->getName());
2441 ma->to_inv.applyCurrentPlayer(player->getName());
2443 setInventoryModified(ma->from_inv);
2444 setInventoryModified(ma->to_inv);
2446 bool from_inv_is_current_player =
2447 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2448 (ma->from_inv.name == player->getName());
2450 bool to_inv_is_current_player =
2451 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2452 (ma->to_inv.name == player->getName());
2455 Disable moving items out of craftpreview
2457 if(ma->from_list == "craftpreview")
2459 infostream<<"Ignoring IMoveAction from "
2460 <<(ma->from_inv.dump())<<":"<<ma->from_list
2461 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2462 <<" because src is "<<ma->from_list<<std::endl;
2468 Disable moving items into craftresult and craftpreview
2470 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2472 infostream<<"Ignoring IMoveAction from "
2473 <<(ma->from_inv.dump())<<":"<<ma->from_list
2474 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2475 <<" because dst is "<<ma->to_list<<std::endl;
2480 // Disallow moving items in elsewhere than player's inventory
2481 // if not allowed to interact
2482 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2483 && (!from_inv_is_current_player
2484 || !to_inv_is_current_player))
2486 infostream<<"Cannot move outside of player's inventory: "
2487 <<"No interact privilege"<<std::endl;
2492 // If player is not an admin, check for ownership of src and dst
2493 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2495 std::string owner_from = getInventoryOwner(ma->from_inv);
2496 if(owner_from != "" && owner_from != player->getName())
2498 infostream<<"WARNING: "<<player->getName()
2499 <<" tried to access an inventory that"
2500 <<" belongs to "<<owner_from<<std::endl;
2505 std::string owner_to = getInventoryOwner(ma->to_inv);
2506 if(owner_to != "" && owner_to != player->getName())
2508 infostream<<"WARNING: "<<player->getName()
2509 <<" tried to access an inventory that"
2510 <<" belongs to "<<owner_to<<std::endl;
2517 Handle restrictions and special cases of the drop action
2519 else if(a->getType() == IACTION_DROP)
2521 IDropAction *da = (IDropAction*)a;
2523 da->from_inv.applyCurrentPlayer(player->getName());
2525 setInventoryModified(da->from_inv);
2527 // Disallow dropping items if not allowed to interact
2528 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2533 // If player is not an admin, check for ownership
2534 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2536 std::string owner_from = getInventoryOwner(da->from_inv);
2537 if(owner_from != "" && owner_from != player->getName())
2539 infostream<<"WARNING: "<<player->getName()
2540 <<" tried to access an inventory that"
2541 <<" belongs to "<<owner_from<<std::endl;
2548 Handle restrictions and special cases of the craft action
2550 else if(a->getType() == IACTION_CRAFT)
2552 ICraftAction *ca = (ICraftAction*)a;
2554 ca->craft_inv.applyCurrentPlayer(player->getName());
2556 setInventoryModified(ca->craft_inv);
2558 //bool craft_inv_is_current_player =
2559 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2560 // (ca->craft_inv.name == player->getName());
2562 // Disallow crafting if not allowed to interact
2563 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2565 infostream<<"Cannot craft: "
2566 <<"No interact privilege"<<std::endl;
2571 // If player is not an admin, check for ownership of inventory
2572 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2574 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2575 if(owner_craft != "" && owner_craft != player->getName())
2577 infostream<<"WARNING: "<<player->getName()
2578 <<" tried to access an inventory that"
2579 <<" belongs to "<<owner_craft<<std::endl;
2587 a->apply(this, srp, this);
2591 else if(command == TOSERVER_CHAT_MESSAGE)
2599 std::string datastring((char*)&data[2], datasize-2);
2600 std::istringstream is(datastring, std::ios_base::binary);
2603 is.read((char*)buf, 2);
2604 u16 len = readU16(buf);
2606 std::wstring message;
2607 for(u16 i=0; i<len; i++)
2609 is.read((char*)buf, 2);
2610 message += (wchar_t)readU16(buf);
2613 // Get player name of this client
2614 std::wstring name = narrow_to_wide(player->getName());
2617 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2618 wide_to_narrow(message));
2619 // If script ate the message, don't proceed
2623 // Line to send to players
2625 // Whether to send to the player that sent the line
2626 bool send_to_sender = false;
2627 // Whether to send to other players
2628 bool send_to_others = false;
2630 // Local player gets all privileges regardless of
2631 // what's set on their account.
2632 u64 privs = getPlayerPrivs(player);
2635 if(message[0] == L'/')
2637 size_t strip_size = 1;
2638 if (message[1] == L'#') // support old-style commans
2640 message = message.substr(strip_size);
2642 WStrfnd f1(message);
2643 f1.next(L" "); // Skip over /#whatever
2644 std::wstring paramstring = f1.next(L"");
2646 ServerCommandContext *ctx = new ServerCommandContext(
2647 str_split(message, L' '),
2654 std::wstring reply(processServerCommand(ctx));
2655 send_to_sender = ctx->flags & SEND_TO_SENDER;
2656 send_to_others = ctx->flags & SEND_TO_OTHERS;
2658 if (ctx->flags & SEND_NO_PREFIX)
2661 line += L"Server: " + reply;
2668 if(privs & PRIV_SHOUT)
2674 send_to_others = true;
2678 line += L"Server: You are not allowed to shout";
2679 send_to_sender = true;
2686 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2689 Send the message to clients
2691 for(core::map<u16, RemoteClient*>::Iterator
2692 i = m_clients.getIterator();
2693 i.atEnd() == false; i++)
2695 // Get client and check that it is valid
2696 RemoteClient *client = i.getNode()->getValue();
2697 assert(client->peer_id == i.getNode()->getKey());
2698 if(client->serialization_version == SER_FMT_VER_INVALID)
2702 bool sender_selected = (peer_id == client->peer_id);
2703 if(sender_selected == true && send_to_sender == false)
2705 if(sender_selected == false && send_to_others == false)
2708 SendChatMessage(client->peer_id, line);
2712 else if(command == TOSERVER_DAMAGE)
2714 std::string datastring((char*)&data[2], datasize-2);
2715 std::istringstream is(datastring, std::ios_base::binary);
2716 u8 damage = readU8(is);
2718 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2720 if(g_settings->getBool("enable_damage"))
2722 actionstream<<player->getName()<<" damaged by "
2723 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2726 srp->setHP(srp->getHP() - damage);
2728 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2731 if(srp->m_hp_not_sent)
2732 SendPlayerHP(player);
2736 // Force send (to correct the client's predicted HP)
2737 SendPlayerHP(player);
2740 else if(command == TOSERVER_PASSWORD)
2743 [0] u16 TOSERVER_PASSWORD
2744 [2] u8[28] old password
2745 [30] u8[28] new password
2748 if(datasize != 2+PASSWORD_SIZE*2)
2750 /*char password[PASSWORD_SIZE];
2751 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2752 password[i] = data[2+i];
2753 password[PASSWORD_SIZE-1] = 0;*/
2755 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2763 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2765 char c = data[2+PASSWORD_SIZE+i];
2771 infostream<<"Server: Client requests a password change from "
2772 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2774 std::string playername = player->getName();
2776 if(m_authmanager.exists(playername) == false)
2778 infostream<<"Server: playername not found in authmanager"<<std::endl;
2779 // Wrong old password supplied!!
2780 SendChatMessage(peer_id, L"playername not found in authmanager");
2784 std::string checkpwd = m_authmanager.getPassword(playername);
2786 if(oldpwd != checkpwd)
2788 infostream<<"Server: invalid old password"<<std::endl;
2789 // Wrong old password supplied!!
2790 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2794 actionstream<<player->getName()<<" changes password"<<std::endl;
2796 m_authmanager.setPassword(playername, newpwd);
2798 infostream<<"Server: password change successful for "<<playername
2800 SendChatMessage(peer_id, L"Password change successful");
2802 else if(command == TOSERVER_PLAYERITEM)
2807 u16 item = readU16(&data[2]);
2808 srp->setWieldIndex(item);
2809 SendWieldedItem(srp);
2811 else if(command == TOSERVER_RESPAWN)
2816 RespawnPlayer(player);
2818 actionstream<<player->getName()<<" respawns at "
2819 <<PP(player->getPosition()/BS)<<std::endl;
2821 // ActiveObject is added to environment in AsyncRunStep after
2822 // the previous addition has been succesfully removed
2824 else if(command == TOSERVER_REQUEST_TEXTURES) {
2825 std::string datastring((char*)&data[2], datasize-2);
2826 std::istringstream is(datastring, std::ios_base::binary);
2829 core::list<TextureRequest> tosend;
2830 u16 numtextures = readU16(is);
2832 infostream<<"Sending "<<numtextures<<" textures to "
2833 <<getPlayerName(peer_id)<<std::endl;
2834 verbosestream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2836 for(int i = 0; i < numtextures; i++) {
2837 std::string name = deSerializeString(is);
2838 tosend.push_back(TextureRequest(name));
2839 verbosestream<<"TOSERVER_REQUEST_TEXTURES: requested texture "
2843 SendTexturesRequested(peer_id, tosend);
2845 // Now the client should know about everything
2846 // (definitions and textures)
2847 getClient(peer_id)->definitions_sent = true;
2849 else if(command == TOSERVER_INTERACT)
2851 std::string datastring((char*)&data[2], datasize-2);
2852 std::istringstream is(datastring, std::ios_base::binary);
2858 [5] u32 length of the next item
2859 [9] serialized PointedThing
2861 0: start digging (from undersurface) or use
2862 1: stop digging (all parameters ignored)
2863 2: digging completed
2864 3: place block or item (to abovesurface)
2867 u8 action = readU8(is);
2868 u16 item_i = readU16(is);
2869 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2870 PointedThing pointed;
2871 pointed.deSerialize(tmp_is);
2873 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2874 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2878 verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
2879 <<" tried to interact, but is dead!"<<std::endl;
2883 v3f player_pos = srp->m_last_good_position;
2885 // Update wielded item
2886 if(srp->getWieldIndex() != item_i)
2888 srp->setWieldIndex(item_i);
2889 SendWieldedItem(srp);
2892 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2893 v3s16 p_under = pointed.node_undersurface;
2894 v3s16 p_above = pointed.node_abovesurface;
2896 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2897 ServerActiveObject *pointed_object = NULL;
2898 if(pointed.type == POINTEDTHING_OBJECT)
2900 pointed_object = m_env->getActiveObject(pointed.object_id);
2901 if(pointed_object == NULL)
2903 verbosestream<<"TOSERVER_INTERACT: "
2904 "pointed object is NULL"<<std::endl;
2910 v3f pointed_pos_under = player_pos;
2911 v3f pointed_pos_above = player_pos;
2912 if(pointed.type == POINTEDTHING_NODE)
2914 pointed_pos_under = intToFloat(p_under, BS);
2915 pointed_pos_above = intToFloat(p_above, BS);
2917 else if(pointed.type == POINTEDTHING_OBJECT)
2919 pointed_pos_under = pointed_object->getBasePosition();
2920 pointed_pos_above = pointed_pos_under;
2924 Check that target is reasonably close
2925 (only when digging or placing things)
2927 if(action == 0 || action == 2 || action == 3)
2929 float d = player_pos.getDistanceFrom(pointed_pos_under);
2930 float max_d = BS * 14; // Just some large enough value
2932 actionstream<<"Player "<<player->getName()
2933 <<" tried to access "<<pointed.dump()
2935 <<"d="<<d<<", max_d="<<max_d
2936 <<". ignoring."<<std::endl;
2937 // Re-send block to revert change on client-side
2938 RemoteClient *client = getClient(peer_id);
2939 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2940 client->SetBlockNotSent(blockpos);
2947 Make sure the player is allowed to do it
2949 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2951 infostream<<"Ignoring interaction from player "<<player->getName()
2952 <<" because privileges are "<<getPlayerPrivs(player)
2958 0: start digging or punch object
2962 if(pointed.type == POINTEDTHING_NODE)
2965 NOTE: This can be used in the future to check if
2966 somebody is cheating, by checking the timing.
2968 MapNode n(CONTENT_IGNORE);
2971 n = m_env->getMap().getNode(p_under);
2973 catch(InvalidPositionException &e)
2975 infostream<<"Server: Not punching: Node not found."
2976 <<" Adding block to emerge queue."
2978 m_emerge_queue.addBlock(peer_id,
2979 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2981 if(n.getContent() != CONTENT_IGNORE)
2982 scriptapi_node_on_punch(m_lua, p_under, n, srp);
2984 else if(pointed.type == POINTEDTHING_OBJECT)
2986 // Skip if object has been removed
2987 if(pointed_object->m_removed)
2990 actionstream<<player->getName()<<" punches object "
2991 <<pointed.object_id<<": "
2992 <<pointed_object->getDescription()<<std::endl;
2994 ItemStack punchitem = srp->getWieldedItem();
2995 ToolCapabilities toolcap =
2996 punchitem.getToolCapabilities(m_itemdef);
2997 v3f dir = (pointed_object->getBasePosition() -
2998 (srp->getPosition() + srp->getEyeOffset())
3000 pointed_object->punch(dir, &toolcap, srp,
3001 srp->m_time_from_last_punch);
3002 srp->m_time_from_last_punch = 0;
3010 else if(action == 1)
3015 2: Digging completed
3017 else if(action == 2)
3019 // Only complete digging of nodes
3020 if(pointed.type == POINTEDTHING_NODE)
3022 MapNode n(CONTENT_IGNORE);
3025 n = m_env->getMap().getNode(p_under);
3027 catch(InvalidPositionException &e)
3029 infostream<<"Server: Not finishing digging: Node not found."
3030 <<" Adding block to emerge queue."
3032 m_emerge_queue.addBlock(peer_id,
3033 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3035 if(n.getContent() != CONTENT_IGNORE)
3036 scriptapi_node_on_dig(m_lua, p_under, n, srp);
3041 3: place block or right-click object
3043 else if(action == 3)
3045 ItemStack item = srp->getWieldedItem();
3047 // Reset build time counter
3048 if(pointed.type == POINTEDTHING_NODE &&
3049 item.getDefinition(m_itemdef).type == ITEM_NODE)
3050 getClient(peer_id)->m_time_from_building = 0.0;
3052 if(pointed.type == POINTEDTHING_OBJECT)
3054 // Right click object
3056 // Skip if object has been removed
3057 if(pointed_object->m_removed)
3060 actionstream<<player->getName()<<" right-clicks object "
3061 <<pointed.object_id<<": "
3062 <<pointed_object->getDescription()<<std::endl;
3065 pointed_object->rightClick(srp);
3067 else if(scriptapi_item_on_place(m_lua,
3068 item, srp, pointed))
3070 // Placement was handled in lua
3072 // Apply returned ItemStack
3073 if(g_settings->getBool("creative_mode") == false)
3074 srp->setWieldedItem(item);
3082 else if(action == 4)
3084 ItemStack item = srp->getWieldedItem();
3086 actionstream<<player->getName()<<" uses "<<item.name
3087 <<", pointing at "<<pointed.dump()<<std::endl;
3089 if(scriptapi_item_on_use(m_lua,
3090 item, srp, pointed))
3092 // Apply returned ItemStack
3093 if(g_settings->getBool("creative_mode") == false)
3094 srp->setWieldedItem(item);
3100 Catch invalid actions
3104 infostream<<"WARNING: Server: Invalid action "
3105 <<action<<std::endl;
3110 infostream<<"Server::ProcessData(): Ignoring "
3111 "unknown command "<<command<<std::endl;
3115 catch(SendFailedException &e)
3117 errorstream<<"Server::ProcessData(): SendFailedException: "
3123 void Server::onMapEditEvent(MapEditEvent *event)
3125 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3126 if(m_ignore_map_edit_events)
3128 MapEditEvent *e = event->clone();
3129 m_unsent_map_edit_queue.push_back(e);
3132 Inventory* Server::getInventory(const InventoryLocation &loc)
3135 case InventoryLocation::UNDEFINED:
3138 case InventoryLocation::CURRENT_PLAYER:
3141 case InventoryLocation::PLAYER:
3143 Player *player = m_env->getPlayer(loc.name.c_str());
3146 return &player->inventory;
3149 case InventoryLocation::NODEMETA:
3151 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3154 return meta->getInventory();
3162 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3165 case InventoryLocation::UNDEFINED:
3168 case InventoryLocation::CURRENT_PLAYER:
3171 case InventoryLocation::PLAYER:
3176 case InventoryLocation::NODEMETA:
3178 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3181 return meta->getOwner();
3189 void Server::setInventoryModified(const InventoryLocation &loc)
3192 case InventoryLocation::UNDEFINED:
3195 case InventoryLocation::PLAYER:
3197 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3198 (m_env->getPlayer(loc.name.c_str()));
3201 srp->m_inventory_not_sent = true;
3204 case InventoryLocation::NODEMETA:
3206 v3s16 blockpos = getNodeBlockPos(loc.p);
3208 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3210 meta->inventoryModified();
3212 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3214 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3216 setBlockNotSent(blockpos);
3224 core::list<PlayerInfo> Server::getPlayerInfo()
3226 DSTACK(__FUNCTION_NAME);
3227 JMutexAutoLock envlock(m_env_mutex);
3228 JMutexAutoLock conlock(m_con_mutex);
3230 core::list<PlayerInfo> list;
3232 core::list<Player*> players = m_env->getPlayers();
3234 core::list<Player*>::Iterator i;
3235 for(i = players.begin();
3236 i != players.end(); i++)
3240 Player *player = *i;
3243 // Copy info from connection to info struct
3244 info.id = player->peer_id;
3245 info.address = m_con.GetPeerAddress(player->peer_id);
3246 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3248 catch(con::PeerNotFoundException &e)
3250 // Set dummy peer info
3252 info.address = Address(0,0,0,0,0);
3256 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3257 info.position = player->getPosition();
3259 list.push_back(info);
3266 void Server::peerAdded(con::Peer *peer)
3268 DSTACK(__FUNCTION_NAME);
3269 verbosestream<<"Server::peerAdded(): peer->id="
3270 <<peer->id<<std::endl;
3273 c.type = PEER_ADDED;
3274 c.peer_id = peer->id;
3276 m_peer_change_queue.push_back(c);
3279 void Server::deletingPeer(con::Peer *peer, bool timeout)
3281 DSTACK(__FUNCTION_NAME);
3282 verbosestream<<"Server::deletingPeer(): peer->id="
3283 <<peer->id<<", timeout="<<timeout<<std::endl;
3286 c.type = PEER_REMOVED;
3287 c.peer_id = peer->id;
3288 c.timeout = timeout;
3289 m_peer_change_queue.push_back(c);
3296 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3298 DSTACK(__FUNCTION_NAME);
3299 std::ostringstream os(std::ios_base::binary);
3301 writeU16(os, TOCLIENT_HP);
3305 std::string s = os.str();
3306 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3308 con.Send(peer_id, 0, data, true);
3311 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3312 const std::wstring &reason)
3314 DSTACK(__FUNCTION_NAME);
3315 std::ostringstream os(std::ios_base::binary);
3317 writeU16(os, TOCLIENT_ACCESS_DENIED);
3318 os<<serializeWideString(reason);
3321 std::string s = os.str();
3322 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3324 con.Send(peer_id, 0, data, true);
3327 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3328 bool set_camera_point_target, v3f camera_point_target)
3330 DSTACK(__FUNCTION_NAME);
3331 std::ostringstream os(std::ios_base::binary);
3333 writeU16(os, TOCLIENT_DEATHSCREEN);
3334 writeU8(os, set_camera_point_target);
3335 writeV3F1000(os, camera_point_target);
3338 std::string s = os.str();
3339 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3341 con.Send(peer_id, 0, data, true);
3344 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3345 IItemDefManager *itemdef)
3347 DSTACK(__FUNCTION_NAME);
3348 std::ostringstream os(std::ios_base::binary);
3352 u32 length of the next item
3353 zlib-compressed serialized ItemDefManager
3355 writeU16(os, TOCLIENT_ITEMDEF);
3356 std::ostringstream tmp_os(std::ios::binary);
3357 itemdef->serialize(tmp_os);
3358 std::ostringstream tmp_os2(std::ios::binary);
3359 compressZlib(tmp_os.str(), tmp_os2);
3360 os<<serializeLongString(tmp_os2.str());
3363 std::string s = os.str();
3364 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3365 <<"): size="<<s.size()<<std::endl;
3366 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3368 con.Send(peer_id, 0, data, true);
3371 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3372 INodeDefManager *nodedef)
3374 DSTACK(__FUNCTION_NAME);
3375 std::ostringstream os(std::ios_base::binary);
3379 u32 length of the next item
3380 zlib-compressed serialized NodeDefManager
3382 writeU16(os, TOCLIENT_NODEDEF);
3383 std::ostringstream tmp_os(std::ios::binary);
3384 nodedef->serialize(tmp_os);
3385 std::ostringstream tmp_os2(std::ios::binary);
3386 compressZlib(tmp_os.str(), tmp_os2);
3387 os<<serializeLongString(tmp_os2.str());
3390 std::string s = os.str();
3391 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3392 <<"): size="<<s.size()<<std::endl;
3393 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3395 con.Send(peer_id, 0, data, true);
3399 Non-static send methods
3402 void Server::SendInventory(u16 peer_id)
3404 DSTACK(__FUNCTION_NAME);
3406 ServerRemotePlayer* player =
3407 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3410 player->m_inventory_not_sent = false;
3416 std::ostringstream os;
3417 //os.imbue(std::locale("C"));
3419 player->inventory.serialize(os);
3421 std::string s = os.str();
3423 SharedBuffer<u8> data(s.size()+2);
3424 writeU16(&data[0], TOCLIENT_INVENTORY);
3425 memcpy(&data[2], s.c_str(), s.size());
3428 m_con.Send(peer_id, 0, data, true);
3431 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3433 DSTACK(__FUNCTION_NAME);
3437 std::ostringstream os(std::ios_base::binary);
3439 writeU16(os, TOCLIENT_PLAYERITEM);
3441 writeU16(os, srp->peer_id);
3442 os<<serializeString(srp->getWieldedItem().getItemString());
3445 std::string s = os.str();
3446 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3448 m_con.SendToAll(0, data, true);
3451 void Server::SendPlayerItems()
3453 DSTACK(__FUNCTION_NAME);
3455 std::ostringstream os(std::ios_base::binary);
3456 core::list<Player *> players = m_env->getPlayers(true);
3458 writeU16(os, TOCLIENT_PLAYERITEM);
3459 writeU16(os, players.size());
3460 core::list<Player *>::Iterator i;
3461 for(i = players.begin(); i != players.end(); ++i)
3464 ServerRemotePlayer *srp =
3465 static_cast<ServerRemotePlayer*>(p);
3466 writeU16(os, p->peer_id);
3467 os<<serializeString(srp->getWieldedItem().getItemString());
3471 std::string s = os.str();
3472 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3474 m_con.SendToAll(0, data, true);
3477 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3479 DSTACK(__FUNCTION_NAME);
3481 std::ostringstream os(std::ios_base::binary);
3485 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3486 os.write((char*)buf, 2);
3489 writeU16(buf, message.size());
3490 os.write((char*)buf, 2);
3493 for(u32 i=0; i<message.size(); i++)
3497 os.write((char*)buf, 2);
3501 std::string s = os.str();
3502 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3504 m_con.Send(peer_id, 0, data, true);
3507 void Server::BroadcastChatMessage(const std::wstring &message)
3509 for(core::map<u16, RemoteClient*>::Iterator
3510 i = m_clients.getIterator();
3511 i.atEnd() == false; i++)
3513 // Get client and check that it is valid
3514 RemoteClient *client = i.getNode()->getValue();
3515 assert(client->peer_id == i.getNode()->getKey());
3516 if(client->serialization_version == SER_FMT_VER_INVALID)
3519 SendChatMessage(client->peer_id, message);
3523 void Server::SendPlayerHP(Player *player)
3525 SendHP(m_con, player->peer_id, player->hp);
3526 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3529 void Server::SendMovePlayer(Player *player)
3531 DSTACK(__FUNCTION_NAME);
3532 std::ostringstream os(std::ios_base::binary);
3534 writeU16(os, TOCLIENT_MOVE_PLAYER);
3535 writeV3F1000(os, player->getPosition());
3536 writeF1000(os, player->getPitch());
3537 writeF1000(os, player->getYaw());
3540 v3f pos = player->getPosition();
3541 f32 pitch = player->getPitch();
3542 f32 yaw = player->getYaw();
3543 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3544 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3551 std::string s = os.str();
3552 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3554 m_con.Send(player->peer_id, 0, data, true);
3557 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3558 core::list<u16> *far_players, float far_d_nodes)
3560 float maxd = far_d_nodes*BS;
3561 v3f p_f = intToFloat(p, BS);
3565 SharedBuffer<u8> reply(replysize);
3566 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3567 writeS16(&reply[2], p.X);
3568 writeS16(&reply[4], p.Y);
3569 writeS16(&reply[6], p.Z);
3571 for(core::map<u16, RemoteClient*>::Iterator
3572 i = m_clients.getIterator();
3573 i.atEnd() == false; i++)
3575 // Get client and check that it is valid
3576 RemoteClient *client = i.getNode()->getValue();
3577 assert(client->peer_id == i.getNode()->getKey());
3578 if(client->serialization_version == SER_FMT_VER_INVALID)
3581 // Don't send if it's the same one
3582 if(client->peer_id == ignore_id)
3588 Player *player = m_env->getPlayer(client->peer_id);
3591 // If player is far away, only set modified blocks not sent
3592 v3f player_pos = player->getPosition();
3593 if(player_pos.getDistanceFrom(p_f) > maxd)
3595 far_players->push_back(client->peer_id);
3602 m_con.Send(client->peer_id, 0, reply, true);
3606 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3607 core::list<u16> *far_players, float far_d_nodes)
3609 float maxd = far_d_nodes*BS;
3610 v3f p_f = intToFloat(p, BS);
3612 for(core::map<u16, RemoteClient*>::Iterator
3613 i = m_clients.getIterator();
3614 i.atEnd() == false; i++)
3616 // Get client and check that it is valid
3617 RemoteClient *client = i.getNode()->getValue();
3618 assert(client->peer_id == i.getNode()->getKey());
3619 if(client->serialization_version == SER_FMT_VER_INVALID)
3622 // Don't send if it's the same one
3623 if(client->peer_id == ignore_id)
3629 Player *player = m_env->getPlayer(client->peer_id);
3632 // If player is far away, only set modified blocks not sent
3633 v3f player_pos = player->getPosition();
3634 if(player_pos.getDistanceFrom(p_f) > maxd)
3636 far_players->push_back(client->peer_id);
3643 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3644 SharedBuffer<u8> reply(replysize);
3645 writeU16(&reply[0], TOCLIENT_ADDNODE);
3646 writeS16(&reply[2], p.X);
3647 writeS16(&reply[4], p.Y);
3648 writeS16(&reply[6], p.Z);
3649 n.serialize(&reply[8], client->serialization_version);
3652 m_con.Send(client->peer_id, 0, reply, true);
3656 void Server::setBlockNotSent(v3s16 p)
3658 for(core::map<u16, RemoteClient*>::Iterator
3659 i = m_clients.getIterator();
3660 i.atEnd()==false; i++)
3662 RemoteClient *client = i.getNode()->getValue();
3663 client->SetBlockNotSent(p);
3667 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3669 DSTACK(__FUNCTION_NAME);
3671 v3s16 p = block->getPos();
3675 bool completely_air = true;
3676 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3677 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3678 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3680 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3682 completely_air = false;
3683 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3688 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3690 infostream<<"[completely air] ";
3691 infostream<<std::endl;
3695 Create a packet with the block in the right format
3698 std::ostringstream os(std::ios_base::binary);
3699 block->serialize(os, ver, false);
3700 std::string s = os.str();
3701 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3703 u32 replysize = 8 + blockdata.getSize();
3704 SharedBuffer<u8> reply(replysize);
3705 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3706 writeS16(&reply[2], p.X);
3707 writeS16(&reply[4], p.Y);
3708 writeS16(&reply[6], p.Z);
3709 memcpy(&reply[8], *blockdata, blockdata.getSize());
3711 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3712 <<": \tpacket size: "<<replysize<<std::endl;*/
3717 m_con.Send(peer_id, 1, reply, true);
3720 void Server::SendBlocks(float dtime)
3722 DSTACK(__FUNCTION_NAME);
3724 JMutexAutoLock envlock(m_env_mutex);
3725 JMutexAutoLock conlock(m_con_mutex);
3727 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3729 core::array<PrioritySortedBlockTransfer> queue;
3731 s32 total_sending = 0;
3734 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3736 for(core::map<u16, RemoteClient*>::Iterator
3737 i = m_clients.getIterator();
3738 i.atEnd() == false; i++)
3740 RemoteClient *client = i.getNode()->getValue();
3741 assert(client->peer_id == i.getNode()->getKey());
3743 // If definitions and textures have not been sent, don't
3744 // send MapBlocks either
3745 if(!client->definitions_sent)
3748 total_sending += client->SendingCount();
3750 if(client->serialization_version == SER_FMT_VER_INVALID)
3753 client->GetNextBlocks(this, dtime, queue);
3758 // Lowest priority number comes first.
3759 // Lowest is most important.
3762 for(u32 i=0; i<queue.size(); i++)
3764 //TODO: Calculate limit dynamically
3765 if(total_sending >= g_settings->getS32
3766 ("max_simultaneous_block_sends_server_total"))
3769 PrioritySortedBlockTransfer q = queue[i];
3771 MapBlock *block = NULL;
3774 block = m_env->getMap().getBlockNoCreate(q.pos);
3776 catch(InvalidPositionException &e)
3781 RemoteClient *client = getClient(q.peer_id);
3783 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3785 client->SentBlock(q.pos);
3791 void Server::PrepareTextures()
3793 DSTACK(__FUNCTION_NAME);
3795 infostream<<"Server: Calculating texture checksums"<<std::endl;
3797 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3798 i != m_mods.end(); i++){
3799 const ModSpec &mod = *i;
3800 std::string texturepath = mod.path + DIR_DELIM + "textures";
3801 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3802 for(u32 j=0; j<dirlist.size(); j++){
3803 if(dirlist[j].dir) // Ignode dirs
3805 std::string tname = dirlist[j].name;
3806 // if name contains illegal characters, ignore the texture
3807 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3808 errorstream<<"Server: ignoring illegal texture name: \""
3809 <<tname<<"\""<<std::endl;
3812 std::string tpath = texturepath + DIR_DELIM + tname;
3814 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3815 if(fis.good() == false){
3816 errorstream<<"Server::PrepareTextures(): Could not open \""
3817 <<tname<<"\" for reading"<<std::endl;
3820 std::ostringstream tmp_os(std::ios_base::binary);
3824 fis.read(buf, 1024);
3825 std::streamsize len = fis.gcount();
3826 tmp_os.write(buf, len);
3835 errorstream<<"Server::PrepareTextures(): Failed to read \""
3836 <<tname<<"\""<<std::endl;
3839 if(tmp_os.str().length() == 0){
3840 errorstream<<"Server::PrepareTextures(): Empty file \""
3841 <<tpath<<"\""<<std::endl;
3846 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3848 unsigned char *digest = sha1.getDigest();
3849 std::string digest_string = base64_encode(digest, 20);
3854 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3855 verbosestream<<"Server: sha1 for "<<tname<<"\tis "<<std::endl;
3860 struct SendableTextureAnnouncement
3863 std::string sha1_digest;
3865 SendableTextureAnnouncement(const std::string name_="",
3866 const std::string sha1_digest_=""):
3868 sha1_digest(sha1_digest_)
3873 void Server::SendTextureAnnouncement(u16 peer_id){
3874 DSTACK(__FUNCTION_NAME);
3876 verbosestream<<"Server: Announcing textures to id("<<peer_id<<")"
3879 core::list<SendableTextureAnnouncement> texture_announcements;
3881 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3884 texture_announcements.push_back(
3885 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3888 //send announcements
3892 u32 number of textures
3896 u16 length of digest string
3900 std::ostringstream os(std::ios_base::binary);
3902 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3903 writeU16(os, texture_announcements.size());
3905 for(core::list<SendableTextureAnnouncement>::Iterator
3906 j = texture_announcements.begin();
3907 j != texture_announcements.end(); j++){
3908 os<<serializeString(j->name);
3909 os<<serializeString(j->sha1_digest);
3913 std::string s = os.str();
3914 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3917 m_con.Send(peer_id, 0, data, true);
3921 struct SendableTexture
3927 SendableTexture(const std::string &name_="", const std::string path_="",
3928 const std::string &data_=""):
3935 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3936 DSTACK(__FUNCTION_NAME);
3938 verbosestream<<"Server::SendTexturesRequested(): "
3939 <<"Sending textures to client"<<std::endl;
3943 // Put 5kB in one bunch (this is not accurate)
3944 u32 bytes_per_bunch = 5000;
3946 core::array< core::list<SendableTexture> > texture_bunches;
3947 texture_bunches.push_back(core::list<SendableTexture>());
3949 u32 texture_size_bunch_total = 0;
3951 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3952 if(m_Textures.find(i->name) == m_Textures.end()){
3953 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3954 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3958 //TODO get path + name
3959 std::string tpath = m_Textures[(*i).name].path;
3962 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3963 if(fis.good() == false){
3964 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3965 <<tpath<<"\" for reading"<<std::endl;
3968 std::ostringstream tmp_os(std::ios_base::binary);
3972 fis.read(buf, 1024);
3973 std::streamsize len = fis.gcount();
3974 tmp_os.write(buf, len);
3975 texture_size_bunch_total += len;
3984 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
3985 <<(*i).name<<"\""<<std::endl;
3988 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
3989 <<tname<<"\""<<std::endl;*/
3991 texture_bunches[texture_bunches.size()-1].push_back(
3992 SendableTexture((*i).name, tpath, tmp_os.str()));
3994 // Start next bunch if got enough data
3995 if(texture_size_bunch_total >= bytes_per_bunch){
3996 texture_bunches.push_back(core::list<SendableTexture>());
3997 texture_size_bunch_total = 0;
4002 /* Create and send packets */
4004 u32 num_bunches = texture_bunches.size();
4005 for(u32 i=0; i<num_bunches; i++)
4009 u16 total number of texture bunches
4010 u16 index of this bunch
4011 u32 number of textures in this bunch
4019 std::ostringstream os(std::ios_base::binary);
4021 writeU16(os, TOCLIENT_TEXTURES);
4022 writeU16(os, num_bunches);
4024 writeU32(os, texture_bunches[i].size());
4026 for(core::list<SendableTexture>::Iterator
4027 j = texture_bunches[i].begin();
4028 j != texture_bunches[i].end(); j++){
4029 os<<serializeString(j->name);
4030 os<<serializeLongString(j->data);
4034 std::string s = os.str();
4035 verbosestream<<"Server::SendTexturesRequested(): bunch "
4036 <<i<<"/"<<num_bunches
4037 <<" textures="<<texture_bunches[i].size()
4038 <<" size=" <<s.size()<<std::endl;
4039 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4041 m_con.Send(peer_id, 0, data, true);
4051 void Server::DiePlayer(Player *player)
4053 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4055 infostream<<"Server::DiePlayer(): Player "
4056 <<player->getName()<<" dies"<<std::endl;
4060 // Trigger scripted stuff
4061 scriptapi_on_dieplayer(m_lua, srp);
4063 // Handle players that are not connected
4064 if(player->peer_id == PEER_ID_INEXISTENT){
4065 RespawnPlayer(player);
4069 SendPlayerHP(player);
4070 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4073 void Server::RespawnPlayer(Player *player)
4075 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4077 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4079 v3f pos = findSpawnPos(m_env->getServerMap());
4080 player->setPosition(pos);
4081 srp->m_last_good_position = pos;
4082 srp->m_last_good_position_age = 0;
4084 SendMovePlayer(player);
4085 SendPlayerHP(player);
4088 void Server::UpdateCrafting(u16 peer_id)
4090 DSTACK(__FUNCTION_NAME);
4092 Player* player = m_env->getPlayer(peer_id);
4095 // Get a preview for crafting
4097 // No crafting in creative mode
4098 if(g_settings->getBool("creative_mode") == false)
4099 getCraftingResult(&player->inventory, preview, false, this);
4101 // Put the new preview in
4102 InventoryList *plist = player->inventory.getList("craftpreview");
4104 assert(plist->getSize() >= 1);
4105 plist->changeItem(0, preview);
4108 RemoteClient* Server::getClient(u16 peer_id)
4110 DSTACK(__FUNCTION_NAME);
4111 //JMutexAutoLock lock(m_con_mutex);
4112 core::map<u16, RemoteClient*>::Node *n;
4113 n = m_clients.find(peer_id);
4114 // A client should exist for all peers
4116 return n->getValue();
4119 std::wstring Server::getStatusString()
4121 std::wostringstream os(std::ios_base::binary);
4124 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4126 os<<L", uptime="<<m_uptime.get();
4127 // Information about clients
4129 for(core::map<u16, RemoteClient*>::Iterator
4130 i = m_clients.getIterator();
4131 i.atEnd() == false; i++)
4133 // Get client and check that it is valid
4134 RemoteClient *client = i.getNode()->getValue();
4135 assert(client->peer_id == i.getNode()->getKey());
4136 if(client->serialization_version == SER_FMT_VER_INVALID)
4139 Player *player = m_env->getPlayer(client->peer_id);
4140 // Get name of player
4141 std::wstring name = L"unknown";
4143 name = narrow_to_wide(player->getName());
4144 // Add name to information string
4148 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4149 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4150 if(g_settings->get("motd") != "")
4151 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4155 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4157 // Add player to auth manager
4158 if(m_authmanager.exists(name) == false)
4160 infostream<<"Server: adding player "<<name
4161 <<" to auth manager"<<std::endl;
4162 m_authmanager.add(name);
4163 m_authmanager.setPrivs(name,
4164 stringToPrivs(g_settings->get("default_privs")));
4166 // Change password and save
4167 m_authmanager.setPassword(name, translatePassword(name, password));
4168 m_authmanager.save();
4171 // Saves g_settings to configpath given at initialization
4172 void Server::saveConfig()
4174 if(m_path_config != "")
4175 g_settings->updateConfigFile(m_path_config.c_str());
4178 void Server::notifyPlayer(const char *name, const std::wstring msg)
4180 Player *player = m_env->getPlayer(name);
4183 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4186 void Server::notifyPlayers(const std::wstring msg)
4188 BroadcastChatMessage(msg);
4191 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4195 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4196 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4199 // IGameDef interface
4201 IItemDefManager* Server::getItemDefManager()
4205 INodeDefManager* Server::getNodeDefManager()
4209 ICraftDefManager* Server::getCraftDefManager()
4213 ITextureSource* Server::getTextureSource()
4217 u16 Server::allocateUnknownNodeId(const std::string &name)
4219 return m_nodedef->allocateDummy(name);
4222 IWritableItemDefManager* Server::getWritableItemDefManager()
4226 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4230 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4235 const ModSpec* Server::getModSpec(const std::string &modname)
4237 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4238 i != m_mods.end(); i++){
4239 const ModSpec &mod = *i;
4240 if(mod.name == modname)
4246 v3f findSpawnPos(ServerMap &map)
4248 //return v3f(50,50,50)*BS;
4253 nodepos = v2s16(0,0);
4258 // Try to find a good place a few times
4259 for(s32 i=0; i<1000; i++)
4262 // We're going to try to throw the player to this position
4263 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4264 -range + (myrand()%(range*2)));
4265 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4266 // Get ground height at point (fallbacks to heightmap function)
4267 s16 groundheight = map.findGroundLevel(nodepos2d);
4268 // Don't go underwater
4269 if(groundheight < WATER_LEVEL)
4271 //infostream<<"-> Underwater"<<std::endl;
4274 // Don't go to high places
4275 if(groundheight > WATER_LEVEL + 4)
4277 //infostream<<"-> Underwater"<<std::endl;
4281 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4282 bool is_good = false;
4284 for(s32 i=0; i<10; i++){
4285 v3s16 blockpos = getNodeBlockPos(nodepos);
4286 map.emergeBlock(blockpos, true);
4287 MapNode n = map.getNodeNoEx(nodepos);
4288 if(n.getContent() == CONTENT_AIR){
4299 // Found a good place
4300 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4306 return intToFloat(nodepos, BS);
4309 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4312 Try to get an existing player
4314 ServerRemotePlayer *player =
4315 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4318 // If player is already connected, cancel
4319 if(player->peer_id != 0)
4321 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4326 player->peer_id = peer_id;
4328 // Re-add player to environment
4329 if(player->m_removed)
4331 player->m_removed = false;
4333 m_env->addActiveObject(player);
4336 // Reset inventory to creative if in creative mode
4337 if(g_settings->getBool("creative_mode"))
4339 // Warning: double code below
4340 // Backup actual inventory
4341 player->inventory_backup = new Inventory(m_itemdef);
4342 *(player->inventory_backup) = player->inventory;
4343 // Set creative inventory
4344 player->resetInventory();
4345 scriptapi_get_creative_inventory(m_lua, player);
4352 If player with the wanted peer_id already exists, cancel.
4354 if(m_env->getPlayer(peer_id) != NULL)
4356 infostream<<"emergePlayer(): Player with wrong name but same"
4357 " peer_id already exists"<<std::endl;
4365 /* Set player position */
4367 infostream<<"Server: Finding spawn place for player \""
4368 <<name<<"\""<<std::endl;
4370 v3f pos = findSpawnPos(m_env->getServerMap());
4372 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4373 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4375 /* Add player to environment */
4376 m_env->addPlayer(player);
4377 m_env->addActiveObject(srp);
4380 scriptapi_on_newplayer(m_lua, srp);
4382 /* Add stuff to inventory */
4383 if(g_settings->getBool("creative_mode"))
4385 // Warning: double code above
4386 // Backup actual inventory
4387 player->inventory_backup = new Inventory(m_itemdef);
4388 *(player->inventory_backup) = player->inventory;
4389 // Set creative inventory
4390 player->resetInventory();
4391 scriptapi_get_creative_inventory(m_lua, player);
4396 } // create new player
4399 void Server::handlePeerChange(PeerChange &c)
4401 JMutexAutoLock envlock(m_env_mutex);
4402 JMutexAutoLock conlock(m_con_mutex);
4404 if(c.type == PEER_ADDED)
4411 core::map<u16, RemoteClient*>::Node *n;
4412 n = m_clients.find(c.peer_id);
4413 // The client shouldn't already exist
4417 RemoteClient *client = new RemoteClient();
4418 client->peer_id = c.peer_id;
4419 m_clients.insert(client->peer_id, client);
4422 else if(c.type == PEER_REMOVED)
4429 core::map<u16, RemoteClient*>::Node *n;
4430 n = m_clients.find(c.peer_id);
4431 // The client should exist
4435 Mark objects to be not known by the client
4437 RemoteClient *client = n->getValue();
4439 for(core::map<u16, bool>::Iterator
4440 i = client->m_known_objects.getIterator();
4441 i.atEnd()==false; i++)
4444 u16 id = i.getNode()->getKey();
4445 ServerActiveObject* obj = m_env->getActiveObject(id);
4447 if(obj && obj->m_known_by_count > 0)
4448 obj->m_known_by_count--;
4451 ServerRemotePlayer* player =
4452 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4454 // Collect information about leaving in chat
4455 std::wstring message;
4459 std::wstring name = narrow_to_wide(player->getName());
4462 message += L" left game";
4464 message += L" (timed out)";
4468 // Remove from environment
4470 player->m_removed = true;
4472 // Set player client disconnected
4474 player->peer_id = 0;
4482 std::ostringstream os(std::ios_base::binary);
4483 for(core::map<u16, RemoteClient*>::Iterator
4484 i = m_clients.getIterator();
4485 i.atEnd() == false; i++)
4487 RemoteClient *client = i.getNode()->getValue();
4488 assert(client->peer_id == i.getNode()->getKey());
4489 if(client->serialization_version == SER_FMT_VER_INVALID)
4492 Player *player = m_env->getPlayer(client->peer_id);
4495 // Get name of player
4496 os<<player->getName()<<" ";
4499 actionstream<<player->getName()<<" "
4500 <<(c.timeout?"times out.":"leaves game.")
4501 <<" List of players: "
4502 <<os.str()<<std::endl;
4507 delete m_clients[c.peer_id];
4508 m_clients.remove(c.peer_id);
4510 // Send player info to all remaining clients
4511 //SendPlayerInfos();
4513 // Send leave chat message to all remaining clients
4514 if(message.length() != 0)
4515 BroadcastChatMessage(message);
4524 void Server::handlePeerChanges()
4526 while(m_peer_change_queue.size() > 0)
4528 PeerChange c = m_peer_change_queue.pop_front();
4530 verbosestream<<"Server: Handling peer change: "
4531 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4534 handlePeerChange(c);
4538 u64 Server::getPlayerPrivs(Player *player)
4542 std::string playername = player->getName();
4543 // Local player gets all privileges regardless of
4544 // what's set on their account.
4545 if(g_settings->get("name") == playername)
4551 return getPlayerAuthPrivs(playername);
4555 void dedicated_server_loop(Server &server, bool &kill)
4557 DSTACK(__FUNCTION_NAME);
4559 verbosestream<<"dedicated_server_loop()"<<std::endl;
4561 IntervalLimiter m_profiler_interval;
4565 float steplen = g_settings->getFloat("dedicated_server_step");
4566 // This is kind of a hack but can be done like this
4567 // because server.step() is very light
4569 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4570 sleep_ms((int)(steplen*1000.0));
4572 server.step(steplen);
4574 if(server.getShutdownRequested() || kill)
4576 infostream<<"Dedicated server quitting"<<std::endl;
4583 float profiler_print_interval =
4584 g_settings->getFloat("profiler_print_interval");
4585 if(profiler_print_interval != 0)
4587 if(m_profiler_interval.step(steplen, profiler_print_interval))
4589 infostream<<"Profiler:"<<std::endl;
4590 g_profiler->print(infostream);
4591 g_profiler->clear();