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"
30 #include "materials.h"
32 #include "servercommand.h"
34 #include "content_mapnode.h"
35 #include "content_nodemeta.h"
37 #include "serverobject.h"
42 #include "scriptapi.h"
47 #include "content_abm.h"
52 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
54 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
56 class MapEditEventIgnorer
59 MapEditEventIgnorer(bool *flag):
68 ~MapEditEventIgnorer()
81 void * ServerThread::Thread()
85 log_register_thread("ServerThread");
87 DSTACK(__FUNCTION_NAME);
89 BEGIN_DEBUG_EXCEPTION_HANDLER
94 //TimeTaker timer("AsyncRunStep() + Receive()");
97 //TimeTaker timer("AsyncRunStep()");
98 m_server->AsyncRunStep();
101 //infostream<<"Running m_server->Receive()"<<std::endl;
104 catch(con::NoIncomingDataException &e)
107 catch(con::PeerNotFoundException &e)
109 infostream<<"Server: PeerNotFoundException"<<std::endl;
113 END_DEBUG_EXCEPTION_HANDLER(errorstream)
118 void * EmergeThread::Thread()
122 log_register_thread("EmergeThread");
124 DSTACK(__FUNCTION_NAME);
126 BEGIN_DEBUG_EXCEPTION_HANDLER
128 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
131 Get block info from queue, emerge them and send them
134 After queue is empty, exit.
138 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
142 SharedPtr<QueuedBlockEmerge> q(qptr);
148 Do not generate over-limit
150 if(blockpos_over_limit(p))
153 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
155 //TimeTaker timer("block emerge");
158 Try to emerge it from somewhere.
160 If it is only wanted as optional, only loading from disk
165 Check if any peer wants it as non-optional. In that case it
168 Also decrement the emerge queue count in clients.
171 bool only_from_disk = true;
174 core::map<u16, u8>::Iterator i;
175 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
177 //u16 peer_id = i.getNode()->getKey();
180 u8 flags = i.getNode()->getValue();
181 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
182 only_from_disk = false;
187 if(enable_mapgen_debug_info)
188 infostream<<"EmergeThread: p="
189 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
190 <<"only_from_disk="<<only_from_disk<<std::endl;
192 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
194 MapBlock *block = NULL;
195 bool got_block = true;
196 core::map<v3s16, MapBlock*> modified_blocks;
199 Try to fetch block from memory or disk.
200 If not found and asked to generate, initialize generator.
203 bool started_generate = false;
204 mapgen::BlockMakeData data;
207 JMutexAutoLock envlock(m_server->m_env_mutex);
209 // Load sector if it isn't loaded
210 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
211 map.loadSectorMeta(p2d);
213 // Attempt to load block
214 block = map.getBlockNoCreateNoEx(p);
215 if(!block || block->isDummy() || !block->isGenerated())
217 if(enable_mapgen_debug_info)
218 infostream<<"EmergeThread: not in memory, "
219 <<"attempting to load from disk"<<std::endl;
221 block = map.loadBlock(p);
224 // If could not load and allowed to generate, start generation
225 // inside this same envlock
226 if(only_from_disk == false &&
227 (block == NULL || block->isGenerated() == false)){
228 if(enable_mapgen_debug_info)
229 infostream<<"EmergeThread: generating"<<std::endl;
230 started_generate = true;
232 map.initBlockMake(&data, p);
237 If generator was initialized, generate now when envlock is free.
242 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
244 TimeTaker t("mapgen::make_block()");
246 mapgen::make_block(&data);
248 if(enable_mapgen_debug_info == false)
249 t.stop(true); // Hide output
253 // Lock environment again to access the map
254 JMutexAutoLock envlock(m_server->m_env_mutex);
256 ScopeProfiler sp(g_profiler, "EmergeThread: after "
257 "mapgen::make_block (envlock)", SPT_AVG);
259 // Blit data back on map, update lighting, add mobs and
260 // whatever this does
261 map.finishBlockMake(&data, modified_blocks);
264 block = map.getBlockNoCreateNoEx(p);
266 // If block doesn't exist, don't try doing anything with it
267 // This happens if the block is not in generation boundaries
272 Do some post-generate stuff
275 v3s16 minp = block->getPos()*MAP_BLOCKSIZE;
276 v3s16 maxp = minp + v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
277 scriptapi_environment_on_generated(m_server->m_lua,
280 if(enable_mapgen_debug_info)
281 infostream<<"EmergeThread: ended up with: "
282 <<analyze_block(block)<<std::endl;
285 Ignore map edit events, they will not need to be
286 sent to anybody because the block hasn't been sent
289 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
291 // Activate objects and stuff
292 m_server->m_env->activateBlock(block, 0);
300 Set sent status of modified blocks on clients
303 // NOTE: Server's clients are also behind the connection mutex
304 JMutexAutoLock lock(m_server->m_con_mutex);
307 Add the originally fetched block to the modified list
311 modified_blocks.insert(p, block);
315 Set the modified blocks unsent for all the clients
318 for(core::map<u16, RemoteClient*>::Iterator
319 i = m_server->m_clients.getIterator();
320 i.atEnd() == false; i++)
322 RemoteClient *client = i.getNode()->getValue();
324 if(modified_blocks.size() > 0)
326 // Remove block from sent history
327 client->SetBlocksNotSent(modified_blocks);
333 END_DEBUG_EXCEPTION_HANDLER(errorstream)
335 log_deregister_thread();
340 void RemoteClient::GetNextBlocks(Server *server, float dtime,
341 core::array<PrioritySortedBlockTransfer> &dest)
343 DSTACK(__FUNCTION_NAME);
346 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
349 m_nothing_to_send_pause_timer -= dtime;
350 m_nearest_unsent_reset_timer += dtime;
352 if(m_nothing_to_send_pause_timer >= 0)
357 // Won't send anything if already sending
358 if(m_blocks_sending.size() >= g_settings->getU16
359 ("max_simultaneous_block_sends_per_client"))
361 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
365 //TimeTaker timer("RemoteClient::GetNextBlocks");
367 Player *player = server->m_env->getPlayer(peer_id);
369 assert(player != NULL);
371 v3f playerpos = player->getPosition();
372 v3f playerspeed = player->getSpeed();
373 v3f playerspeeddir(0,0,0);
374 if(playerspeed.getLength() > 1.0*BS)
375 playerspeeddir = playerspeed / playerspeed.getLength();
376 // Predict to next block
377 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
379 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
381 v3s16 center = getNodeBlockPos(center_nodepos);
383 // Camera position and direction
384 v3f camera_pos = player->getEyePosition();
385 v3f camera_dir = v3f(0,0,1);
386 camera_dir.rotateYZBy(player->getPitch());
387 camera_dir.rotateXZBy(player->getYaw());
389 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
390 <<camera_dir.Z<<")"<<std::endl;*/
393 Get the starting value of the block finder radius.
396 if(m_last_center != center)
398 m_nearest_unsent_d = 0;
399 m_last_center = center;
402 /*infostream<<"m_nearest_unsent_reset_timer="
403 <<m_nearest_unsent_reset_timer<<std::endl;*/
405 // Reset periodically to workaround for some bugs or stuff
406 if(m_nearest_unsent_reset_timer > 20.0)
408 m_nearest_unsent_reset_timer = 0;
409 m_nearest_unsent_d = 0;
410 //infostream<<"Resetting m_nearest_unsent_d for "
411 // <<server->getPlayerName(peer_id)<<std::endl;
414 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
415 s16 d_start = m_nearest_unsent_d;
417 //infostream<<"d_start="<<d_start<<std::endl;
419 u16 max_simul_sends_setting = g_settings->getU16
420 ("max_simultaneous_block_sends_per_client");
421 u16 max_simul_sends_usually = max_simul_sends_setting;
424 Check the time from last addNode/removeNode.
426 Decrease send rate if player is building stuff.
428 m_time_from_building += dtime;
429 if(m_time_from_building < g_settings->getFloat(
430 "full_block_send_enable_min_time_from_building"))
432 max_simul_sends_usually
433 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
437 Number of blocks sending + number of blocks selected for sending
439 u32 num_blocks_selected = m_blocks_sending.size();
442 next time d will be continued from the d from which the nearest
443 unsent block was found this time.
445 This is because not necessarily any of the blocks found this
446 time are actually sent.
448 s32 new_nearest_unsent_d = -1;
450 s16 d_max = g_settings->getS16("max_block_send_distance");
451 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
453 // Don't loop very much at a time
454 s16 max_d_increment_at_time = 2;
455 if(d_max > d_start + max_d_increment_at_time)
456 d_max = d_start + max_d_increment_at_time;
457 /*if(d_max_gen > d_start+2)
458 d_max_gen = d_start+2;*/
460 //infostream<<"Starting from "<<d_start<<std::endl;
462 s32 nearest_emerged_d = -1;
463 s32 nearest_emergefull_d = -1;
464 s32 nearest_sent_d = -1;
465 bool queue_is_full = false;
468 for(d = d_start; d <= d_max; d++)
470 /*errorstream<<"checking d="<<d<<" for "
471 <<server->getPlayerName(peer_id)<<std::endl;*/
472 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
475 If m_nearest_unsent_d was changed by the EmergeThread
476 (it can change it to 0 through SetBlockNotSent),
478 Else update m_nearest_unsent_d
480 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
482 d = m_nearest_unsent_d;
483 last_nearest_unsent_d = m_nearest_unsent_d;
487 Get the border/face dot coordinates of a "d-radiused"
490 core::list<v3s16> list;
491 getFacePositions(list, d);
493 core::list<v3s16>::Iterator li;
494 for(li=list.begin(); li!=list.end(); li++)
496 v3s16 p = *li + center;
500 - Don't allow too many simultaneous transfers
501 - EXCEPT when the blocks are very close
503 Also, don't send blocks that are already flying.
506 // Start with the usual maximum
507 u16 max_simul_dynamic = max_simul_sends_usually;
509 // If block is very close, allow full maximum
510 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
511 max_simul_dynamic = max_simul_sends_setting;
513 // Don't select too many blocks for sending
514 if(num_blocks_selected >= max_simul_dynamic)
516 queue_is_full = true;
517 goto queue_full_break;
520 // Don't send blocks that are currently being transferred
521 if(m_blocks_sending.find(p) != NULL)
527 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
528 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
529 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
530 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
531 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
532 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
535 // If this is true, inexistent block will be made from scratch
536 bool generate = d <= d_max_gen;
539 /*// Limit the generating area vertically to 2/3
540 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
543 // Limit the send area vertically to 1/2
544 if(abs(p.Y - center.Y) > d_max / 2)
550 If block is far away, don't generate it unless it is
556 // Block center y in nodes
557 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
558 // Don't generate if it's very high or very low
559 if(y < -64 || y > 64)
563 v2s16 p2d_nodes_center(
567 // Get ground height in nodes
568 s16 gh = server->m_env->getServerMap().findGroundLevel(
571 // If differs a lot, don't generate
572 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
574 // Actually, don't even send it
580 //infostream<<"d="<<d<<std::endl;
583 Don't generate or send if not in sight
584 FIXME This only works if the client uses a small enough
585 FOV setting. The default of 72 degrees is fine.
588 float camera_fov = (72.0*PI/180) * 4./3.;
589 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
595 Don't send already sent blocks
598 if(m_blocks_sent.find(p) != NULL)
605 Check if map has this block
607 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
609 bool surely_not_found_on_disk = false;
610 bool block_is_invalid = false;
613 // Reset usage timer, this block will be of use in the future.
614 block->resetUsageTimer();
616 // Block is dummy if data doesn't exist.
617 // It means it has been not found from disk and not generated
620 surely_not_found_on_disk = true;
623 // Block is valid if lighting is up-to-date and data exists
624 if(block->isValid() == false)
626 block_is_invalid = true;
629 /*if(block->isFullyGenerated() == false)
631 block_is_invalid = true;
636 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
637 v2s16 chunkpos = map->sector_to_chunk(p2d);
638 if(map->chunkNonVolatile(chunkpos) == false)
639 block_is_invalid = true;
641 if(block->isGenerated() == false)
642 block_is_invalid = true;
645 If block is not close, don't send it unless it is near
648 Block is near ground level if night-time mesh
649 differs from day-time mesh.
653 if(block->dayNightDiffed() == false)
660 If block has been marked to not exist on disk (dummy)
661 and generating new ones is not wanted, skip block.
663 if(generate == false && surely_not_found_on_disk == true)
670 Add inexistent block to emerge queue.
672 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
674 //TODO: Get value from somewhere
675 // Allow only one block in emerge queue
676 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
677 // Allow two blocks in queue per client
678 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
680 // Make it more responsive when needing to generate stuff
681 if(surely_not_found_on_disk)
683 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
685 //infostream<<"Adding block to emerge queue"<<std::endl;
687 // Add it to the emerge queue and trigger the thread
690 if(generate == false)
691 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
693 server->m_emerge_queue.addBlock(peer_id, p, flags);
694 server->m_emergethread.trigger();
696 if(nearest_emerged_d == -1)
697 nearest_emerged_d = d;
699 if(nearest_emergefull_d == -1)
700 nearest_emergefull_d = d;
707 if(nearest_sent_d == -1)
711 Add block to send queue
714 /*errorstream<<"sending from d="<<d<<" to "
715 <<server->getPlayerName(peer_id)<<std::endl;*/
717 PrioritySortedBlockTransfer q((float)d, p, peer_id);
721 num_blocks_selected += 1;
726 //infostream<<"Stopped at "<<d<<std::endl;
728 // If nothing was found for sending and nothing was queued for
729 // emerging, continue next time browsing from here
730 if(nearest_emerged_d != -1){
731 new_nearest_unsent_d = nearest_emerged_d;
732 } else if(nearest_emergefull_d != -1){
733 new_nearest_unsent_d = nearest_emergefull_d;
735 if(d > g_settings->getS16("max_block_send_distance")){
736 new_nearest_unsent_d = 0;
737 m_nothing_to_send_pause_timer = 2.0;
738 /*infostream<<"GetNextBlocks(): d wrapped around for "
739 <<server->getPlayerName(peer_id)
740 <<"; setting to 0 and pausing"<<std::endl;*/
742 if(nearest_sent_d != -1)
743 new_nearest_unsent_d = nearest_sent_d;
745 new_nearest_unsent_d = d;
749 if(new_nearest_unsent_d != -1)
750 m_nearest_unsent_d = new_nearest_unsent_d;
752 /*timer_result = timer.stop(true);
753 if(timer_result != 0)
754 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
757 void RemoteClient::GotBlock(v3s16 p)
759 if(m_blocks_sending.find(p) != NULL)
760 m_blocks_sending.remove(p);
763 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
764 " m_blocks_sending"<<std::endl;*/
765 m_excess_gotblocks++;
767 m_blocks_sent.insert(p, true);
770 void RemoteClient::SentBlock(v3s16 p)
772 if(m_blocks_sending.find(p) == NULL)
773 m_blocks_sending.insert(p, 0.0);
775 infostream<<"RemoteClient::SentBlock(): Sent block"
776 " already in m_blocks_sending"<<std::endl;
779 void RemoteClient::SetBlockNotSent(v3s16 p)
781 m_nearest_unsent_d = 0;
783 if(m_blocks_sending.find(p) != NULL)
784 m_blocks_sending.remove(p);
785 if(m_blocks_sent.find(p) != NULL)
786 m_blocks_sent.remove(p);
789 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
791 m_nearest_unsent_d = 0;
793 for(core::map<v3s16, MapBlock*>::Iterator
794 i = blocks.getIterator();
795 i.atEnd()==false; i++)
797 v3s16 p = i.getNode()->getKey();
799 if(m_blocks_sending.find(p) != NULL)
800 m_blocks_sending.remove(p);
801 if(m_blocks_sent.find(p) != NULL)
802 m_blocks_sent.remove(p);
810 PlayerInfo::PlayerInfo()
816 void PlayerInfo::PrintLine(std::ostream *s)
819 (*s)<<"\""<<name<<"\" ("
820 <<(position.X/10)<<","<<(position.Y/10)
821 <<","<<(position.Z/10)<<") ";
823 (*s)<<" avg_rtt="<<avg_rtt;
827 u32 PIChecksum(core::list<PlayerInfo> &l)
829 core::list<PlayerInfo>::Iterator i;
832 for(i=l.begin(); i!=l.end(); i++)
834 checksum += a * (i->id+1);
835 checksum ^= 0x435aafcd;
846 std::string mapsavedir,
847 std::string configpath
850 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
851 m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"),
852 m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"),
854 m_itemdef(createItemDefManager()),
855 m_nodedef(createNodeDefManager()),
856 m_craftdef(createCraftDefManager()),
858 m_emergethread(this),
860 m_time_of_day_send_timer(0),
862 m_mapsavedir(mapsavedir),
863 m_configpath(configpath),
864 m_shutdown_requested(false),
865 m_ignore_map_edit_events(false),
866 m_ignore_map_edit_events_peer_id(0)
868 m_liquid_transform_timer = 0.0;
869 m_print_info_timer = 0.0;
870 m_objectdata_timer = 0.0;
871 m_emergethread_trigger_timer = 0.0;
872 m_savemap_timer = 0.0;
876 m_step_dtime_mutex.Init();
879 JMutexAutoLock envlock(m_env_mutex);
880 JMutexAutoLock conlock(m_con_mutex);
882 // Path to builtin.lua
883 std::string builtinpath = porting::path_data + DIR_DELIM + "builtin.lua";
885 // Add default global mod search path
886 m_modspaths.push_front(porting::path_data + DIR_DELIM + "mods");
887 // Add world mod search path
888 m_modspaths.push_front(mapsavedir + DIR_DELIM + "worldmods");
889 // Add user mod search path
890 m_modspaths.push_front(porting::path_userdata + DIR_DELIM + "usermods");
892 // Print out mod search paths
893 infostream<<"Mod search paths:"<<std::endl;
894 for(core::list<std::string>::Iterator i = m_modspaths.begin();
895 i != m_modspaths.end(); i++){
896 std::string modspath = *i;
897 infostream<<" "<<modspath<<std::endl;
900 // Initialize scripting
902 infostream<<"Server: Initializing scripting"<<std::endl;
903 m_lua = script_init();
906 scriptapi_export(m_lua, this);
907 // Load and run builtin.lua
908 infostream<<"Server: Loading builtin Lua stuff from \""<<builtinpath
910 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
912 errorstream<<"Server: Failed to load and run "
913 <<builtinpath<<std::endl;
914 throw ModError("Failed to load and run "+builtinpath);
916 // Load and run "mod" scripts
917 m_mods = getMods(m_modspaths);
918 for(core::list<ModSpec>::Iterator i = m_mods.begin();
919 i != m_mods.end(); i++){
920 const ModSpec &mod = *i;
921 infostream<<"Server: Loading mod \""<<mod.name<<"\""<<std::endl;
922 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
923 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
925 errorstream<<"Server: Failed to load and run "
926 <<scriptpath<<std::endl;
927 throw ModError("Failed to load and run "+scriptpath);
931 // Read Textures and calculate sha1 sums
934 // Apply item aliases in the node definition manager
935 m_nodedef->updateAliases(m_itemdef);
937 // Initialize Environment
939 m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua,
942 // Give environment reference to scripting api
943 scriptapi_add_environment(m_lua, m_env);
945 // Register us to receive map edit events
946 m_env->getMap().addEventReceiver(this);
948 // If file exists, load environment metadata
949 if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt"))
951 infostream<<"Server: Loading environment metadata"<<std::endl;
952 m_env->loadMeta(m_mapsavedir);
956 infostream<<"Server: Loading players"<<std::endl;
957 m_env->deSerializePlayers(m_mapsavedir);
960 Add some test ActiveBlockModifiers to environment
962 add_legacy_abms(m_env, m_nodedef);
967 infostream<<"Server::~Server()"<<std::endl;
970 Send shutdown message
973 JMutexAutoLock conlock(m_con_mutex);
975 std::wstring line = L"*** Server shutting down";
978 Send the message to clients
980 for(core::map<u16, RemoteClient*>::Iterator
981 i = m_clients.getIterator();
982 i.atEnd() == false; i++)
984 // Get client and check that it is valid
985 RemoteClient *client = i.getNode()->getValue();
986 assert(client->peer_id == i.getNode()->getKey());
987 if(client->serialization_version == SER_FMT_VER_INVALID)
991 SendChatMessage(client->peer_id, line);
993 catch(con::PeerNotFoundException &e)
999 JMutexAutoLock envlock(m_env_mutex);
1004 infostream<<"Server: Saving players"<<std::endl;
1005 m_env->serializePlayers(m_mapsavedir);
1008 Save environment metadata
1010 infostream<<"Server: Saving environment metadata"<<std::endl;
1011 m_env->saveMeta(m_mapsavedir);
1023 JMutexAutoLock clientslock(m_con_mutex);
1025 for(core::map<u16, RemoteClient*>::Iterator
1026 i = m_clients.getIterator();
1027 i.atEnd() == false; i++)
1030 // NOTE: These are removed by env destructor
1032 u16 peer_id = i.getNode()->getKey();
1033 JMutexAutoLock envlock(m_env_mutex);
1034 m_env->removePlayer(peer_id);
1038 delete i.getNode()->getValue();
1042 // Delete Environment
1049 // Deinitialize scripting
1050 infostream<<"Server: Deinitializing scripting"<<std::endl;
1051 script_deinit(m_lua);
1054 void Server::start(unsigned short port)
1056 DSTACK(__FUNCTION_NAME);
1057 // Stop thread if already running
1060 // Initialize connection
1061 m_con.SetTimeoutMs(30);
1065 m_thread.setRun(true);
1068 infostream<<"Server: Started on port "<<port<<std::endl;
1073 DSTACK(__FUNCTION_NAME);
1075 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1077 // Stop threads (set run=false first so both start stopping)
1078 m_thread.setRun(false);
1079 m_emergethread.setRun(false);
1081 m_emergethread.stop();
1083 infostream<<"Server: Threads stopped"<<std::endl;
1086 void Server::step(float dtime)
1088 DSTACK(__FUNCTION_NAME);
1093 JMutexAutoLock lock(m_step_dtime_mutex);
1094 m_step_dtime += dtime;
1098 void Server::AsyncRunStep()
1100 DSTACK(__FUNCTION_NAME);
1102 g_profiler->add("Server::AsyncRunStep (num)", 1);
1106 JMutexAutoLock lock1(m_step_dtime_mutex);
1107 dtime = m_step_dtime;
1111 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
1112 // Send blocks to clients
1119 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1121 //infostream<<"Server steps "<<dtime<<std::endl;
1122 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1125 JMutexAutoLock lock1(m_step_dtime_mutex);
1126 m_step_dtime -= dtime;
1133 m_uptime.set(m_uptime.get() + dtime);
1137 // Process connection's timeouts
1138 JMutexAutoLock lock2(m_con_mutex);
1139 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1140 m_con.RunTimeouts(dtime);
1144 // This has to be called so that the client list gets synced
1145 // with the peer list of the connection
1146 handlePeerChanges();
1150 Update m_time_of_day and overall game time
1153 JMutexAutoLock envlock(m_env_mutex);
1155 m_time_counter += dtime;
1156 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1157 u32 units = (u32)(m_time_counter*speed);
1158 m_time_counter -= (f32)units / speed;
1160 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1162 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1165 Send to clients at constant intervals
1168 m_time_of_day_send_timer -= dtime;
1169 if(m_time_of_day_send_timer < 0.0)
1171 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1173 //JMutexAutoLock envlock(m_env_mutex);
1174 JMutexAutoLock conlock(m_con_mutex);
1176 for(core::map<u16, RemoteClient*>::Iterator
1177 i = m_clients.getIterator();
1178 i.atEnd() == false; i++)
1180 RemoteClient *client = i.getNode()->getValue();
1181 //Player *player = m_env->getPlayer(client->peer_id);
1183 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1184 m_env->getTimeOfDay());
1186 m_con.Send(client->peer_id, 0, data, true);
1192 JMutexAutoLock lock(m_env_mutex);
1194 ScopeProfiler sp(g_profiler, "SEnv step");
1195 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1199 const float map_timer_and_unload_dtime = 2.92;
1200 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1202 JMutexAutoLock lock(m_env_mutex);
1203 // Run Map's timers and unload unused data
1204 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1205 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1206 g_settings->getFloat("server_unload_unused_data_timeout"));
1217 JMutexAutoLock lock(m_env_mutex);
1218 JMutexAutoLock lock2(m_con_mutex);
1220 ScopeProfiler sp(g_profiler, "Server: handle players");
1222 //float player_max_speed = BS * 4.0; // Normal speed
1223 float player_max_speed = BS * 20; // Fast speed
1224 float player_max_speed_up = BS * 20;
1226 player_max_speed *= 2.5; // Tolerance
1227 player_max_speed_up *= 2.5;
1229 for(core::map<u16, RemoteClient*>::Iterator
1230 i = m_clients.getIterator();
1231 i.atEnd() == false; i++)
1233 RemoteClient *client = i.getNode()->getValue();
1234 ServerRemotePlayer *player =
1235 static_cast<ServerRemotePlayer*>
1236 (m_env->getPlayer(client->peer_id));
1241 Check player movements
1243 NOTE: Actually the server should handle player physics like the
1244 client does and compare player's position to what is calculated
1245 on our side. This is required when eg. players fly due to an
1248 player->m_last_good_position_age += dtime;
1249 if(player->m_last_good_position_age >= 2.0){
1250 float age = player->m_last_good_position_age;
1251 v3f diff = (player->getPosition() - player->m_last_good_position);
1252 float d_vert = diff.Y;
1254 float d_horiz = diff.getLength();
1255 /*infostream<<player->getName()<<"'s horizontal speed is "
1256 <<(d_horiz/age)<<std::endl;*/
1257 if(d_horiz <= age * player_max_speed &&
1258 (d_vert < 0 || d_vert < age * player_max_speed_up)){
1259 player->m_last_good_position = player->getPosition();
1261 actionstream<<"Player "<<player->getName()
1262 <<" moved too fast; resetting position"
1264 player->setPosition(player->m_last_good_position);
1265 SendMovePlayer(player);
1267 player->m_last_good_position_age = 0;
1271 Handle player HPs (die if hp=0)
1273 if(player->hp == 0 && player->m_hp_not_sent)
1277 Send player inventories and HPs if necessary
1279 if(player->m_inventory_not_sent){
1280 UpdateCrafting(player->peer_id);
1281 SendInventory(player->peer_id);
1283 if(player->m_hp_not_sent){
1284 SendPlayerHP(player);
1290 if(!player->m_is_in_environment){
1291 player->m_removed = false;
1293 m_env->addActiveObject(player);
1298 /* Transform liquids */
1299 m_liquid_transform_timer += dtime;
1300 if(m_liquid_transform_timer >= 1.00)
1302 m_liquid_transform_timer -= 1.00;
1304 JMutexAutoLock lock(m_env_mutex);
1306 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1308 core::map<v3s16, MapBlock*> modified_blocks;
1309 m_env->getMap().transformLiquids(modified_blocks);
1314 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1315 ServerMap &map = ((ServerMap&)m_env->getMap());
1316 map.updateLighting(modified_blocks, lighting_modified_blocks);
1318 // Add blocks modified by lighting to modified_blocks
1319 for(core::map<v3s16, MapBlock*>::Iterator
1320 i = lighting_modified_blocks.getIterator();
1321 i.atEnd() == false; i++)
1323 MapBlock *block = i.getNode()->getValue();
1324 modified_blocks.insert(block->getPos(), block);
1328 Set the modified blocks unsent for all the clients
1331 JMutexAutoLock lock2(m_con_mutex);
1333 for(core::map<u16, RemoteClient*>::Iterator
1334 i = m_clients.getIterator();
1335 i.atEnd() == false; i++)
1337 RemoteClient *client = i.getNode()->getValue();
1339 if(modified_blocks.size() > 0)
1341 // Remove block from sent history
1342 client->SetBlocksNotSent(modified_blocks);
1347 // Periodically print some info
1349 float &counter = m_print_info_timer;
1355 JMutexAutoLock lock2(m_con_mutex);
1357 if(m_clients.size() != 0)
1358 infostream<<"Players:"<<std::endl;
1359 for(core::map<u16, RemoteClient*>::Iterator
1360 i = m_clients.getIterator();
1361 i.atEnd() == false; i++)
1363 //u16 peer_id = i.getNode()->getKey();
1364 RemoteClient *client = i.getNode()->getValue();
1365 Player *player = m_env->getPlayer(client->peer_id);
1368 infostream<<"* "<<player->getName()<<"\t";
1369 client->PrintInfo(infostream);
1374 //if(g_settings->getBool("enable_experimental"))
1378 Check added and deleted active objects
1381 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1382 JMutexAutoLock envlock(m_env_mutex);
1383 JMutexAutoLock conlock(m_con_mutex);
1385 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1387 // Radius inside which objects are active
1388 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1389 radius *= MAP_BLOCKSIZE;
1391 for(core::map<u16, RemoteClient*>::Iterator
1392 i = m_clients.getIterator();
1393 i.atEnd() == false; i++)
1395 RemoteClient *client = i.getNode()->getValue();
1397 // If definitions and textures have not been sent, don't
1398 // send objects either
1399 if(!client->definitions_sent)
1402 Player *player = m_env->getPlayer(client->peer_id);
1405 // This can happen if the client timeouts somehow
1406 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1408 <<" has no associated player"<<std::endl;*/
1411 v3s16 pos = floatToInt(player->getPosition(), BS);
1413 core::map<u16, bool> removed_objects;
1414 core::map<u16, bool> added_objects;
1415 m_env->getRemovedActiveObjects(pos, radius,
1416 client->m_known_objects, removed_objects);
1417 m_env->getAddedActiveObjects(pos, radius,
1418 client->m_known_objects, added_objects);
1420 // Ignore if nothing happened
1421 if(removed_objects.size() == 0 && added_objects.size() == 0)
1423 //infostream<<"active objects: none changed"<<std::endl;
1427 std::string data_buffer;
1431 // Handle removed objects
1432 writeU16((u8*)buf, removed_objects.size());
1433 data_buffer.append(buf, 2);
1434 for(core::map<u16, bool>::Iterator
1435 i = removed_objects.getIterator();
1436 i.atEnd()==false; i++)
1439 u16 id = i.getNode()->getKey();
1440 ServerActiveObject* obj = m_env->getActiveObject(id);
1442 // Add to data buffer for sending
1443 writeU16((u8*)buf, i.getNode()->getKey());
1444 data_buffer.append(buf, 2);
1446 // Remove from known objects
1447 client->m_known_objects.remove(i.getNode()->getKey());
1449 if(obj && obj->m_known_by_count > 0)
1450 obj->m_known_by_count--;
1453 // Handle added objects
1454 writeU16((u8*)buf, added_objects.size());
1455 data_buffer.append(buf, 2);
1456 for(core::map<u16, bool>::Iterator
1457 i = added_objects.getIterator();
1458 i.atEnd()==false; i++)
1461 u16 id = i.getNode()->getKey();
1462 ServerActiveObject* obj = m_env->getActiveObject(id);
1465 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1467 infostream<<"WARNING: "<<__FUNCTION_NAME
1468 <<": NULL object"<<std::endl;
1470 type = obj->getType();
1472 // Add to data buffer for sending
1473 writeU16((u8*)buf, id);
1474 data_buffer.append(buf, 2);
1475 writeU8((u8*)buf, type);
1476 data_buffer.append(buf, 1);
1479 data_buffer.append(serializeLongString(
1480 obj->getClientInitializationData()));
1482 data_buffer.append(serializeLongString(""));
1484 // Add to known objects
1485 client->m_known_objects.insert(i.getNode()->getKey(), false);
1488 obj->m_known_by_count++;
1492 SharedBuffer<u8> reply(2 + data_buffer.size());
1493 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1494 memcpy((char*)&reply[2], data_buffer.c_str(),
1495 data_buffer.size());
1497 m_con.Send(client->peer_id, 0, reply, true);
1499 infostream<<"Server: Sent object remove/add: "
1500 <<removed_objects.size()<<" removed, "
1501 <<added_objects.size()<<" added, "
1502 <<"packet size is "<<reply.getSize()<<std::endl;
1507 Collect a list of all the objects known by the clients
1508 and report it back to the environment.
1511 core::map<u16, bool> all_known_objects;
1513 for(core::map<u16, RemoteClient*>::Iterator
1514 i = m_clients.getIterator();
1515 i.atEnd() == false; i++)
1517 RemoteClient *client = i.getNode()->getValue();
1518 // Go through all known objects of client
1519 for(core::map<u16, bool>::Iterator
1520 i = client->m_known_objects.getIterator();
1521 i.atEnd()==false; i++)
1523 u16 id = i.getNode()->getKey();
1524 all_known_objects[id] = true;
1528 m_env->setKnownActiveObjects(whatever);
1534 Send object messages
1537 JMutexAutoLock envlock(m_env_mutex);
1538 JMutexAutoLock conlock(m_con_mutex);
1540 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1543 // Value = data sent by object
1544 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1546 // Get active object messages from environment
1549 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1553 core::list<ActiveObjectMessage>* message_list = NULL;
1554 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1555 n = buffered_messages.find(aom.id);
1558 message_list = new core::list<ActiveObjectMessage>;
1559 buffered_messages.insert(aom.id, message_list);
1563 message_list = n->getValue();
1565 message_list->push_back(aom);
1568 // Route data to every client
1569 for(core::map<u16, RemoteClient*>::Iterator
1570 i = m_clients.getIterator();
1571 i.atEnd()==false; i++)
1573 RemoteClient *client = i.getNode()->getValue();
1574 std::string reliable_data;
1575 std::string unreliable_data;
1576 // Go through all objects in message buffer
1577 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1578 j = buffered_messages.getIterator();
1579 j.atEnd()==false; j++)
1581 // If object is not known by client, skip it
1582 u16 id = j.getNode()->getKey();
1583 if(client->m_known_objects.find(id) == NULL)
1585 // Get message list of object
1586 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1587 // Go through every message
1588 for(core::list<ActiveObjectMessage>::Iterator
1589 k = list->begin(); k != list->end(); k++)
1591 // Compose the full new data with header
1592 ActiveObjectMessage aom = *k;
1593 std::string new_data;
1596 writeU16((u8*)&buf[0], aom.id);
1597 new_data.append(buf, 2);
1599 new_data += serializeString(aom.datastring);
1600 // Add data to buffer
1602 reliable_data += new_data;
1604 unreliable_data += new_data;
1608 reliable_data and unreliable_data are now ready.
1611 if(reliable_data.size() > 0)
1613 SharedBuffer<u8> reply(2 + reliable_data.size());
1614 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1615 memcpy((char*)&reply[2], reliable_data.c_str(),
1616 reliable_data.size());
1618 m_con.Send(client->peer_id, 0, reply, true);
1620 if(unreliable_data.size() > 0)
1622 SharedBuffer<u8> reply(2 + unreliable_data.size());
1623 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1624 memcpy((char*)&reply[2], unreliable_data.c_str(),
1625 unreliable_data.size());
1626 // Send as unreliable
1627 m_con.Send(client->peer_id, 0, reply, false);
1630 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1632 infostream<<"Server: Size of object message data: "
1633 <<"reliable: "<<reliable_data.size()
1634 <<", unreliable: "<<unreliable_data.size()
1639 // Clear buffered_messages
1640 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1641 i = buffered_messages.getIterator();
1642 i.atEnd()==false; i++)
1644 delete i.getNode()->getValue();
1648 } // enable_experimental
1651 Send queued-for-sending map edit events.
1654 // Don't send too many at a time
1657 // Single change sending is disabled if queue size is not small
1658 bool disable_single_change_sending = false;
1659 if(m_unsent_map_edit_queue.size() >= 4)
1660 disable_single_change_sending = true;
1662 bool got_any_events = false;
1664 // We'll log the amount of each
1667 while(m_unsent_map_edit_queue.size() != 0)
1669 got_any_events = true;
1671 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1673 // Players far away from the change are stored here.
1674 // Instead of sending the changes, MapBlocks are set not sent
1676 core::list<u16> far_players;
1678 if(event->type == MEET_ADDNODE)
1680 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1681 prof.add("MEET_ADDNODE", 1);
1682 if(disable_single_change_sending)
1683 sendAddNode(event->p, event->n, event->already_known_by_peer,
1686 sendAddNode(event->p, event->n, event->already_known_by_peer,
1689 else if(event->type == MEET_REMOVENODE)
1691 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1692 prof.add("MEET_REMOVENODE", 1);
1693 if(disable_single_change_sending)
1694 sendRemoveNode(event->p, event->already_known_by_peer,
1697 sendRemoveNode(event->p, event->already_known_by_peer,
1700 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1702 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1703 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1704 setBlockNotSent(event->p);
1706 else if(event->type == MEET_OTHER)
1708 infostream<<"Server: MEET_OTHER"<<std::endl;
1709 prof.add("MEET_OTHER", 1);
1710 for(core::map<v3s16, bool>::Iterator
1711 i = event->modified_blocks.getIterator();
1712 i.atEnd()==false; i++)
1714 v3s16 p = i.getNode()->getKey();
1720 prof.add("unknown", 1);
1721 infostream<<"WARNING: Server: Unknown MapEditEvent "
1722 <<((u32)event->type)<<std::endl;
1726 Set blocks not sent to far players
1728 if(far_players.size() > 0)
1730 // Convert list format to that wanted by SetBlocksNotSent
1731 core::map<v3s16, MapBlock*> modified_blocks2;
1732 for(core::map<v3s16, bool>::Iterator
1733 i = event->modified_blocks.getIterator();
1734 i.atEnd()==false; i++)
1736 v3s16 p = i.getNode()->getKey();
1737 modified_blocks2.insert(p,
1738 m_env->getMap().getBlockNoCreateNoEx(p));
1740 // Set blocks not sent
1741 for(core::list<u16>::Iterator
1742 i = far_players.begin();
1743 i != far_players.end(); i++)
1746 RemoteClient *client = getClient(peer_id);
1749 client->SetBlocksNotSent(modified_blocks2);
1755 /*// Don't send too many at a time
1757 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1763 infostream<<"Server: MapEditEvents:"<<std::endl;
1764 prof.print(infostream);
1770 Trigger emergethread (it somehow gets to a non-triggered but
1771 bysy state sometimes)
1774 float &counter = m_emergethread_trigger_timer;
1780 m_emergethread.trigger();
1784 // Save map, players and auth stuff
1786 float &counter = m_savemap_timer;
1788 if(counter >= g_settings->getFloat("server_map_save_interval"))
1792 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1795 if(m_authmanager.isModified())
1796 m_authmanager.save();
1799 if(m_banmanager.isModified())
1800 m_banmanager.save();
1803 JMutexAutoLock lock(m_env_mutex);
1805 // Save changed parts of map
1806 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1809 m_env->serializePlayers(m_mapsavedir);
1811 // Save environment metadata
1812 m_env->saveMeta(m_mapsavedir);
1817 void Server::Receive()
1819 DSTACK(__FUNCTION_NAME);
1820 SharedBuffer<u8> data;
1825 JMutexAutoLock conlock(m_con_mutex);
1826 datasize = m_con.Receive(peer_id, data);
1829 // This has to be called so that the client list gets synced
1830 // with the peer list of the connection
1831 handlePeerChanges();
1833 ProcessData(*data, datasize, peer_id);
1835 catch(con::InvalidIncomingDataException &e)
1837 infostream<<"Server::Receive(): "
1838 "InvalidIncomingDataException: what()="
1839 <<e.what()<<std::endl;
1841 catch(con::PeerNotFoundException &e)
1843 //NOTE: This is not needed anymore
1845 // The peer has been disconnected.
1846 // Find the associated player and remove it.
1848 /*JMutexAutoLock envlock(m_env_mutex);
1850 infostream<<"ServerThread: peer_id="<<peer_id
1851 <<" has apparently closed connection. "
1852 <<"Removing player."<<std::endl;
1854 m_env->removePlayer(peer_id);*/
1858 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1860 DSTACK(__FUNCTION_NAME);
1861 // Environment is locked first.
1862 JMutexAutoLock envlock(m_env_mutex);
1863 JMutexAutoLock conlock(m_con_mutex);
1866 Address address = m_con.GetPeerAddress(peer_id);
1868 // drop player if is ip is banned
1869 if(m_banmanager.isIpBanned(address.serializeString())){
1870 SendAccessDenied(m_con, peer_id,
1871 L"Your ip is banned. Banned name was "
1872 +narrow_to_wide(m_banmanager.getBanName(
1873 address.serializeString())));
1874 m_con.DeletePeer(peer_id);
1878 catch(con::PeerNotFoundException &e)
1880 infostream<<"Server::ProcessData(): Cancelling: peer "
1881 <<peer_id<<" not found"<<std::endl;
1885 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1893 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1895 if(command == TOSERVER_INIT)
1897 // [0] u16 TOSERVER_INIT
1898 // [2] u8 SER_FMT_VER_HIGHEST
1899 // [3] u8[20] player_name
1900 // [23] u8[28] password <--- can be sent without this, from old versions
1902 if(datasize < 2+1+PLAYERNAME_SIZE)
1905 infostream<<"Server: Got TOSERVER_INIT from "
1906 <<peer_id<<std::endl;
1908 // First byte after command is maximum supported
1909 // serialization version
1910 u8 client_max = data[2];
1911 u8 our_max = SER_FMT_VER_HIGHEST;
1912 // Use the highest version supported by both
1913 u8 deployed = core::min_(client_max, our_max);
1914 // If it's lower than the lowest supported, give up.
1915 if(deployed < SER_FMT_VER_LOWEST)
1916 deployed = SER_FMT_VER_INVALID;
1918 //peer->serialization_version = deployed;
1919 getClient(peer_id)->pending_serialization_version = deployed;
1921 if(deployed == SER_FMT_VER_INVALID)
1923 infostream<<"Server: Cannot negotiate "
1924 "serialization version with peer "
1925 <<peer_id<<std::endl;
1926 SendAccessDenied(m_con, peer_id, std::wstring(
1927 L"Your client's version is not supported.\n"
1928 L"Server version is ")
1929 + narrow_to_wide(VERSION_STRING) + L"."
1935 Read and check network protocol version
1938 u16 net_proto_version = 0;
1939 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1941 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1944 getClient(peer_id)->net_proto_version = net_proto_version;
1946 if(net_proto_version == 0)
1948 SendAccessDenied(m_con, peer_id, std::wstring(
1949 L"Your client's version is not supported.\n"
1950 L"Server version is ")
1951 + narrow_to_wide(VERSION_STRING) + L"."
1956 if(g_settings->getBool("strict_protocol_version_checking"))
1958 if(net_proto_version != PROTOCOL_VERSION)
1960 SendAccessDenied(m_con, peer_id, std::wstring(
1961 L"Your client's version is not supported.\n"
1962 L"Server version is ")
1963 + narrow_to_wide(VERSION_STRING) + L",\n"
1964 + L"server's PROTOCOL_VERSION is "
1965 + narrow_to_wide(itos(PROTOCOL_VERSION))
1966 + L", client's PROTOCOL_VERSION is "
1967 + narrow_to_wide(itos(net_proto_version))
1978 char playername[PLAYERNAME_SIZE];
1979 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1981 playername[i] = data[3+i];
1983 playername[PLAYERNAME_SIZE-1] = 0;
1985 if(playername[0]=='\0')
1987 infostream<<"Server: Player has empty name"<<std::endl;
1988 SendAccessDenied(m_con, peer_id,
1993 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1995 infostream<<"Server: Player has invalid name"<<std::endl;
1996 SendAccessDenied(m_con, peer_id,
1997 L"Name contains unallowed characters");
2002 char password[PASSWORD_SIZE];
2003 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2005 // old version - assume blank password
2010 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2012 password[i] = data[23+i];
2014 password[PASSWORD_SIZE-1] = 0;
2017 // Add player to auth manager
2018 if(m_authmanager.exists(playername) == false)
2020 std::wstring default_password =
2021 narrow_to_wide(g_settings->get("default_password"));
2022 std::string translated_default_password =
2023 translatePassword(playername, default_password);
2025 // If default_password is empty, allow any initial password
2026 if (default_password.length() == 0)
2027 translated_default_password = password;
2029 infostream<<"Server: adding player "<<playername
2030 <<" to auth manager"<<std::endl;
2031 m_authmanager.add(playername);
2032 m_authmanager.setPassword(playername, translated_default_password);
2033 m_authmanager.setPrivs(playername,
2034 stringToPrivs(g_settings->get("default_privs")));
2035 m_authmanager.save();
2038 std::string checkpwd = m_authmanager.getPassword(playername);
2040 /*infostream<<"Server: Client gave password '"<<password
2041 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2043 if(password != checkpwd)
2045 infostream<<"Server: peer_id="<<peer_id
2046 <<": supplied invalid password for "
2047 <<playername<<std::endl;
2048 SendAccessDenied(m_con, peer_id, L"Invalid password");
2052 // Enforce user limit.
2053 // Don't enforce for users that have some admin right
2054 if(m_clients.size() >= g_settings->getU16("max_users") &&
2055 (m_authmanager.getPrivs(playername)
2056 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2057 playername != g_settings->get("name"))
2059 SendAccessDenied(m_con, peer_id, L"Too many users.");
2064 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2066 // If failed, cancel
2069 infostream<<"Server: peer_id="<<peer_id
2070 <<": failed to emerge player"<<std::endl;
2075 Answer with a TOCLIENT_INIT
2078 SharedBuffer<u8> reply(2+1+6+8);
2079 writeU16(&reply[0], TOCLIENT_INIT);
2080 writeU8(&reply[2], deployed);
2081 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2082 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2085 m_con.Send(peer_id, 0, reply, true);
2089 Send complete position information
2091 SendMovePlayer(player);
2096 if(command == TOSERVER_INIT2)
2098 infostream<<"Server: Got TOSERVER_INIT2 from "
2099 <<peer_id<<std::endl;
2102 getClient(peer_id)->serialization_version
2103 = getClient(peer_id)->pending_serialization_version;
2106 Send some initialization data
2109 // Send item definitions
2110 SendItemDef(m_con, peer_id, m_itemdef);
2112 // Send node definitions
2113 SendNodeDef(m_con, peer_id, m_nodedef);
2115 // Send texture announcement
2116 SendTextureAnnouncement(peer_id);
2118 // Send player info to all players
2119 //SendPlayerInfos();
2121 // Send inventory to player
2122 UpdateCrafting(peer_id);
2123 SendInventory(peer_id);
2125 // Send player items to all players
2128 Player *player = m_env->getPlayer(peer_id);
2131 SendPlayerHP(player);
2133 // Show death screen if necessary
2135 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
2139 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2140 m_env->getTimeOfDay());
2141 m_con.Send(peer_id, 0, data, true);
2144 // Send information about server to player in chat
2145 SendChatMessage(peer_id, getStatusString());
2147 // Send information about joining in chat
2149 std::wstring name = L"unknown";
2150 Player *player = m_env->getPlayer(peer_id);
2152 name = narrow_to_wide(player->getName());
2154 std::wstring message;
2157 message += L" joined game";
2158 BroadcastChatMessage(message);
2161 // Warnings about protocol version can be issued here
2162 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2164 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2171 std::ostringstream os(std::ios_base::binary);
2172 for(core::map<u16, RemoteClient*>::Iterator
2173 i = m_clients.getIterator();
2174 i.atEnd() == false; i++)
2176 RemoteClient *client = i.getNode()->getValue();
2177 assert(client->peer_id == i.getNode()->getKey());
2178 if(client->serialization_version == SER_FMT_VER_INVALID)
2181 Player *player = m_env->getPlayer(client->peer_id);
2184 // Get name of player
2185 os<<player->getName()<<" ";
2188 actionstream<<player->getName()<<" joins game. List of players: "
2189 <<os.str()<<std::endl;
2195 if(peer_ser_ver == SER_FMT_VER_INVALID)
2197 infostream<<"Server::ProcessData(): Cancelling: Peer"
2198 " serialization format invalid or not initialized."
2199 " Skipping incoming command="<<command<<std::endl;
2203 Player *player = m_env->getPlayer(peer_id);
2204 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2207 infostream<<"Server::ProcessData(): Cancelling: "
2208 "No player for peer_id="<<peer_id
2212 if(command == TOSERVER_PLAYERPOS)
2214 if(datasize < 2+12+12+4+4)
2218 v3s32 ps = readV3S32(&data[start+2]);
2219 v3s32 ss = readV3S32(&data[start+2+12]);
2220 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2221 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2222 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2223 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2224 pitch = wrapDegrees(pitch);
2225 yaw = wrapDegrees(yaw);
2227 player->setPosition(position);
2228 player->setSpeed(speed);
2229 player->setPitch(pitch);
2230 player->setYaw(yaw);
2232 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2233 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2234 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2236 else if(command == TOSERVER_GOTBLOCKS)
2249 u16 count = data[2];
2250 for(u16 i=0; i<count; i++)
2252 if((s16)datasize < 2+1+(i+1)*6)
2253 throw con::InvalidIncomingDataException
2254 ("GOTBLOCKS length is too short");
2255 v3s16 p = readV3S16(&data[2+1+i*6]);
2256 /*infostream<<"Server: GOTBLOCKS ("
2257 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2258 RemoteClient *client = getClient(peer_id);
2259 client->GotBlock(p);
2262 else if(command == TOSERVER_DELETEDBLOCKS)
2275 u16 count = data[2];
2276 for(u16 i=0; i<count; i++)
2278 if((s16)datasize < 2+1+(i+1)*6)
2279 throw con::InvalidIncomingDataException
2280 ("DELETEDBLOCKS length is too short");
2281 v3s16 p = readV3S16(&data[2+1+i*6]);
2282 /*infostream<<"Server: DELETEDBLOCKS ("
2283 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2284 RemoteClient *client = getClient(peer_id);
2285 client->SetBlockNotSent(p);
2288 else if(command == TOSERVER_CLICK_OBJECT)
2290 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2293 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2295 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2298 else if(command == TOSERVER_GROUND_ACTION)
2300 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2304 else if(command == TOSERVER_RELEASE)
2306 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2309 else if(command == TOSERVER_SIGNTEXT)
2311 infostream<<"Server: SIGNTEXT not supported anymore"
2315 else if(command == TOSERVER_SIGNNODETEXT)
2317 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2325 std::string datastring((char*)&data[2], datasize-2);
2326 std::istringstream is(datastring, std::ios_base::binary);
2329 is.read((char*)buf, 6);
2330 v3s16 p = readV3S16(buf);
2331 is.read((char*)buf, 2);
2332 u16 textlen = readU16(buf);
2334 for(u16 i=0; i<textlen; i++)
2336 is.read((char*)buf, 1);
2337 text += (char)buf[0];
2340 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2344 meta->setText(text);
2346 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2347 <<" at "<<PP(p)<<std::endl;
2349 v3s16 blockpos = getNodeBlockPos(p);
2350 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2353 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2357 setBlockNotSent(blockpos);
2359 else if(command == TOSERVER_INVENTORY_ACTION)
2361 // Strip command and create a stream
2362 std::string datastring((char*)&data[2], datasize-2);
2363 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2364 std::istringstream is(datastring, std::ios_base::binary);
2366 InventoryAction *a = InventoryAction::deSerialize(is);
2369 infostream<<"TOSERVER_INVENTORY_ACTION: "
2370 <<"InventoryAction::deSerialize() returned NULL"
2376 Note: Always set inventory not sent, to repair cases
2377 where the client made a bad prediction.
2381 Handle restrictions and special cases of the move action
2383 if(a->getType() == IACTION_MOVE)
2385 IMoveAction *ma = (IMoveAction*)a;
2387 ma->from_inv.applyCurrentPlayer(player->getName());
2388 ma->to_inv.applyCurrentPlayer(player->getName());
2390 setInventoryModified(ma->from_inv);
2391 setInventoryModified(ma->to_inv);
2393 bool from_inv_is_current_player =
2394 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2395 (ma->from_inv.name == player->getName());
2397 bool to_inv_is_current_player =
2398 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2399 (ma->to_inv.name == player->getName());
2402 Disable moving items out of craftpreview
2404 if(ma->from_list == "craftpreview")
2406 infostream<<"Ignoring IMoveAction from "
2407 <<(ma->from_inv.dump())<<":"<<ma->from_list
2408 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2409 <<" because src is "<<ma->from_list<<std::endl;
2415 Disable moving items into craftresult and craftpreview
2417 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2419 infostream<<"Ignoring IMoveAction from "
2420 <<(ma->from_inv.dump())<<":"<<ma->from_list
2421 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2422 <<" because dst is "<<ma->to_list<<std::endl;
2427 // Disallow moving items in elsewhere than player's inventory
2428 // if not allowed to interact
2429 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
2430 && (!from_inv_is_current_player
2431 || !to_inv_is_current_player))
2433 infostream<<"Cannot move outside of player's inventory: "
2434 <<"No interact privilege"<<std::endl;
2439 // If player is not an admin, check for ownership of src and dst
2440 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2442 std::string owner_from = getInventoryOwner(ma->from_inv);
2443 if(owner_from != "" && owner_from != player->getName())
2445 infostream<<"WARNING: "<<player->getName()
2446 <<" tried to access an inventory that"
2447 <<" belongs to "<<owner_from<<std::endl;
2452 std::string owner_to = getInventoryOwner(ma->to_inv);
2453 if(owner_to != "" && owner_to != player->getName())
2455 infostream<<"WARNING: "<<player->getName()
2456 <<" tried to access an inventory that"
2457 <<" belongs to "<<owner_to<<std::endl;
2464 Handle restrictions and special cases of the drop action
2466 else if(a->getType() == IACTION_DROP)
2468 IDropAction *da = (IDropAction*)a;
2470 da->from_inv.applyCurrentPlayer(player->getName());
2472 setInventoryModified(da->from_inv);
2474 // Disallow dropping items if not allowed to interact
2475 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2480 // If player is not an admin, check for ownership
2481 else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2483 std::string owner_from = getInventoryOwner(da->from_inv);
2484 if(owner_from != "" && owner_from != player->getName())
2486 infostream<<"WARNING: "<<player->getName()
2487 <<" tried to access an inventory that"
2488 <<" belongs to "<<owner_from<<std::endl;
2495 Handle restrictions and special cases of the craft action
2497 else if(a->getType() == IACTION_CRAFT)
2499 ICraftAction *ca = (ICraftAction*)a;
2501 ca->craft_inv.applyCurrentPlayer(player->getName());
2503 setInventoryModified(ca->craft_inv);
2505 //bool craft_inv_is_current_player =
2506 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2507 // (ca->craft_inv.name == player->getName());
2509 // Disallow crafting if not allowed to interact
2510 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2512 infostream<<"Cannot craft: "
2513 <<"No interact privilege"<<std::endl;
2518 // If player is not an admin, check for ownership of inventory
2519 if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
2521 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2522 if(owner_craft != "" && owner_craft != player->getName())
2524 infostream<<"WARNING: "<<player->getName()
2525 <<" tried to access an inventory that"
2526 <<" belongs to "<<owner_craft<<std::endl;
2534 a->apply(this, srp, this);
2538 else if(command == TOSERVER_CHAT_MESSAGE)
2546 std::string datastring((char*)&data[2], datasize-2);
2547 std::istringstream is(datastring, std::ios_base::binary);
2550 is.read((char*)buf, 2);
2551 u16 len = readU16(buf);
2553 std::wstring message;
2554 for(u16 i=0; i<len; i++)
2556 is.read((char*)buf, 2);
2557 message += (wchar_t)readU16(buf);
2560 // Get player name of this client
2561 std::wstring name = narrow_to_wide(player->getName());
2564 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2565 wide_to_narrow(message));
2566 // If script ate the message, don't proceed
2570 // Line to send to players
2572 // Whether to send to the player that sent the line
2573 bool send_to_sender = false;
2574 // Whether to send to other players
2575 bool send_to_others = false;
2577 // Local player gets all privileges regardless of
2578 // what's set on their account.
2579 u64 privs = getPlayerPrivs(player);
2582 if(message[0] == L'/')
2584 size_t strip_size = 1;
2585 if (message[1] == L'#') // support old-style commans
2587 message = message.substr(strip_size);
2589 WStrfnd f1(message);
2590 f1.next(L" "); // Skip over /#whatever
2591 std::wstring paramstring = f1.next(L"");
2593 ServerCommandContext *ctx = new ServerCommandContext(
2594 str_split(message, L' '),
2601 std::wstring reply(processServerCommand(ctx));
2602 send_to_sender = ctx->flags & SEND_TO_SENDER;
2603 send_to_others = ctx->flags & SEND_TO_OTHERS;
2605 if (ctx->flags & SEND_NO_PREFIX)
2608 line += L"Server: " + reply;
2615 if(privs & PRIV_SHOUT)
2621 send_to_others = true;
2625 line += L"Server: You are not allowed to shout";
2626 send_to_sender = true;
2633 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2636 Send the message to clients
2638 for(core::map<u16, RemoteClient*>::Iterator
2639 i = m_clients.getIterator();
2640 i.atEnd() == false; i++)
2642 // Get client and check that it is valid
2643 RemoteClient *client = i.getNode()->getValue();
2644 assert(client->peer_id == i.getNode()->getKey());
2645 if(client->serialization_version == SER_FMT_VER_INVALID)
2649 bool sender_selected = (peer_id == client->peer_id);
2650 if(sender_selected == true && send_to_sender == false)
2652 if(sender_selected == false && send_to_others == false)
2655 SendChatMessage(client->peer_id, line);
2659 else if(command == TOSERVER_DAMAGE)
2661 std::string datastring((char*)&data[2], datasize-2);
2662 std::istringstream is(datastring, std::ios_base::binary);
2663 u8 damage = readU8(is);
2665 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2667 if(g_settings->getBool("enable_damage"))
2669 actionstream<<player->getName()<<" damaged by "
2670 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2673 srp->setHP(srp->getHP() - damage);
2675 if(srp->getHP() == 0 && srp->m_hp_not_sent)
2678 if(srp->m_hp_not_sent)
2679 SendPlayerHP(player);
2683 // Force send (to correct the client's predicted HP)
2684 SendPlayerHP(player);
2687 else if(command == TOSERVER_PASSWORD)
2690 [0] u16 TOSERVER_PASSWORD
2691 [2] u8[28] old password
2692 [30] u8[28] new password
2695 if(datasize != 2+PASSWORD_SIZE*2)
2697 /*char password[PASSWORD_SIZE];
2698 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2699 password[i] = data[2+i];
2700 password[PASSWORD_SIZE-1] = 0;*/
2702 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2710 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2712 char c = data[2+PASSWORD_SIZE+i];
2718 infostream<<"Server: Client requests a password change from "
2719 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2721 std::string playername = player->getName();
2723 if(m_authmanager.exists(playername) == false)
2725 infostream<<"Server: playername not found in authmanager"<<std::endl;
2726 // Wrong old password supplied!!
2727 SendChatMessage(peer_id, L"playername not found in authmanager");
2731 std::string checkpwd = m_authmanager.getPassword(playername);
2733 if(oldpwd != checkpwd)
2735 infostream<<"Server: invalid old password"<<std::endl;
2736 // Wrong old password supplied!!
2737 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2741 actionstream<<player->getName()<<" changes password"<<std::endl;
2743 m_authmanager.setPassword(playername, newpwd);
2745 infostream<<"Server: password change successful for "<<playername
2747 SendChatMessage(peer_id, L"Password change successful");
2749 else if(command == TOSERVER_PLAYERITEM)
2754 u16 item = readU16(&data[2]);
2755 srp->setWieldIndex(item);
2756 SendWieldedItem(srp);
2758 else if(command == TOSERVER_RESPAWN)
2763 RespawnPlayer(player);
2765 actionstream<<player->getName()<<" respawns at "
2766 <<PP(player->getPosition()/BS)<<std::endl;
2768 // ActiveObject is added to environment in AsyncRunStep after
2769 // the previous addition has been succesfully removed
2771 else if(command == TOSERVER_REQUEST_TEXTURES) {
2772 std::string datastring((char*)&data[2], datasize-2);
2773 std::istringstream is(datastring, std::ios_base::binary);
2775 infostream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2777 core::list<TextureRequest> tosend;
2779 u16 numtextures = readU16(is);
2781 for(int i = 0; i < numtextures; i++) {
2783 std::string name = deSerializeString(is);
2785 tosend.push_back(TextureRequest(name));
2786 infostream<<"TOSERVER_REQUEST_TEXTURES: requested texture " << name <<std::endl;
2789 SendTexturesRequested(peer_id, tosend);
2791 // Now the client should know about everything
2792 // (definitions and textures)
2793 getClient(peer_id)->definitions_sent = true;
2795 else if(command == TOSERVER_INTERACT)
2797 std::string datastring((char*)&data[2], datasize-2);
2798 std::istringstream is(datastring, std::ios_base::binary);
2804 [5] u32 length of the next item
2805 [9] serialized PointedThing
2807 0: start digging (from undersurface) or use
2808 1: stop digging (all parameters ignored)
2809 2: digging completed
2810 3: place block or item (to abovesurface)
2813 u8 action = readU8(is);
2814 u16 item_i = readU16(is);
2815 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2816 PointedThing pointed;
2817 pointed.deSerialize(tmp_is);
2819 infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<<item_i<<", pointed="<<pointed.dump()<<std::endl;
2823 infostream<<"TOSERVER_INTERACT: "<<srp->getName()
2824 <<" tried to interact, but is dead!"<<std::endl;
2828 v3f player_pos = srp->m_last_good_position;
2830 // Update wielded item
2831 if(srp->getWieldIndex() != item_i)
2833 srp->setWieldIndex(item_i);
2834 SendWieldedItem(srp);
2837 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2838 v3s16 p_under = pointed.node_undersurface;
2839 v3s16 p_above = pointed.node_abovesurface;
2841 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2842 ServerActiveObject *pointed_object = NULL;
2843 if(pointed.type == POINTEDTHING_OBJECT)
2845 pointed_object = m_env->getActiveObject(pointed.object_id);
2846 if(pointed_object == NULL)
2848 infostream<<"TOSERVER_INTERACT: "
2849 "pointed object is NULL"<<std::endl;
2855 v3f pointed_pos_under = player_pos;
2856 v3f pointed_pos_above = player_pos;
2857 if(pointed.type == POINTEDTHING_NODE)
2859 pointed_pos_under = intToFloat(p_under, BS);
2860 pointed_pos_above = intToFloat(p_above, BS);
2862 else if(pointed.type == POINTEDTHING_OBJECT)
2864 pointed_pos_under = pointed_object->getBasePosition();
2865 pointed_pos_above = pointed_pos_under;
2869 Check that target is reasonably close
2870 (only when digging or placing things)
2872 if(action == 0 || action == 2 || action == 3)
2874 float d = player_pos.getDistanceFrom(pointed_pos_under);
2875 float max_d = BS * 10; // Just some large enough value
2877 actionstream<<"Player "<<player->getName()
2878 <<" tried to access "<<pointed.dump()
2880 <<"d="<<d<<", max_d="<<max_d
2881 <<". ignoring."<<std::endl;
2882 // Re-send block to revert change on client-side
2883 RemoteClient *client = getClient(peer_id);
2884 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2885 client->SetBlockNotSent(blockpos);
2892 Make sure the player is allowed to do it
2894 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2896 infostream<<"Ignoring interaction from player "<<player->getName()
2897 <<" because privileges are "<<getPlayerPrivs(player)
2903 0: start digging or punch object
2907 if(pointed.type == POINTEDTHING_NODE)
2910 NOTE: This can be used in the future to check if
2911 somebody is cheating, by checking the timing.
2913 MapNode n(CONTENT_IGNORE);
2916 n = m_env->getMap().getNode(p_under);
2918 catch(InvalidPositionException &e)
2920 infostream<<"Server: Not punching: Node not found."
2921 <<" Adding block to emerge queue."
2923 m_emerge_queue.addBlock(peer_id,
2924 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2926 if(n.getContent() != CONTENT_IGNORE)
2927 scriptapi_node_on_punch(m_lua, p_under, n, srp);
2929 else if(pointed.type == POINTEDTHING_OBJECT)
2931 // Skip if object has been removed
2932 if(pointed_object->m_removed)
2935 actionstream<<player->getName()<<" punches object "
2936 <<pointed.object_id<<std::endl;
2939 pointed_object->punch(srp, srp->m_time_from_last_punch);
2940 srp->m_time_from_last_punch = 0;
2948 else if(action == 1)
2953 2: Digging completed
2955 else if(action == 2)
2957 // Only complete digging of nodes
2958 if(pointed.type == POINTEDTHING_NODE)
2960 MapNode n(CONTENT_IGNORE);
2963 n = m_env->getMap().getNode(p_under);
2965 catch(InvalidPositionException &e)
2967 infostream<<"Server: Not finishing digging: Node not found."
2968 <<" Adding block to emerge queue."
2970 m_emerge_queue.addBlock(peer_id,
2971 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2973 if(n.getContent() != CONTENT_IGNORE)
2974 scriptapi_node_on_dig(m_lua, p_under, n, srp);
2979 3: place block or right-click object
2981 else if(action == 3)
2983 ItemStack item = srp->getWieldedItem();
2985 // Reset build time counter
2986 if(pointed.type == POINTEDTHING_NODE &&
2987 item.getDefinition(m_itemdef).type == ITEM_NODE)
2988 getClient(peer_id)->m_time_from_building = 0.0;
2990 if(pointed.type == POINTEDTHING_OBJECT)
2992 // Right click object
2994 // Skip if object has been removed
2995 if(pointed_object->m_removed)
2998 actionstream<<player->getName()<<" right-clicks object "
2999 <<pointed.object_id<<std::endl;
3002 pointed_object->rightClick(srp);
3004 else if(scriptapi_item_on_place(m_lua,
3005 item, srp, pointed))
3007 // Placement was handled in lua
3009 // Apply returned ItemStack
3010 if(g_settings->getBool("creative_mode") == false)
3011 srp->setWieldedItem(item);
3019 else if(action == 4)
3021 ItemStack item = srp->getWieldedItem();
3023 actionstream<<player->getName()<<" uses "<<item.name
3024 <<", pointing at "<<pointed.dump()<<std::endl;
3026 if(scriptapi_item_on_use(m_lua,
3027 item, srp, pointed))
3029 // Apply returned ItemStack
3030 if(g_settings->getBool("creative_mode") == false)
3031 srp->setWieldedItem(item);
3037 Catch invalid actions
3041 infostream<<"WARNING: Server: Invalid action "
3042 <<action<<std::endl;
3047 infostream<<"Server::ProcessData(): Ignoring "
3048 "unknown command "<<command<<std::endl;
3052 catch(SendFailedException &e)
3054 errorstream<<"Server::ProcessData(): SendFailedException: "
3060 void Server::onMapEditEvent(MapEditEvent *event)
3062 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3063 if(m_ignore_map_edit_events)
3065 MapEditEvent *e = event->clone();
3066 m_unsent_map_edit_queue.push_back(e);
3069 Inventory* Server::getInventory(const InventoryLocation &loc)
3072 case InventoryLocation::UNDEFINED:
3075 case InventoryLocation::CURRENT_PLAYER:
3078 case InventoryLocation::PLAYER:
3080 Player *player = m_env->getPlayer(loc.name.c_str());
3083 return &player->inventory;
3086 case InventoryLocation::NODEMETA:
3088 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3091 return meta->getInventory();
3099 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3102 case InventoryLocation::UNDEFINED:
3105 case InventoryLocation::CURRENT_PLAYER:
3108 case InventoryLocation::PLAYER:
3113 case InventoryLocation::NODEMETA:
3115 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3118 return meta->getOwner();
3126 void Server::setInventoryModified(const InventoryLocation &loc)
3129 case InventoryLocation::UNDEFINED:
3132 case InventoryLocation::PLAYER:
3134 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3135 (m_env->getPlayer(loc.name.c_str()));
3138 srp->m_inventory_not_sent = true;
3141 case InventoryLocation::NODEMETA:
3143 v3s16 blockpos = getNodeBlockPos(loc.p);
3145 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3147 meta->inventoryModified();
3149 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3151 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3153 setBlockNotSent(blockpos);
3161 core::list<PlayerInfo> Server::getPlayerInfo()
3163 DSTACK(__FUNCTION_NAME);
3164 JMutexAutoLock envlock(m_env_mutex);
3165 JMutexAutoLock conlock(m_con_mutex);
3167 core::list<PlayerInfo> list;
3169 core::list<Player*> players = m_env->getPlayers();
3171 core::list<Player*>::Iterator i;
3172 for(i = players.begin();
3173 i != players.end(); i++)
3177 Player *player = *i;
3180 // Copy info from connection to info struct
3181 info.id = player->peer_id;
3182 info.address = m_con.GetPeerAddress(player->peer_id);
3183 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3185 catch(con::PeerNotFoundException &e)
3187 // Set dummy peer info
3189 info.address = Address(0,0,0,0,0);
3193 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3194 info.position = player->getPosition();
3196 list.push_back(info);
3203 void Server::peerAdded(con::Peer *peer)
3205 DSTACK(__FUNCTION_NAME);
3206 infostream<<"Server::peerAdded(): peer->id="
3207 <<peer->id<<std::endl;
3210 c.type = PEER_ADDED;
3211 c.peer_id = peer->id;
3213 m_peer_change_queue.push_back(c);
3216 void Server::deletingPeer(con::Peer *peer, bool timeout)
3218 DSTACK(__FUNCTION_NAME);
3219 infostream<<"Server::deletingPeer(): peer->id="
3220 <<peer->id<<", timeout="<<timeout<<std::endl;
3223 c.type = PEER_REMOVED;
3224 c.peer_id = peer->id;
3225 c.timeout = timeout;
3226 m_peer_change_queue.push_back(c);
3233 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3235 DSTACK(__FUNCTION_NAME);
3236 std::ostringstream os(std::ios_base::binary);
3238 writeU16(os, TOCLIENT_HP);
3242 std::string s = os.str();
3243 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3245 con.Send(peer_id, 0, data, true);
3248 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3249 const std::wstring &reason)
3251 DSTACK(__FUNCTION_NAME);
3252 std::ostringstream os(std::ios_base::binary);
3254 writeU16(os, TOCLIENT_ACCESS_DENIED);
3255 os<<serializeWideString(reason);
3258 std::string s = os.str();
3259 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3261 con.Send(peer_id, 0, data, true);
3264 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3265 bool set_camera_point_target, v3f camera_point_target)
3267 DSTACK(__FUNCTION_NAME);
3268 std::ostringstream os(std::ios_base::binary);
3270 writeU16(os, TOCLIENT_DEATHSCREEN);
3271 writeU8(os, set_camera_point_target);
3272 writeV3F1000(os, camera_point_target);
3275 std::string s = os.str();
3276 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3278 con.Send(peer_id, 0, data, true);
3281 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3282 IItemDefManager *itemdef)
3284 DSTACK(__FUNCTION_NAME);
3285 std::ostringstream os(std::ios_base::binary);
3289 u32 length of the next item
3290 zlib-compressed serialized ItemDefManager
3292 writeU16(os, TOCLIENT_ITEMDEF);
3293 std::ostringstream tmp_os(std::ios::binary);
3294 itemdef->serialize(tmp_os);
3295 std::ostringstream tmp_os2(std::ios::binary);
3296 compressZlib(tmp_os.str(), tmp_os2);
3297 os<<serializeLongString(tmp_os2.str());
3300 std::string s = os.str();
3301 infostream<<"Server::SendItemDef(): Sending item definitions: size="
3302 <<s.size()<<std::endl;
3303 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3305 con.Send(peer_id, 0, data, true);
3308 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3309 INodeDefManager *nodedef)
3311 DSTACK(__FUNCTION_NAME);
3312 std::ostringstream os(std::ios_base::binary);
3316 u32 length of the next item
3317 zlib-compressed serialized NodeDefManager
3319 writeU16(os, TOCLIENT_NODEDEF);
3320 std::ostringstream tmp_os(std::ios::binary);
3321 nodedef->serialize(tmp_os);
3322 std::ostringstream tmp_os2(std::ios::binary);
3323 compressZlib(tmp_os.str(), tmp_os2);
3324 os<<serializeLongString(tmp_os2.str());
3327 std::string s = os.str();
3328 infostream<<"Server::SendNodeDef(): Sending node definitions: size="
3329 <<s.size()<<std::endl;
3330 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3332 con.Send(peer_id, 0, data, true);
3336 Non-static send methods
3339 void Server::SendInventory(u16 peer_id)
3341 DSTACK(__FUNCTION_NAME);
3343 ServerRemotePlayer* player =
3344 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3347 player->m_inventory_not_sent = false;
3353 std::ostringstream os;
3354 //os.imbue(std::locale("C"));
3356 player->inventory.serialize(os);
3358 std::string s = os.str();
3360 SharedBuffer<u8> data(s.size()+2);
3361 writeU16(&data[0], TOCLIENT_INVENTORY);
3362 memcpy(&data[2], s.c_str(), s.size());
3365 m_con.Send(peer_id, 0, data, true);
3368 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3370 DSTACK(__FUNCTION_NAME);
3374 std::ostringstream os(std::ios_base::binary);
3376 writeU16(os, TOCLIENT_PLAYERITEM);
3378 writeU16(os, srp->peer_id);
3379 os<<serializeString(srp->getWieldedItem().getItemString());
3382 std::string s = os.str();
3383 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3385 m_con.SendToAll(0, data, true);
3388 void Server::SendPlayerItems()
3390 DSTACK(__FUNCTION_NAME);
3392 std::ostringstream os(std::ios_base::binary);
3393 core::list<Player *> players = m_env->getPlayers(true);
3395 writeU16(os, TOCLIENT_PLAYERITEM);
3396 writeU16(os, players.size());
3397 core::list<Player *>::Iterator i;
3398 for(i = players.begin(); i != players.end(); ++i)
3401 ServerRemotePlayer *srp =
3402 static_cast<ServerRemotePlayer*>(p);
3403 writeU16(os, p->peer_id);
3404 os<<serializeString(srp->getWieldedItem().getItemString());
3408 std::string s = os.str();
3409 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3411 m_con.SendToAll(0, data, true);
3414 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3416 DSTACK(__FUNCTION_NAME);
3418 std::ostringstream os(std::ios_base::binary);
3422 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3423 os.write((char*)buf, 2);
3426 writeU16(buf, message.size());
3427 os.write((char*)buf, 2);
3430 for(u32 i=0; i<message.size(); i++)
3434 os.write((char*)buf, 2);
3438 std::string s = os.str();
3439 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3441 m_con.Send(peer_id, 0, data, true);
3444 void Server::BroadcastChatMessage(const std::wstring &message)
3446 for(core::map<u16, RemoteClient*>::Iterator
3447 i = m_clients.getIterator();
3448 i.atEnd() == false; i++)
3450 // Get client and check that it is valid
3451 RemoteClient *client = i.getNode()->getValue();
3452 assert(client->peer_id == i.getNode()->getKey());
3453 if(client->serialization_version == SER_FMT_VER_INVALID)
3456 SendChatMessage(client->peer_id, message);
3460 void Server::SendPlayerHP(Player *player)
3462 SendHP(m_con, player->peer_id, player->hp);
3463 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3466 void Server::SendMovePlayer(Player *player)
3468 DSTACK(__FUNCTION_NAME);
3469 std::ostringstream os(std::ios_base::binary);
3471 writeU16(os, TOCLIENT_MOVE_PLAYER);
3472 writeV3F1000(os, player->getPosition());
3473 writeF1000(os, player->getPitch());
3474 writeF1000(os, player->getYaw());
3477 v3f pos = player->getPosition();
3478 f32 pitch = player->getPitch();
3479 f32 yaw = player->getYaw();
3480 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
3481 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3488 std::string s = os.str();
3489 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3491 m_con.Send(player->peer_id, 0, data, true);
3494 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3495 core::list<u16> *far_players, float far_d_nodes)
3497 float maxd = far_d_nodes*BS;
3498 v3f p_f = intToFloat(p, BS);
3502 SharedBuffer<u8> reply(replysize);
3503 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3504 writeS16(&reply[2], p.X);
3505 writeS16(&reply[4], p.Y);
3506 writeS16(&reply[6], p.Z);
3508 for(core::map<u16, RemoteClient*>::Iterator
3509 i = m_clients.getIterator();
3510 i.atEnd() == false; i++)
3512 // Get client and check that it is valid
3513 RemoteClient *client = i.getNode()->getValue();
3514 assert(client->peer_id == i.getNode()->getKey());
3515 if(client->serialization_version == SER_FMT_VER_INVALID)
3518 // Don't send if it's the same one
3519 if(client->peer_id == ignore_id)
3525 Player *player = m_env->getPlayer(client->peer_id);
3528 // If player is far away, only set modified blocks not sent
3529 v3f player_pos = player->getPosition();
3530 if(player_pos.getDistanceFrom(p_f) > maxd)
3532 far_players->push_back(client->peer_id);
3539 m_con.Send(client->peer_id, 0, reply, true);
3543 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3544 core::list<u16> *far_players, float far_d_nodes)
3546 float maxd = far_d_nodes*BS;
3547 v3f p_f = intToFloat(p, BS);
3549 for(core::map<u16, RemoteClient*>::Iterator
3550 i = m_clients.getIterator();
3551 i.atEnd() == false; i++)
3553 // Get client and check that it is valid
3554 RemoteClient *client = i.getNode()->getValue();
3555 assert(client->peer_id == i.getNode()->getKey());
3556 if(client->serialization_version == SER_FMT_VER_INVALID)
3559 // Don't send if it's the same one
3560 if(client->peer_id == ignore_id)
3566 Player *player = m_env->getPlayer(client->peer_id);
3569 // If player is far away, only set modified blocks not sent
3570 v3f player_pos = player->getPosition();
3571 if(player_pos.getDistanceFrom(p_f) > maxd)
3573 far_players->push_back(client->peer_id);
3580 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3581 SharedBuffer<u8> reply(replysize);
3582 writeU16(&reply[0], TOCLIENT_ADDNODE);
3583 writeS16(&reply[2], p.X);
3584 writeS16(&reply[4], p.Y);
3585 writeS16(&reply[6], p.Z);
3586 n.serialize(&reply[8], client->serialization_version);
3589 m_con.Send(client->peer_id, 0, reply, true);
3593 void Server::setBlockNotSent(v3s16 p)
3595 for(core::map<u16, RemoteClient*>::Iterator
3596 i = m_clients.getIterator();
3597 i.atEnd()==false; i++)
3599 RemoteClient *client = i.getNode()->getValue();
3600 client->SetBlockNotSent(p);
3604 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3606 DSTACK(__FUNCTION_NAME);
3608 v3s16 p = block->getPos();
3612 bool completely_air = true;
3613 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3614 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3615 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3617 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3619 completely_air = false;
3620 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3625 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3627 infostream<<"[completely air] ";
3628 infostream<<std::endl;
3632 Create a packet with the block in the right format
3635 std::ostringstream os(std::ios_base::binary);
3636 block->serialize(os, ver, false);
3637 std::string s = os.str();
3638 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3640 u32 replysize = 8 + blockdata.getSize();
3641 SharedBuffer<u8> reply(replysize);
3642 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3643 writeS16(&reply[2], p.X);
3644 writeS16(&reply[4], p.Y);
3645 writeS16(&reply[6], p.Z);
3646 memcpy(&reply[8], *blockdata, blockdata.getSize());
3648 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3649 <<": \tpacket size: "<<replysize<<std::endl;*/
3654 m_con.Send(peer_id, 1, reply, true);
3657 void Server::SendBlocks(float dtime)
3659 DSTACK(__FUNCTION_NAME);
3661 JMutexAutoLock envlock(m_env_mutex);
3662 JMutexAutoLock conlock(m_con_mutex);
3664 //TimeTaker timer("Server::SendBlocks");
3666 core::array<PrioritySortedBlockTransfer> queue;
3668 s32 total_sending = 0;
3671 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3673 for(core::map<u16, RemoteClient*>::Iterator
3674 i = m_clients.getIterator();
3675 i.atEnd() == false; i++)
3677 RemoteClient *client = i.getNode()->getValue();
3678 assert(client->peer_id == i.getNode()->getKey());
3680 // If definitions and textures have not been sent, don't
3681 // send MapBlocks either
3682 if(!client->definitions_sent)
3685 total_sending += client->SendingCount();
3687 if(client->serialization_version == SER_FMT_VER_INVALID)
3690 client->GetNextBlocks(this, dtime, queue);
3695 // Lowest priority number comes first.
3696 // Lowest is most important.
3699 for(u32 i=0; i<queue.size(); i++)
3701 //TODO: Calculate limit dynamically
3702 if(total_sending >= g_settings->getS32
3703 ("max_simultaneous_block_sends_server_total"))
3706 PrioritySortedBlockTransfer q = queue[i];
3708 MapBlock *block = NULL;
3711 block = m_env->getMap().getBlockNoCreate(q.pos);
3713 catch(InvalidPositionException &e)
3718 RemoteClient *client = getClient(q.peer_id);
3720 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3722 client->SentBlock(q.pos);
3728 void Server::PrepareTextures() {
3729 DSTACK(__FUNCTION_NAME);
3731 infostream<<"Server::PrepareTextures(): Calculate sha1 sums of textures"<<std::endl;
3733 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3734 i != m_mods.end(); i++){
3735 const ModSpec &mod = *i;
3736 std::string texturepath = mod.path + DIR_DELIM + "textures";
3737 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3738 for(u32 j=0; j<dirlist.size(); j++){
3739 if(dirlist[j].dir) // Ignode dirs
3741 std::string tname = dirlist[j].name;
3742 // if name contains illegal characters, ignore the texture
3743 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3744 errorstream<<"Server: ignoring illegal texture name: \""
3745 <<tname<<"\""<<std::endl;
3748 std::string tpath = texturepath + DIR_DELIM + tname;
3750 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3751 if(fis.good() == false){
3752 errorstream<<"Server::PrepareTextures(): Could not open \""
3753 <<tname<<"\" for reading"<<std::endl;
3756 std::ostringstream tmp_os(std::ios_base::binary);
3760 fis.read(buf, 1024);
3761 std::streamsize len = fis.gcount();
3762 tmp_os.write(buf, len);
3771 errorstream<<"Server::PrepareTextures(): Failed to read \""
3772 <<tname<<"\""<<std::endl;
3775 if(tmp_os.str().length() == 0){
3776 errorstream<<"Server::PrepareTextures(): Empty file \""
3777 <<tpath<<"\""<<std::endl;
3782 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3784 unsigned char *digest = sha1.getDigest();
3785 std::string digest_string = base64_encode(digest, 20);
3790 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3791 infostream<<"Server::PrepareTextures(): added sha1 for "<< tname <<std::endl;
3796 struct SendableTextureAnnouncement
3799 std::string sha1_digest;
3801 SendableTextureAnnouncement(const std::string name_="",
3802 const std::string sha1_digest_=""):
3804 sha1_digest(sha1_digest_)
3809 void Server::SendTextureAnnouncement(u16 peer_id){
3810 DSTACK(__FUNCTION_NAME);
3812 infostream<<"Server::SendTextureAnnouncement()"<<std::endl;
3814 core::list<SendableTextureAnnouncement> texture_announcements;
3816 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3819 texture_announcements.push_back(
3820 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3823 //send announcements
3827 u32 number of textures
3831 u16 length of digest string
3835 std::ostringstream os(std::ios_base::binary);
3837 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3838 writeU16(os, texture_announcements.size());
3840 for(core::list<SendableTextureAnnouncement>::Iterator
3841 j = texture_announcements.begin();
3842 j != texture_announcements.end(); j++){
3843 os<<serializeString(j->name);
3844 os<<serializeString(j->sha1_digest);
3848 std::string s = os.str();
3849 infostream<<"Server::SendTextureAnnouncement(): Send to client"<<std::endl;
3850 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3853 m_con.Send(peer_id, 0, data, true);
3857 struct SendableTexture
3863 SendableTexture(const std::string &name_="", const std::string path_="",
3864 const std::string &data_=""):
3871 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3872 DSTACK(__FUNCTION_NAME);
3874 infostream<<"Server::SendTexturesRequested(): Sending textures to client"<<std::endl;
3878 // Put 5kB in one bunch (this is not accurate)
3879 u32 bytes_per_bunch = 5000;
3881 core::array< core::list<SendableTexture> > texture_bunches;
3882 texture_bunches.push_back(core::list<SendableTexture>());
3884 u32 texture_size_bunch_total = 0;
3886 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3887 if(m_Textures.find(i->name) == m_Textures.end()){
3888 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3889 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3893 //TODO get path + name
3894 std::string tpath = m_Textures[(*i).name].path;
3897 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3898 if(fis.good() == false){
3899 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3900 <<tpath<<"\" for reading"<<std::endl;
3903 std::ostringstream tmp_os(std::ios_base::binary);
3907 fis.read(buf, 1024);
3908 std::streamsize len = fis.gcount();
3909 tmp_os.write(buf, len);
3910 texture_size_bunch_total += len;
3919 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
3920 <<(*i).name<<"\""<<std::endl;
3923 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
3924 <<tname<<"\""<<std::endl;*/
3926 texture_bunches[texture_bunches.size()-1].push_back(
3927 SendableTexture((*i).name, tpath, tmp_os.str()));
3929 // Start next bunch if got enough data
3930 if(texture_size_bunch_total >= bytes_per_bunch){
3931 texture_bunches.push_back(core::list<SendableTexture>());
3932 texture_size_bunch_total = 0;
3937 /* Create and send packets */
3939 u32 num_bunches = texture_bunches.size();
3940 for(u32 i=0; i<num_bunches; i++)
3944 u16 total number of texture bunches
3945 u16 index of this bunch
3946 u32 number of textures in this bunch
3954 std::ostringstream os(std::ios_base::binary);
3956 writeU16(os, TOCLIENT_TEXTURES);
3957 writeU16(os, num_bunches);
3959 writeU32(os, texture_bunches[i].size());
3961 for(core::list<SendableTexture>::Iterator
3962 j = texture_bunches[i].begin();
3963 j != texture_bunches[i].end(); j++){
3964 os<<serializeString(j->name);
3965 os<<serializeLongString(j->data);
3969 std::string s = os.str();
3970 infostream<<"Server::SendTexturesRequested(): bunch "<<i<<"/"<<num_bunches
3971 <<" textures="<<texture_bunches[i].size()
3972 <<" size=" <<s.size()<<std::endl;
3973 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3975 m_con.Send(peer_id, 0, data, true);
3985 void Server::DiePlayer(Player *player)
3987 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
3989 infostream<<"Server::DiePlayer(): Player "
3990 <<player->getName()<<" dies"<<std::endl;
3994 // Trigger scripted stuff
3995 scriptapi_on_dieplayer(m_lua, srp);
3997 // Handle players that are not connected
3998 if(player->peer_id == PEER_ID_INEXISTENT){
3999 RespawnPlayer(player);
4003 SendPlayerHP(player);
4004 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4007 void Server::RespawnPlayer(Player *player)
4009 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4011 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4013 v3f pos = findSpawnPos(m_env->getServerMap());
4014 player->setPosition(pos);
4015 srp->m_last_good_position = pos;
4016 srp->m_last_good_position_age = 0;
4018 SendMovePlayer(player);
4019 SendPlayerHP(player);
4022 void Server::UpdateCrafting(u16 peer_id)
4024 DSTACK(__FUNCTION_NAME);
4026 Player* player = m_env->getPlayer(peer_id);
4029 // Get a preview for crafting
4031 // No crafting in creative mode
4032 if(g_settings->getBool("creative_mode") == false)
4033 getCraftingResult(&player->inventory, preview, false, this);
4035 // Put the new preview in
4036 InventoryList *plist = player->inventory.getList("craftpreview");
4038 assert(plist->getSize() >= 1);
4039 plist->changeItem(0, preview);
4042 RemoteClient* Server::getClient(u16 peer_id)
4044 DSTACK(__FUNCTION_NAME);
4045 //JMutexAutoLock lock(m_con_mutex);
4046 core::map<u16, RemoteClient*>::Node *n;
4047 n = m_clients.find(peer_id);
4048 // A client should exist for all peers
4050 return n->getValue();
4053 std::wstring Server::getStatusString()
4055 std::wostringstream os(std::ios_base::binary);
4058 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4060 os<<L", uptime="<<m_uptime.get();
4061 // Information about clients
4063 for(core::map<u16, RemoteClient*>::Iterator
4064 i = m_clients.getIterator();
4065 i.atEnd() == false; i++)
4067 // Get client and check that it is valid
4068 RemoteClient *client = i.getNode()->getValue();
4069 assert(client->peer_id == i.getNode()->getKey());
4070 if(client->serialization_version == SER_FMT_VER_INVALID)
4073 Player *player = m_env->getPlayer(client->peer_id);
4074 // Get name of player
4075 std::wstring name = L"unknown";
4077 name = narrow_to_wide(player->getName());
4078 // Add name to information string
4082 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4083 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4084 if(g_settings->get("motd") != "")
4085 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4089 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4091 // Add player to auth manager
4092 if(m_authmanager.exists(name) == false)
4094 infostream<<"Server: adding player "<<name
4095 <<" to auth manager"<<std::endl;
4096 m_authmanager.add(name);
4097 m_authmanager.setPrivs(name,
4098 stringToPrivs(g_settings->get("default_privs")));
4100 // Change password and save
4101 m_authmanager.setPassword(name, translatePassword(name, password));
4102 m_authmanager.save();
4105 // Saves g_settings to configpath given at initialization
4106 void Server::saveConfig()
4108 if(m_configpath != "")
4109 g_settings->updateConfigFile(m_configpath.c_str());
4112 void Server::notifyPlayer(const char *name, const std::wstring msg)
4114 Player *player = m_env->getPlayer(name);
4117 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4120 void Server::notifyPlayers(const std::wstring msg)
4122 BroadcastChatMessage(msg);
4125 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4129 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4130 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4133 // IGameDef interface
4135 IItemDefManager* Server::getItemDefManager()
4139 INodeDefManager* Server::getNodeDefManager()
4143 ICraftDefManager* Server::getCraftDefManager()
4147 ITextureSource* Server::getTextureSource()
4151 u16 Server::allocateUnknownNodeId(const std::string &name)
4153 return m_nodedef->allocateDummy(name);
4156 IWritableItemDefManager* Server::getWritableItemDefManager()
4160 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4164 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4169 const ModSpec* Server::getModSpec(const std::string &modname)
4171 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4172 i != m_mods.end(); i++){
4173 const ModSpec &mod = *i;
4174 if(mod.name == modname)
4180 v3f findSpawnPos(ServerMap &map)
4182 //return v3f(50,50,50)*BS;
4187 nodepos = v2s16(0,0);
4192 // Try to find a good place a few times
4193 for(s32 i=0; i<1000; i++)
4196 // We're going to try to throw the player to this position
4197 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4198 -range + (myrand()%(range*2)));
4199 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4200 // Get ground height at point (fallbacks to heightmap function)
4201 s16 groundheight = map.findGroundLevel(nodepos2d);
4202 // Don't go underwater
4203 if(groundheight < WATER_LEVEL)
4205 //infostream<<"-> Underwater"<<std::endl;
4208 // Don't go to high places
4209 if(groundheight > WATER_LEVEL + 4)
4211 //infostream<<"-> Underwater"<<std::endl;
4215 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4216 bool is_good = false;
4218 for(s32 i=0; i<10; i++){
4219 v3s16 blockpos = getNodeBlockPos(nodepos);
4220 map.emergeBlock(blockpos, true);
4221 MapNode n = map.getNodeNoEx(nodepos);
4222 if(n.getContent() == CONTENT_AIR){
4233 // Found a good place
4234 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4240 return intToFloat(nodepos, BS);
4243 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4246 Try to get an existing player
4248 ServerRemotePlayer *player =
4249 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4252 // If player is already connected, cancel
4253 if(player->peer_id != 0)
4255 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4260 player->peer_id = peer_id;
4262 // Re-add player to environment
4263 if(player->m_removed)
4265 player->m_removed = false;
4267 m_env->addActiveObject(player);
4270 // Reset inventory to creative if in creative mode
4271 if(g_settings->getBool("creative_mode"))
4273 // Warning: double code below
4274 // Backup actual inventory
4275 player->inventory_backup = new Inventory(m_itemdef);
4276 *(player->inventory_backup) = player->inventory;
4277 // Set creative inventory
4278 player->resetInventory();
4279 scriptapi_get_creative_inventory(m_lua, player);
4286 If player with the wanted peer_id already exists, cancel.
4288 if(m_env->getPlayer(peer_id) != NULL)
4290 infostream<<"emergePlayer(): Player with wrong name but same"
4291 " peer_id already exists"<<std::endl;
4299 /* Set player position */
4301 infostream<<"Server: Finding spawn place for player \""
4302 <<name<<"\""<<std::endl;
4304 v3f pos = findSpawnPos(m_env->getServerMap());
4306 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4307 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4309 /* Add player to environment */
4310 m_env->addPlayer(player);
4311 m_env->addActiveObject(srp);
4314 scriptapi_on_newplayer(m_lua, srp);
4316 /* Add stuff to inventory */
4317 if(g_settings->getBool("creative_mode"))
4319 // Warning: double code above
4320 // Backup actual inventory
4321 player->inventory_backup = new Inventory(m_itemdef);
4322 *(player->inventory_backup) = player->inventory;
4323 // Set creative inventory
4324 player->resetInventory();
4325 scriptapi_get_creative_inventory(m_lua, player);
4330 } // create new player
4333 void Server::handlePeerChange(PeerChange &c)
4335 JMutexAutoLock envlock(m_env_mutex);
4336 JMutexAutoLock conlock(m_con_mutex);
4338 if(c.type == PEER_ADDED)
4345 core::map<u16, RemoteClient*>::Node *n;
4346 n = m_clients.find(c.peer_id);
4347 // The client shouldn't already exist
4351 RemoteClient *client = new RemoteClient();
4352 client->peer_id = c.peer_id;
4353 m_clients.insert(client->peer_id, client);
4356 else if(c.type == PEER_REMOVED)
4363 core::map<u16, RemoteClient*>::Node *n;
4364 n = m_clients.find(c.peer_id);
4365 // The client should exist
4369 Mark objects to be not known by the client
4371 RemoteClient *client = n->getValue();
4373 for(core::map<u16, bool>::Iterator
4374 i = client->m_known_objects.getIterator();
4375 i.atEnd()==false; i++)
4378 u16 id = i.getNode()->getKey();
4379 ServerActiveObject* obj = m_env->getActiveObject(id);
4381 if(obj && obj->m_known_by_count > 0)
4382 obj->m_known_by_count--;
4385 ServerRemotePlayer* player =
4386 static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
4388 // Collect information about leaving in chat
4389 std::wstring message;
4393 std::wstring name = narrow_to_wide(player->getName());
4396 message += L" left game";
4398 message += L" (timed out)";
4402 // Remove from environment
4404 player->m_removed = true;
4406 // Set player client disconnected
4408 player->peer_id = 0;
4416 std::ostringstream os(std::ios_base::binary);
4417 for(core::map<u16, RemoteClient*>::Iterator
4418 i = m_clients.getIterator();
4419 i.atEnd() == false; i++)
4421 RemoteClient *client = i.getNode()->getValue();
4422 assert(client->peer_id == i.getNode()->getKey());
4423 if(client->serialization_version == SER_FMT_VER_INVALID)
4426 Player *player = m_env->getPlayer(client->peer_id);
4429 // Get name of player
4430 os<<player->getName()<<" ";
4433 actionstream<<player->getName()<<" "
4434 <<(c.timeout?"times out.":"leaves game.")
4435 <<" List of players: "
4436 <<os.str()<<std::endl;
4441 delete m_clients[c.peer_id];
4442 m_clients.remove(c.peer_id);
4444 // Send player info to all remaining clients
4445 //SendPlayerInfos();
4447 // Send leave chat message to all remaining clients
4448 if(message.length() != 0)
4449 BroadcastChatMessage(message);
4458 void Server::handlePeerChanges()
4460 while(m_peer_change_queue.size() > 0)
4462 PeerChange c = m_peer_change_queue.pop_front();
4464 infostream<<"Server: Handling peer change: "
4465 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4468 handlePeerChange(c);
4472 u64 Server::getPlayerPrivs(Player *player)
4476 std::string playername = player->getName();
4477 // Local player gets all privileges regardless of
4478 // what's set on their account.
4479 if(g_settings->get("name") == playername)
4485 return getPlayerAuthPrivs(playername);
4489 void dedicated_server_loop(Server &server, bool &kill)
4491 DSTACK(__FUNCTION_NAME);
4493 infostream<<DTIME<<std::endl;
4494 infostream<<"========================"<<std::endl;
4495 infostream<<"Running dedicated server"<<std::endl;
4496 infostream<<"========================"<<std::endl;
4497 infostream<<std::endl;
4499 IntervalLimiter m_profiler_interval;
4503 // This is kind of a hack but can be done like this
4504 // because server.step() is very light
4506 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4511 if(server.getShutdownRequested() || kill)
4513 infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4520 float profiler_print_interval =
4521 g_settings->getFloat("profiler_print_interval");
4522 if(profiler_print_interval != 0)
4524 if(m_profiler_interval.step(0.030, profiler_print_interval))
4526 infostream<<"Profiler:"<<std::endl;
4527 g_profiler->print(infostream);
4528 g_profiler->clear();
4535 static int counter = 0;
4541 core::list<PlayerInfo> list = server.getPlayerInfo();
4542 core::list<PlayerInfo>::Iterator i;
4543 static u32 sum_old = 0;
4544 u32 sum = PIChecksum(list);
4547 infostream<<DTIME<<"Player info:"<<std::endl;
4548 for(i=list.begin(); i!=list.end(); i++)
4550 i->PrintLine(&infostream);