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 HandlePlayerHP(player, 0);
1276 Send player inventories and HPs if necessary
1278 if(player->m_inventory_not_sent){
1279 UpdateCrafting(player->peer_id);
1280 SendInventory(player->peer_id);
1282 if(player->m_hp_not_sent){
1283 SendPlayerHP(player);
1287 Add to environment if is not in respawn screen
1289 if(!player->m_is_in_environment && !player->m_respawn_active){
1290 player->m_removed = false;
1292 m_env->addActiveObject(player);
1297 /* Transform liquids */
1298 m_liquid_transform_timer += dtime;
1299 if(m_liquid_transform_timer >= 1.00)
1301 m_liquid_transform_timer -= 1.00;
1303 JMutexAutoLock lock(m_env_mutex);
1305 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1307 core::map<v3s16, MapBlock*> modified_blocks;
1308 m_env->getMap().transformLiquids(modified_blocks);
1313 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1314 ServerMap &map = ((ServerMap&)m_env->getMap());
1315 map.updateLighting(modified_blocks, lighting_modified_blocks);
1317 // Add blocks modified by lighting to modified_blocks
1318 for(core::map<v3s16, MapBlock*>::Iterator
1319 i = lighting_modified_blocks.getIterator();
1320 i.atEnd() == false; i++)
1322 MapBlock *block = i.getNode()->getValue();
1323 modified_blocks.insert(block->getPos(), block);
1327 Set the modified blocks unsent for all the clients
1330 JMutexAutoLock lock2(m_con_mutex);
1332 for(core::map<u16, RemoteClient*>::Iterator
1333 i = m_clients.getIterator();
1334 i.atEnd() == false; i++)
1336 RemoteClient *client = i.getNode()->getValue();
1338 if(modified_blocks.size() > 0)
1340 // Remove block from sent history
1341 client->SetBlocksNotSent(modified_blocks);
1346 // Periodically print some info
1348 float &counter = m_print_info_timer;
1354 JMutexAutoLock lock2(m_con_mutex);
1356 if(m_clients.size() != 0)
1357 infostream<<"Players:"<<std::endl;
1358 for(core::map<u16, RemoteClient*>::Iterator
1359 i = m_clients.getIterator();
1360 i.atEnd() == false; i++)
1362 //u16 peer_id = i.getNode()->getKey();
1363 RemoteClient *client = i.getNode()->getValue();
1364 Player *player = m_env->getPlayer(client->peer_id);
1367 infostream<<"* "<<player->getName()<<"\t";
1368 client->PrintInfo(infostream);
1373 //if(g_settings->getBool("enable_experimental"))
1377 Check added and deleted active objects
1380 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1381 JMutexAutoLock envlock(m_env_mutex);
1382 JMutexAutoLock conlock(m_con_mutex);
1384 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1386 // Radius inside which objects are active
1387 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1388 radius *= MAP_BLOCKSIZE;
1390 for(core::map<u16, RemoteClient*>::Iterator
1391 i = m_clients.getIterator();
1392 i.atEnd() == false; i++)
1394 RemoteClient *client = i.getNode()->getValue();
1396 // If definitions and textures have not been sent, don't
1397 // send objects either
1398 if(!client->definitions_sent)
1401 Player *player = m_env->getPlayer(client->peer_id);
1404 // This can happen if the client timeouts somehow
1405 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1407 <<" has no associated player"<<std::endl;*/
1410 v3s16 pos = floatToInt(player->getPosition(), BS);
1412 core::map<u16, bool> removed_objects;
1413 core::map<u16, bool> added_objects;
1414 m_env->getRemovedActiveObjects(pos, radius,
1415 client->m_known_objects, removed_objects);
1416 m_env->getAddedActiveObjects(pos, radius,
1417 client->m_known_objects, added_objects);
1419 // Ignore if nothing happened
1420 if(removed_objects.size() == 0 && added_objects.size() == 0)
1422 //infostream<<"active objects: none changed"<<std::endl;
1426 std::string data_buffer;
1430 // Handle removed objects
1431 writeU16((u8*)buf, removed_objects.size());
1432 data_buffer.append(buf, 2);
1433 for(core::map<u16, bool>::Iterator
1434 i = removed_objects.getIterator();
1435 i.atEnd()==false; i++)
1438 u16 id = i.getNode()->getKey();
1439 ServerActiveObject* obj = m_env->getActiveObject(id);
1441 // Add to data buffer for sending
1442 writeU16((u8*)buf, i.getNode()->getKey());
1443 data_buffer.append(buf, 2);
1445 // Remove from known objects
1446 client->m_known_objects.remove(i.getNode()->getKey());
1448 if(obj && obj->m_known_by_count > 0)
1449 obj->m_known_by_count--;
1452 // Handle added objects
1453 writeU16((u8*)buf, added_objects.size());
1454 data_buffer.append(buf, 2);
1455 for(core::map<u16, bool>::Iterator
1456 i = added_objects.getIterator();
1457 i.atEnd()==false; i++)
1460 u16 id = i.getNode()->getKey();
1461 ServerActiveObject* obj = m_env->getActiveObject(id);
1464 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1466 infostream<<"WARNING: "<<__FUNCTION_NAME
1467 <<": NULL object"<<std::endl;
1469 type = obj->getType();
1471 // Add to data buffer for sending
1472 writeU16((u8*)buf, id);
1473 data_buffer.append(buf, 2);
1474 writeU8((u8*)buf, type);
1475 data_buffer.append(buf, 1);
1478 data_buffer.append(serializeLongString(
1479 obj->getClientInitializationData()));
1481 data_buffer.append(serializeLongString(""));
1483 // Add to known objects
1484 client->m_known_objects.insert(i.getNode()->getKey(), false);
1487 obj->m_known_by_count++;
1491 SharedBuffer<u8> reply(2 + data_buffer.size());
1492 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1493 memcpy((char*)&reply[2], data_buffer.c_str(),
1494 data_buffer.size());
1496 m_con.Send(client->peer_id, 0, reply, true);
1498 infostream<<"Server: Sent object remove/add: "
1499 <<removed_objects.size()<<" removed, "
1500 <<added_objects.size()<<" added, "
1501 <<"packet size is "<<reply.getSize()<<std::endl;
1506 Collect a list of all the objects known by the clients
1507 and report it back to the environment.
1510 core::map<u16, bool> all_known_objects;
1512 for(core::map<u16, RemoteClient*>::Iterator
1513 i = m_clients.getIterator();
1514 i.atEnd() == false; i++)
1516 RemoteClient *client = i.getNode()->getValue();
1517 // Go through all known objects of client
1518 for(core::map<u16, bool>::Iterator
1519 i = client->m_known_objects.getIterator();
1520 i.atEnd()==false; i++)
1522 u16 id = i.getNode()->getKey();
1523 all_known_objects[id] = true;
1527 m_env->setKnownActiveObjects(whatever);
1533 Send object messages
1536 JMutexAutoLock envlock(m_env_mutex);
1537 JMutexAutoLock conlock(m_con_mutex);
1539 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1542 // Value = data sent by object
1543 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1545 // Get active object messages from environment
1548 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1552 core::list<ActiveObjectMessage>* message_list = NULL;
1553 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1554 n = buffered_messages.find(aom.id);
1557 message_list = new core::list<ActiveObjectMessage>;
1558 buffered_messages.insert(aom.id, message_list);
1562 message_list = n->getValue();
1564 message_list->push_back(aom);
1567 // Route data to every client
1568 for(core::map<u16, RemoteClient*>::Iterator
1569 i = m_clients.getIterator();
1570 i.atEnd()==false; i++)
1572 RemoteClient *client = i.getNode()->getValue();
1573 std::string reliable_data;
1574 std::string unreliable_data;
1575 // Go through all objects in message buffer
1576 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1577 j = buffered_messages.getIterator();
1578 j.atEnd()==false; j++)
1580 // If object is not known by client, skip it
1581 u16 id = j.getNode()->getKey();
1582 if(client->m_known_objects.find(id) == NULL)
1584 // Get message list of object
1585 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1586 // Go through every message
1587 for(core::list<ActiveObjectMessage>::Iterator
1588 k = list->begin(); k != list->end(); k++)
1590 // Compose the full new data with header
1591 ActiveObjectMessage aom = *k;
1592 std::string new_data;
1595 writeU16((u8*)&buf[0], aom.id);
1596 new_data.append(buf, 2);
1598 new_data += serializeString(aom.datastring);
1599 // Add data to buffer
1601 reliable_data += new_data;
1603 unreliable_data += new_data;
1607 reliable_data and unreliable_data are now ready.
1610 if(reliable_data.size() > 0)
1612 SharedBuffer<u8> reply(2 + reliable_data.size());
1613 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1614 memcpy((char*)&reply[2], reliable_data.c_str(),
1615 reliable_data.size());
1617 m_con.Send(client->peer_id, 0, reply, true);
1619 if(unreliable_data.size() > 0)
1621 SharedBuffer<u8> reply(2 + unreliable_data.size());
1622 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1623 memcpy((char*)&reply[2], unreliable_data.c_str(),
1624 unreliable_data.size());
1625 // Send as unreliable
1626 m_con.Send(client->peer_id, 0, reply, false);
1629 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1631 infostream<<"Server: Size of object message data: "
1632 <<"reliable: "<<reliable_data.size()
1633 <<", unreliable: "<<unreliable_data.size()
1638 // Clear buffered_messages
1639 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1640 i = buffered_messages.getIterator();
1641 i.atEnd()==false; i++)
1643 delete i.getNode()->getValue();
1647 } // enable_experimental
1650 Send queued-for-sending map edit events.
1653 // Don't send too many at a time
1656 // Single change sending is disabled if queue size is not small
1657 bool disable_single_change_sending = false;
1658 if(m_unsent_map_edit_queue.size() >= 4)
1659 disable_single_change_sending = true;
1661 bool got_any_events = false;
1663 // We'll log the amount of each
1666 while(m_unsent_map_edit_queue.size() != 0)
1668 got_any_events = true;
1670 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1672 // Players far away from the change are stored here.
1673 // Instead of sending the changes, MapBlocks are set not sent
1675 core::list<u16> far_players;
1677 if(event->type == MEET_ADDNODE)
1679 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1680 prof.add("MEET_ADDNODE", 1);
1681 if(disable_single_change_sending)
1682 sendAddNode(event->p, event->n, event->already_known_by_peer,
1685 sendAddNode(event->p, event->n, event->already_known_by_peer,
1688 else if(event->type == MEET_REMOVENODE)
1690 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1691 prof.add("MEET_REMOVENODE", 1);
1692 if(disable_single_change_sending)
1693 sendRemoveNode(event->p, event->already_known_by_peer,
1696 sendRemoveNode(event->p, event->already_known_by_peer,
1699 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1701 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1702 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1703 setBlockNotSent(event->p);
1705 else if(event->type == MEET_OTHER)
1707 infostream<<"Server: MEET_OTHER"<<std::endl;
1708 prof.add("MEET_OTHER", 1);
1709 for(core::map<v3s16, bool>::Iterator
1710 i = event->modified_blocks.getIterator();
1711 i.atEnd()==false; i++)
1713 v3s16 p = i.getNode()->getKey();
1719 prof.add("unknown", 1);
1720 infostream<<"WARNING: Server: Unknown MapEditEvent "
1721 <<((u32)event->type)<<std::endl;
1725 Set blocks not sent to far players
1727 if(far_players.size() > 0)
1729 // Convert list format to that wanted by SetBlocksNotSent
1730 core::map<v3s16, MapBlock*> modified_blocks2;
1731 for(core::map<v3s16, bool>::Iterator
1732 i = event->modified_blocks.getIterator();
1733 i.atEnd()==false; i++)
1735 v3s16 p = i.getNode()->getKey();
1736 modified_blocks2.insert(p,
1737 m_env->getMap().getBlockNoCreateNoEx(p));
1739 // Set blocks not sent
1740 for(core::list<u16>::Iterator
1741 i = far_players.begin();
1742 i != far_players.end(); i++)
1745 RemoteClient *client = getClient(peer_id);
1748 client->SetBlocksNotSent(modified_blocks2);
1754 /*// Don't send too many at a time
1756 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1762 infostream<<"Server: MapEditEvents:"<<std::endl;
1763 prof.print(infostream);
1769 Trigger emergethread (it somehow gets to a non-triggered but
1770 bysy state sometimes)
1773 float &counter = m_emergethread_trigger_timer;
1779 m_emergethread.trigger();
1783 // Save map, players and auth stuff
1785 float &counter = m_savemap_timer;
1787 if(counter >= g_settings->getFloat("server_map_save_interval"))
1791 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1794 if(m_authmanager.isModified())
1795 m_authmanager.save();
1798 if(m_banmanager.isModified())
1799 m_banmanager.save();
1802 JMutexAutoLock lock(m_env_mutex);
1804 // Save changed parts of map
1805 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1808 m_env->serializePlayers(m_mapsavedir);
1810 // Save environment metadata
1811 m_env->saveMeta(m_mapsavedir);
1816 void Server::Receive()
1818 DSTACK(__FUNCTION_NAME);
1819 SharedBuffer<u8> data;
1824 JMutexAutoLock conlock(m_con_mutex);
1825 datasize = m_con.Receive(peer_id, data);
1828 // This has to be called so that the client list gets synced
1829 // with the peer list of the connection
1830 handlePeerChanges();
1832 ProcessData(*data, datasize, peer_id);
1834 catch(con::InvalidIncomingDataException &e)
1836 infostream<<"Server::Receive(): "
1837 "InvalidIncomingDataException: what()="
1838 <<e.what()<<std::endl;
1840 catch(con::PeerNotFoundException &e)
1842 //NOTE: This is not needed anymore
1844 // The peer has been disconnected.
1845 // Find the associated player and remove it.
1847 /*JMutexAutoLock envlock(m_env_mutex);
1849 infostream<<"ServerThread: peer_id="<<peer_id
1850 <<" has apparently closed connection. "
1851 <<"Removing player."<<std::endl;
1853 m_env->removePlayer(peer_id);*/
1857 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1859 DSTACK(__FUNCTION_NAME);
1860 // Environment is locked first.
1861 JMutexAutoLock envlock(m_env_mutex);
1862 JMutexAutoLock conlock(m_con_mutex);
1865 Address address = m_con.GetPeerAddress(peer_id);
1867 // drop player if is ip is banned
1868 if(m_banmanager.isIpBanned(address.serializeString())){
1869 SendAccessDenied(m_con, peer_id,
1870 L"Your ip is banned. Banned name was "
1871 +narrow_to_wide(m_banmanager.getBanName(
1872 address.serializeString())));
1873 m_con.DeletePeer(peer_id);
1877 catch(con::PeerNotFoundException &e)
1879 infostream<<"Server::ProcessData(): Cancelling: peer "
1880 <<peer_id<<" not found"<<std::endl;
1884 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1892 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1894 if(command == TOSERVER_INIT)
1896 // [0] u16 TOSERVER_INIT
1897 // [2] u8 SER_FMT_VER_HIGHEST
1898 // [3] u8[20] player_name
1899 // [23] u8[28] password <--- can be sent without this, from old versions
1901 if(datasize < 2+1+PLAYERNAME_SIZE)
1904 infostream<<"Server: Got TOSERVER_INIT from "
1905 <<peer_id<<std::endl;
1907 // First byte after command is maximum supported
1908 // serialization version
1909 u8 client_max = data[2];
1910 u8 our_max = SER_FMT_VER_HIGHEST;
1911 // Use the highest version supported by both
1912 u8 deployed = core::min_(client_max, our_max);
1913 // If it's lower than the lowest supported, give up.
1914 if(deployed < SER_FMT_VER_LOWEST)
1915 deployed = SER_FMT_VER_INVALID;
1917 //peer->serialization_version = deployed;
1918 getClient(peer_id)->pending_serialization_version = deployed;
1920 if(deployed == SER_FMT_VER_INVALID)
1922 infostream<<"Server: Cannot negotiate "
1923 "serialization version with peer "
1924 <<peer_id<<std::endl;
1925 SendAccessDenied(m_con, peer_id, std::wstring(
1926 L"Your client's version is not supported.\n"
1927 L"Server version is ")
1928 + narrow_to_wide(VERSION_STRING) + L"."
1934 Read and check network protocol version
1937 u16 net_proto_version = 0;
1938 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1940 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1943 getClient(peer_id)->net_proto_version = net_proto_version;
1945 if(net_proto_version == 0)
1947 SendAccessDenied(m_con, peer_id, std::wstring(
1948 L"Your client's version is not supported.\n"
1949 L"Server version is ")
1950 + narrow_to_wide(VERSION_STRING) + L"."
1955 if(g_settings->getBool("strict_protocol_version_checking"))
1957 if(net_proto_version != PROTOCOL_VERSION)
1959 SendAccessDenied(m_con, peer_id, std::wstring(
1960 L"Your client's version is not supported.\n"
1961 L"Server version is ")
1962 + narrow_to_wide(VERSION_STRING) + L",\n"
1963 + L"server's PROTOCOL_VERSION is "
1964 + narrow_to_wide(itos(PROTOCOL_VERSION))
1965 + L", client's PROTOCOL_VERSION is "
1966 + narrow_to_wide(itos(net_proto_version))
1977 char playername[PLAYERNAME_SIZE];
1978 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1980 playername[i] = data[3+i];
1982 playername[PLAYERNAME_SIZE-1] = 0;
1984 if(playername[0]=='\0')
1986 infostream<<"Server: Player has empty name"<<std::endl;
1987 SendAccessDenied(m_con, peer_id,
1992 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1994 infostream<<"Server: Player has invalid name"<<std::endl;
1995 SendAccessDenied(m_con, peer_id,
1996 L"Name contains unallowed characters");
2001 char password[PASSWORD_SIZE];
2002 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2004 // old version - assume blank password
2009 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2011 password[i] = data[23+i];
2013 password[PASSWORD_SIZE-1] = 0;
2016 // Add player to auth manager
2017 if(m_authmanager.exists(playername) == false)
2019 std::wstring default_password =
2020 narrow_to_wide(g_settings->get("default_password"));
2021 std::string translated_default_password =
2022 translatePassword(playername, default_password);
2024 // If default_password is empty, allow any initial password
2025 if (default_password.length() == 0)
2026 translated_default_password = password;
2028 infostream<<"Server: adding player "<<playername
2029 <<" to auth manager"<<std::endl;
2030 m_authmanager.add(playername);
2031 m_authmanager.setPassword(playername, translated_default_password);
2032 m_authmanager.setPrivs(playername,
2033 stringToPrivs(g_settings->get("default_privs")));
2034 m_authmanager.save();
2037 std::string checkpwd = m_authmanager.getPassword(playername);
2039 /*infostream<<"Server: Client gave password '"<<password
2040 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2042 if(password != checkpwd)
2044 infostream<<"Server: peer_id="<<peer_id
2045 <<": supplied invalid password for "
2046 <<playername<<std::endl;
2047 SendAccessDenied(m_con, peer_id, L"Invalid password");
2051 // Enforce user limit.
2052 // Don't enforce for users that have some admin right
2053 if(m_clients.size() >= g_settings->getU16("max_users") &&
2054 (m_authmanager.getPrivs(playername)
2055 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
2056 playername != g_settings->get("name"))
2058 SendAccessDenied(m_con, peer_id, L"Too many users.");
2063 ServerRemotePlayer *player = emergePlayer(playername, peer_id);
2065 // If failed, cancel
2068 infostream<<"Server: peer_id="<<peer_id
2069 <<": failed to emerge player"<<std::endl;
2074 Answer with a TOCLIENT_INIT
2077 SharedBuffer<u8> reply(2+1+6+8);
2078 writeU16(&reply[0], TOCLIENT_INIT);
2079 writeU8(&reply[2], deployed);
2080 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2081 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2084 m_con.Send(peer_id, 0, reply, true);
2088 Send complete position information
2090 SendMovePlayer(player);
2095 if(command == TOSERVER_INIT2)
2097 infostream<<"Server: Got TOSERVER_INIT2 from "
2098 <<peer_id<<std::endl;
2101 getClient(peer_id)->serialization_version
2102 = getClient(peer_id)->pending_serialization_version;
2105 Send some initialization data
2108 // Send item definitions
2109 SendItemDef(m_con, peer_id, m_itemdef);
2111 // Send node definitions
2112 SendNodeDef(m_con, peer_id, m_nodedef);
2114 // Send texture announcement
2115 SendTextureAnnouncement(peer_id);
2117 // Send player info to all players
2118 //SendPlayerInfos();
2120 // Send inventory to player
2121 UpdateCrafting(peer_id);
2122 SendInventory(peer_id);
2124 // Send player items to all players
2127 Player *player = m_env->getPlayer(peer_id);
2130 SendPlayerHP(player);
2134 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2135 m_env->getTimeOfDay());
2136 m_con.Send(peer_id, 0, data, true);
2139 // Send information about server to player in chat
2140 SendChatMessage(peer_id, getStatusString());
2142 // Send information about joining in chat
2144 std::wstring name = L"unknown";
2145 Player *player = m_env->getPlayer(peer_id);
2147 name = narrow_to_wide(player->getName());
2149 std::wstring message;
2152 message += L" joined game";
2153 BroadcastChatMessage(message);
2156 // Warnings about protocol version can be issued here
2157 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2159 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2163 Check HP, respawn if necessary
2165 HandlePlayerHP(player, 0);
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 if(g_settings->getBool("enable_damage"))
2667 actionstream<<player->getName()<<" damaged by "
2668 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2671 HandlePlayerHP(player, damage);
2675 SendPlayerHP(player);
2678 else if(command == TOSERVER_PASSWORD)
2681 [0] u16 TOSERVER_PASSWORD
2682 [2] u8[28] old password
2683 [30] u8[28] new password
2686 if(datasize != 2+PASSWORD_SIZE*2)
2688 /*char password[PASSWORD_SIZE];
2689 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2690 password[i] = data[2+i];
2691 password[PASSWORD_SIZE-1] = 0;*/
2693 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2701 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2703 char c = data[2+PASSWORD_SIZE+i];
2709 infostream<<"Server: Client requests a password change from "
2710 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2712 std::string playername = player->getName();
2714 if(m_authmanager.exists(playername) == false)
2716 infostream<<"Server: playername not found in authmanager"<<std::endl;
2717 // Wrong old password supplied!!
2718 SendChatMessage(peer_id, L"playername not found in authmanager");
2722 std::string checkpwd = m_authmanager.getPassword(playername);
2724 if(oldpwd != checkpwd)
2726 infostream<<"Server: invalid old password"<<std::endl;
2727 // Wrong old password supplied!!
2728 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2732 actionstream<<player->getName()<<" changes password"<<std::endl;
2734 m_authmanager.setPassword(playername, newpwd);
2736 infostream<<"Server: password change successful for "<<playername
2738 SendChatMessage(peer_id, L"Password change successful");
2740 else if(command == TOSERVER_PLAYERITEM)
2745 u16 item = readU16(&data[2]);
2746 srp->setWieldIndex(item);
2747 SendWieldedItem(srp);
2749 else if(command == TOSERVER_RESPAWN)
2754 srp->m_respawn_active = false;
2756 RespawnPlayer(player);
2758 actionstream<<player->getName()<<" respawns at "
2759 <<PP(player->getPosition()/BS)<<std::endl;
2761 // ActiveObject is added to environment in AsyncRunStep after
2762 // the previous addition has been succesfully removed
2764 else if(command == TOSERVER_REQUEST_TEXTURES) {
2765 std::string datastring((char*)&data[2], datasize-2);
2766 std::istringstream is(datastring, std::ios_base::binary);
2768 infostream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl;
2770 core::list<TextureRequest> tosend;
2772 u16 numtextures = readU16(is);
2774 for(int i = 0; i < numtextures; i++) {
2776 std::string name = deSerializeString(is);
2778 tosend.push_back(TextureRequest(name));
2779 infostream<<"TOSERVER_REQUEST_TEXTURES: requested texture " << name <<std::endl;
2782 SendTexturesRequested(peer_id, tosend);
2784 // Now the client should know about everything
2785 // (definitions and textures)
2786 getClient(peer_id)->definitions_sent = true;
2788 else if(command == TOSERVER_INTERACT)
2790 std::string datastring((char*)&data[2], datasize-2);
2791 std::istringstream is(datastring, std::ios_base::binary);
2797 [5] u32 length of the next item
2798 [9] serialized PointedThing
2800 0: start digging (from undersurface) or use
2801 1: stop digging (all parameters ignored)
2802 2: digging completed
2803 3: place block or item (to abovesurface)
2806 u8 action = readU8(is);
2807 u16 item_i = readU16(is);
2808 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2809 PointedThing pointed;
2810 pointed.deSerialize(tmp_is);
2812 infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<<item_i<<", pointed="<<pointed.dump()<<std::endl;
2814 v3f player_pos = srp->m_last_good_position;
2816 // Update wielded item
2817 if(srp->getWieldIndex() != item_i)
2819 srp->setWieldIndex(item_i);
2820 SendWieldedItem(srp);
2823 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2824 v3s16 p_under = pointed.node_undersurface;
2825 v3s16 p_above = pointed.node_abovesurface;
2827 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2828 ServerActiveObject *pointed_object = NULL;
2829 if(pointed.type == POINTEDTHING_OBJECT)
2831 pointed_object = m_env->getActiveObject(pointed.object_id);
2832 if(pointed_object == NULL)
2834 infostream<<"TOSERVER_INTERACT: "
2835 "pointed object is NULL"<<std::endl;
2841 v3f pointed_pos_under = player_pos;
2842 v3f pointed_pos_above = player_pos;
2843 if(pointed.type == POINTEDTHING_NODE)
2845 pointed_pos_under = intToFloat(p_under, BS);
2846 pointed_pos_above = intToFloat(p_above, BS);
2848 else if(pointed.type == POINTEDTHING_OBJECT)
2850 pointed_pos_under = pointed_object->getBasePosition();
2851 pointed_pos_above = pointed_pos_under;
2855 Check that target is reasonably close
2856 (only when digging or placing things)
2858 if(action == 0 || action == 2 || action == 3)
2860 float d = player_pos.getDistanceFrom(pointed_pos_under);
2861 float max_d = BS * 10; // Just some large enough value
2863 actionstream<<"Player "<<player->getName()
2864 <<" tried to access "<<pointed.dump()
2866 <<"d="<<d<<", max_d="<<max_d
2867 <<". ignoring."<<std::endl;
2868 // Re-send block to revert change on client-side
2869 RemoteClient *client = getClient(peer_id);
2870 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2871 client->SetBlockNotSent(blockpos);
2878 Make sure the player is allowed to do it
2880 if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
2882 infostream<<"Ignoring interaction from player "<<player->getName()
2883 <<" because privileges are "<<getPlayerPrivs(player)
2889 0: start digging or punch object
2893 if(pointed.type == POINTEDTHING_NODE)
2896 NOTE: This can be used in the future to check if
2897 somebody is cheating, by checking the timing.
2899 MapNode n(CONTENT_IGNORE);
2902 n = m_env->getMap().getNode(p_under);
2904 catch(InvalidPositionException &e)
2906 infostream<<"Server: Not punching: Node not found."
2907 <<" Adding block to emerge queue."
2909 m_emerge_queue.addBlock(peer_id,
2910 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2912 if(n.getContent() != CONTENT_IGNORE)
2913 scriptapi_node_on_punch(m_lua, p_under, n, srp);
2915 else if(pointed.type == POINTEDTHING_OBJECT)
2917 // Skip if object has been removed
2918 if(pointed_object->m_removed)
2921 actionstream<<player->getName()<<" punches object "
2922 <<pointed.object_id<<std::endl;
2925 pointed_object->punch(srp, srp->m_time_from_last_punch);
2926 srp->m_time_from_last_punch = 0;
2934 else if(action == 1)
2939 2: Digging completed
2941 else if(action == 2)
2943 // Only complete digging of nodes
2944 if(pointed.type == POINTEDTHING_NODE)
2946 MapNode n(CONTENT_IGNORE);
2949 n = m_env->getMap().getNode(p_under);
2951 catch(InvalidPositionException &e)
2953 infostream<<"Server: Not finishing digging: Node not found."
2954 <<" Adding block to emerge queue."
2956 m_emerge_queue.addBlock(peer_id,
2957 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
2959 if(n.getContent() != CONTENT_IGNORE)
2960 scriptapi_node_on_dig(m_lua, p_under, n, srp);
2965 3: place block or right-click object
2967 else if(action == 3)
2969 ItemStack item = srp->getWieldedItem();
2971 // Reset build time counter
2972 if(pointed.type == POINTEDTHING_NODE &&
2973 item.getDefinition(m_itemdef).type == ITEM_NODE)
2974 getClient(peer_id)->m_time_from_building = 0.0;
2976 if(pointed.type == POINTEDTHING_OBJECT)
2978 // Right click object
2980 // Skip if object has been removed
2981 if(pointed_object->m_removed)
2984 actionstream<<player->getName()<<" right-clicks object "
2985 <<pointed.object_id<<std::endl;
2988 pointed_object->rightClick(srp);
2990 else if(scriptapi_item_on_place(m_lua,
2991 item, srp, pointed))
2993 // Placement was handled in lua
2995 // Apply returned ItemStack
2996 if(g_settings->getBool("creative_mode") == false)
2997 srp->setWieldedItem(item);
3005 else if(action == 4)
3007 ItemStack item = srp->getWieldedItem();
3009 actionstream<<player->getName()<<" uses "<<item.name
3010 <<", pointing at "<<pointed.dump()<<std::endl;
3012 if(scriptapi_item_on_use(m_lua,
3013 item, srp, pointed))
3015 // Apply returned ItemStack
3016 if(g_settings->getBool("creative_mode") == false)
3017 srp->setWieldedItem(item);
3023 Catch invalid actions
3027 infostream<<"WARNING: Server: Invalid action "
3028 <<action<<std::endl;
3033 infostream<<"Server::ProcessData(): Ignoring "
3034 "unknown command "<<command<<std::endl;
3038 catch(SendFailedException &e)
3040 errorstream<<"Server::ProcessData(): SendFailedException: "
3046 void Server::onMapEditEvent(MapEditEvent *event)
3048 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3049 if(m_ignore_map_edit_events)
3051 MapEditEvent *e = event->clone();
3052 m_unsent_map_edit_queue.push_back(e);
3055 Inventory* Server::getInventory(const InventoryLocation &loc)
3058 case InventoryLocation::UNDEFINED:
3061 case InventoryLocation::CURRENT_PLAYER:
3064 case InventoryLocation::PLAYER:
3066 Player *player = m_env->getPlayer(loc.name.c_str());
3069 return &player->inventory;
3072 case InventoryLocation::NODEMETA:
3074 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3077 return meta->getInventory();
3085 std::string Server::getInventoryOwner(const InventoryLocation &loc)
3088 case InventoryLocation::UNDEFINED:
3091 case InventoryLocation::CURRENT_PLAYER:
3094 case InventoryLocation::PLAYER:
3099 case InventoryLocation::NODEMETA:
3101 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3104 return meta->getOwner();
3112 void Server::setInventoryModified(const InventoryLocation &loc)
3115 case InventoryLocation::UNDEFINED:
3118 case InventoryLocation::PLAYER:
3120 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
3121 (m_env->getPlayer(loc.name.c_str()));
3124 srp->m_inventory_not_sent = true;
3127 case InventoryLocation::NODEMETA:
3129 v3s16 blockpos = getNodeBlockPos(loc.p);
3131 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3133 meta->inventoryModified();
3135 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3137 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3139 setBlockNotSent(blockpos);
3147 core::list<PlayerInfo> Server::getPlayerInfo()
3149 DSTACK(__FUNCTION_NAME);
3150 JMutexAutoLock envlock(m_env_mutex);
3151 JMutexAutoLock conlock(m_con_mutex);
3153 core::list<PlayerInfo> list;
3155 core::list<Player*> players = m_env->getPlayers();
3157 core::list<Player*>::Iterator i;
3158 for(i = players.begin();
3159 i != players.end(); i++)
3163 Player *player = *i;
3166 // Copy info from connection to info struct
3167 info.id = player->peer_id;
3168 info.address = m_con.GetPeerAddress(player->peer_id);
3169 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3171 catch(con::PeerNotFoundException &e)
3173 // Set dummy peer info
3175 info.address = Address(0,0,0,0,0);
3179 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3180 info.position = player->getPosition();
3182 list.push_back(info);
3189 void Server::peerAdded(con::Peer *peer)
3191 DSTACK(__FUNCTION_NAME);
3192 infostream<<"Server::peerAdded(): peer->id="
3193 <<peer->id<<std::endl;
3196 c.type = PEER_ADDED;
3197 c.peer_id = peer->id;
3199 m_peer_change_queue.push_back(c);
3202 void Server::deletingPeer(con::Peer *peer, bool timeout)
3204 DSTACK(__FUNCTION_NAME);
3205 infostream<<"Server::deletingPeer(): peer->id="
3206 <<peer->id<<", timeout="<<timeout<<std::endl;
3209 c.type = PEER_REMOVED;
3210 c.peer_id = peer->id;
3211 c.timeout = timeout;
3212 m_peer_change_queue.push_back(c);
3219 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3221 DSTACK(__FUNCTION_NAME);
3222 std::ostringstream os(std::ios_base::binary);
3224 writeU16(os, TOCLIENT_HP);
3228 std::string s = os.str();
3229 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3231 con.Send(peer_id, 0, data, true);
3234 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3235 const std::wstring &reason)
3237 DSTACK(__FUNCTION_NAME);
3238 std::ostringstream os(std::ios_base::binary);
3240 writeU16(os, TOCLIENT_ACCESS_DENIED);
3241 os<<serializeWideString(reason);
3244 std::string s = os.str();
3245 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3247 con.Send(peer_id, 0, data, true);
3250 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3251 bool set_camera_point_target, v3f camera_point_target)
3253 DSTACK(__FUNCTION_NAME);
3254 std::ostringstream os(std::ios_base::binary);
3256 writeU16(os, TOCLIENT_DEATHSCREEN);
3257 writeU8(os, set_camera_point_target);
3258 writeV3F1000(os, camera_point_target);
3261 std::string s = os.str();
3262 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3264 con.Send(peer_id, 0, data, true);
3267 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3268 IItemDefManager *itemdef)
3270 DSTACK(__FUNCTION_NAME);
3271 std::ostringstream os(std::ios_base::binary);
3275 u32 length of the next item
3276 zlib-compressed serialized ItemDefManager
3278 writeU16(os, TOCLIENT_ITEMDEF);
3279 std::ostringstream tmp_os(std::ios::binary);
3280 itemdef->serialize(tmp_os);
3281 std::ostringstream tmp_os2(std::ios::binary);
3282 compressZlib(tmp_os.str(), tmp_os2);
3283 os<<serializeLongString(tmp_os2.str());
3286 std::string s = os.str();
3287 infostream<<"Server::SendItemDef(): Sending item definitions: size="
3288 <<s.size()<<std::endl;
3289 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3291 con.Send(peer_id, 0, data, true);
3294 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3295 INodeDefManager *nodedef)
3297 DSTACK(__FUNCTION_NAME);
3298 std::ostringstream os(std::ios_base::binary);
3302 u32 length of the next item
3303 zlib-compressed serialized NodeDefManager
3305 writeU16(os, TOCLIENT_NODEDEF);
3306 std::ostringstream tmp_os(std::ios::binary);
3307 nodedef->serialize(tmp_os);
3308 std::ostringstream tmp_os2(std::ios::binary);
3309 compressZlib(tmp_os.str(), tmp_os2);
3310 os<<serializeLongString(tmp_os2.str());
3313 std::string s = os.str();
3314 infostream<<"Server::SendNodeDef(): Sending node definitions: size="
3315 <<s.size()<<std::endl;
3316 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3318 con.Send(peer_id, 0, data, true);
3322 Non-static send methods
3325 void Server::SendInventory(u16 peer_id)
3327 DSTACK(__FUNCTION_NAME);
3329 ServerRemotePlayer* player =
3330 static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
3333 player->m_inventory_not_sent = false;
3339 std::ostringstream os;
3340 //os.imbue(std::locale("C"));
3342 player->inventory.serialize(os);
3344 std::string s = os.str();
3346 SharedBuffer<u8> data(s.size()+2);
3347 writeU16(&data[0], TOCLIENT_INVENTORY);
3348 memcpy(&data[2], s.c_str(), s.size());
3351 m_con.Send(peer_id, 0, data, true);
3354 void Server::SendWieldedItem(const ServerRemotePlayer* srp)
3356 DSTACK(__FUNCTION_NAME);
3360 std::ostringstream os(std::ios_base::binary);
3362 writeU16(os, TOCLIENT_PLAYERITEM);
3364 writeU16(os, srp->peer_id);
3365 os<<serializeString(srp->getWieldedItem().getItemString());
3368 std::string s = os.str();
3369 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3371 m_con.SendToAll(0, data, true);
3374 void Server::SendPlayerItems()
3376 DSTACK(__FUNCTION_NAME);
3378 std::ostringstream os(std::ios_base::binary);
3379 core::list<Player *> players = m_env->getPlayers(true);
3381 writeU16(os, TOCLIENT_PLAYERITEM);
3382 writeU16(os, players.size());
3383 core::list<Player *>::Iterator i;
3384 for(i = players.begin(); i != players.end(); ++i)
3387 ServerRemotePlayer *srp =
3388 static_cast<ServerRemotePlayer*>(p);
3389 writeU16(os, p->peer_id);
3390 os<<serializeString(srp->getWieldedItem().getItemString());
3394 std::string s = os.str();
3395 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3397 m_con.SendToAll(0, data, true);
3400 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3402 DSTACK(__FUNCTION_NAME);
3404 std::ostringstream os(std::ios_base::binary);
3408 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3409 os.write((char*)buf, 2);
3412 writeU16(buf, message.size());
3413 os.write((char*)buf, 2);
3416 for(u32 i=0; i<message.size(); i++)
3420 os.write((char*)buf, 2);
3424 std::string s = os.str();
3425 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3427 m_con.Send(peer_id, 0, data, true);
3430 void Server::BroadcastChatMessage(const std::wstring &message)
3432 for(core::map<u16, RemoteClient*>::Iterator
3433 i = m_clients.getIterator();
3434 i.atEnd() == false; i++)
3436 // Get client and check that it is valid
3437 RemoteClient *client = i.getNode()->getValue();
3438 assert(client->peer_id == i.getNode()->getKey());
3439 if(client->serialization_version == SER_FMT_VER_INVALID)
3442 SendChatMessage(client->peer_id, message);
3446 void Server::SendPlayerHP(Player *player)
3448 SendHP(m_con, player->peer_id, player->hp);
3449 static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
3452 void Server::SendMovePlayer(Player *player)
3454 DSTACK(__FUNCTION_NAME);
3455 std::ostringstream os(std::ios_base::binary);
3457 writeU16(os, TOCLIENT_MOVE_PLAYER);
3458 writeV3F1000(os, player->getPosition());
3459 writeF1000(os, player->getPitch());
3460 writeF1000(os, player->getYaw());
3463 v3f pos = player->getPosition();
3464 f32 pitch = player->getPitch();
3465 f32 yaw = player->getYaw();
3466 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
3467 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3474 std::string s = os.str();
3475 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3477 m_con.Send(player->peer_id, 0, data, true);
3480 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3481 core::list<u16> *far_players, float far_d_nodes)
3483 float maxd = far_d_nodes*BS;
3484 v3f p_f = intToFloat(p, BS);
3488 SharedBuffer<u8> reply(replysize);
3489 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3490 writeS16(&reply[2], p.X);
3491 writeS16(&reply[4], p.Y);
3492 writeS16(&reply[6], p.Z);
3494 for(core::map<u16, RemoteClient*>::Iterator
3495 i = m_clients.getIterator();
3496 i.atEnd() == false; i++)
3498 // Get client and check that it is valid
3499 RemoteClient *client = i.getNode()->getValue();
3500 assert(client->peer_id == i.getNode()->getKey());
3501 if(client->serialization_version == SER_FMT_VER_INVALID)
3504 // Don't send if it's the same one
3505 if(client->peer_id == ignore_id)
3511 Player *player = m_env->getPlayer(client->peer_id);
3514 // If player is far away, only set modified blocks not sent
3515 v3f player_pos = player->getPosition();
3516 if(player_pos.getDistanceFrom(p_f) > maxd)
3518 far_players->push_back(client->peer_id);
3525 m_con.Send(client->peer_id, 0, reply, true);
3529 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3530 core::list<u16> *far_players, float far_d_nodes)
3532 float maxd = far_d_nodes*BS;
3533 v3f p_f = intToFloat(p, BS);
3535 for(core::map<u16, RemoteClient*>::Iterator
3536 i = m_clients.getIterator();
3537 i.atEnd() == false; i++)
3539 // Get client and check that it is valid
3540 RemoteClient *client = i.getNode()->getValue();
3541 assert(client->peer_id == i.getNode()->getKey());
3542 if(client->serialization_version == SER_FMT_VER_INVALID)
3545 // Don't send if it's the same one
3546 if(client->peer_id == ignore_id)
3552 Player *player = m_env->getPlayer(client->peer_id);
3555 // If player is far away, only set modified blocks not sent
3556 v3f player_pos = player->getPosition();
3557 if(player_pos.getDistanceFrom(p_f) > maxd)
3559 far_players->push_back(client->peer_id);
3566 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3567 SharedBuffer<u8> reply(replysize);
3568 writeU16(&reply[0], TOCLIENT_ADDNODE);
3569 writeS16(&reply[2], p.X);
3570 writeS16(&reply[4], p.Y);
3571 writeS16(&reply[6], p.Z);
3572 n.serialize(&reply[8], client->serialization_version);
3575 m_con.Send(client->peer_id, 0, reply, true);
3579 void Server::setBlockNotSent(v3s16 p)
3581 for(core::map<u16, RemoteClient*>::Iterator
3582 i = m_clients.getIterator();
3583 i.atEnd()==false; i++)
3585 RemoteClient *client = i.getNode()->getValue();
3586 client->SetBlockNotSent(p);
3590 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3592 DSTACK(__FUNCTION_NAME);
3594 v3s16 p = block->getPos();
3598 bool completely_air = true;
3599 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3600 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3601 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3603 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3605 completely_air = false;
3606 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3611 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3613 infostream<<"[completely air] ";
3614 infostream<<std::endl;
3618 Create a packet with the block in the right format
3621 std::ostringstream os(std::ios_base::binary);
3622 block->serialize(os, ver, false);
3623 std::string s = os.str();
3624 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3626 u32 replysize = 8 + blockdata.getSize();
3627 SharedBuffer<u8> reply(replysize);
3628 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3629 writeS16(&reply[2], p.X);
3630 writeS16(&reply[4], p.Y);
3631 writeS16(&reply[6], p.Z);
3632 memcpy(&reply[8], *blockdata, blockdata.getSize());
3634 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3635 <<": \tpacket size: "<<replysize<<std::endl;*/
3640 m_con.Send(peer_id, 1, reply, true);
3643 void Server::SendBlocks(float dtime)
3645 DSTACK(__FUNCTION_NAME);
3647 JMutexAutoLock envlock(m_env_mutex);
3648 JMutexAutoLock conlock(m_con_mutex);
3650 //TimeTaker timer("Server::SendBlocks");
3652 core::array<PrioritySortedBlockTransfer> queue;
3654 s32 total_sending = 0;
3657 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3659 for(core::map<u16, RemoteClient*>::Iterator
3660 i = m_clients.getIterator();
3661 i.atEnd() == false; i++)
3663 RemoteClient *client = i.getNode()->getValue();
3664 assert(client->peer_id == i.getNode()->getKey());
3666 // If definitions and textures have not been sent, don't
3667 // send MapBlocks either
3668 if(!client->definitions_sent)
3671 total_sending += client->SendingCount();
3673 if(client->serialization_version == SER_FMT_VER_INVALID)
3676 client->GetNextBlocks(this, dtime, queue);
3681 // Lowest priority number comes first.
3682 // Lowest is most important.
3685 for(u32 i=0; i<queue.size(); i++)
3687 //TODO: Calculate limit dynamically
3688 if(total_sending >= g_settings->getS32
3689 ("max_simultaneous_block_sends_server_total"))
3692 PrioritySortedBlockTransfer q = queue[i];
3694 MapBlock *block = NULL;
3697 block = m_env->getMap().getBlockNoCreate(q.pos);
3699 catch(InvalidPositionException &e)
3704 RemoteClient *client = getClient(q.peer_id);
3706 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3708 client->SentBlock(q.pos);
3714 void Server::PrepareTextures() {
3715 DSTACK(__FUNCTION_NAME);
3717 infostream<<"Server::PrepareTextures(): Calculate sha1 sums of textures"<<std::endl;
3719 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3720 i != m_mods.end(); i++){
3721 const ModSpec &mod = *i;
3722 std::string texturepath = mod.path + DIR_DELIM + "textures";
3723 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
3724 for(u32 j=0; j<dirlist.size(); j++){
3725 if(dirlist[j].dir) // Ignode dirs
3727 std::string tname = dirlist[j].name;
3728 // if name contains illegal characters, ignore the texture
3729 if(!string_allowed(tname, TEXTURENAME_ALLOWED_CHARS)){
3730 errorstream<<"Server: ignoring illegal texture name: \""
3731 <<tname<<"\""<<std::endl;
3734 std::string tpath = texturepath + DIR_DELIM + tname;
3736 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3737 if(fis.good() == false){
3738 errorstream<<"Server::PrepareTextures(): Could not open \""
3739 <<tname<<"\" for reading"<<std::endl;
3742 std::ostringstream tmp_os(std::ios_base::binary);
3746 fis.read(buf, 1024);
3747 std::streamsize len = fis.gcount();
3748 tmp_os.write(buf, len);
3757 errorstream<<"Server::PrepareTextures(): Failed to read \""
3758 <<tname<<"\""<<std::endl;
3761 if(tmp_os.str().length() == 0){
3762 errorstream<<"Server::PrepareTextures(): Empty file \""
3763 <<tpath<<"\""<<std::endl;
3768 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3770 unsigned char *digest = sha1.getDigest();
3771 std::string digest_string = base64_encode(digest, 20);
3776 this->m_Textures[tname] = TextureInformation(tpath,digest_string);
3777 infostream<<"Server::PrepareTextures(): added sha1 for "<< tname <<std::endl;
3782 struct SendableTextureAnnouncement
3785 std::string sha1_digest;
3787 SendableTextureAnnouncement(const std::string name_="",
3788 const std::string sha1_digest_=""):
3790 sha1_digest(sha1_digest_)
3795 void Server::SendTextureAnnouncement(u16 peer_id){
3796 DSTACK(__FUNCTION_NAME);
3798 infostream<<"Server::SendTextureAnnouncement()"<<std::endl;
3800 core::list<SendableTextureAnnouncement> texture_announcements;
3802 for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) {
3805 texture_announcements.push_back(
3806 SendableTextureAnnouncement(i->first, i->second.sha1_digest));
3809 //send announcements
3813 u32 number of textures
3817 u16 length of digest string
3821 std::ostringstream os(std::ios_base::binary);
3823 writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES);
3824 writeU16(os, texture_announcements.size());
3826 for(core::list<SendableTextureAnnouncement>::Iterator
3827 j = texture_announcements.begin();
3828 j != texture_announcements.end(); j++){
3829 os<<serializeString(j->name);
3830 os<<serializeString(j->sha1_digest);
3834 std::string s = os.str();
3835 infostream<<"Server::SendTextureAnnouncement(): Send to client"<<std::endl;
3836 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3839 m_con.Send(peer_id, 0, data, true);
3843 struct SendableTexture
3849 SendableTexture(const std::string &name_="", const std::string path_="",
3850 const std::string &data_=""):
3857 void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) {
3858 DSTACK(__FUNCTION_NAME);
3860 infostream<<"Server::SendTexturesRequested(): Sending textures to client"<<std::endl;
3864 // Put 5kB in one bunch (this is not accurate)
3865 u32 bytes_per_bunch = 5000;
3867 core::array< core::list<SendableTexture> > texture_bunches;
3868 texture_bunches.push_back(core::list<SendableTexture>());
3870 u32 texture_size_bunch_total = 0;
3872 for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) {
3873 if(m_Textures.find(i->name) == m_Textures.end()){
3874 errorstream<<"Server::SendTexturesRequested(): Client asked for "
3875 <<"unknown texture \""<<(i->name)<<"\""<<std::endl;
3879 //TODO get path + name
3880 std::string tpath = m_Textures[(*i).name].path;
3883 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3884 if(fis.good() == false){
3885 errorstream<<"Server::SendTexturesRequested(): Could not open \""
3886 <<tpath<<"\" for reading"<<std::endl;
3889 std::ostringstream tmp_os(std::ios_base::binary);
3893 fis.read(buf, 1024);
3894 std::streamsize len = fis.gcount();
3895 tmp_os.write(buf, len);
3896 texture_size_bunch_total += len;
3905 errorstream<<"Server::SendTexturesRequested(): Failed to read \""
3906 <<(*i).name<<"\""<<std::endl;
3909 /*infostream<<"Server::SendTexturesRequested(): Loaded \""
3910 <<tname<<"\""<<std::endl;*/
3912 texture_bunches[texture_bunches.size()-1].push_back(
3913 SendableTexture((*i).name, tpath, tmp_os.str()));
3915 // Start next bunch if got enough data
3916 if(texture_size_bunch_total >= bytes_per_bunch){
3917 texture_bunches.push_back(core::list<SendableTexture>());
3918 texture_size_bunch_total = 0;
3923 /* Create and send packets */
3925 u32 num_bunches = texture_bunches.size();
3926 for(u32 i=0; i<num_bunches; i++)
3930 u16 total number of texture bunches
3931 u16 index of this bunch
3932 u32 number of textures in this bunch
3940 std::ostringstream os(std::ios_base::binary);
3942 writeU16(os, TOCLIENT_TEXTURES);
3943 writeU16(os, num_bunches);
3945 writeU32(os, texture_bunches[i].size());
3947 for(core::list<SendableTexture>::Iterator
3948 j = texture_bunches[i].begin();
3949 j != texture_bunches[i].end(); j++){
3950 os<<serializeString(j->name);
3951 os<<serializeLongString(j->data);
3955 std::string s = os.str();
3956 infostream<<"Server::SendTexturesRequested(): bunch "<<i<<"/"<<num_bunches
3957 <<" textures="<<texture_bunches[i].size()
3958 <<" size=" <<s.size()<<std::endl;
3959 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3961 m_con.Send(peer_id, 0, data, true);
3971 void Server::HandlePlayerHP(Player *player, s16 damage)
3973 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
3975 if(srp->m_respawn_active)
3978 if(player->hp > damage)
3981 player->hp -= damage;
3982 SendPlayerHP(player);
3987 infostream<<"Server::HandlePlayerHP(): Player "
3988 <<player->getName()<<" dies"<<std::endl;
3992 // Trigger scripted stuff
3993 scriptapi_on_dieplayer(m_lua, srp);
3995 // Handle players that are not connected
3996 if(player->peer_id == PEER_ID_INEXISTENT){
3997 RespawnPlayer(player);
4001 SendPlayerHP(player);
4003 RemoteClient *client = getClient(player->peer_id);
4004 if(client->net_proto_version >= 3)
4006 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4007 srp->m_removed = true;
4008 srp->m_respawn_active = true;
4012 RespawnPlayer(player);
4016 void Server::RespawnPlayer(Player *player)
4019 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4020 bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4022 v3f pos = findSpawnPos(m_env->getServerMap());
4023 player->setPosition(pos);
4024 srp->m_last_good_position = pos;
4025 srp->m_last_good_position_age = 0;
4027 SendMovePlayer(player);
4028 SendPlayerHP(player);
4031 void Server::UpdateCrafting(u16 peer_id)
4033 DSTACK(__FUNCTION_NAME);
4035 Player* player = m_env->getPlayer(peer_id);
4038 // Get a preview for crafting
4040 // No crafting in creative mode
4041 if(g_settings->getBool("creative_mode") == false)
4042 getCraftingResult(&player->inventory, preview, false, this);
4044 // Put the new preview in
4045 InventoryList *plist = player->inventory.getList("craftpreview");
4047 assert(plist->getSize() >= 1);
4048 plist->changeItem(0, preview);
4051 RemoteClient* Server::getClient(u16 peer_id)
4053 DSTACK(__FUNCTION_NAME);
4054 //JMutexAutoLock lock(m_con_mutex);
4055 core::map<u16, RemoteClient*>::Node *n;
4056 n = m_clients.find(peer_id);
4057 // A client should exist for all peers
4059 return n->getValue();
4062 std::wstring Server::getStatusString()
4064 std::wostringstream os(std::ios_base::binary);
4067 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4069 os<<L", uptime="<<m_uptime.get();
4070 // Information about clients
4072 for(core::map<u16, RemoteClient*>::Iterator
4073 i = m_clients.getIterator();
4074 i.atEnd() == false; i++)
4076 // Get client and check that it is valid
4077 RemoteClient *client = i.getNode()->getValue();
4078 assert(client->peer_id == i.getNode()->getKey());
4079 if(client->serialization_version == SER_FMT_VER_INVALID)
4082 Player *player = m_env->getPlayer(client->peer_id);
4083 // Get name of player
4084 std::wstring name = L"unknown";
4086 name = narrow_to_wide(player->getName());
4087 // Add name to information string
4091 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4092 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4093 if(g_settings->get("motd") != "")
4094 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4098 void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
4100 // Add player to auth manager
4101 if(m_authmanager.exists(name) == false)
4103 infostream<<"Server: adding player "<<name
4104 <<" to auth manager"<<std::endl;
4105 m_authmanager.add(name);
4106 m_authmanager.setPrivs(name,
4107 stringToPrivs(g_settings->get("default_privs")));
4109 // Change password and save
4110 m_authmanager.setPassword(name, translatePassword(name, password));
4111 m_authmanager.save();
4114 // Saves g_settings to configpath given at initialization
4115 void Server::saveConfig()
4117 if(m_configpath != "")
4118 g_settings->updateConfigFile(m_configpath.c_str());
4121 void Server::notifyPlayer(const char *name, const std::wstring msg)
4123 Player *player = m_env->getPlayer(name);
4126 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4129 void Server::notifyPlayers(const std::wstring msg)
4131 BroadcastChatMessage(msg);
4134 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4138 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4139 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4142 // IGameDef interface
4144 IItemDefManager* Server::getItemDefManager()
4148 INodeDefManager* Server::getNodeDefManager()
4152 ICraftDefManager* Server::getCraftDefManager()
4156 ITextureSource* Server::getTextureSource()
4160 u16 Server::allocateUnknownNodeId(const std::string &name)
4162 return m_nodedef->allocateDummy(name);
4165 IWritableItemDefManager* Server::getWritableItemDefManager()
4169 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4173 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4178 const ModSpec* Server::getModSpec(const std::string &modname)
4180 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4181 i != m_mods.end(); i++){
4182 const ModSpec &mod = *i;
4183 if(mod.name == modname)
4189 v3f findSpawnPos(ServerMap &map)
4191 //return v3f(50,50,50)*BS;
4196 nodepos = v2s16(0,0);
4201 // Try to find a good place a few times
4202 for(s32 i=0; i<1000; i++)
4205 // We're going to try to throw the player to this position
4206 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4207 -range + (myrand()%(range*2)));
4208 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4209 // Get ground height at point (fallbacks to heightmap function)
4210 s16 groundheight = map.findGroundLevel(nodepos2d);
4211 // Don't go underwater
4212 if(groundheight < WATER_LEVEL)
4214 //infostream<<"-> Underwater"<<std::endl;
4217 // Don't go to high places
4218 if(groundheight > WATER_LEVEL + 4)
4220 //infostream<<"-> Underwater"<<std::endl;
4224 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4225 bool is_good = false;
4227 for(s32 i=0; i<10; i++){
4228 v3s16 blockpos = getNodeBlockPos(nodepos);
4229 map.emergeBlock(blockpos, true);
4230 MapNode n = map.getNodeNoEx(nodepos);
4231 if(n.getContent() == CONTENT_AIR){
4242 // Found a good place
4243 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4249 return intToFloat(nodepos, BS);
4252 ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
4255 Try to get an existing player
4257 ServerRemotePlayer *player =
4258 static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
4261 // If player is already connected, cancel
4262 if(player->peer_id != 0)
4264 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4269 player->peer_id = peer_id;
4271 // Reset inventory to creative if in creative mode
4272 if(g_settings->getBool("creative_mode"))
4274 // Warning: double code below
4275 // Backup actual inventory
4276 player->inventory_backup = new Inventory(m_itemdef);
4277 *(player->inventory_backup) = player->inventory;
4278 // Set creative inventory
4279 player->resetInventory();
4280 scriptapi_get_creative_inventory(m_lua, player);
4287 If player with the wanted peer_id already exists, cancel.
4289 if(m_env->getPlayer(peer_id) != NULL)
4291 infostream<<"emergePlayer(): Player with wrong name but same"
4292 " peer_id already exists"<<std::endl;
4300 /* Set player position */
4302 infostream<<"Server: Finding spawn place for player \""
4303 <<name<<"\""<<std::endl;
4305 v3f pos = findSpawnPos(m_env->getServerMap());
4307 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4309 /* Add player to environment */
4310 m_env->addPlayer(player);
4313 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
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);