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.
23 #include "clientserver.h"
25 #include "jmutexautolock.h"
27 #include "constants.h"
29 #include "materials.h"
32 #include "servercommand.h"
34 #include "content_mapnode.h"
35 #include "content_craft.h"
36 #include "content_nodemeta.h"
38 #include "serverobject.h"
43 #include "scriptapi.h"
47 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
49 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
51 class MapEditEventIgnorer
54 MapEditEventIgnorer(bool *flag):
63 ~MapEditEventIgnorer()
76 void * ServerThread::Thread()
80 log_register_thread("ServerThread");
82 DSTACK(__FUNCTION_NAME);
84 BEGIN_DEBUG_EXCEPTION_HANDLER
89 //TimeTaker timer("AsyncRunStep() + Receive()");
92 //TimeTaker timer("AsyncRunStep()");
93 m_server->AsyncRunStep();
96 //infostream<<"Running m_server->Receive()"<<std::endl;
99 catch(con::NoIncomingDataException &e)
102 catch(con::PeerNotFoundException &e)
104 infostream<<"Server: PeerNotFoundException"<<std::endl;
108 END_DEBUG_EXCEPTION_HANDLER(errorstream)
113 void * EmergeThread::Thread()
117 log_register_thread("EmergeThread");
119 DSTACK(__FUNCTION_NAME);
121 BEGIN_DEBUG_EXCEPTION_HANDLER
123 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
126 Get block info from queue, emerge them and send them
129 After queue is empty, exit.
133 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
137 SharedPtr<QueuedBlockEmerge> q(qptr);
143 Do not generate over-limit
145 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
146 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
147 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
148 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
149 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
150 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
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 //core::map<v3s16, MapBlock*> changed_blocks;
195 //core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
197 MapBlock *block = NULL;
198 bool got_block = true;
199 core::map<v3s16, MapBlock*> modified_blocks;
202 Fetch block from map or generate a single block
205 JMutexAutoLock envlock(m_server->m_env_mutex);
207 // Load sector if it isn't loaded
208 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
209 //map.loadSectorFull(p2d);
210 map.loadSectorMeta(p2d);
212 block = map.getBlockNoCreateNoEx(p);
213 if(!block || block->isDummy() || !block->isGenerated())
215 if(enable_mapgen_debug_info)
216 infostream<<"EmergeThread: not in memory, loading"<<std::endl;
218 // Get, load or create sector
219 /*ServerMapSector *sector =
220 (ServerMapSector*)map.createSector(p2d);*/
222 // Load/generate block
224 /*block = map.emergeBlock(p, sector, changed_blocks,
225 lighting_invalidated_blocks);*/
227 block = map.loadBlock(p);
229 if(only_from_disk == false)
231 if(block == NULL || block->isGenerated() == false)
233 if(enable_mapgen_debug_info)
234 infostream<<"EmergeThread: generating"<<std::endl;
235 block = map.generateBlock(p, modified_blocks);
239 if(enable_mapgen_debug_info)
240 infostream<<"EmergeThread: ended up with: "
241 <<analyze_block(block)<<std::endl;
250 Ignore map edit events, they will not need to be
251 sent to anybody because the block hasn't been sent
254 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
256 // Activate objects and stuff
257 m_server->m_env->activateBlock(block, 3600);
262 /*if(block->getLightingExpired()){
263 lighting_invalidated_blocks[block->getPos()] = block;
267 // TODO: Some additional checking and lighting updating,
272 JMutexAutoLock envlock(m_server->m_env_mutex);
277 Collect a list of blocks that have been modified in
278 addition to the fetched one.
282 if(lighting_invalidated_blocks.size() > 0)
284 /*infostream<<"lighting "<<lighting_invalidated_blocks.size()
285 <<" blocks"<<std::endl;*/
287 // 50-100ms for single block generation
288 //TimeTaker timer("** EmergeThread updateLighting");
290 // Update lighting without locking the environment mutex,
291 // add modified blocks to changed blocks
292 map.updateLighting(lighting_invalidated_blocks, modified_blocks);
295 // Add all from changed_blocks to modified_blocks
296 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
297 i.atEnd() == false; i++)
299 MapBlock *block = i.getNode()->getValue();
300 modified_blocks.insert(block->getPos(), block);
304 // If we got no block, there should be no invalidated blocks
307 //assert(lighting_invalidated_blocks.size() == 0);
313 Set sent status of modified blocks on clients
316 // NOTE: Server's clients are also behind the connection mutex
317 JMutexAutoLock lock(m_server->m_con_mutex);
320 Add the originally fetched block to the modified list
324 modified_blocks.insert(p, block);
328 Set the modified blocks unsent for all the clients
331 for(core::map<u16, RemoteClient*>::Iterator
332 i = m_server->m_clients.getIterator();
333 i.atEnd() == false; i++)
335 RemoteClient *client = i.getNode()->getValue();
337 if(modified_blocks.size() > 0)
339 // Remove block from sent history
340 client->SetBlocksNotSent(modified_blocks);
346 END_DEBUG_EXCEPTION_HANDLER(errorstream)
351 void RemoteClient::GetNextBlocks(Server *server, float dtime,
352 core::array<PrioritySortedBlockTransfer> &dest)
354 DSTACK(__FUNCTION_NAME);
357 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
360 m_nothing_to_send_pause_timer -= dtime;
361 m_nearest_unsent_reset_timer += dtime;
363 if(m_nothing_to_send_pause_timer >= 0)
368 // Won't send anything if already sending
369 if(m_blocks_sending.size() >= g_settings->getU16
370 ("max_simultaneous_block_sends_per_client"))
372 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
376 //TimeTaker timer("RemoteClient::GetNextBlocks");
378 Player *player = server->m_env->getPlayer(peer_id);
380 assert(player != NULL);
382 v3f playerpos = player->getPosition();
383 v3f playerspeed = player->getSpeed();
384 v3f playerspeeddir(0,0,0);
385 if(playerspeed.getLength() > 1.0*BS)
386 playerspeeddir = playerspeed / playerspeed.getLength();
387 // Predict to next block
388 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
390 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
392 v3s16 center = getNodeBlockPos(center_nodepos);
394 // Camera position and direction
395 v3f camera_pos = player->getEyePosition();
396 v3f camera_dir = v3f(0,0,1);
397 camera_dir.rotateYZBy(player->getPitch());
398 camera_dir.rotateXZBy(player->getYaw());
400 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
401 <<camera_dir.Z<<")"<<std::endl;*/
404 Get the starting value of the block finder radius.
407 if(m_last_center != center)
409 m_nearest_unsent_d = 0;
410 m_last_center = center;
413 /*infostream<<"m_nearest_unsent_reset_timer="
414 <<m_nearest_unsent_reset_timer<<std::endl;*/
416 // Reset periodically to workaround for some bugs or stuff
417 if(m_nearest_unsent_reset_timer > 20.0)
419 m_nearest_unsent_reset_timer = 0;
420 m_nearest_unsent_d = 0;
421 //infostream<<"Resetting m_nearest_unsent_d for "
422 // <<server->getPlayerName(peer_id)<<std::endl;
425 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
426 s16 d_start = m_nearest_unsent_d;
428 //infostream<<"d_start="<<d_start<<std::endl;
430 u16 max_simul_sends_setting = g_settings->getU16
431 ("max_simultaneous_block_sends_per_client");
432 u16 max_simul_sends_usually = max_simul_sends_setting;
435 Check the time from last addNode/removeNode.
437 Decrease send rate if player is building stuff.
439 m_time_from_building += dtime;
440 if(m_time_from_building < g_settings->getFloat(
441 "full_block_send_enable_min_time_from_building"))
443 max_simul_sends_usually
444 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
448 Number of blocks sending + number of blocks selected for sending
450 u32 num_blocks_selected = m_blocks_sending.size();
453 next time d will be continued from the d from which the nearest
454 unsent block was found this time.
456 This is because not necessarily any of the blocks found this
457 time are actually sent.
459 s32 new_nearest_unsent_d = -1;
461 s16 d_max = g_settings->getS16("max_block_send_distance");
462 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
464 // Don't loop very much at a time
465 s16 max_d_increment_at_time = 2;
466 if(d_max > d_start + max_d_increment_at_time)
467 d_max = d_start + max_d_increment_at_time;
468 /*if(d_max_gen > d_start+2)
469 d_max_gen = d_start+2;*/
471 //infostream<<"Starting from "<<d_start<<std::endl;
473 s32 nearest_emerged_d = -1;
474 s32 nearest_emergefull_d = -1;
475 s32 nearest_sent_d = -1;
476 bool queue_is_full = false;
479 for(d = d_start; d <= d_max; d++)
481 /*errorstream<<"checking d="<<d<<" for "
482 <<server->getPlayerName(peer_id)<<std::endl;*/
483 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
486 If m_nearest_unsent_d was changed by the EmergeThread
487 (it can change it to 0 through SetBlockNotSent),
489 Else update m_nearest_unsent_d
491 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
493 d = m_nearest_unsent_d;
494 last_nearest_unsent_d = m_nearest_unsent_d;
498 Get the border/face dot coordinates of a "d-radiused"
501 core::list<v3s16> list;
502 getFacePositions(list, d);
504 core::list<v3s16>::Iterator li;
505 for(li=list.begin(); li!=list.end(); li++)
507 v3s16 p = *li + center;
511 - Don't allow too many simultaneous transfers
512 - EXCEPT when the blocks are very close
514 Also, don't send blocks that are already flying.
517 // Start with the usual maximum
518 u16 max_simul_dynamic = max_simul_sends_usually;
520 // If block is very close, allow full maximum
521 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
522 max_simul_dynamic = max_simul_sends_setting;
524 // Don't select too many blocks for sending
525 if(num_blocks_selected >= max_simul_dynamic)
527 queue_is_full = true;
528 goto queue_full_break;
531 // Don't send blocks that are currently being transferred
532 if(m_blocks_sending.find(p) != NULL)
538 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
539 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
540 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
541 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
542 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
543 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
546 // If this is true, inexistent block will be made from scratch
547 bool generate = d <= d_max_gen;
550 /*// Limit the generating area vertically to 2/3
551 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
554 // Limit the send area vertically to 1/2
555 if(abs(p.Y - center.Y) > d_max / 2)
561 If block is far away, don't generate it unless it is
567 // Block center y in nodes
568 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
569 // Don't generate if it's very high or very low
570 if(y < -64 || y > 64)
574 v2s16 p2d_nodes_center(
578 // Get ground height in nodes
579 s16 gh = server->m_env->getServerMap().findGroundLevel(
582 // If differs a lot, don't generate
583 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
585 // Actually, don't even send it
591 //infostream<<"d="<<d<<std::endl;
594 Don't generate or send if not in sight
595 FIXME This only works if the client uses a small enough
596 FOV setting. The default of 72 degrees is fine.
599 float camera_fov = (72.0*PI/180) * 4./3.;
600 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
606 Don't send already sent blocks
609 if(m_blocks_sent.find(p) != NULL)
616 Check if map has this block
618 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
620 bool surely_not_found_on_disk = false;
621 bool block_is_invalid = false;
624 // Reset usage timer, this block will be of use in the future.
625 block->resetUsageTimer();
627 // Block is dummy if data doesn't exist.
628 // It means it has been not found from disk and not generated
631 surely_not_found_on_disk = true;
634 // Block is valid if lighting is up-to-date and data exists
635 if(block->isValid() == false)
637 block_is_invalid = true;
640 /*if(block->isFullyGenerated() == false)
642 block_is_invalid = true;
647 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
648 v2s16 chunkpos = map->sector_to_chunk(p2d);
649 if(map->chunkNonVolatile(chunkpos) == false)
650 block_is_invalid = true;
652 if(block->isGenerated() == false)
653 block_is_invalid = true;
656 If block is not close, don't send it unless it is near
659 Block is near ground level if night-time mesh
660 differs from day-time mesh.
664 if(block->dayNightDiffed() == false)
671 If block has been marked to not exist on disk (dummy)
672 and generating new ones is not wanted, skip block.
674 if(generate == false && surely_not_found_on_disk == true)
681 Add inexistent block to emerge queue.
683 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
685 //TODO: Get value from somewhere
686 // Allow only one block in emerge queue
687 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
688 // Allow two blocks in queue per client
689 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
690 if(server->m_emerge_queue.peerItemCount(peer_id) < 25)
692 //infostream<<"Adding block to emerge queue"<<std::endl;
694 // Add it to the emerge queue and trigger the thread
697 if(generate == false)
698 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
700 server->m_emerge_queue.addBlock(peer_id, p, flags);
701 server->m_emergethread.trigger();
703 if(nearest_emerged_d == -1)
704 nearest_emerged_d = d;
706 if(nearest_emergefull_d == -1)
707 nearest_emergefull_d = d;
714 if(nearest_sent_d == -1)
718 Add block to send queue
721 /*errorstream<<"sending from d="<<d<<" to "
722 <<server->getPlayerName(peer_id)<<std::endl;*/
724 PrioritySortedBlockTransfer q((float)d, p, peer_id);
728 num_blocks_selected += 1;
733 //infostream<<"Stopped at "<<d<<std::endl;
735 // If nothing was found for sending and nothing was queued for
736 // emerging, continue next time browsing from here
737 if(nearest_emerged_d != -1){
738 new_nearest_unsent_d = nearest_emerged_d;
739 } else if(nearest_emergefull_d != -1){
740 new_nearest_unsent_d = nearest_emergefull_d;
742 if(d > g_settings->getS16("max_block_send_distance")){
743 new_nearest_unsent_d = 0;
744 m_nothing_to_send_pause_timer = 2.0;
745 /*infostream<<"GetNextBlocks(): d wrapped around for "
746 <<server->getPlayerName(peer_id)
747 <<"; setting to 0 and pausing"<<std::endl;*/
749 if(nearest_sent_d != -1)
750 new_nearest_unsent_d = nearest_sent_d;
752 new_nearest_unsent_d = d;
756 if(new_nearest_unsent_d != -1)
757 m_nearest_unsent_d = new_nearest_unsent_d;
759 /*timer_result = timer.stop(true);
760 if(timer_result != 0)
761 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
764 void RemoteClient::SendObjectData(
767 core::map<v3s16, bool> &stepped_blocks
770 DSTACK(__FUNCTION_NAME);
772 // Can't send anything without knowing version
773 if(serialization_version == SER_FMT_VER_INVALID)
775 infostream<<"RemoteClient::SendObjectData(): Not sending, no version."
781 Send a TOCLIENT_OBJECTDATA packet.
785 u16 number of player positions
797 std::ostringstream os(std::ios_base::binary);
801 writeU16(buf, TOCLIENT_OBJECTDATA);
802 os.write((char*)buf, 2);
805 Get and write player data
808 // Get connected players
809 core::list<Player*> players = server->m_env->getPlayers(true);
811 // Write player count
812 u16 playercount = players.size();
813 writeU16(buf, playercount);
814 os.write((char*)buf, 2);
816 core::list<Player*>::Iterator i;
817 for(i = players.begin();
818 i != players.end(); i++)
822 v3f pf = player->getPosition();
823 v3f sf = player->getSpeed();
825 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
826 v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
827 s32 pitch_i (player->getPitch() * 100);
828 s32 yaw_i (player->getYaw() * 100);
830 writeU16(buf, player->peer_id);
831 os.write((char*)buf, 2);
832 writeV3S32(buf, position_i);
833 os.write((char*)buf, 12);
834 writeV3S32(buf, speed_i);
835 os.write((char*)buf, 12);
836 writeS32(buf, pitch_i);
837 os.write((char*)buf, 4);
838 writeS32(buf, yaw_i);
839 os.write((char*)buf, 4);
843 Get and write object data (dummy, for compatibility)
848 os.write((char*)buf, 2);
854 //infostream<<"Server: Sending object data to "<<peer_id<<std::endl;
857 std::string s = os.str();
858 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
859 // Send as unreliable
860 server->m_con.Send(peer_id, 0, data, false);
863 void RemoteClient::GotBlock(v3s16 p)
865 if(m_blocks_sending.find(p) != NULL)
866 m_blocks_sending.remove(p);
869 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
870 " m_blocks_sending"<<std::endl;*/
871 m_excess_gotblocks++;
873 m_blocks_sent.insert(p, true);
876 void RemoteClient::SentBlock(v3s16 p)
878 if(m_blocks_sending.find(p) == NULL)
879 m_blocks_sending.insert(p, 0.0);
881 infostream<<"RemoteClient::SentBlock(): Sent block"
882 " already in m_blocks_sending"<<std::endl;
885 void RemoteClient::SetBlockNotSent(v3s16 p)
887 m_nearest_unsent_d = 0;
889 if(m_blocks_sending.find(p) != NULL)
890 m_blocks_sending.remove(p);
891 if(m_blocks_sent.find(p) != NULL)
892 m_blocks_sent.remove(p);
895 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
897 m_nearest_unsent_d = 0;
899 for(core::map<v3s16, MapBlock*>::Iterator
900 i = blocks.getIterator();
901 i.atEnd()==false; i++)
903 v3s16 p = i.getNode()->getKey();
905 if(m_blocks_sending.find(p) != NULL)
906 m_blocks_sending.remove(p);
907 if(m_blocks_sent.find(p) != NULL)
908 m_blocks_sent.remove(p);
916 PlayerInfo::PlayerInfo()
922 void PlayerInfo::PrintLine(std::ostream *s)
925 (*s)<<"\""<<name<<"\" ("
926 <<(position.X/10)<<","<<(position.Y/10)
927 <<","<<(position.Z/10)<<") ";
929 (*s)<<" avg_rtt="<<avg_rtt;
933 u32 PIChecksum(core::list<PlayerInfo> &l)
935 core::list<PlayerInfo>::Iterator i;
938 for(i=l.begin(); i!=l.end(); i++)
940 checksum += a * (i->id+1);
941 checksum ^= 0x435aafcd;
952 ModSpec(const std::string &name_="", const std::string path_=""):
958 static core::list<ModSpec> getMods(core::list<std::string> &modspaths)
960 core::list<ModSpec> mods;
961 for(core::list<std::string>::Iterator i = modspaths.begin();
962 i != modspaths.end(); i++){
963 std::string modspath = *i;
964 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(modspath);
965 for(u32 j=0; j<dirlist.size(); j++){
968 std::string modname = dirlist[j].name;
969 std::string modpath = modspath + DIR_DELIM + modname;
970 mods.push_back(ModSpec(modname, modpath));
981 std::string mapsavedir,
982 std::string configpath
985 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
986 m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"),
987 m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"),
989 m_toolmgr(createToolDefManager()),
990 m_nodemgr(createNodeDefManager()),
992 m_emergethread(this),
994 m_time_of_day_send_timer(0),
996 m_mapsavedir(mapsavedir),
997 m_configpath(configpath),
998 m_shutdown_requested(false),
999 m_ignore_map_edit_events(false),
1000 m_ignore_map_edit_events_peer_id(0)
1002 m_liquid_transform_timer = 0.0;
1003 m_print_info_timer = 0.0;
1004 m_objectdata_timer = 0.0;
1005 m_emergethread_trigger_timer = 0.0;
1006 m_savemap_timer = 0.0;
1010 m_step_dtime_mutex.Init();
1013 JMutexAutoLock envlock(m_env_mutex);
1014 JMutexAutoLock conlock(m_con_mutex);
1016 infostream<<"m_nodemgr="<<m_nodemgr<<std::endl;
1018 // Initialize default node definitions
1019 content_mapnode_init(m_nodemgr);
1021 // Add default global mod path
1022 m_modspaths.push_back(porting::path_data + DIR_DELIM + "mods");
1024 // Initialize scripting
1026 infostream<<"Server: Initializing scripting"<<std::endl;
1027 m_lua = script_init();
1030 scriptapi_export(m_lua, this);
1031 // Load and run scripts
1032 core::list<ModSpec> mods = getMods(m_modspaths);
1033 for(core::list<ModSpec>::Iterator i = mods.begin();
1034 i != mods.end(); i++){
1036 infostream<<"Server: Loading mod \""<<mod.name<<"\""<<std::endl;
1037 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1038 bool success = script_load(m_lua, scriptpath.c_str());
1040 errorstream<<"Server: Failed to load and run "
1041 <<scriptpath<<std::endl;
1046 // Initialize Environment
1048 m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua, this);
1050 // Give environment reference to scripting api
1051 scriptapi_add_environment(m_lua, m_env);
1053 // Register us to receive map edit events
1054 m_env->getMap().addEventReceiver(this);
1056 // If file exists, load environment metadata
1057 if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt"))
1059 infostream<<"Server: Loading environment metadata"<<std::endl;
1060 m_env->loadMeta(m_mapsavedir);
1064 infostream<<"Server: Loading players"<<std::endl;
1065 m_env->deSerializePlayers(m_mapsavedir);
1070 infostream<<"Server::~Server()"<<std::endl;
1073 Send shutdown message
1076 JMutexAutoLock conlock(m_con_mutex);
1078 std::wstring line = L"*** Server shutting down";
1081 Send the message to clients
1083 for(core::map<u16, RemoteClient*>::Iterator
1084 i = m_clients.getIterator();
1085 i.atEnd() == false; i++)
1087 // Get client and check that it is valid
1088 RemoteClient *client = i.getNode()->getValue();
1089 assert(client->peer_id == i.getNode()->getKey());
1090 if(client->serialization_version == SER_FMT_VER_INVALID)
1094 SendChatMessage(client->peer_id, line);
1096 catch(con::PeerNotFoundException &e)
1102 JMutexAutoLock envlock(m_env_mutex);
1107 infostream<<"Server: Saving players"<<std::endl;
1108 m_env->serializePlayers(m_mapsavedir);
1111 Save environment metadata
1113 infostream<<"Server: Saving environment metadata"<<std::endl;
1114 m_env->saveMeta(m_mapsavedir);
1126 JMutexAutoLock clientslock(m_con_mutex);
1128 for(core::map<u16, RemoteClient*>::Iterator
1129 i = m_clients.getIterator();
1130 i.atEnd() == false; i++)
1133 // NOTE: These are removed by env destructor
1135 u16 peer_id = i.getNode()->getKey();
1136 JMutexAutoLock envlock(m_env_mutex);
1137 m_env->removePlayer(peer_id);
1141 delete i.getNode()->getValue();
1145 // Delete Environment
1151 // Deinitialize scripting
1152 infostream<<"Server: Deinitializing scripting"<<std::endl;
1153 script_deinit(m_lua);
1156 void Server::start(unsigned short port)
1158 DSTACK(__FUNCTION_NAME);
1159 // Stop thread if already running
1162 // Initialize connection
1163 m_con.SetTimeoutMs(30);
1167 m_thread.setRun(true);
1170 infostream<<"Server: Started on port "<<port<<std::endl;
1175 DSTACK(__FUNCTION_NAME);
1177 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1179 // Stop threads (set run=false first so both start stopping)
1180 m_thread.setRun(false);
1181 m_emergethread.setRun(false);
1183 m_emergethread.stop();
1185 infostream<<"Server: Threads stopped"<<std::endl;
1188 void Server::step(float dtime)
1190 DSTACK(__FUNCTION_NAME);
1195 JMutexAutoLock lock(m_step_dtime_mutex);
1196 m_step_dtime += dtime;
1200 void Server::AsyncRunStep()
1202 DSTACK(__FUNCTION_NAME);
1204 g_profiler->add("Server::AsyncRunStep (num)", 1);
1208 JMutexAutoLock lock1(m_step_dtime_mutex);
1209 dtime = m_step_dtime;
1213 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
1214 // Send blocks to clients
1221 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1223 //infostream<<"Server steps "<<dtime<<std::endl;
1224 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1227 JMutexAutoLock lock1(m_step_dtime_mutex);
1228 m_step_dtime -= dtime;
1235 m_uptime.set(m_uptime.get() + dtime);
1239 // Process connection's timeouts
1240 JMutexAutoLock lock2(m_con_mutex);
1241 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1242 m_con.RunTimeouts(dtime);
1246 // This has to be called so that the client list gets synced
1247 // with the peer list of the connection
1248 handlePeerChanges();
1252 Update m_time_of_day and overall game time
1255 JMutexAutoLock envlock(m_env_mutex);
1257 m_time_counter += dtime;
1258 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1259 u32 units = (u32)(m_time_counter*speed);
1260 m_time_counter -= (f32)units / speed;
1262 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1264 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1267 Send to clients at constant intervals
1270 m_time_of_day_send_timer -= dtime;
1271 if(m_time_of_day_send_timer < 0.0)
1273 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1275 //JMutexAutoLock envlock(m_env_mutex);
1276 JMutexAutoLock conlock(m_con_mutex);
1278 for(core::map<u16, RemoteClient*>::Iterator
1279 i = m_clients.getIterator();
1280 i.atEnd() == false; i++)
1282 RemoteClient *client = i.getNode()->getValue();
1283 //Player *player = m_env->getPlayer(client->peer_id);
1285 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1286 m_env->getTimeOfDay());
1288 m_con.Send(client->peer_id, 0, data, true);
1294 JMutexAutoLock lock(m_env_mutex);
1296 ScopeProfiler sp(g_profiler, "SEnv step");
1297 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1301 const float map_timer_and_unload_dtime = 5.15;
1302 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1304 JMutexAutoLock lock(m_env_mutex);
1305 // Run Map's timers and unload unused data
1306 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1307 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1308 g_settings->getFloat("server_unload_unused_data_timeout"));
1318 m_liquid_transform_timer += dtime;
1319 if(m_liquid_transform_timer >= 1.00)
1321 m_liquid_transform_timer -= 1.00;
1323 JMutexAutoLock lock(m_env_mutex);
1325 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1327 core::map<v3s16, MapBlock*> modified_blocks;
1328 m_env->getMap().transformLiquids(modified_blocks);
1333 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1334 ServerMap &map = ((ServerMap&)m_env->getMap());
1335 map.updateLighting(modified_blocks, lighting_modified_blocks);
1337 // Add blocks modified by lighting to modified_blocks
1338 for(core::map<v3s16, MapBlock*>::Iterator
1339 i = lighting_modified_blocks.getIterator();
1340 i.atEnd() == false; i++)
1342 MapBlock *block = i.getNode()->getValue();
1343 modified_blocks.insert(block->getPos(), block);
1347 Set the modified blocks unsent for all the clients
1350 JMutexAutoLock lock2(m_con_mutex);
1352 for(core::map<u16, RemoteClient*>::Iterator
1353 i = m_clients.getIterator();
1354 i.atEnd() == false; i++)
1356 RemoteClient *client = i.getNode()->getValue();
1358 if(modified_blocks.size() > 0)
1360 // Remove block from sent history
1361 client->SetBlocksNotSent(modified_blocks);
1366 // Periodically print some info
1368 float &counter = m_print_info_timer;
1374 JMutexAutoLock lock2(m_con_mutex);
1376 if(m_clients.size() != 0)
1377 infostream<<"Players:"<<std::endl;
1378 for(core::map<u16, RemoteClient*>::Iterator
1379 i = m_clients.getIterator();
1380 i.atEnd() == false; i++)
1382 //u16 peer_id = i.getNode()->getKey();
1383 RemoteClient *client = i.getNode()->getValue();
1384 Player *player = m_env->getPlayer(client->peer_id);
1387 infostream<<"* "<<player->getName()<<"\t";
1388 client->PrintInfo(infostream);
1393 //if(g_settings->getBool("enable_experimental"))
1397 Check added and deleted active objects
1400 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1401 JMutexAutoLock envlock(m_env_mutex);
1402 JMutexAutoLock conlock(m_con_mutex);
1404 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1406 // Radius inside which objects are active
1407 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1408 radius *= MAP_BLOCKSIZE;
1410 for(core::map<u16, RemoteClient*>::Iterator
1411 i = m_clients.getIterator();
1412 i.atEnd() == false; i++)
1414 RemoteClient *client = i.getNode()->getValue();
1415 Player *player = m_env->getPlayer(client->peer_id);
1418 // This can happen if the client timeouts somehow
1419 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1421 <<" has no associated player"<<std::endl;*/
1424 v3s16 pos = floatToInt(player->getPosition(), BS);
1426 core::map<u16, bool> removed_objects;
1427 core::map<u16, bool> added_objects;
1428 m_env->getRemovedActiveObjects(pos, radius,
1429 client->m_known_objects, removed_objects);
1430 m_env->getAddedActiveObjects(pos, radius,
1431 client->m_known_objects, added_objects);
1433 // Ignore if nothing happened
1434 if(removed_objects.size() == 0 && added_objects.size() == 0)
1436 //infostream<<"active objects: none changed"<<std::endl;
1440 std::string data_buffer;
1444 // Handle removed objects
1445 writeU16((u8*)buf, removed_objects.size());
1446 data_buffer.append(buf, 2);
1447 for(core::map<u16, bool>::Iterator
1448 i = removed_objects.getIterator();
1449 i.atEnd()==false; i++)
1452 u16 id = i.getNode()->getKey();
1453 ServerActiveObject* obj = m_env->getActiveObject(id);
1455 // Add to data buffer for sending
1456 writeU16((u8*)buf, i.getNode()->getKey());
1457 data_buffer.append(buf, 2);
1459 // Remove from known objects
1460 client->m_known_objects.remove(i.getNode()->getKey());
1462 if(obj && obj->m_known_by_count > 0)
1463 obj->m_known_by_count--;
1466 // Handle added objects
1467 writeU16((u8*)buf, added_objects.size());
1468 data_buffer.append(buf, 2);
1469 for(core::map<u16, bool>::Iterator
1470 i = added_objects.getIterator();
1471 i.atEnd()==false; i++)
1474 u16 id = i.getNode()->getKey();
1475 ServerActiveObject* obj = m_env->getActiveObject(id);
1478 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1480 infostream<<"WARNING: "<<__FUNCTION_NAME
1481 <<": NULL object"<<std::endl;
1483 type = obj->getType();
1485 // Add to data buffer for sending
1486 writeU16((u8*)buf, id);
1487 data_buffer.append(buf, 2);
1488 writeU8((u8*)buf, type);
1489 data_buffer.append(buf, 1);
1492 data_buffer.append(serializeLongString(
1493 obj->getClientInitializationData()));
1495 data_buffer.append(serializeLongString(""));
1497 // Add to known objects
1498 client->m_known_objects.insert(i.getNode()->getKey(), false);
1501 obj->m_known_by_count++;
1505 SharedBuffer<u8> reply(2 + data_buffer.size());
1506 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1507 memcpy((char*)&reply[2], data_buffer.c_str(),
1508 data_buffer.size());
1510 m_con.Send(client->peer_id, 0, reply, true);
1512 infostream<<"Server: Sent object remove/add: "
1513 <<removed_objects.size()<<" removed, "
1514 <<added_objects.size()<<" added, "
1515 <<"packet size is "<<reply.getSize()<<std::endl;
1520 Collect a list of all the objects known by the clients
1521 and report it back to the environment.
1524 core::map<u16, bool> all_known_objects;
1526 for(core::map<u16, RemoteClient*>::Iterator
1527 i = m_clients.getIterator();
1528 i.atEnd() == false; i++)
1530 RemoteClient *client = i.getNode()->getValue();
1531 // Go through all known objects of client
1532 for(core::map<u16, bool>::Iterator
1533 i = client->m_known_objects.getIterator();
1534 i.atEnd()==false; i++)
1536 u16 id = i.getNode()->getKey();
1537 all_known_objects[id] = true;
1541 m_env->setKnownActiveObjects(whatever);
1547 Send object messages
1550 JMutexAutoLock envlock(m_env_mutex);
1551 JMutexAutoLock conlock(m_con_mutex);
1553 //ScopeProfiler sp(g_profiler, "Server: sending object messages");
1556 // Value = data sent by object
1557 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1559 // Get active object messages from environment
1562 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1566 core::list<ActiveObjectMessage>* message_list = NULL;
1567 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1568 n = buffered_messages.find(aom.id);
1571 message_list = new core::list<ActiveObjectMessage>;
1572 buffered_messages.insert(aom.id, message_list);
1576 message_list = n->getValue();
1578 message_list->push_back(aom);
1581 // Route data to every client
1582 for(core::map<u16, RemoteClient*>::Iterator
1583 i = m_clients.getIterator();
1584 i.atEnd()==false; i++)
1586 RemoteClient *client = i.getNode()->getValue();
1587 std::string reliable_data;
1588 std::string unreliable_data;
1589 // Go through all objects in message buffer
1590 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1591 j = buffered_messages.getIterator();
1592 j.atEnd()==false; j++)
1594 // If object is not known by client, skip it
1595 u16 id = j.getNode()->getKey();
1596 if(client->m_known_objects.find(id) == NULL)
1598 // Get message list of object
1599 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1600 // Go through every message
1601 for(core::list<ActiveObjectMessage>::Iterator
1602 k = list->begin(); k != list->end(); k++)
1604 // Compose the full new data with header
1605 ActiveObjectMessage aom = *k;
1606 std::string new_data;
1609 writeU16((u8*)&buf[0], aom.id);
1610 new_data.append(buf, 2);
1612 new_data += serializeString(aom.datastring);
1613 // Add data to buffer
1615 reliable_data += new_data;
1617 unreliable_data += new_data;
1621 reliable_data and unreliable_data are now ready.
1624 if(reliable_data.size() > 0)
1626 SharedBuffer<u8> reply(2 + reliable_data.size());
1627 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1628 memcpy((char*)&reply[2], reliable_data.c_str(),
1629 reliable_data.size());
1631 m_con.Send(client->peer_id, 0, reply, true);
1633 if(unreliable_data.size() > 0)
1635 SharedBuffer<u8> reply(2 + unreliable_data.size());
1636 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1637 memcpy((char*)&reply[2], unreliable_data.c_str(),
1638 unreliable_data.size());
1639 // Send as unreliable
1640 m_con.Send(client->peer_id, 0, reply, false);
1643 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1645 infostream<<"Server: Size of object message data: "
1646 <<"reliable: "<<reliable_data.size()
1647 <<", unreliable: "<<unreliable_data.size()
1652 // Clear buffered_messages
1653 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1654 i = buffered_messages.getIterator();
1655 i.atEnd()==false; i++)
1657 delete i.getNode()->getValue();
1661 } // enable_experimental
1664 Send queued-for-sending map edit events.
1667 // Don't send too many at a time
1670 // Single change sending is disabled if queue size is not small
1671 bool disable_single_change_sending = false;
1672 if(m_unsent_map_edit_queue.size() >= 4)
1673 disable_single_change_sending = true;
1675 bool got_any_events = false;
1677 // We'll log the amount of each
1680 while(m_unsent_map_edit_queue.size() != 0)
1682 got_any_events = true;
1684 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1686 // Players far away from the change are stored here.
1687 // Instead of sending the changes, MapBlocks are set not sent
1689 core::list<u16> far_players;
1691 if(event->type == MEET_ADDNODE)
1693 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1694 prof.add("MEET_ADDNODE", 1);
1695 if(disable_single_change_sending)
1696 sendAddNode(event->p, event->n, event->already_known_by_peer,
1699 sendAddNode(event->p, event->n, event->already_known_by_peer,
1702 else if(event->type == MEET_REMOVENODE)
1704 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1705 prof.add("MEET_REMOVENODE", 1);
1706 if(disable_single_change_sending)
1707 sendRemoveNode(event->p, event->already_known_by_peer,
1710 sendRemoveNode(event->p, event->already_known_by_peer,
1713 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1715 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1716 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1717 setBlockNotSent(event->p);
1719 else if(event->type == MEET_OTHER)
1721 infostream<<"Server: MEET_OTHER"<<std::endl;
1722 prof.add("MEET_OTHER", 1);
1723 for(core::map<v3s16, bool>::Iterator
1724 i = event->modified_blocks.getIterator();
1725 i.atEnd()==false; i++)
1727 v3s16 p = i.getNode()->getKey();
1733 prof.add("unknown", 1);
1734 infostream<<"WARNING: Server: Unknown MapEditEvent "
1735 <<((u32)event->type)<<std::endl;
1739 Set blocks not sent to far players
1741 if(far_players.size() > 0)
1743 // Convert list format to that wanted by SetBlocksNotSent
1744 core::map<v3s16, MapBlock*> modified_blocks2;
1745 for(core::map<v3s16, bool>::Iterator
1746 i = event->modified_blocks.getIterator();
1747 i.atEnd()==false; i++)
1749 v3s16 p = i.getNode()->getKey();
1750 modified_blocks2.insert(p,
1751 m_env->getMap().getBlockNoCreateNoEx(p));
1753 // Set blocks not sent
1754 for(core::list<u16>::Iterator
1755 i = far_players.begin();
1756 i != far_players.end(); i++)
1759 RemoteClient *client = getClient(peer_id);
1762 client->SetBlocksNotSent(modified_blocks2);
1768 /*// Don't send too many at a time
1770 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1776 infostream<<"Server: MapEditEvents:"<<std::endl;
1777 prof.print(infostream);
1783 Send object positions
1786 float &counter = m_objectdata_timer;
1788 if(counter >= g_settings->getFloat("objectdata_interval"))
1790 JMutexAutoLock lock1(m_env_mutex);
1791 JMutexAutoLock lock2(m_con_mutex);
1793 //ScopeProfiler sp(g_profiler, "Server: sending player positions");
1795 SendObjectData(counter);
1802 Trigger emergethread (it somehow gets to a non-triggered but
1803 bysy state sometimes)
1806 float &counter = m_emergethread_trigger_timer;
1812 m_emergethread.trigger();
1816 // Save map, players and auth stuff
1818 float &counter = m_savemap_timer;
1820 if(counter >= g_settings->getFloat("server_map_save_interval"))
1824 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1827 if(m_authmanager.isModified())
1828 m_authmanager.save();
1831 if(m_banmanager.isModified())
1832 m_banmanager.save();
1835 JMutexAutoLock lock(m_env_mutex);
1837 /*// Unload unused data (delete from memory)
1838 m_env->getMap().unloadUnusedData(
1839 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1841 /*u32 deleted_count = m_env->getMap().unloadUnusedData(
1842 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1845 // Save only changed parts
1846 m_env->getMap().save(true);
1848 /*if(deleted_count > 0)
1850 infostream<<"Server: Unloaded "<<deleted_count
1851 <<" blocks from memory"<<std::endl;
1855 m_env->serializePlayers(m_mapsavedir);
1857 // Save environment metadata
1858 m_env->saveMeta(m_mapsavedir);
1863 void Server::Receive()
1865 DSTACK(__FUNCTION_NAME);
1866 SharedBuffer<u8> data;
1871 JMutexAutoLock conlock(m_con_mutex);
1872 datasize = m_con.Receive(peer_id, data);
1875 // This has to be called so that the client list gets synced
1876 // with the peer list of the connection
1877 handlePeerChanges();
1879 ProcessData(*data, datasize, peer_id);
1881 catch(con::InvalidIncomingDataException &e)
1883 infostream<<"Server::Receive(): "
1884 "InvalidIncomingDataException: what()="
1885 <<e.what()<<std::endl;
1887 catch(con::PeerNotFoundException &e)
1889 //NOTE: This is not needed anymore
1891 // The peer has been disconnected.
1892 // Find the associated player and remove it.
1894 /*JMutexAutoLock envlock(m_env_mutex);
1896 infostream<<"ServerThread: peer_id="<<peer_id
1897 <<" has apparently closed connection. "
1898 <<"Removing player."<<std::endl;
1900 m_env->removePlayer(peer_id);*/
1904 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1906 DSTACK(__FUNCTION_NAME);
1907 // Environment is locked first.
1908 JMutexAutoLock envlock(m_env_mutex);
1909 JMutexAutoLock conlock(m_con_mutex);
1912 Address address = m_con.GetPeerAddress(peer_id);
1914 // drop player if is ip is banned
1915 if(m_banmanager.isIpBanned(address.serializeString())){
1916 SendAccessDenied(m_con, peer_id,
1917 L"Your ip is banned. Banned name was "
1918 +narrow_to_wide(m_banmanager.getBanName(
1919 address.serializeString())));
1920 m_con.DeletePeer(peer_id);
1924 catch(con::PeerNotFoundException &e)
1926 infostream<<"Server::ProcessData(): Cancelling: peer "
1927 <<peer_id<<" not found"<<std::endl;
1931 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1939 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1941 if(command == TOSERVER_INIT)
1943 // [0] u16 TOSERVER_INIT
1944 // [2] u8 SER_FMT_VER_HIGHEST
1945 // [3] u8[20] player_name
1946 // [23] u8[28] password <--- can be sent without this, from old versions
1948 if(datasize < 2+1+PLAYERNAME_SIZE)
1951 infostream<<"Server: Got TOSERVER_INIT from "
1952 <<peer_id<<std::endl;
1954 // First byte after command is maximum supported
1955 // serialization version
1956 u8 client_max = data[2];
1957 u8 our_max = SER_FMT_VER_HIGHEST;
1958 // Use the highest version supported by both
1959 u8 deployed = core::min_(client_max, our_max);
1960 // If it's lower than the lowest supported, give up.
1961 if(deployed < SER_FMT_VER_LOWEST)
1962 deployed = SER_FMT_VER_INVALID;
1964 //peer->serialization_version = deployed;
1965 getClient(peer_id)->pending_serialization_version = deployed;
1967 if(deployed == SER_FMT_VER_INVALID)
1969 infostream<<"Server: Cannot negotiate "
1970 "serialization version with peer "
1971 <<peer_id<<std::endl;
1972 SendAccessDenied(m_con, peer_id,
1973 L"Your client is too old (map format)");
1978 Read and check network protocol version
1981 u16 net_proto_version = 0;
1982 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1984 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1987 getClient(peer_id)->net_proto_version = net_proto_version;
1989 if(net_proto_version == 0)
1991 SendAccessDenied(m_con, peer_id,
1992 L"Your client is too old. Please upgrade.");
1996 /* Uhh... this should actually be a warning but let's do it like this */
1997 if(g_settings->getBool("strict_protocol_version_checking"))
1999 if(net_proto_version < PROTOCOL_VERSION)
2001 SendAccessDenied(m_con, peer_id,
2002 L"Your client is too old. Please upgrade.");
2012 char playername[PLAYERNAME_SIZE];
2013 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2015 playername[i] = data[3+i];
2017 playername[PLAYERNAME_SIZE-1] = 0;
2019 if(playername[0]=='\0')
2021 infostream<<"Server: Player has empty name"<<std::endl;
2022 SendAccessDenied(m_con, peer_id,
2027 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2029 infostream<<"Server: Player has invalid name"<<std::endl;
2030 SendAccessDenied(m_con, peer_id,
2031 L"Name contains unallowed characters");
2036 char password[PASSWORD_SIZE];
2037 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2039 // old version - assume blank password
2044 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2046 password[i] = data[23+i];
2048 password[PASSWORD_SIZE-1] = 0;
2051 std::string checkpwd;
2052 if(m_authmanager.exists(playername))
2054 checkpwd = m_authmanager.getPassword(playername);
2058 checkpwd = g_settings->get("default_password");
2061 /*infostream<<"Server: Client gave password '"<<password
2062 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2064 if(password != checkpwd && m_authmanager.exists(playername))
2066 infostream<<"Server: peer_id="<<peer_id
2067 <<": supplied invalid password for "
2068 <<playername<<std::endl;
2069 SendAccessDenied(m_con, peer_id, L"Invalid password");
2073 // Add player to auth manager
2074 if(m_authmanager.exists(playername) == false)
2076 infostream<<"Server: adding player "<<playername
2077 <<" to auth manager"<<std::endl;
2078 m_authmanager.add(playername);
2079 m_authmanager.setPassword(playername, checkpwd);
2080 m_authmanager.setPrivs(playername,
2081 stringToPrivs(g_settings->get("default_privs")));
2082 m_authmanager.save();
2085 // Enforce user limit.
2086 // Don't enforce for users that have some admin right
2087 if(m_clients.size() >= g_settings->getU16("max_users") &&
2088 (m_authmanager.getPrivs(playername)
2089 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 &&
2090 playername != g_settings->get("name"))
2092 SendAccessDenied(m_con, peer_id, L"Too many users.");
2097 Player *player = emergePlayer(playername, password, peer_id);
2099 // If failed, cancel
2102 infostream<<"Server: peer_id="<<peer_id
2103 <<": failed to emerge player"<<std::endl;
2108 Answer with a TOCLIENT_INIT
2111 SharedBuffer<u8> reply(2+1+6+8);
2112 writeU16(&reply[0], TOCLIENT_INIT);
2113 writeU8(&reply[2], deployed);
2114 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2115 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2118 m_con.Send(peer_id, 0, reply, true);
2122 Send complete position information
2124 SendMovePlayer(player);
2129 if(command == TOSERVER_INIT2)
2131 infostream<<"Server: Got TOSERVER_INIT2 from "
2132 <<peer_id<<std::endl;
2135 getClient(peer_id)->serialization_version
2136 = getClient(peer_id)->pending_serialization_version;
2139 Send some initialization data
2143 SendTextures(peer_id);
2145 // Send tool definitions
2146 SendToolDef(m_con, peer_id, m_toolmgr);
2148 // Send node definitions
2149 SendNodeDef(m_con, peer_id, m_nodemgr);
2151 // Send player info to all players
2154 // Send inventory to player
2155 UpdateCrafting(peer_id);
2156 SendInventory(peer_id);
2158 // Send player items to all players
2161 Player *player = m_env->getPlayer(peer_id);
2164 SendPlayerHP(player);
2168 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2169 m_env->getTimeOfDay());
2170 m_con.Send(peer_id, 0, data, true);
2173 // Send information about server to player in chat
2174 SendChatMessage(peer_id, getStatusString());
2176 // Send information about joining in chat
2178 std::wstring name = L"unknown";
2179 Player *player = m_env->getPlayer(peer_id);
2181 name = narrow_to_wide(player->getName());
2183 std::wstring message;
2186 message += L" joined game";
2187 BroadcastChatMessage(message);
2190 // Warnings about protocol version can be issued here
2191 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2193 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2197 Check HP, respawn if necessary
2199 HandlePlayerHP(player, 0);
2205 std::ostringstream os(std::ios_base::binary);
2206 for(core::map<u16, RemoteClient*>::Iterator
2207 i = m_clients.getIterator();
2208 i.atEnd() == false; i++)
2210 RemoteClient *client = i.getNode()->getValue();
2211 assert(client->peer_id == i.getNode()->getKey());
2212 if(client->serialization_version == SER_FMT_VER_INVALID)
2215 Player *player = m_env->getPlayer(client->peer_id);
2218 // Get name of player
2219 os<<player->getName()<<" ";
2222 actionstream<<player->getName()<<" joins game. List of players: "
2223 <<os.str()<<std::endl;
2229 if(peer_ser_ver == SER_FMT_VER_INVALID)
2231 infostream<<"Server::ProcessData(): Cancelling: Peer"
2232 " serialization format invalid or not initialized."
2233 " Skipping incoming command="<<command<<std::endl;
2237 Player *player = m_env->getPlayer(peer_id);
2240 infostream<<"Server::ProcessData(): Cancelling: "
2241 "No player for peer_id="<<peer_id
2245 if(command == TOSERVER_PLAYERPOS)
2247 if(datasize < 2+12+12+4+4)
2251 v3s32 ps = readV3S32(&data[start+2]);
2252 v3s32 ss = readV3S32(&data[start+2+12]);
2253 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2254 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2255 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2256 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2257 pitch = wrapDegrees(pitch);
2258 yaw = wrapDegrees(yaw);
2260 player->setPosition(position);
2261 player->setSpeed(speed);
2262 player->setPitch(pitch);
2263 player->setYaw(yaw);
2265 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2266 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2267 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2269 else if(command == TOSERVER_GOTBLOCKS)
2282 u16 count = data[2];
2283 for(u16 i=0; i<count; i++)
2285 if((s16)datasize < 2+1+(i+1)*6)
2286 throw con::InvalidIncomingDataException
2287 ("GOTBLOCKS length is too short");
2288 v3s16 p = readV3S16(&data[2+1+i*6]);
2289 /*infostream<<"Server: GOTBLOCKS ("
2290 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2291 RemoteClient *client = getClient(peer_id);
2292 client->GotBlock(p);
2295 else if(command == TOSERVER_DELETEDBLOCKS)
2308 u16 count = data[2];
2309 for(u16 i=0; i<count; i++)
2311 if((s16)datasize < 2+1+(i+1)*6)
2312 throw con::InvalidIncomingDataException
2313 ("DELETEDBLOCKS length is too short");
2314 v3s16 p = readV3S16(&data[2+1+i*6]);
2315 /*infostream<<"Server: DELETEDBLOCKS ("
2316 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2317 RemoteClient *client = getClient(peer_id);
2318 client->SetBlockNotSent(p);
2321 else if(command == TOSERVER_CLICK_OBJECT)
2323 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2326 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2331 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2337 [2] u8 button (0=left, 1=right)
2341 u8 button = readU8(&data[2]);
2342 u16 id = readS16(&data[3]);
2343 u16 item_i = readU16(&data[5]);
2345 ServerActiveObject *obj = m_env->getActiveObject(id);
2349 infostream<<"Server: CLICK_ACTIVEOBJECT: object not found"
2354 // Skip if object has been removed
2358 //TODO: Check that object is reasonably close
2360 // Get ServerRemotePlayer
2361 ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
2363 // Update wielded item
2364 srp->wieldItem(item_i);
2366 // Left click, pick/punch
2369 actionstream<<player->getName()<<" punches object "
2370 <<obj->getId()<<std::endl;
2377 Try creating inventory item
2379 InventoryItem *item = obj->createPickedUpItem();
2383 InventoryList *ilist = player->inventory.getList("main");
2386 actionstream<<player->getName()<<" picked up "
2387 <<item->getName()<<std::endl;
2388 if(g_settings->getBool("creative_mode") == false)
2390 // Skip if inventory has no free space
2391 if(ilist->roomForItem(item) == false)
2393 infostream<<"Player inventory has no free space"<<std::endl;
2397 // Add to inventory and send inventory
2398 ilist->addItem(item);
2399 UpdateCrafting(player->peer_id);
2400 SendInventory(player->peer_id);
2403 // Remove object from environment
2404 obj->m_removed = true;
2410 Item cannot be picked up. Punch it instead.
2413 actionstream<<player->getName()<<" punches object "
2414 <<obj->getId()<<std::endl;
2416 ToolItem *titem = NULL;
2417 std::string toolname = "";
2419 InventoryList *mlist = player->inventory.getList("main");
2422 InventoryItem *item = mlist->getItem(item_i);
2423 if(item && (std::string)item->getName() == "ToolItem")
2425 titem = (ToolItem*)item;
2426 toolname = titem->getToolName();
2430 v3f playerpos = player->getPosition();
2431 v3f objpos = obj->getBasePosition();
2432 v3f dir = (objpos - playerpos).normalize();
2434 u16 wear = obj->punch(toolname, dir, player->getName());
2438 bool weared_out = titem->addWear(wear);
2440 mlist->deleteItem(item_i);
2441 SendInventory(player->peer_id);
2446 // Right click, do something with object
2449 actionstream<<player->getName()<<" right clicks object "
2450 <<obj->getId()<<std::endl;
2453 obj->rightClick(srp);
2457 Update player state to client
2459 SendPlayerHP(player);
2460 UpdateCrafting(player->peer_id);
2461 SendInventory(player->peer_id);
2463 else if(command == TOSERVER_GROUND_ACTION)
2471 [3] v3s16 nodepos_undersurface
2472 [9] v3s16 nodepos_abovesurface
2477 2: stop digging (all parameters ignored)
2478 3: digging completed
2480 u8 action = readU8(&data[2]);
2482 p_under.X = readS16(&data[3]);
2483 p_under.Y = readS16(&data[5]);
2484 p_under.Z = readS16(&data[7]);
2486 p_over.X = readS16(&data[9]);
2487 p_over.Y = readS16(&data[11]);
2488 p_over.Z = readS16(&data[13]);
2489 u16 item_i = readU16(&data[15]);
2491 //TODO: Check that target is reasonably close
2499 NOTE: This can be used in the future to check if
2500 somebody is cheating, by checking the timing.
2507 else if(action == 2)
2510 RemoteClient *client = getClient(peer_id);
2511 JMutexAutoLock digmutex(client->m_dig_mutex);
2512 client->m_dig_tool_item = -1;
2517 3: Digging completed
2519 else if(action == 3)
2521 // Mandatory parameter; actually used for nothing
2522 core::map<v3s16, MapBlock*> modified_blocks;
2524 content_t material = CONTENT_IGNORE;
2525 u8 mineral = MINERAL_NONE;
2527 bool cannot_remove_node = false;
2531 MapNode n = m_env->getMap().getNode(p_under);
2533 mineral = n.getMineral(m_nodemgr);
2534 // Get material at position
2535 material = n.getContent();
2536 // If not yet cancelled
2537 if(cannot_remove_node == false)
2539 // If it's not diggable, do nothing
2540 if(m_nodemgr->get(material).diggable == false)
2542 infostream<<"Server: Not finishing digging: "
2543 <<"Node not diggable"
2545 cannot_remove_node = true;
2548 // If not yet cancelled
2549 if(cannot_remove_node == false)
2551 // Get node metadata
2552 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
2553 if(meta && meta->nodeRemovalDisabled() == true)
2555 infostream<<"Server: Not finishing digging: "
2556 <<"Node metadata disables removal"
2558 cannot_remove_node = true;
2562 catch(InvalidPositionException &e)
2564 infostream<<"Server: Not finishing digging: Node not found."
2565 <<" Adding block to emerge queue."
2567 m_emerge_queue.addBlock(peer_id,
2568 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2569 cannot_remove_node = true;
2572 // Make sure the player is allowed to do it
2573 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2575 infostream<<"Player "<<player->getName()<<" cannot remove node"
2576 <<" because privileges are "<<getPlayerPrivs(player)
2578 cannot_remove_node = true;
2582 If node can't be removed, set block to be re-sent to
2585 if(cannot_remove_node)
2587 infostream<<"Server: Not finishing digging."<<std::endl;
2589 // Client probably has wrong data.
2590 // Set block not sent, so that client will get
2592 infostream<<"Client "<<peer_id<<" tried to dig "
2593 <<"node; but node cannot be removed."
2594 <<" setting MapBlock not sent."<<std::endl;
2595 RemoteClient *client = getClient(peer_id);
2596 v3s16 blockpos = getNodeBlockPos(p_under);
2597 client->SetBlockNotSent(blockpos);
2602 actionstream<<player->getName()<<" digs "<<PP(p_under)
2603 <<", gets material "<<(int)material<<", mineral "
2604 <<(int)mineral<<std::endl;
2607 Send the removal to all close-by players.
2608 - If other player is close, send REMOVENODE
2609 - Otherwise set blocks not sent
2611 core::list<u16> far_players;
2612 sendRemoveNode(p_under, peer_id, &far_players, 30);
2615 Update and send inventory
2618 if(g_settings->getBool("creative_mode") == false)
2623 InventoryList *mlist = player->inventory.getList("main");
2626 InventoryItem *item = mlist->getItem(item_i);
2627 if(item && (std::string)item->getName() == "ToolItem")
2629 ToolItem *titem = (ToolItem*)item;
2630 std::string toolname = titem->getToolName();
2632 // Get digging properties for material and tool
2633 ToolDiggingProperties tp =
2634 m_toolmgr->getDiggingProperties(toolname);
2635 DiggingProperties prop =
2636 getDiggingProperties(material, &tp, m_nodemgr);
2638 if(prop.diggable == false)
2640 infostream<<"Server: WARNING: Player digged"
2641 <<" with impossible material + tool"
2642 <<" combination"<<std::endl;
2645 bool weared_out = titem->addWear(prop.wear);
2649 mlist->deleteItem(item_i);
2655 Add dug item to inventory
2658 InventoryItem *item = NULL;
2660 if(mineral != MINERAL_NONE)
2661 item = getDiggedMineralItem(mineral, this);
2666 const std::string &dug_s = m_nodemgr->get(material).dug_item;
2669 std::istringstream is(dug_s, std::ios::binary);
2670 item = InventoryItem::deSerialize(is, this);
2676 // Add a item to inventory
2677 player->inventory.addItem("main", item);
2680 UpdateCrafting(player->peer_id);
2681 SendInventory(player->peer_id);
2686 if(mineral != MINERAL_NONE)
2687 item = getDiggedMineralItem(mineral, this);
2692 const std::string &extra_dug_s = m_nodemgr->get(material).extra_dug_item;
2693 s32 extra_rarity = m_nodemgr->get(material).extra_dug_item_rarity;
2694 if(extra_dug_s != "" && extra_rarity != 0
2695 && myrand() % extra_rarity == 0)
2697 std::istringstream is(extra_dug_s, std::ios::binary);
2698 item = InventoryItem::deSerialize(is, this);
2704 // Add a item to inventory
2705 player->inventory.addItem("main", item);
2708 UpdateCrafting(player->peer_id);
2709 SendInventory(player->peer_id);
2715 (this takes some time so it is done after the quick stuff)
2718 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2720 m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
2723 Set blocks not sent to far players
2725 for(core::list<u16>::Iterator
2726 i = far_players.begin();
2727 i != far_players.end(); i++)
2730 RemoteClient *client = getClient(peer_id);
2733 client->SetBlocksNotSent(modified_blocks);
2740 else if(action == 1)
2743 InventoryList *ilist = player->inventory.getList("main");
2748 InventoryItem *item = ilist->getItem(item_i);
2750 // If there is no item, it is not possible to add it anywhere
2755 Handle material items
2757 if(std::string("MaterialItem") == item->getName())
2760 // Don't add a node if this is not a free space
2761 MapNode n2 = m_env->getMap().getNode(p_over);
2762 bool no_enough_privs =
2763 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2765 infostream<<"Player "<<player->getName()<<" cannot add node"
2766 <<" because privileges are "<<getPlayerPrivs(player)
2769 if(m_nodemgr->get(n2).buildable_to == false
2772 // Client probably has wrong data.
2773 // Set block not sent, so that client will get
2775 infostream<<"Client "<<peer_id<<" tried to place"
2776 <<" node in invalid position; setting"
2777 <<" MapBlock not sent."<<std::endl;
2778 RemoteClient *client = getClient(peer_id);
2779 v3s16 blockpos = getNodeBlockPos(p_over);
2780 client->SetBlockNotSent(blockpos);
2784 catch(InvalidPositionException &e)
2786 infostream<<"Server: Ignoring ADDNODE: Node not found"
2787 <<" Adding block to emerge queue."
2789 m_emerge_queue.addBlock(peer_id,
2790 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2794 // Reset build time counter
2795 getClient(peer_id)->m_time_from_building = 0.0;
2798 MaterialItem *mitem = (MaterialItem*)item;
2800 n.setContent(mitem->getMaterial());
2802 actionstream<<player->getName()<<" places material "
2803 <<(int)mitem->getMaterial()
2804 <<" at "<<PP(p_under)<<std::endl;
2806 // Calculate direction for wall mounted stuff
2807 if(m_nodemgr->get(n).wall_mounted)
2808 n.param2 = packDir(p_under - p_over);
2810 // Calculate the direction for furnaces and chests and stuff
2811 if(m_nodemgr->get(n).param_type == CPT_FACEDIR_SIMPLE)
2813 v3f playerpos = player->getPosition();
2814 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2815 blockpos = blockpos.normalize();
2817 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2831 Send to all close-by players
2833 core::list<u16> far_players;
2834 sendAddNode(p_over, n, 0, &far_players, 30);
2839 InventoryList *ilist = player->inventory.getList("main");
2840 if(g_settings->getBool("creative_mode") == false && ilist)
2842 // Remove from inventory and send inventory
2843 if(mitem->getCount() == 1)
2844 ilist->deleteItem(item_i);
2848 UpdateCrafting(peer_id);
2849 SendInventory(peer_id);
2855 This takes some time so it is done after the quick stuff
2857 core::map<v3s16, MapBlock*> modified_blocks;
2859 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2861 std::string p_name = std::string(player->getName());
2862 m_env->getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
2865 Set blocks not sent to far players
2867 for(core::list<u16>::Iterator
2868 i = far_players.begin();
2869 i != far_players.end(); i++)
2872 RemoteClient *client = getClient(peer_id);
2875 client->SetBlocksNotSent(modified_blocks);
2879 Calculate special events
2882 /*if(n.d == CONTENT_MESE)
2885 for(s16 z=-1; z<=1; z++)
2886 for(s16 y=-1; y<=1; y++)
2887 for(s16 x=-1; x<=1; x++)
2894 Place other item (not a block)
2898 v3s16 blockpos = getNodeBlockPos(p_over);
2901 Check that the block is loaded so that the item
2902 can properly be added to the static list too
2904 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2907 infostream<<"Error while placing object: "
2908 "block not found"<<std::endl;
2913 If in creative mode, item dropping is disabled unless
2914 player has build privileges
2916 if(g_settings->getBool("creative_mode") &&
2917 (getPlayerPrivs(player) & PRIV_BUILD) == 0)
2919 infostream<<"Not allowing player to drop item: "
2920 "creative mode and no build privs"<<std::endl;
2924 // Calculate a position for it
2925 v3f pos = intToFloat(p_over, BS);
2927 /*pos.Y -= BS*0.25; // let it drop a bit
2929 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2930 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;*/
2935 ServerActiveObject *obj = item->createSAO(m_env, 0, pos);
2939 infostream<<"WARNING: item resulted in NULL object, "
2940 <<"not placing onto map"
2945 actionstream<<player->getName()<<" places "<<item->getName()
2946 <<" at "<<PP(p_over)<<std::endl;
2948 // Add the object to the environment
2949 m_env->addActiveObject(obj);
2951 infostream<<"Placed object"<<std::endl;
2953 if(g_settings->getBool("creative_mode") == false)
2955 // Delete the right amount of items from the slot
2956 u16 dropcount = item->getDropCount();
2958 // Delete item if all gone
2959 if(item->getCount() <= dropcount)
2961 if(item->getCount() < dropcount)
2962 infostream<<"WARNING: Server: dropped more items"
2963 <<" than the slot contains"<<std::endl;
2965 InventoryList *ilist = player->inventory.getList("main");
2967 // Remove from inventory and send inventory
2968 ilist->deleteItem(item_i);
2970 // Else decrement it
2972 item->remove(dropcount);
2975 UpdateCrafting(peer_id);
2976 SendInventory(peer_id);
2984 Catch invalid actions
2988 infostream<<"WARNING: Server: Invalid action "
2989 <<action<<std::endl;
2993 else if(command == TOSERVER_RELEASE)
3002 infostream<<"TOSERVER_RELEASE ignored"<<std::endl;
3005 else if(command == TOSERVER_SIGNTEXT)
3007 infostream<<"Server: TOSERVER_SIGNTEXT not supported anymore"
3011 else if(command == TOSERVER_SIGNNODETEXT)
3013 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3021 std::string datastring((char*)&data[2], datasize-2);
3022 std::istringstream is(datastring, std::ios_base::binary);
3025 is.read((char*)buf, 6);
3026 v3s16 p = readV3S16(buf);
3027 is.read((char*)buf, 2);
3028 u16 textlen = readU16(buf);
3030 for(u16 i=0; i<textlen; i++)
3032 is.read((char*)buf, 1);
3033 text += (char)buf[0];
3036 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3039 if(meta->typeId() != CONTENT_SIGN_WALL)
3041 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3042 signmeta->setText(text);
3044 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign "
3045 <<" at "<<PP(p)<<std::endl;
3047 v3s16 blockpos = getNodeBlockPos(p);
3048 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3051 block->setChangedFlag();
3054 for(core::map<u16, RemoteClient*>::Iterator
3055 i = m_clients.getIterator();
3056 i.atEnd()==false; i++)
3058 RemoteClient *client = i.getNode()->getValue();
3059 client->SetBlockNotSent(blockpos);
3062 else if(command == TOSERVER_INVENTORY_ACTION)
3064 /*// Ignore inventory changes if in creative mode
3065 if(g_settings->getBool("creative_mode") == true)
3067 infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3071 // Strip command and create a stream
3072 std::string datastring((char*)&data[2], datasize-2);
3073 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3074 std::istringstream is(datastring, std::ios_base::binary);
3076 InventoryAction *a = InventoryAction::deSerialize(is);
3081 c.current_player = player;
3084 Handle craftresult specially if not in creative mode
3086 bool disable_action = false;
3087 if(a->getType() == IACTION_MOVE
3088 && g_settings->getBool("creative_mode") == false)
3090 IMoveAction *ma = (IMoveAction*)a;
3091 if(ma->to_inv == "current_player" &&
3092 ma->from_inv == "current_player")
3094 InventoryList *rlist = player->inventory.getList("craftresult");
3096 InventoryList *clist = player->inventory.getList("craft");
3098 InventoryList *mlist = player->inventory.getList("main");
3101 Craftresult is no longer preview if something
3104 if(ma->to_list == "craftresult"
3105 && ma->from_list != "craftresult")
3107 // If it currently is a preview, remove
3109 if(player->craftresult_is_preview)
3111 rlist->deleteItem(0);
3113 player->craftresult_is_preview = false;
3116 Crafting takes place if this condition is true.
3118 if(player->craftresult_is_preview &&
3119 ma->from_list == "craftresult")
3121 player->craftresult_is_preview = false;
3122 clist->decrementMaterials(1);
3124 /* Print out action */
3125 InventoryList *list =
3126 player->inventory.getList("craftresult");
3128 InventoryItem *item = list->getItem(0);
3129 std::string itemname = "NULL";
3131 itemname = item->getName();
3132 actionstream<<player->getName()<<" crafts "
3133 <<itemname<<std::endl;
3136 If the craftresult is placed on itself, move it to
3137 main inventory instead of doing the action
3139 if(ma->to_list == "craftresult"
3140 && ma->from_list == "craftresult")
3142 disable_action = true;
3144 InventoryItem *item1 = rlist->changeItem(0, NULL);
3145 mlist->addItem(item1);
3148 // Disallow moving items if not allowed to build
3149 else if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3153 // if it's a locking chest, only allow the owner or server admins to move items
3154 else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3156 Strfnd fn(ma->from_inv);
3157 std::string id0 = fn.next(":");
3158 if(id0 == "nodemeta")
3161 p.X = stoi(fn.next(","));
3162 p.Y = stoi(fn.next(","));
3163 p.Z = stoi(fn.next(","));
3164 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3165 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3166 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3167 if (lcm->getOwner() != player->getName())
3172 else if (ma->to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3174 Strfnd fn(ma->to_inv);
3175 std::string id0 = fn.next(":");
3176 if(id0 == "nodemeta")
3179 p.X = stoi(fn.next(","));
3180 p.Y = stoi(fn.next(","));
3181 p.Z = stoi(fn.next(","));
3182 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3183 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3184 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3185 if (lcm->getOwner() != player->getName())
3192 if(disable_action == false)
3194 // Feed action to player inventory
3202 UpdateCrafting(player->peer_id);
3203 SendInventory(player->peer_id);
3208 infostream<<"TOSERVER_INVENTORY_ACTION: "
3209 <<"InventoryAction::deSerialize() returned NULL"
3213 else if(command == TOSERVER_CHAT_MESSAGE)
3221 std::string datastring((char*)&data[2], datasize-2);
3222 std::istringstream is(datastring, std::ios_base::binary);
3225 is.read((char*)buf, 2);
3226 u16 len = readU16(buf);
3228 std::wstring message;
3229 for(u16 i=0; i<len; i++)
3231 is.read((char*)buf, 2);
3232 message += (wchar_t)readU16(buf);
3235 // Get player name of this client
3236 std::wstring name = narrow_to_wide(player->getName());
3238 // Line to send to players
3240 // Whether to send to the player that sent the line
3241 bool send_to_sender = false;
3242 // Whether to send to other players
3243 bool send_to_others = false;
3245 // Local player gets all privileges regardless of
3246 // what's set on their account.
3247 u64 privs = getPlayerPrivs(player);
3250 if(message[0] == L'/')
3252 size_t strip_size = 1;
3253 if (message[1] == L'#') // support old-style commans
3255 message = message.substr(strip_size);
3257 WStrfnd f1(message);
3258 f1.next(L" "); // Skip over /#whatever
3259 std::wstring paramstring = f1.next(L"");
3261 ServerCommandContext *ctx = new ServerCommandContext(
3262 str_split(message, L' '),
3269 std::wstring reply(processServerCommand(ctx));
3270 send_to_sender = ctx->flags & SEND_TO_SENDER;
3271 send_to_others = ctx->flags & SEND_TO_OTHERS;
3273 if (ctx->flags & SEND_NO_PREFIX)
3276 line += L"Server: " + reply;
3283 if(privs & PRIV_SHOUT)
3289 send_to_others = true;
3293 line += L"Server: You are not allowed to shout";
3294 send_to_sender = true;
3301 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3304 Send the message to clients
3306 for(core::map<u16, RemoteClient*>::Iterator
3307 i = m_clients.getIterator();
3308 i.atEnd() == false; i++)
3310 // Get client and check that it is valid
3311 RemoteClient *client = i.getNode()->getValue();
3312 assert(client->peer_id == i.getNode()->getKey());
3313 if(client->serialization_version == SER_FMT_VER_INVALID)
3317 bool sender_selected = (peer_id == client->peer_id);
3318 if(sender_selected == true && send_to_sender == false)
3320 if(sender_selected == false && send_to_others == false)
3323 SendChatMessage(client->peer_id, line);
3327 else if(command == TOSERVER_DAMAGE)
3329 std::string datastring((char*)&data[2], datasize-2);
3330 std::istringstream is(datastring, std::ios_base::binary);
3331 u8 damage = readU8(is);
3333 if(g_settings->getBool("enable_damage"))
3335 actionstream<<player->getName()<<" damaged by "
3336 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
3339 HandlePlayerHP(player, damage);
3343 SendPlayerHP(player);
3346 else if(command == TOSERVER_PASSWORD)
3349 [0] u16 TOSERVER_PASSWORD
3350 [2] u8[28] old password
3351 [30] u8[28] new password
3354 if(datasize != 2+PASSWORD_SIZE*2)
3356 /*char password[PASSWORD_SIZE];
3357 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3358 password[i] = data[2+i];
3359 password[PASSWORD_SIZE-1] = 0;*/
3361 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3369 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3371 char c = data[2+PASSWORD_SIZE+i];
3377 infostream<<"Server: Client requests a password change from "
3378 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3380 std::string playername = player->getName();
3382 if(m_authmanager.exists(playername) == false)
3384 infostream<<"Server: playername not found in authmanager"<<std::endl;
3385 // Wrong old password supplied!!
3386 SendChatMessage(peer_id, L"playername not found in authmanager");
3390 std::string checkpwd = m_authmanager.getPassword(playername);
3392 if(oldpwd != checkpwd)
3394 infostream<<"Server: invalid old password"<<std::endl;
3395 // Wrong old password supplied!!
3396 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3400 actionstream<<player->getName()<<" changes password"<<std::endl;
3402 m_authmanager.setPassword(playername, newpwd);
3404 infostream<<"Server: password change successful for "<<playername
3406 SendChatMessage(peer_id, L"Password change successful");
3408 else if(command == TOSERVER_PLAYERITEM)
3413 u16 item = readU16(&data[2]);
3414 player->wieldItem(item);
3415 SendWieldedItem(player);
3417 else if(command == TOSERVER_RESPAWN)
3422 RespawnPlayer(player);
3424 actionstream<<player->getName()<<" respawns at "
3425 <<PP(player->getPosition()/BS)<<std::endl;
3429 infostream<<"Server::ProcessData(): Ignoring "
3430 "unknown command "<<command<<std::endl;
3434 catch(SendFailedException &e)
3436 errorstream<<"Server::ProcessData(): SendFailedException: "
3442 void Server::onMapEditEvent(MapEditEvent *event)
3444 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3445 if(m_ignore_map_edit_events)
3447 MapEditEvent *e = event->clone();
3448 m_unsent_map_edit_queue.push_back(e);
3451 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3453 if(id == "current_player")
3455 assert(c->current_player);
3456 return &(c->current_player->inventory);
3460 std::string id0 = fn.next(":");
3462 if(id0 == "nodemeta")
3465 p.X = stoi(fn.next(","));
3466 p.Y = stoi(fn.next(","));
3467 p.Z = stoi(fn.next(","));
3468 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3470 return meta->getInventory();
3471 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3472 <<"no metadata found"<<std::endl;
3476 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3479 void Server::inventoryModified(InventoryContext *c, std::string id)
3481 if(id == "current_player")
3483 assert(c->current_player);
3485 UpdateCrafting(c->current_player->peer_id);
3486 SendInventory(c->current_player->peer_id);
3491 std::string id0 = fn.next(":");
3493 if(id0 == "nodemeta")
3496 p.X = stoi(fn.next(","));
3497 p.Y = stoi(fn.next(","));
3498 p.Z = stoi(fn.next(","));
3499 v3s16 blockpos = getNodeBlockPos(p);
3501 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3503 meta->inventoryModified();
3505 for(core::map<u16, RemoteClient*>::Iterator
3506 i = m_clients.getIterator();
3507 i.atEnd()==false; i++)
3509 RemoteClient *client = i.getNode()->getValue();
3510 client->SetBlockNotSent(blockpos);
3516 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3519 core::list<PlayerInfo> Server::getPlayerInfo()
3521 DSTACK(__FUNCTION_NAME);
3522 JMutexAutoLock envlock(m_env_mutex);
3523 JMutexAutoLock conlock(m_con_mutex);
3525 core::list<PlayerInfo> list;
3527 core::list<Player*> players = m_env->getPlayers();
3529 core::list<Player*>::Iterator i;
3530 for(i = players.begin();
3531 i != players.end(); i++)
3535 Player *player = *i;
3538 // Copy info from connection to info struct
3539 info.id = player->peer_id;
3540 info.address = m_con.GetPeerAddress(player->peer_id);
3541 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3543 catch(con::PeerNotFoundException &e)
3545 // Set dummy peer info
3547 info.address = Address(0,0,0,0,0);
3551 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3552 info.position = player->getPosition();
3554 list.push_back(info);
3561 void Server::peerAdded(con::Peer *peer)
3563 DSTACK(__FUNCTION_NAME);
3564 infostream<<"Server::peerAdded(): peer->id="
3565 <<peer->id<<std::endl;
3568 c.type = PEER_ADDED;
3569 c.peer_id = peer->id;
3571 m_peer_change_queue.push_back(c);
3574 void Server::deletingPeer(con::Peer *peer, bool timeout)
3576 DSTACK(__FUNCTION_NAME);
3577 infostream<<"Server::deletingPeer(): peer->id="
3578 <<peer->id<<", timeout="<<timeout<<std::endl;
3581 c.type = PEER_REMOVED;
3582 c.peer_id = peer->id;
3583 c.timeout = timeout;
3584 m_peer_change_queue.push_back(c);
3591 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3593 DSTACK(__FUNCTION_NAME);
3594 std::ostringstream os(std::ios_base::binary);
3596 writeU16(os, TOCLIENT_HP);
3600 std::string s = os.str();
3601 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3603 con.Send(peer_id, 0, data, true);
3606 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3607 const std::wstring &reason)
3609 DSTACK(__FUNCTION_NAME);
3610 std::ostringstream os(std::ios_base::binary);
3612 writeU16(os, TOCLIENT_ACCESS_DENIED);
3613 os<<serializeWideString(reason);
3616 std::string s = os.str();
3617 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3619 con.Send(peer_id, 0, data, true);
3622 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3623 bool set_camera_point_target, v3f camera_point_target)
3625 DSTACK(__FUNCTION_NAME);
3626 std::ostringstream os(std::ios_base::binary);
3628 writeU16(os, TOCLIENT_DEATHSCREEN);
3629 writeU8(os, set_camera_point_target);
3630 writeV3F1000(os, camera_point_target);
3633 std::string s = os.str();
3634 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3636 con.Send(peer_id, 0, data, true);
3639 void Server::SendToolDef(con::Connection &con, u16 peer_id,
3640 IToolDefManager *tooldef)
3642 DSTACK(__FUNCTION_NAME);
3643 infostream<<"Server: Sending tool definitions"<<std::endl;
3644 std::ostringstream os(std::ios_base::binary);
3648 u32 length of the next item
3649 serialized ToolDefManager
3651 writeU16(os, TOCLIENT_TOOLDEF);
3652 std::ostringstream tmp_os(std::ios::binary);
3653 tooldef->serialize(tmp_os);
3654 os<<serializeLongString(tmp_os.str());
3657 std::string s = os.str();
3658 infostream<<"Server: Sending tool definitions: data size: "
3659 <<s.size()<<std::endl;
3660 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3662 con.Send(peer_id, 0, data, true);
3665 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3666 INodeDefManager *nodedef)
3668 DSTACK(__FUNCTION_NAME);
3669 infostream<<"Server: Sending node definitions"<<std::endl;
3670 std::ostringstream os(std::ios_base::binary);
3674 u32 length of the next item
3675 serialized NodeDefManager
3677 writeU16(os, TOCLIENT_NODEDEF);
3678 std::ostringstream tmp_os(std::ios::binary);
3679 nodedef->serialize(tmp_os);
3680 os<<serializeLongString(tmp_os.str());
3683 std::string s = os.str();
3684 infostream<<"Server: Sending node definitions: data size: "
3685 <<s.size()<<std::endl;
3686 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3688 con.Send(peer_id, 0, data, true);
3692 Non-static send methods
3695 void Server::SendObjectData(float dtime)
3697 DSTACK(__FUNCTION_NAME);
3699 core::map<v3s16, bool> stepped_blocks;
3701 for(core::map<u16, RemoteClient*>::Iterator
3702 i = m_clients.getIterator();
3703 i.atEnd() == false; i++)
3705 u16 peer_id = i.getNode()->getKey();
3706 RemoteClient *client = i.getNode()->getValue();
3707 assert(client->peer_id == peer_id);
3709 if(client->serialization_version == SER_FMT_VER_INVALID)
3712 client->SendObjectData(this, dtime, stepped_blocks);
3716 void Server::SendPlayerInfos()
3718 DSTACK(__FUNCTION_NAME);
3720 //JMutexAutoLock envlock(m_env_mutex);
3722 // Get connected players
3723 core::list<Player*> players = m_env->getPlayers(true);
3725 u32 player_count = players.getSize();
3726 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3728 SharedBuffer<u8> data(datasize);
3729 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3732 core::list<Player*>::Iterator i;
3733 for(i = players.begin();
3734 i != players.end(); i++)
3736 Player *player = *i;
3738 /*infostream<<"Server sending player info for player with "
3739 "peer_id="<<player->peer_id<<std::endl;*/
3741 writeU16(&data[start], player->peer_id);
3742 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3743 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3744 start += 2+PLAYERNAME_SIZE;
3747 //JMutexAutoLock conlock(m_con_mutex);
3750 m_con.SendToAll(0, data, true);
3753 void Server::SendInventory(u16 peer_id)
3755 DSTACK(__FUNCTION_NAME);
3757 Player* player = m_env->getPlayer(peer_id);
3764 std::ostringstream os;
3765 //os.imbue(std::locale("C"));
3767 player->inventory.serialize(os);
3769 std::string s = os.str();
3771 SharedBuffer<u8> data(s.size()+2);
3772 writeU16(&data[0], TOCLIENT_INVENTORY);
3773 memcpy(&data[2], s.c_str(), s.size());
3776 m_con.Send(peer_id, 0, data, true);
3779 std::string getWieldedItemString(const Player *player)
3781 const InventoryItem *item = player->getWieldItem();
3783 return std::string("");
3784 std::ostringstream os(std::ios_base::binary);
3785 item->serialize(os);
3789 void Server::SendWieldedItem(const Player* player)
3791 DSTACK(__FUNCTION_NAME);
3795 std::ostringstream os(std::ios_base::binary);
3797 writeU16(os, TOCLIENT_PLAYERITEM);
3799 writeU16(os, player->peer_id);
3800 os<<serializeString(getWieldedItemString(player));
3803 std::string s = os.str();
3804 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3806 m_con.SendToAll(0, data, true);
3809 void Server::SendPlayerItems()
3811 DSTACK(__FUNCTION_NAME);
3813 std::ostringstream os(std::ios_base::binary);
3814 core::list<Player *> players = m_env->getPlayers(true);
3816 writeU16(os, TOCLIENT_PLAYERITEM);
3817 writeU16(os, players.size());
3818 core::list<Player *>::Iterator i;
3819 for(i = players.begin(); i != players.end(); ++i)
3822 writeU16(os, p->peer_id);
3823 os<<serializeString(getWieldedItemString(p));
3827 std::string s = os.str();
3828 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3830 m_con.SendToAll(0, data, true);
3833 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3835 DSTACK(__FUNCTION_NAME);
3837 std::ostringstream os(std::ios_base::binary);
3841 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3842 os.write((char*)buf, 2);
3845 writeU16(buf, message.size());
3846 os.write((char*)buf, 2);
3849 for(u32 i=0; i<message.size(); i++)
3853 os.write((char*)buf, 2);
3857 std::string s = os.str();
3858 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3860 m_con.Send(peer_id, 0, data, true);
3863 void Server::BroadcastChatMessage(const std::wstring &message)
3865 for(core::map<u16, RemoteClient*>::Iterator
3866 i = m_clients.getIterator();
3867 i.atEnd() == false; i++)
3869 // Get client and check that it is valid
3870 RemoteClient *client = i.getNode()->getValue();
3871 assert(client->peer_id == i.getNode()->getKey());
3872 if(client->serialization_version == SER_FMT_VER_INVALID)
3875 SendChatMessage(client->peer_id, message);
3879 void Server::SendPlayerHP(Player *player)
3881 SendHP(m_con, player->peer_id, player->hp);
3884 void Server::SendMovePlayer(Player *player)
3886 DSTACK(__FUNCTION_NAME);
3887 std::ostringstream os(std::ios_base::binary);
3889 writeU16(os, TOCLIENT_MOVE_PLAYER);
3890 writeV3F1000(os, player->getPosition());
3891 writeF1000(os, player->getPitch());
3892 writeF1000(os, player->getYaw());
3895 v3f pos = player->getPosition();
3896 f32 pitch = player->getPitch();
3897 f32 yaw = player->getYaw();
3898 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
3899 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3906 std::string s = os.str();
3907 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3909 m_con.Send(player->peer_id, 0, data, true);
3912 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3913 core::list<u16> *far_players, float far_d_nodes)
3915 float maxd = far_d_nodes*BS;
3916 v3f p_f = intToFloat(p, BS);
3920 SharedBuffer<u8> reply(replysize);
3921 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3922 writeS16(&reply[2], p.X);
3923 writeS16(&reply[4], p.Y);
3924 writeS16(&reply[6], p.Z);
3926 for(core::map<u16, RemoteClient*>::Iterator
3927 i = m_clients.getIterator();
3928 i.atEnd() == false; i++)
3930 // Get client and check that it is valid
3931 RemoteClient *client = i.getNode()->getValue();
3932 assert(client->peer_id == i.getNode()->getKey());
3933 if(client->serialization_version == SER_FMT_VER_INVALID)
3936 // Don't send if it's the same one
3937 if(client->peer_id == ignore_id)
3943 Player *player = m_env->getPlayer(client->peer_id);
3946 // If player is far away, only set modified blocks not sent
3947 v3f player_pos = player->getPosition();
3948 if(player_pos.getDistanceFrom(p_f) > maxd)
3950 far_players->push_back(client->peer_id);
3957 m_con.Send(client->peer_id, 0, reply, true);
3961 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3962 core::list<u16> *far_players, float far_d_nodes)
3964 float maxd = far_d_nodes*BS;
3965 v3f p_f = intToFloat(p, BS);
3967 for(core::map<u16, RemoteClient*>::Iterator
3968 i = m_clients.getIterator();
3969 i.atEnd() == false; i++)
3971 // Get client and check that it is valid
3972 RemoteClient *client = i.getNode()->getValue();
3973 assert(client->peer_id == i.getNode()->getKey());
3974 if(client->serialization_version == SER_FMT_VER_INVALID)
3977 // Don't send if it's the same one
3978 if(client->peer_id == ignore_id)
3984 Player *player = m_env->getPlayer(client->peer_id);
3987 // If player is far away, only set modified blocks not sent
3988 v3f player_pos = player->getPosition();
3989 if(player_pos.getDistanceFrom(p_f) > maxd)
3991 far_players->push_back(client->peer_id);
3998 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3999 SharedBuffer<u8> reply(replysize);
4000 writeU16(&reply[0], TOCLIENT_ADDNODE);
4001 writeS16(&reply[2], p.X);
4002 writeS16(&reply[4], p.Y);
4003 writeS16(&reply[6], p.Z);
4004 n.serialize(&reply[8], client->serialization_version);
4007 m_con.Send(client->peer_id, 0, reply, true);
4011 void Server::setBlockNotSent(v3s16 p)
4013 for(core::map<u16, RemoteClient*>::Iterator
4014 i = m_clients.getIterator();
4015 i.atEnd()==false; i++)
4017 RemoteClient *client = i.getNode()->getValue();
4018 client->SetBlockNotSent(p);
4022 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4024 DSTACK(__FUNCTION_NAME);
4026 v3s16 p = block->getPos();
4030 bool completely_air = true;
4031 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4032 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4033 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4035 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4037 completely_air = false;
4038 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4043 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4045 infostream<<"[completely air] ";
4046 infostream<<std::endl;
4050 Create a packet with the block in the right format
4053 std::ostringstream os(std::ios_base::binary);
4054 block->serialize(os, ver);
4055 std::string s = os.str();
4056 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4058 u32 replysize = 8 + blockdata.getSize();
4059 SharedBuffer<u8> reply(replysize);
4060 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4061 writeS16(&reply[2], p.X);
4062 writeS16(&reply[4], p.Y);
4063 writeS16(&reply[6], p.Z);
4064 memcpy(&reply[8], *blockdata, blockdata.getSize());
4066 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4067 <<": \tpacket size: "<<replysize<<std::endl;*/
4072 m_con.Send(peer_id, 1, reply, true);
4075 void Server::SendBlocks(float dtime)
4077 DSTACK(__FUNCTION_NAME);
4079 JMutexAutoLock envlock(m_env_mutex);
4080 JMutexAutoLock conlock(m_con_mutex);
4082 //TimeTaker timer("Server::SendBlocks");
4084 core::array<PrioritySortedBlockTransfer> queue;
4086 s32 total_sending = 0;
4089 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4091 for(core::map<u16, RemoteClient*>::Iterator
4092 i = m_clients.getIterator();
4093 i.atEnd() == false; i++)
4095 RemoteClient *client = i.getNode()->getValue();
4096 assert(client->peer_id == i.getNode()->getKey());
4098 total_sending += client->SendingCount();
4100 if(client->serialization_version == SER_FMT_VER_INVALID)
4103 client->GetNextBlocks(this, dtime, queue);
4108 // Lowest priority number comes first.
4109 // Lowest is most important.
4112 for(u32 i=0; i<queue.size(); i++)
4114 //TODO: Calculate limit dynamically
4115 if(total_sending >= g_settings->getS32
4116 ("max_simultaneous_block_sends_server_total"))
4119 PrioritySortedBlockTransfer q = queue[i];
4121 MapBlock *block = NULL;
4124 block = m_env->getMap().getBlockNoCreate(q.pos);
4126 catch(InvalidPositionException &e)
4131 RemoteClient *client = getClient(q.peer_id);
4133 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4135 client->SentBlock(q.pos);
4141 struct SendableTexture
4147 SendableTexture(const std::string &name_="", const std::string path_="",
4148 const std::string &data_=""):
4155 void Server::SendTextures(u16 peer_id)
4157 DSTACK(__FUNCTION_NAME);
4159 infostream<<"Server::SendTextures(): Sending textures to client"<<std::endl;
4163 core::list<SendableTexture> textures;
4164 core::list<ModSpec> mods = getMods(m_modspaths);
4165 for(core::list<ModSpec>::Iterator i = mods.begin();
4166 i != mods.end(); i++){
4168 std::string texturepath = mod.path + DIR_DELIM + "textures";
4169 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
4170 for(u32 j=0; j<dirlist.size(); j++){
4171 if(dirlist[j].dir) // Ignode dirs
4173 std::string tname = dirlist[j].name;
4174 std::string tpath = texturepath + DIR_DELIM + tname;
4176 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4177 if(fis.good() == false){
4178 errorstream<<"Server::SendTextures(): Could not open \""
4179 <<tname<<"\" for reading"<<std::endl;
4182 std::ostringstream tmp_os(std::ios_base::binary);
4186 fis.read(buf, 1024);
4187 std::streamsize len = fis.gcount();
4188 tmp_os.write(buf, len);
4197 errorstream<<"Server::SendTextures(): Failed to read \""
4198 <<tname<<"\""<<std::endl;
4201 errorstream<<"Server::SendTextures(): Loaded \""
4202 <<tname<<"\""<<std::endl;
4204 textures.push_back(SendableTexture(tname, tpath, tmp_os.str()));
4208 /* Create and send packet */
4212 u32 number of textures
4220 std::ostringstream os(std::ios_base::binary);
4222 writeU16(os, TOCLIENT_TEXTURES);
4223 writeU32(os, textures.size());
4225 for(core::list<SendableTexture>::Iterator i = textures.begin();
4226 i != textures.end(); i++){
4227 os<<serializeString(i->name);
4228 os<<serializeLongString(i->data);
4232 std::string s = os.str();
4233 infostream<<"Server::SendTextures(): number of textures: "
4234 <<textures.size()<<", data size: "<<s.size()<<std::endl;
4235 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4237 m_con.Send(peer_id, 0, data, true);
4244 void Server::HandlePlayerHP(Player *player, s16 damage)
4246 if(player->hp > damage)
4248 player->hp -= damage;
4249 SendPlayerHP(player);
4253 infostream<<"Server::HandlePlayerHP(): Player "
4254 <<player->getName()<<" dies"<<std::endl;
4258 //TODO: Throw items around
4260 // Handle players that are not connected
4261 if(player->peer_id == PEER_ID_INEXISTENT){
4262 RespawnPlayer(player);
4266 SendPlayerHP(player);
4268 RemoteClient *client = getClient(player->peer_id);
4269 if(client->net_proto_version >= 3)
4271 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4275 RespawnPlayer(player);
4280 void Server::RespawnPlayer(Player *player)
4282 v3f pos = findSpawnPos(m_env->getServerMap());
4283 player->setPosition(pos);
4285 SendMovePlayer(player);
4286 SendPlayerHP(player);
4289 void Server::UpdateCrafting(u16 peer_id)
4291 DSTACK(__FUNCTION_NAME);
4293 Player* player = m_env->getPlayer(peer_id);
4297 Calculate crafting stuff
4299 if(g_settings->getBool("creative_mode") == false)
4301 InventoryList *clist = player->inventory.getList("craft");
4302 InventoryList *rlist = player->inventory.getList("craftresult");
4304 if(rlist && rlist->getUsedSlots() == 0)
4305 player->craftresult_is_preview = true;
4307 if(rlist && player->craftresult_is_preview)
4309 rlist->clearItems();
4311 if(clist && rlist && player->craftresult_is_preview)
4313 InventoryItem *items[9];
4314 for(u16 i=0; i<9; i++)
4316 items[i] = clist->getItem(i);
4319 // Get result of crafting grid
4320 InventoryItem *result = craft_get_result(items, this);
4322 rlist->addItem(result);
4325 } // if creative_mode == false
4328 RemoteClient* Server::getClient(u16 peer_id)
4330 DSTACK(__FUNCTION_NAME);
4331 //JMutexAutoLock lock(m_con_mutex);
4332 core::map<u16, RemoteClient*>::Node *n;
4333 n = m_clients.find(peer_id);
4334 // A client should exist for all peers
4336 return n->getValue();
4339 std::wstring Server::getStatusString()
4341 std::wostringstream os(std::ios_base::binary);
4344 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4346 os<<L", uptime="<<m_uptime.get();
4347 // Information about clients
4349 for(core::map<u16, RemoteClient*>::Iterator
4350 i = m_clients.getIterator();
4351 i.atEnd() == false; i++)
4353 // Get client and check that it is valid
4354 RemoteClient *client = i.getNode()->getValue();
4355 assert(client->peer_id == i.getNode()->getKey());
4356 if(client->serialization_version == SER_FMT_VER_INVALID)
4359 Player *player = m_env->getPlayer(client->peer_id);
4360 // Get name of player
4361 std::wstring name = L"unknown";
4363 name = narrow_to_wide(player->getName());
4364 // Add name to information string
4368 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4369 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4370 if(g_settings->get("motd") != "")
4371 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4375 // Saves g_settings to configpath given at initialization
4376 void Server::saveConfig()
4378 if(m_configpath != "")
4379 g_settings->updateConfigFile(m_configpath.c_str());
4382 void Server::notifyPlayer(const char *name, const std::wstring msg)
4384 Player *player = m_env->getPlayer(name);
4387 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4390 void Server::notifyPlayers(const std::wstring msg)
4392 BroadcastChatMessage(msg);
4395 // IGameDef interface
4397 IToolDefManager* Server::getToolDefManager()
4401 INodeDefManager* Server::getNodeDefManager()
4405 ITextureSource* Server::getTextureSource()
4410 IWritableToolDefManager* Server::getWritableToolDefManager()
4414 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4419 v3f findSpawnPos(ServerMap &map)
4421 //return v3f(50,50,50)*BS;
4426 nodepos = v2s16(0,0);
4431 // Try to find a good place a few times
4432 for(s32 i=0; i<1000; i++)
4435 // We're going to try to throw the player to this position
4436 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4437 -range + (myrand()%(range*2)));
4438 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4439 // Get ground height at point (fallbacks to heightmap function)
4440 s16 groundheight = map.findGroundLevel(nodepos2d);
4441 // Don't go underwater
4442 if(groundheight < WATER_LEVEL)
4444 //infostream<<"-> Underwater"<<std::endl;
4447 // Don't go to high places
4448 if(groundheight > WATER_LEVEL + 4)
4450 //infostream<<"-> Underwater"<<std::endl;
4454 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4455 bool is_good = false;
4457 for(s32 i=0; i<10; i++){
4458 v3s16 blockpos = getNodeBlockPos(nodepos);
4459 map.emergeBlock(blockpos, true);
4460 MapNode n = map.getNodeNoEx(nodepos);
4461 if(n.getContent() == CONTENT_AIR){
4472 // Found a good place
4473 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4479 return intToFloat(nodepos, BS);
4482 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4485 Try to get an existing player
4487 Player *player = m_env->getPlayer(name);
4490 // If player is already connected, cancel
4491 if(player->peer_id != 0)
4493 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4498 player->peer_id = peer_id;
4500 // Reset inventory to creative if in creative mode
4501 if(g_settings->getBool("creative_mode"))
4503 // Warning: double code below
4504 // Backup actual inventory
4505 player->inventory_backup = new Inventory();
4506 *(player->inventory_backup) = player->inventory;
4507 // Set creative inventory
4508 craft_set_creative_inventory(player, this);
4515 If player with the wanted peer_id already exists, cancel.
4517 if(m_env->getPlayer(peer_id) != NULL)
4519 infostream<<"emergePlayer(): Player with wrong name but same"
4520 " peer_id already exists"<<std::endl;
4528 // Add authentication stuff
4529 m_authmanager.add(name);
4530 m_authmanager.setPassword(name, password);
4531 m_authmanager.setPrivs(name,
4532 stringToPrivs(g_settings->get("default_privs")));
4538 infostream<<"Server: Finding spawn place for player \""
4539 <<name<<"\""<<std::endl;
4541 v3f pos = findSpawnPos(m_env->getServerMap());
4543 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4546 Add player to environment
4549 m_env->addPlayer(player);
4552 Add stuff to inventory
4555 if(g_settings->getBool("creative_mode"))
4557 // Warning: double code above
4558 // Backup actual inventory
4559 player->inventory_backup = new Inventory();
4560 *(player->inventory_backup) = player->inventory;
4561 // Set creative inventory
4562 craft_set_creative_inventory(player, this);
4564 else if(g_settings->getBool("give_initial_stuff"))
4566 craft_give_initial_stuff(player, this);
4571 } // create new player
4574 void Server::handlePeerChange(PeerChange &c)
4576 JMutexAutoLock envlock(m_env_mutex);
4577 JMutexAutoLock conlock(m_con_mutex);
4579 if(c.type == PEER_ADDED)
4586 core::map<u16, RemoteClient*>::Node *n;
4587 n = m_clients.find(c.peer_id);
4588 // The client shouldn't already exist
4592 RemoteClient *client = new RemoteClient();
4593 client->peer_id = c.peer_id;
4594 m_clients.insert(client->peer_id, client);
4597 else if(c.type == PEER_REMOVED)
4604 core::map<u16, RemoteClient*>::Node *n;
4605 n = m_clients.find(c.peer_id);
4606 // The client should exist
4610 Mark objects to be not known by the client
4612 RemoteClient *client = n->getValue();
4614 for(core::map<u16, bool>::Iterator
4615 i = client->m_known_objects.getIterator();
4616 i.atEnd()==false; i++)
4619 u16 id = i.getNode()->getKey();
4620 ServerActiveObject* obj = m_env->getActiveObject(id);
4622 if(obj && obj->m_known_by_count > 0)
4623 obj->m_known_by_count--;
4626 // Collect information about leaving in chat
4627 std::wstring message;
4629 Player *player = m_env->getPlayer(c.peer_id);
4632 std::wstring name = narrow_to_wide(player->getName());
4635 message += L" left game";
4637 message += L" (timed out)";
4643 m_env->removePlayer(c.peer_id);
4646 // Set player client disconnected
4648 Player *player = m_env->getPlayer(c.peer_id);
4650 player->peer_id = 0;
4657 std::ostringstream os(std::ios_base::binary);
4658 for(core::map<u16, RemoteClient*>::Iterator
4659 i = m_clients.getIterator();
4660 i.atEnd() == false; i++)
4662 RemoteClient *client = i.getNode()->getValue();
4663 assert(client->peer_id == i.getNode()->getKey());
4664 if(client->serialization_version == SER_FMT_VER_INVALID)
4667 Player *player = m_env->getPlayer(client->peer_id);
4670 // Get name of player
4671 os<<player->getName()<<" ";
4674 actionstream<<player->getName()<<" "
4675 <<(c.timeout?"times out.":"leaves game.")
4676 <<" List of players: "
4677 <<os.str()<<std::endl;
4682 delete m_clients[c.peer_id];
4683 m_clients.remove(c.peer_id);
4685 // Send player info to all remaining clients
4688 // Send leave chat message to all remaining clients
4689 BroadcastChatMessage(message);
4698 void Server::handlePeerChanges()
4700 while(m_peer_change_queue.size() > 0)
4702 PeerChange c = m_peer_change_queue.pop_front();
4704 infostream<<"Server: Handling peer change: "
4705 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4708 handlePeerChange(c);
4712 u64 Server::getPlayerPrivs(Player *player)
4716 std::string playername = player->getName();
4717 // Local player gets all privileges regardless of
4718 // what's set on their account.
4719 if(g_settings->get("name") == playername)
4725 return getPlayerAuthPrivs(playername);
4729 void dedicated_server_loop(Server &server, bool &kill)
4731 DSTACK(__FUNCTION_NAME);
4733 infostream<<DTIME<<std::endl;
4734 infostream<<"========================"<<std::endl;
4735 infostream<<"Running dedicated server"<<std::endl;
4736 infostream<<"========================"<<std::endl;
4737 infostream<<std::endl;
4739 IntervalLimiter m_profiler_interval;
4743 // This is kind of a hack but can be done like this
4744 // because server.step() is very light
4746 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4751 if(server.getShutdownRequested() || kill)
4753 infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4760 float profiler_print_interval =
4761 g_settings->getFloat("profiler_print_interval");
4762 if(profiler_print_interval != 0)
4764 if(m_profiler_interval.step(0.030, profiler_print_interval))
4766 infostream<<"Profiler:"<<std::endl;
4767 g_profiler->print(infostream);
4768 g_profiler->clear();
4775 static int counter = 0;
4781 core::list<PlayerInfo> list = server.getPlayerInfo();
4782 core::list<PlayerInfo>::Iterator i;
4783 static u32 sum_old = 0;
4784 u32 sum = PIChecksum(list);
4787 infostream<<DTIME<<"Player info:"<<std::endl;
4788 for(i=list.begin(); i!=list.end(); i++)
4790 i->PrintLine(&infostream);